agentleFS
jerseycheesejerseycheese/agent-skills/skills/backlog-routing/SKILL.md

backlog-routing

Skill4 starsChanged 16 days agoMITView on GitHub

Works a GitHub milestone with several agents at once: intake findings as issues, shape and batch the milestone, route batches to the cheapest capable model, dispatch, review, release. Merge authority comes from the repo adapter. Trigger on: "route the backlog", "plan the milestone", "dispatch the batches", "file issues from my playtest notes".

The file

Show its rules and text

We split this skill into the rules it gives an agent

18 rules. About 0 are common, 11 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈11

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Don't re-implement any of those here.

    line 30
  2. Very specific:

    Every repo that uses this needs an adapter skill (for example <repo>-backlog-routing).

    line 38
  3. Distinctive:

    Wait for the OK, then create or update the milestone and set membership.

    line 116
  4. Distinctive:

    put both issues in one batch, or

    line 136
  5. Very specific:

    Keep needs-local issues together, so the local check happens once.

    line 142
  6. Very specific:

    If new issues land in the milestone mid-run, re-run plan.

    line 153
  7. Very specific:

    Before launching, show the route block for each batch in the wave and wait for the user's OK.

    line 161
  8. Distinctive:

    When no other-family seat is routed for review, the adapter's reviewer is the second family on its own, as long as it isn't the family …

    line 197
  9. Distinctive:

    Verify every finding yourself before relaying it.

    line 203
  10. Distinctive:

    When the PR is green with no unanswered verified findings, check the merge policy.

    line 229
  11. Distinctive:

    Add the PR to the tracker's Review queue with:

    line 235
  12. Distinctive:

    Keep a check-in scheduled (roughly hourly) while any batch PR is open.

    line 258
  13. Distinctive:

    After it merges, hand the human the adapter's human-only release steps (tag, promoting the release branch, publishing the release) as text.

    line 268
  14. Very specific:

    Lane count comes from the window: When route says the right seat is tight, run fewer lanes in the wave rather than moving batches to a …

    line 294
  15. Distinctive:

    No lane uses a notification-wait tool to watch CI.

    line 324
  16. Very specific:

    Keep one canonical file and symlink the others locally rather than keeping copies.

    line 332
  17. Distinctive:

    Every card links out to GitHub.

    line 354
  18. Very specific:

    Keeping it accurate: Every stage that edits the tracker rewrites the state block in the same edit, and bumps updated.

    line 356

≈ “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

Backlog routing

The job is throughput without losing control. Lots of agents, each on the cheapest model that can actually do its piece, none of them stepping on each other, and nothing merged unless the repo's merge policy allows it. By default that means the human reads every PR first.

It's built from skills that already exist. This one decides what runs where, in what order, on which model. The rest is delegated:

NeedDelegate to
Which provider and modelroute (your routing table plus current burn)
Rankingprioritize-issues
Labels, dedupe, clusteringissue-maintenance
Visual finding triagevisual-qa-pipeline (its severity ladder)
Work inside a laneanalyze-issue → tdd-implement → ship-issue steps 1–5
CI redci-fix-with-memory
After mergepost-merge
Claims of doneevidence-check

Don't re-implement any of those here.

Requirements. GitHub for issues, milestones, sub-issues and PRs (gh, or a GitHub MCP server). Any agent host works for the orchestrator. Where this skill names a specific tool (Claude Code, Codex, Antigravity), it's an example of a kind of lane, not a requirement.

0. The adapter comes first

Every repo that uses this needs an adapter skill (for example <repo>-backlog-routing). Read it before any stage. If there's no adapter, stop and write one first, using the contract below. Don't guess a repo's gate commands or release process.

The adapter supplies:

  • Base branch and any branch that's off limits (a release-only main, say).
  • Gate commands a lane must show passing, and which extra gates trigger on which kinds of change.
  • Local-only criteria: what can't be proven in a cloud container (OS-specific visual baselines, live API keys that live in the user's browser, a human walking a flow, headful playtests).
  • Merge policy: who merges, and what must be shown first. With no policy the default is human-only: no agent merges, approves, or enables auto-merge. An adapter can give merging to the orchestrator for the PRs it names (say, everything except drafts and PRs with a Local check), and lists the conditions to show first (gates, CI, a clean review gate). It also names the second reviewer (a bot, or a seat the orchestrator drives), how long to wait for a bot, and the --bot profile the review scripts take for it (none means bot reviews don't count).
  • Milestone and release convention: how milestones are named, what a release PR contains, which release steps belong to the human.
  • Label names for type, priority, size, model tier, and the two this skill needs (needs-local, run-tracker). Use only labels that exist in the repo.
  • PR template path and any rule about rendering it.
  • Trap list: failure modes lanes have actually hit in this repo. It goes into every brief.

1. Hard rules (every stage)

  • Merge authority comes from the adapter; the default is the human. With no merge policy, never merge, never approve, never enable auto-merge. With one, merge only the PRs it names, only once a tool result shows every condition it lists, and only from the review gate. Approving and enabling auto-merge count as merging. Lanes never merge. Never push to or open PRs against a branch the adapter marks off limits.
  • Each stage runs when asked. Finishing one stage doesn't start the next unless the user said to chain them. A merge policy that lets the orchestrator merge is that instruction for close-out: it runs after each merge the orchestrator makes.
  • Stages that create things are dry-run first. intake and shape show what they'd write and wait for an OK. dispatch shows what it's about to launch.
  • Claims need proof. "Green", "merged", "done" point at a tool result (a check run, a gate output, a diff). See evidence-check.

2. Stages

Invoke as backlog-routing <stage> [args].

intake <notes | screenshots | log | issue list>

Turn raw findings into issues the later stages can route.

  1. Split the input into one finding per problem. Visual and UX findings go through visual-qa-pipeline's severity ladder:
    • Critical and Major get their own issue.
    • Minor and cosmetic ones go into one roll-up issue with a checkbox each.
  2. Dedupe each finding against open issues (semantic search plus a title search). If it matches an existing issue, propose a comment on that issue instead of a new one.
  3. Draft each issue with the repo's template (the adapter can name one for playtest findings), plus two sections:
    • Likely files: grep for the component, route, or class name and list the real paths. plan uses these for collision checks, so a guess here costs a conflict later.
    • How to prove it: the gate or local check that shows it's fixed. If only a local check can prove it, add needs-local.
  4. Labels: type, priority, size, and model tier, using the repo's definitions. Tier is reasoning difficulty, not size.
  5. Suggest a milestone, or an epic parent, for each.
  6. Show the whole batch as a table. File only after the user says so. For an epic parent, attach children with the sub-issue API.

shape <milestone>

Propose what goes in a milestone and in what order.

  1. Rank candidates with prioritize-issues. Put anything the user explicitly named first.
  2. Leave out:
    • issues blocked by something outside the milestone
    • issues held in their body ("lands after", "needs a decision")
    • frontier-tier issues, unless the user wants them in and accepts they run in the orchestrator or by hand
  3. Epics. An epic can span milestones. Pull in only the children that are ready, and state the epic's progress in the proposal ("#N: 2 of 5 children in this milestone").
  4. Draft the milestone description: what it's for, the ordered list of issues, and what's out of scope. That description is the contract the later stages plan against.
  5. Wait for the OK, then create or update the milestone and set membership.

plan <milestone>

Turn the milestone into waves of batches, and write the run tracker.

  1. Load state.
    • Open issues in the milestone, with bodies and comments. The run-tracker issue isn't work: leave it out of batching, and if one already exists, update it in place instead of making another.
    • Open PRs, and branches matching the batch prefix or an issue number. Anything already in motion is excluded. A leftover branch or worktree isn't proof it was abandoned: ask.
  2. Dependencies.

    • Blocked-by and sub-issue order.
    • "Lands with/after" text in bodies.
    • Draft or held PRs.

    Anything whose dependency is still open goes to a later wave.

  3. Collisions. Intersect the likely-file sets pairwise (re-grep if an issue lacks them). Shared templates, shared CSS, and config files are the usual culprits. For each overlap, either:

    • put both issues in one batch, or
    • name one owner, and tell the other batch in writing to leave that file alone.

    Trial merges prove nothing: conflicts show up after the first merge lands.

  4. Batch. Group issues that share a domain and file set, so each batch is one reviewable PR:
    • Aim for 1–4 issues and a diff a person can read in one sitting.
    • Keep needs-local issues together, so the local check happens once.
  5. Route each batch through route (section 3). That gives each batch a seat, a brief shape (one brief, or one per issue), and a run location. It also gives each wave a lane count that fits the 5-hour window. If route says to wait for a reset, the wave waits.
  6. Write the tracker from templates/tracker.md, as an issue labeled run-tracker in the milestone. For each batch it holds:

    • the waves and the collision owners
    • a brief, rendered from templates/brief.md

    The tracker is where the live state lives, so no manifest gets committed per run. Fill in its backlog-routing:state block too (section 6).

  7. If new issues land in the milestone mid-run, re-run plan. It re-plans the waves that haven't started and leaves running batches alone.

dispatch <milestone> [wave]

Launch a wave. Start only batches whose dependencies are merged, and say which ones are waiting on what.

Before launching, show the route block for each batch in the wave and wait for the user's OK. route recommends; the user decides. Then, by seat:

  • Paste-brief lanes (tools the orchestrator can't launch, such as Antigravity or the Codex CLI). Pin the brief (or briefs) in the tracker as copy-paste blocks, and tell the user which tool and model to paste each into. On a seat that drops multi-issue briefs, a batch of N issues becomes N briefs run one after another on the same branch, each naming one issue. Those tools can't be launched from here, so the batch rejoins the system through its branch name and PR (section 4).
  • Local agent sessions. A task the user starts on their machine in a worktree, carrying the brief. Use a suggested-task card if the host has them, otherwise a printed prompt. In Claude Code, sub-lanes inside a session use the in-harness Agent tool with a model override; child claude -p processes don't work as lanes.
  • Cloud agent sessions. One cloud session per batch, created with the routed model, whose first message sets the goal condition and then gives the brief (/goal <condition> in Claude Code). Prefer a session per batch over worktrees in one container, so parallel installs don't run out of disk. A cloud session spends the same subscription window as local use of that provider. Use one only when route puts the batch on that provider and its proof doesn't need anything local-only.
  • Record each launch in the tracker (batch, seat, session or card link, time started), and set the batch's status to dispatched with dispatchedAt in the state block. Log each route with route's logger, passing the chosen seat whenever it differs from the recommendation.

review gate

Runs on each batch PR once CI is green on its head.

  1. Two reviewers from different model families where available:

    • the seat route picks for the code review phase, which must not be the family that wrote the batch
    • a second reviewer the adapter names. It can be a review bot the repo already runs, or a seat the orchestrator drives, in which case nothing posts on its own: the orchestrator sends it a read-only review brief naming the PR and head sha, and the reviewer writes its findings somewhere the orchestrator can read. The adapter also says which to use when more than one is available, and what to do when one can't run.

    When no other-family seat is routed for review, the adapter's reviewer is the second family on its own, as long as it isn't the family writing the lanes. A review of the head has to exist: a missing one means the gate hasn't passed. For a bot, the adapter says how long to wait. If no reviewer can run, the PR goes to the human with "other-family review missing" on its queue line.

    Security, concurrency, and architectural diffs get the table's escalation seat.

  2. Verify every finding yourself before relaying it. Check that it still applies at the PR head, since the lane may already have fixed it. Relay only real findings to the batch, which fixes them and pushes. Then record the outcome, by who wrote the review:

    • Orchestrator-posted review (a seat the orchestrator drives). Post the verified findings and the sha you reviewed as one PR comment with scripts/post-review.sh <pr> <sha> <open> <reviewer>, the findings on stdin. It refuses a sha that isn't the current head. <open> is how many still need a fix. A fix push makes the comment stale, so the next round posts a new one, and the newest comment naming the head wins. A finding you dismissed as not real stays out of the comment.
    • Bot review threads. Clear each thread you've verified, fixed or not real, with scripts/resolve-thread.sh --bot <name> <thread-id> <sha>. It replies on the thread pointing at the commit (the fix, or the head you verified against when the finding isn't real) and resolves it. It refuses any thread that bot didn't start or that isn't on an open PR in this repo. A finding stays open until someone does. A bot that posts findings after you stopped relying on it is still answered this way.

    scripts/pr-ready.sh [--bot <name>] <pr> does the mechanical part. It prints 6 lines (head sha, CI, draft, the review, unresolved bot findings with thread ids and outdated ones flagged, mergeable state) and exits 0 only when all of them pass. The review line passes on the newest orchestrator-posted comment naming the head with 0 open findings, from the account gh runs as. A review bot counts only when the adapter opts into it with --bot (bundled profile: codex, the Codex GitHub connector; another bot needs a profile added to both scripts). Then its summary with every row Completed on the head sha also passes, a summary still running blocks, a failed one (a usage limit, say) counts as no bot review, and its unresolved threads are findings. A stale summary or comment (a push landed after it; bots don't re-review on push) or no review at all fails.

  3. When the PR is green with no unanswered verified findings, check the merge policy.
    • The orchestrator merges. The policy names this kind of PR. Show each condition it lists with a tool result, merge pinned to the head you checked (gh pr merge --match-head-commit <sha>), then run close-out. If the head moved, run the review gate again. A condition you can't show means the human's case below.
    • The human merges. That's the default, and the policy for anything it keeps with them. Add the PR to the tracker's Review queue with:

      • the link
      • one line on what changed
      • what proves it (the check run, gate output)
      • the Local check before merge steps, if any

      Set the batch's pr and status in the state block, and localCheck if one is needed. Then tell the user. That queue is the human's inbox.

close-out

Runs after each merge, whoever makes it.

  1. post-merge for the linked issues: close with a completion comment and tick the acceptance criteria.
  2. Mark the batch merged in the tracker and its state block. Check squash merges by content, not ancestry.
  3. Check every issue actually shipped. For each issue the batch named, confirm the merged PR closes it and its diff touches that issue's files. On a seat known to drop work, a batch can merge with one issue silently skipped. Put any dropped issue back into plan, and note what the recovery cost in the tracker, so the routing table's recovery rule has data behind it.
  4. Dispatch whatever that merge unblocked, if the user has said to keep the wave rolling. Otherwise list what's now ready.
  5. Keep a check-in scheduled (roughly hourly) while any batch PR is open. A quiet check-in writes nothing.

release <milestone>

Runs when the only open issue left in the milestone is the run-tracker issue. This stage closes the tracker at the end.

  1. Open the release-prep PR the adapter describes (release notes entry, version bump) against the base branch.
  2. After it merges, hand the human the adapter's human-only release steps (tag, promoting the release branch, publishing the release) as text. Never run them.
  3. Close the tracker and the milestone. Update epic progress on parents with children in later milestones.

3. Routing

route makes the call, not this skill. Your routing table (see the route skill's setup) already says which seat leads each phase of work, and route adds current burn. Keeping a second table here would drift from yours. So for each batch, pass route the phase and the shape:

Stage or workPhase to pass route
intake, shape, planplanning, specs, architecture
a batch of independent issuesbulk implementation
a wave of independent batchessimple parallel dispatch
batches that depend on each other, or need re-planning mid-runcomplex orchestration
review gatecode review
a batch whose CI stays redroot-cause debugging
close-out, release, tracker upkeepanything unnamed

Also pass: how many issues the batch holds, how many batches run at once, and whether it's a autonomous goal run. Those decide which usage window the work spends and whether a brief has to be split.

Rules that stay here:

  • Lane count comes from the window. When route says the right seat is tight, run fewer lanes in the wave rather than moving batches to a scarcer seat.
  • Run location. local when a batch has a needs-local issue, when its proof needs anything the adapter lists as local-only, or when route puts it on a local-only tool (Antigravity, Codex CLI). Otherwise cloud.
  • Keep the orchestrator light. The stages here are mostly mechanical, so run them on the table's default seat, and escalate only for a genuinely hard plan. Run them where route can read burn, usually the user's machine. A cloud orchestrator has to ask for a burn reading.
  • Cross-family review. The family that wrote a batch doesn't review it.
  • Record the lane in the PR body with a Lane: <provider>/<model>, <cloud|local> line, so the human can see who did what.

Fallback, only when route can't run at all (no table on this machine, no reading from the user). Use the issue's model-tier label, say the pick has no usage data behind it, and prefer the highest-throughput seat for implementation:

Tier labelFallback seat
light, standardthe table's bulk-implementation seat, one issue per brief
advanceda strong reasoning seat
frontiernot batched: the orchestrator or the human

4. Conventions every lane follows

  • Branch batch/<milestone>-<slug> off the adapter's base branch, fresh from the remote. Never a stale local checkout.
  • One PR per batch, body rendered from the repo's template, with every covered issue linked (Closes #n).
  • The brief's goal condition has to be something the session can show in its own output: gate commands passing, the check run green, threads answered. It can't be "the code is good".
  • No lane uses a notification-wait tool to watch CI. Poll with a blocking loop, or end the turn and let the PR subscription wake it.
  • One issue per brief on seats that drop work. A multi-issue batch on such a seat runs as one brief per issue on the shared branch. Each brief says which issues earlier briefs already handled, and names its own issue only.
  • A lane that dies after pushing may still have left a PR. Check the branch and PR head before re-dispatching, and resume the old session rather than starting fresh.
  • Each tool reads its own instruction file (CLAUDE.md, AGENTS.md, GEMINI.md, and so on). Keep one canonical file and symlink the others locally rather than keeping copies. Shared skills go in .agents/skills/; see skill-parity.

5. Templates

  • templates/brief.md: the per-batch brief, vendor-neutral, pasteable anywhere.
  • templates/tracker.md: the run tracker issue body.
  • templates/intake-issue.md: the extra sections intake adds to every issue.

6. Dashboard

dashboard/index.html is a read-only board for a run: one self-contained page, no build step, no backend. It reads the tracker's backlog-routing:state block, then layers live GitHub state on top: PR state, CI on the PR head, review decisions, unresolved threads, and milestone progress. It flags what needs a look:

  • a batch dispatched more than 6 hours ago with no PR (possibly dropped)
  • red CI or a merge conflict
  • a merged batch whose issues are still open
  • a batch/<milestone>-* PR the tracker doesn't know about
  • a state block that hasn't been updated in 2 hours while batches are open

Every card links out to GitHub. Reviewing and merging still happen there.

Keeping it accurate. Every stage that edits the tracker rewrites the state block in the same edit, and bumps updated. The block must stay valid JSON; the page shows a parse error rather than guessing.

Opening it.

  • Locally: open the file with ?repo=owner/name&milestone=vX.Y on the end. ?demo=1 shows a sample run.
  • Hosted: turn on GitHub Pages for the repo that holds this skill, and open …/skills/backlog-routing/dashboard/?repo=…&milestone=…, from a phone too.

Token. Optional, pasted into Settings, stored only in that browser. Use a fine-grained, read-only token with Issues, Pull requests and Checks (or Commit statuses) read access on the repo. Without one, the page works on public repos only (about 60 requests an hour, manual refresh) and can't count unresolved review threads.

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.