agentleFS
simiancraftsimiancraft/simiancraft-skills/skills/burn-down-github-issues/SKILL.md

burn-down-github-issues

Skill8 starsChanged 4 months agoMITView on GitHub

Run an unattended burndown of a GitHub issue backlog as cards on a per-operator GitHub Projects board whose lanes are an explicit state machine: appraise and size the inbox, carve what is over the ceiling, fix the ready ones in parallel git worktrees, prove each fix on a draft pull request, have an isolated second-engine reviewer judge it, land one branch at a time with freshness checks, and dead-letter per phase whatever a machine cannot finish. Use when the task is "work the backlog unattended", "triage and fix recent issues", "run the issue loop", "burn down issues", or "where is issue N on the board". Requires a per-repository burn-down-github-issues.config.ts at the target repo's root (the loop refuses to start without it), the prove-work-on-github skill, the codex and claude CLIs for the default seats, and a gh token with the project scope for the board. Skip for one-off fixes to a known issue you are already working interactively, and for backlogs whose issues are mostly product decisions rather than code.

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Appraises the Inbox: Read-only seats size each card.

    line 120
  2. Very specific:

    Every burndown is resumed from a GitHub Projects board named <project>_burndown_<operator> (acme-app_burndown_the-simian, say), owned by …

    line 136
  3. Very specific:

    When a seat raises a question nobody has ruled on (needs-decision), the card does not park straight away.

    line 160
  4. Distinctive:

    Only two things park a card for a person: the merge boundary refusing an approved change, and the issue changing under the review.

    line 172

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Burn Down GitHub Issues

A burndown is a board. Every issue the loop touches is a card, every card is in exactly one lane (a column of the board; the fix pipeline also calls an issue's worktree its lane), and the lanes are the leaf states of a statechart (lib/machine.ts, in XState's vocabulary) that says which seat runs on a card in that lane, what it may decide, and where each decision moves the card. The board is a GitHub Projects board per operator per repository, so a person who starts a burndown comes back to their own board and the loop resumes from it; the console prints the same cards in the same words. The tracker holds the facts (labels, pull requests, claims, records); the board is a projection of those facts that a person can read at a glance, and every run starts by placing every card where its facts say before any seat moves one.

Seats are polymorphic. A seat is an engine running whatever prompt the card's lane calls for (appraiser, close confirmer, carver, cut confirmer, worker, worker in revision, reviewer), then letting go; the card's position is the only input that changes what a seat does. Three rules hold across every seat: the reviewer and the confirmers run on a different engine than the author seats, claims on the issue thread are the lock that keeps two seats off one card, and merging is the one serial lane. references/state-machine.md is the machine in prose.

The loop is shared; the repository is config. Nothing in this skill is copied into a repository. Everything true of a repository (remotes, branches, commands, path aliases, invalidation paths) lives in burn-down-github-issues.config.ts at that repository's root, and the loop refuses to start without one, naming the missing file and the fields it lacks.

Standards the loop enforces

These travel with the skill because an adopter cannot be assumed to have house rules of its own. The first three are enforced by the driver, so no prompt drift can lose them; the rest are written into the prompts and checked by the reviewer.

  • A failing or unfinished build never merges. The pull master waits on the pull request's checks at the last moment before merging and dead-letters the landing instead when they fail or never finish. A green local gate is not a substitute; the checks the pipeline runs are the ones that count.
  • Nothing lands except through a reviewed pull request. The loop never pushes to the base branch; the gated merge is the only write it makes there.
  • Upstream is more correct until the work is merged, and no seat begins on a stale lane. The base is fetched and merged forward before a fix starts, before proof is captured, before a revision, before a review, and before the merge; what lands is a head that contains everything upstream has. Whether proof or an approval survives a catch-up is decided by whether the base moved into the import closure of the work ("did the world move beneath us"); whether the catch-up happens is not.
  • Pushed history is merged forward, never rebased. Catch-ups merge the base into the branch, so nothing another reader has fetched is rewritten.
  • No agent or bot is an author or co-author. Authorship is for humans; the reviewer hard-blocks on it.
  • Claims carry receipts. Proof follows prove-work-on-github: pinned, resolvable, re-checkable by a stranger. Narrative alone never carries a load-bearing claim.
  • Commits and pull requests describe the code, not the process. Conventional Commits, imperative, facts only; any mention of agents, prompts, or local tooling is a block.
  • Shared services are never reset or reseeded to reproduce a claim, and servers bind per-issue ports; other lanes are reading that state as their own evidence.

Run it

From inside the target repository (any directory of it, including a worktree):

bun run <this-skill-dir>/board.ts                      # once per operator: find or create the board, verify it, record the pointer
bun run <this-skill-dir>/lanes.ts                      # write the 37 lanes and the Phase field onto that board; idempotent
bun run <this-skill-dir>/loop.ts --dry-run             # place every card, print the backlog by lane and what would run; no GitHub or working-tree write
bun run <this-skill-dir>/loop.ts --limit 3             # work three Ready cards
bun run <this-skill-dir>/loop.ts --max-points 5        # raise the size ceiling for this run only
bun run <this-skill-dir>/loop.ts --only 12,34          # restrict the run to these issues, whatever their age
bun run <this-skill-dir>/loop.ts --no-appraise         # skip the inbox; --appraise-limit N caps it instead
bun run <this-skill-dir>/loop.ts --closure <file>      # print the import closure; verifies pathAliases
bun run <this-skill-dir>/loop.ts --worker codex:gpt-5.6-sol --reviewer claude:claude-opus-5
bun run <this-skill-dir>/loop.ts --appraiser codex:gpt-5.6-sol --confirmer claude:claude-opus-5   # the sizing seats
bun run <this-skill-dir>/loop.ts --pulse 2             # console board every 2 minutes (default 5); --silent turns it off
bun run <this-skill-dir>/loop.ts --floor once          # walk the deployed base once and work no issue; also liveness, watch, drain
bun run <this-skill-dir>/watch.ts                      # follow the current run; --wait for its terminal lines only
bun run <this-skill-dir>/card.ts --issue <n> --show    # where one card is; --lane <key> moves it by hand, --lanes lists the table
bun run <this-skill-dir>/claim-race.ts --issue <n> --contenders 3 --rounds 3   # prove the claim lock on a loop/skip issue
bun run <fix-skill-dir>/fix.ts --issue <n> --redrive   # lift a dead letter or a park and continue its pull request
bun run <fix-skill-dir>/fix.ts --issue <n> --land      # land an approved pull request the merge boundary parked

claim-race.ts also reads --contend and --start <ms>, which the parent passes to each contender process it spawns (the shared release instant, in Unix milliseconds); they are not for direct use.

Everything an operator or agent does to a run is one of these commands. Watching in particular is watch.ts, never a tail/kill/pgrep pipeline; references/operating.md says why.

<this-skill-dir> is the filesystem path of this directory wherever the collection is checked out or installed; it is a path, not a skill name. The seat flags (--worker, --reviewer, --confirmer, --appraiser, --carver, --carve-confirmer, --callback-seat, and --walker) take engine[:model] specs resolved against the engine registry in ../fix-github-issue/lib/engines.ts. The config file sets the same seats and every loop knob (ageDays, maxPoints, autoMerge, limit, concurrency, and the rest); a flag beats the config for the run it is given on.

What a run does

  1. Repairs and reconciles. Half-written label transitions, merges a dead run never recorded, stranded pull requests with a trusted verdict, torn claims and pauses, and trunks whose tree moved outside the loop are all settled before anything new is selected.
  2. Places every card. Each open issue in the window, and each card already on the board, is put where its facts say: closed is Done, a hold label is its human lane, a loop/dlq: <phase> label is that phase's dead-letter lane, an open pull request is Drafted or Ready for review, a trunk is Epic, a blocker is a wait, a size within the ceiling is Ready, over it is To carve, and no size is the Inbox. Only cards whose lane differs are written. The console prints the backlog by lane.
  3. Appraises the Inbox. Read-only seats size each card; the card moves to Ready, To carve, Done (a confirmed close with a receipt), or a human lane. The size callback hands an oversized issue to the sibling carve-github-issue skill, which cuts it into children along its highest natural seam and holds the parent as an Epic while they move.
  4. Works Ready. Up to concurrency cards at once, each in its own worktree, each moving through Coding and Proving (two seats, code-github-issue then prove-github-issue, with the driver moving the card from the push and the pull request each leaves), Ready for review, Evidence under review, and the landing lanes to Merged; or back to Sent back on a rejection; or into a dead-letter or human lane when a machine gives up or a person is needed.
  5. Walks the floor and finishes. With floor configured, every merge went up onto the floor as it landed, and the loop has been walking the deployed base on its cadence, pausing the line when a walk found it wrong. The run walks on until its merges are verified there (or the drain window closes), then releases the instance lock. See references/floor.md.

The board

Every burndown is resumed from a GitHub Projects board named <project>_burndown_<operator> (acme-app_burndown_the-simian, say), owned by the repository's owner and linked to the repository. One board per operator per repository: the person who starts a burndown comes back to their own board and picks up where they left off, and two operators on one repository never share one. board.ts finds it or creates it, reads it back to verify, and writes the pointer to <worktreeRoot>/runs/board.json; the board is the state, the file is only where it is. Creating one needs the project token scope (gh auth refresh -h github.com -s project); reading needs only read:project, and the script names the missing scope instead of failing in GraphQL. See references/adopting.md, "The board".

The lanes are the loop's state machine drawn as kanban: one lane per state a card can be in, thirty-seven of them in eleven phases, with one dead-letter lane per phase, a panel lane where frontier models weigh a question before it parks, and three lanes only a person can move a card out of. The machine is data (lib/machine.ts), tested against the lane table, exportable to stately.ai/viz, and chartable with Graphviz; see references/state-machine.md. A Phase field on every card is the collapsed view, so a board grouped by Phase is the eleven-column summary and a later dashboard of every operator's burndown is a query over these boards, not a second state store.

A repository without a board runs the same loop: the placement is still computed and is still the queue; it is simply not written anywhere a person can look at between runs.

A decision panel before a person

When a seat raises a question nobody has ruled on (needs-decision), the card does not park straight away. The raising seat's model and two other frontier models on different engines each try to answer it from the code, the conventions, and the thread, without seeing one another, and each posts its review on the issue. If all three decide every question alike, on cited facts that are found in the base, the decisions are recorded on the issue and the card goes back to be appraised. Otherwise it parks as before, with the reviews and a receipt of what was decided and what is still open (lettered options) already on the thread. It runs only when three distinct models are reachable; configure it with panel (references/adopting.md) and read the lane in references/state-machine.md, "Panel".

Dead letters, per phase

Only two things park a card for a person: the merge boundary refusing an approved change, and the issue changing under the review. Everything a machine could not finish is a dead letter in its own phase's queue, carried on the issue as loop/dlq: appraisal, carve, work, review, or landing, with the reason on the thread and the same label on the pull request. Each queue is meant to be triaged differently (references/state-machine.md, "Dead letters"); today every one waits for a person, and the redrive is removing the label or fix.ts --redrive, which lifts the letter, counts the redrive on the issue as loop/redrives: N, and continues the pull request the work left rather than opening another.

Read next

NeedRead
Run one and watch it: identifying the driver, reading the console board, what is not a bug, what to check afterwards, landing a parked pull request by handreferences/operating.md
Adopt the loop in a repository: the config template, the two fields that actually bite, preconditions, the board and its token scope, first-run order, stopping a runreferences/adopting.md
How and why the loop works: the board as state, the placement as queue, the seats, the pool, crash recovery, known gapsreferences/architecture.md
The state machine the lanes draw: phases, every lane's entry actions and exits, reconcile precedence, the per-phase dead letters, the polymorphic pool, what the tests check, what is not built yetreferences/state-machine.md
Check what merged on the running environment: the floor block, the cadence, the walk and its ledger, the line it pauses, the callbacks, incidents, the drainreferences/floor.md
The fix pipeline itself: the verdict-file contract, the review budget, the merge boundary, staleness, resuming, the dead letters it writes../fix-github-issue/references/pipeline.md

Hard dependencies

  • The fix-github-issue skill, which owns the worker, the reviewer, and the pull master; the loop imports it by relative path and calls it once per Ready card. One named issue is that skill's fix.ts, not a flag here.
  • The appraise-github-issues and carve-github-issue skills, which own the appraisal and the knife; the loop renders their prompts and runs them in process.
  • The prove-work-on-github skill, loaded by name in the worker and reviewer prompts; the pull master's staleness rule implements its references/freshness-and-reproof.md.
  • The emoji-readout skill, whose renderer prints each floor walk.
  • With floor configured, the driver skill for its environment kind (playwright-harness for web, ios-simulator or android-emulator-harness for mobile), loaded by name in the walk prompt.
  • Bun, which runs loop.ts.
  • gh authenticated with push and merge rights on the target repository, and the project scope for the board.
  • The CLIs the seats name (by default codex and claude), on PATH. Keep worker and reviewer on different engines; a reviewer built from the same model as the author shares its blind spots by construction.

The ceiling, named

The loop executes the tracker, not your intent: an internally coherent issue pointing the wrong way is implemented competently in the wrong direction, and the only guard is the convention docs the config names. Issue bodies and comments are an untrusted instruction channel read by agents running with their approval gates bypassed; the worktree confinement is a prompt contract, not a sandbox, so run this only on trackers whose authors you trust as far as the credentials the loop holds. The merge boundary computes migration and ci from the diff's paths, but data and stored-string are runtime effects a path cannot reveal; for those it holds two independent self-reports and parks rather than trusts. The reviewer runs as the same GitHub account as the worker, so its independence is model-level, not identity-level. Instance locks identify their holder by pid, so a pid reused by an unrelated process reads as a live holder until that process exits. The pipeline still runs a Ready card from Coding to Merged inside one process, so the polymorphic pool is a fact at the driver's seams and a design past them (references/state-machine.md, "The agent pool"). And of the five dead-letter queues only the review queue has been exercised end to end, by a redrive that continued a parked pull request to a merge; the others are written, not proven.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.