agentsclimarketplace

Failure streak cooldown auto issue report

Skill kjuhwa/skills-hub/skills/observability/failure-streak-cooldown-auto-issue-report

When a long-running agent hits a repeating failure, file one GitHub issue — not ten — by combining a minimum-streak threshold, a per-error-signature cooldown, an open-issue search for de-duplication, and sanitized logs, then persist the decision in a local state file so the next run resumes the throttle.From its SKILL.md

Install
npx -y skills add kjuhwa/skills-hub --skill failure-streak-cooldown-auto-issue-report

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

4.2 KB, 908 tokens by cl100k_base, as published. Nobody here has run it

Auto Issue Reporting with Streak + Cooldown + De-dup

Problem: a daemon that self-repairs can enter a failure loop. You want one heads-up issue on the upstream repo, not a flood. The pattern below is the minimum that behaves well in production.

The four gates

Only file an issue if all four are true:

  1. Symptom gate — the failure-signal set contains either failure_loop_detected, or (recurring_error AND high_failure_ratio). Transient errors never file.
  2. Streak gate — the consecutive-failure counter is ≥ minStreak (default 5). Single flukes never file.
  3. Cooldown gatenow - lastReportedAt ≥ cooldownMs (default 24h) OR the current error signature is not in the recentIssueKeys ring buffer (last 20). So a brand-new failure mode bypasses the cooldown; a familiar one is suppressed.
  4. Open-issue gate — before POSTing, query GET /search/issues?q=repo:X is:issue is:open "<title>"; if an open match exists, record the hit but do not file a duplicate.

All gates default to "do not report." Missing GitHub token → silently skip.

Stable error key (for the cooldown ring)

Do not key cooldown on the full error message — it mutates. Instead:

const keyed = signals
  .filter(s => s.startsWith('recurring_errsig') || s.startsWith('ban_gene:')
            || s === 'recurring_error'         || s === 'failure_loop_detected'
            || s === 'high_failure_ratio')
  .sort()
  .join('|');
const errorKey = sha256(keyed || 'unknown').slice(0, 16);

A failure's "identity" is the sorted set of structural signals. Two manifestations of the same underlying bug produce the same 16-char key and collapse into one cooldown.

State persistence (survives restart)

// memory/evolution/issue_reporter_state.json
{
  "lastReportedAt": "2026-04-17T08:00:00.000Z",
  "recentIssueKeys": ["abc123...", "def456...", "..."],
  "lastIssueUrl": "https://github.com/owner/repo/issues/1234",
  "lastIssueNumber": 1234,
  "lastSkippedAt": "2026-04-18T02:30:00.000Z"
}

Ring size 20 is plenty — the cooldown window is longer than you'll ever accumulate distinct keys for.

Sanitization is non-optional

Every string that goes into the issue body passes through a redactor that masks tokens, absolute paths, emails, and anything resembling a secret. Truncate logs to the tail (slice(-2000)) — that's where the crash actually is, plus it bounds the blast radius of a sanitizer miss.

Also include sanitized-only fields:

  • Evolver/runtime version (fine)
  • Platform + arch (fine)
  • Truncated node id (abc1234567…)
  • Recent events as a table (reason column capped at 80 chars)

Never include: full PATH, full cwd, hostname, env dump.

Configurable envelope

Env varDefaultPurpose
EVOLVER_AUTO_ISSUEtrueKill switch
EVOLVER_ISSUE_REPOowner/repoTarget repository
EVOLVER_ISSUE_COOLDOWN_MS86400000Per-signature window
EVOLVER_ISSUE_MIN_STREAK5Minimum consecutive failures
GITHUB_TOKEN (or GH_TOKEN, GITHUB_PAT)Auth, resolved in that order

The token-env fallback chain matters: CI uses GITHUB_TOKEN, local dev uses GH_TOKEN or GITHUB_PAT. Accept all three.

Failure handling of the reporter itself

The issue poster is best-effort. Wrap the whole thing in try/catch; on failure, log one line and continue the main loop. Never let the observability subsystem wedge the thing being observed.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,499. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.