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".
In this repository34 other files it gives its agents.
- abstraction-finderSkill
- analyze-issueSkill
- band-aid-finderSkill
- browser-debugger-cliSkill
- ci-fix-with-memorySkill
- code-health-auditSkill
- comment-reaperSkill
- cyoaSkill
- dead-code-cleanupSkill
- doc-rotSkill
- drupal-mental-modelSkill
- ds-guardSkill
- evidence-checkSkill
- github-screenshotSkill
- issue-maintenanceSkill
- kissSkill
- plain-language-auditSkill
- post-mergeSkill
- prioritize-issuesSkill
- project-bootstrapSkill
- project-pulseSkill
- pr-review-fix-pipelineSkill
- routeSkill
- ship-issueSkill
- skill-paritySkill
- tdd-implementSkill
- test-fixSkill
- test-reaperSkill
- test-workflowSkill
- update-routingSkill
- visual-crawlSkill
- visual-qa-pipelineSkill
- worktree-enhancedSkill
- wrap-it-upSkill
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
- Distinctive: line 30
Don't re-implement any of those here.
- Very specific: line 38
Every repo that uses this needs an adapter skill (for example <repo>-backlog-routing).
- Distinctive: line 116
Wait for the OK, then create or update the milestone and set membership.
- Distinctive: line 136
put both issues in one batch, or
- Very specific: line 142
Keep needs-local issues together, so the local check happens once.
- Very specific: line 153
If new issues land in the milestone mid-run, re-run plan.
- Very specific: line 161
Before launching, show the route block for each batch in the wave and wait for the user's OK.
- Distinctive: line 197
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 …
- Distinctive: line 203
Verify every finding yourself before relaying it.
- Distinctive: line 229
When the PR is green with no unanswered verified findings, check the merge policy.
- Distinctive: line 235
Add the PR to the tracker's Review queue with:
- Distinctive: line 258
Keep a check-in scheduled (roughly hourly) while any batch PR is open.
- Distinctive: line 268
After it merges, hand the human the adapter's human-only release steps (tag, promoting the release branch, publishing the release) as text.
- Very specific: line 294
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 …
- Distinctive: line 324
No lane uses a notification-wait tool to watch CI.
- Very specific: line 332
Keep one canonical file and symlink the others locally rather than keeping copies.
- Distinctive: line 354
Every card links out to GitHub.
- Very specific: line 356
Keeping it accurate: Every stage that edits the tracker rewrites the state block in the same edit, and bumps updated.
≈ “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.
Files
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:
| Need | Delegate to |
| Which provider and model | route (your routing table plus current burn) |
| Ranking | prioritize-issues |
| Labels, dedupe, clustering | issue-maintenance |
| Visual finding triage | visual-qa-pipeline (its severity ladder) |
| Work inside a lane | analyze-issue → tdd-implement → ship-issue steps 1–5 |
| CI red | ci-fix-with-memory |
| After merge | post-merge |
| Claims of done | evidence-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
--botprofile 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.
intakeandshapeshow what they'd write and wait for an OK.dispatchshows 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.
- 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.
- 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.
- 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.
planuses 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.
- Likely files: grep for the component, route, or class name and list the real paths.
- Labels: type, priority, size, and model tier, using the repo's definitions. Tier is reasoning difficulty, not size.
- Suggest a milestone, or an epic parent, for each.
- 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.
- Rank candidates with
prioritize-issues. Put anything the user explicitly named first. - 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
- 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").
- 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.
- 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.
- Load state.
- Open issues in the milestone, with bodies and comments. The
run-trackerissue 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.
- Open issues in the milestone, with bodies and comments. The
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.
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.
- 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-localissues together, so the local check happens once.
- 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. Ifroutesays to wait for a reset, the wave waits. Write the tracker from
templates/tracker.md, as an issue labeledrun-trackerin 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:stateblock too (section 6).- 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
modeloverride; childclaude -pprocesses 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 whenrouteputs 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
statustodispatchedwithdispatchedAtin the state block. Log each route withroute'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.
Two reviewers from different model families where available:
- the seat
routepicks 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.
- the seat
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 accountghruns 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.- Orchestrator-posted review (a seat the orchestrator drives). Post the verified findings and the sha you
reviewed as one PR comment with
- 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
prandstatusin the state block, andlocalCheckif one is needed. Then tell the user. That queue is the human's inbox.
- 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 (
close-out
Runs after each merge, whoever makes it.
post-mergefor the linked issues: close with a completion comment and tick the acceptance criteria.- Mark the batch merged in the tracker and its state block. Check squash merges by content, not ancestry.
- 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. - Dispatch whatever that merge unblocked, if the user has said to keep the wave rolling. Otherwise list what's now ready.
- 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.
- Open the release-prep PR the adapter describes (release notes entry, version bump) against the base branch.
- 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.
- 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 work | Phase to pass route |
intake, shape, plan | planning, specs, architecture |
| a batch of independent issues | bulk implementation |
| a wave of independent batches | simple parallel dispatch |
| batches that depend on each other, or need re-planning mid-run | complex orchestration |
| review gate | code review |
| a batch whose CI stays red | root-cause debugging |
close-out, release, tracker upkeep | anything 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
routesays the right seat is tight, run fewer lanes in the wave rather than moving batches to a scarcer seat. - Run location.
localwhen a batch has aneeds-localissue, when its proof needs anything the adapter lists as local-only, or whenrouteputs it on a local-only tool (Antigravity, Codex CLI). Otherwisecloud. - 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 whereroutecan 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 label | Fallback seat |
| light, standard | the table's bulk-implementation seat, one issue per brief |
| advanced | a strong reasoning seat |
| frontier | not 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/; seeskill-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.Yon the end.?demo=1shows 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.
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
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.

