Dispatching Sub-Agents
This skill is the dispatch half of a multi-agent issue-orchestration system. It covers everything between "an issue is ready to work" and "a sub-agent has opened a PR": picking the issue, resolving model and effort, writing the brief, launching in parallel, recovering stalls, and verifying completions.
Companions in the same family: the issue-filing skill (gh-issue-filing for GitHub, jira-issue-filing for Jira) defines what a dispatchable issue looks like; the issue control-field skill (gh-issue-labels for GitHub labels, jira-issue-fields for Jira fields) defines the control taxonomy this skill reads; the issue-locking skill (gh-issue-locking / jira-issue-locking) defines the claim that must precede every dispatch; the orchestrating-slots skill runs the loop that calls this one; the driving-prs-to-merge skill defines what the agent owes after gh pr create.
Project bindings
Every value below is project-specific. The adopting project must define these in its own CLAUDE.md; this skill refers to them by placeholder. Do not copy the example column into a new project unverified.
| Binding | Placeholder | Example |
|---|---|---|
| Integration branch PRs target | <integration-branch> |
dev (NOT the default branch, so issue auto-close never fires — close explicitly on merge) |
| Repo root | <repo-root> |
resolve dynamically: git rev-parse --show-toplevel — hardcoding a path rots |
| Worktree location | <worktree-dir> |
<repo-root>/.worktrees/<name> (git-ignored) |
| Branch naming | <branch-convention> |
feat|fix|chore|docs/<N>-<slug> (encodes the issue number) |
| Commit message convention | <commit-convention> |
lowercase conventional-commit subject (lowercase because the project's title-format check may reject leading capitals); body ends with Closes #<N> |
| Toolchain prefix for git hooks | <toolchain-prefix> |
e.g. a runtime-version bootstrap such as source <version-manager> && use <version> && (empty if the project's hooks need no runtime bootstrap, or it has no hooks) |
| Lockfile-faithful install | <lockfile-install-cmd> |
the ecosystem's frozen-lockfile install (e.g. <pkg-manager> install --frozen-lockfile) |
| Force-push policy | <force-push-policy> |
sub-agents may force-push their own branch with --force-with-lease; orchestrator handles any case where permission-blocking applies |
| Derived files never committed | <derived-files> |
generated status/manifest files (regenerated by post-merge automation) |
| Model tiers | <cheap-model> / <workhorse-model> / <premium-models> |
haiku / sonnet / opus, fable |
| Auto-merge invocation | <auto-merge-cmd> |
gh pr merge <N> --auto — verify whether a strategy flag is accepted; some merge queues reject one and enrollment silently drops |
| Pre-push hook cost | <hook-cost> |
e.g. several minutes (full local unit suite) |
| Traceability scheme (optional) | <traceability-scheme> |
REQ-<PREFIX>-<NUMBER> tags in test names |
| Design source of truth (UI projects) | <design-source> |
the project's authoritative design artifacts (e.g. a checked-in design-system/ folder or a referenced design tool) |
| Test-layer menu | <test-layers> |
unit / integration / smoke / E2E |
| Bot reviewer(s) | <bot-reviewer> |
the project's automated PR-review bot, if any |
The operator login is never a binding: resolve it at session start with gh api user --jq .login. Hardcoded logins in dispatch templates are a documented hazard — a stale login can sit in a template for weeks while a different operator runs the sessions.
1. Selecting the next issue
Apply these rules in order; each exists because its violation has a known cost:
- Operator-tagged priority first. P0/P1 before P2/P3. The operator's triage outranks your assessment of interestingness.
- File-disjoint from in-flight PRs. If an open PR in the merge pipeline touches file X, do not pick an issue that also touches X. Two branches editing the same file produce rebase loops and merge-queue thrash — the second PR rebuilds its base every time the first advances.
- File-disjoint from running agents. If agent A is working file Y right now, agent B gets a non-Y issue. Same conflict mechanics, earlier in the pipeline. Build a quick conflict-zone map (issue → likely files, from the issue body and your repo knowledge) before each dispatch round.
- Bundle same-surface small fixes. If N tiny issues all touch the same file or module (e.g. four copy-string fixes in one component), bundle them into ONE dispatch and ONE PR carrying multiple
Closes #Nlines. Review cost is per-PR, not per-line: a 4-string-edit PR costs the same review effort as a 1-string-edit PR, and one PR can't conflict with itself. - Don't stack changes on a shared base file. Avoid dispatching a second change to the same enforcement-layer or shared-base file (a common handler base, a shared config) until the first PR actually merges — the second is built on a base the first is about to invalidate.
Tie-break: when in doubt, prefer the smaller issue. A 2-line copy fix shipping beats a 200-file refactor stalled.
After picking, read the issue's control fields — they drive model and effort selection:
gh issue view <N> --json labels
Skip anything carrying the project's hold marker (e.g. a do-not-dispatch label, or the equivalent status/field in Jira) — see the control-field skill. Holds must be honored from the machine-readable field, not just remembered from comments; explicit "do not implement" comments have failed to stop a dispatch that broke a deploy for hours.
2. Resolving model and effort
Resolve both from three sources, highest precedence first: (1) an explicit operator chat instruction for this dispatch always wins, even over the issue's control fields; (2) the issue's control fields (a model field like agent-model:*, an effort field like agent-effort:*) are the persistent per-issue knob; (3) defaults — <workhorse-model> for anything that writes or modifies code, <cheap-model> only for narrow mechanical tasks where errors are immediately visible, <premium-models> never on your own initiative. A premium-model setting counts as the operator's explicit instruction. If still ambiguous, default to <workhorse-model> and proceed. Pass the model explicitly on every Agent call. Effort has no API parameter — translate the field into a prose directive inside the brief. Full taxonomy, tier rationale, incident evidence, and the deliberate absence of a cheap-tier setting: see the control-field skill.
Premium-access fallback. If an issue carries a premium-model setting and your session cannot dispatch on that model, release the claim and leave the setting in place so an operator session with access picks it up. See the control-field skill for the full fallback steps.
3. Lock before dispatch
Claim the issue before spawning the agent, never after — the window between dispatch and lock is exactly when concurrent operators double-claim. The claim has three signals: the claim marker (<claim-label> or the tracker's claim field), the assignee set to your resolved operator login, and a machine-parseable lock comment. Re-verify the assignee list is empty immediately before locking; queue/status markers alone are not authoritative — a stale ready-to-dispatch marker has caused multiple double-locked issues. Full protocol, lock-comment format, and stale-expiry: see the issue-locking skill.
4. The dispatch brief — eight required sections
This is the core of the skill. Every section earned its place by a failure class that occurred when it was omitted. Include all eight; the toolchain and hygiene blocks go in verbatim (placeholders substituted), not summarized — they are "LEARNED FROM RESCUES" and their omission is the most-repeated source of failed pushes.
(a) Issue reference — the body is the spec
Tell the agent to read the issue first and treat it as the spec:
Run `gh issue view <N> --comments` (or the tracker's equivalent fetch)
and read the full issue and comment thread before writing any code.
The issue body is the spec.
Do not paraphrase the full body into the brief — paraphrased specs drift from the source of truth, and the agent then implements your summary instead of the requirement. Restate only the acceptance criteria (in section e) as a scope check.
(b) Working environment — fresh worktree off the freshly-fetched integration branch
Verbatim commands, placeholders substituted:
git -C <repo-root> fetch origin <integration-branch>
git -C <repo-root> worktree add \
<worktree-dir>/<descriptive-name> \
-b <branch-convention> origin/<integration-branch>
cd <worktree-dir>/<descriptive-name>
Never the primary checkout, never branched from whatever happens to be checked out. Agents that work in the primary checkout collide with the orchestrator and with each other; agents that branch from a stale or wrong base ship diffs full of unrelated changes. The branch name encodes the issue number so PRs, locks, and worktrees are mutually traceable.
(c) Toolchain prefix — hooks need the right runtime
If <toolchain-prefix> is non-empty, include the exact shell prefix that makes the project's git hooks runnable in a fresh non-interactive shell, and the rule that goes with it:
Every shell that runs `git commit` or `git push` must be prefixed with:
<toolchain-prefix>
Never use --no-verify. If a hook blocks you, fix what it is flagging.
Sub-agent shells are non-interactive; without the prefix the hook's runtime is missing, the hook fails confusingly, and the agent reaches for --no-verify — which ships exactly what the hook would have caught.
If <toolchain-prefix> is empty, state explicitly in the brief that no prefix is needed, but retain the --no-verify prohibition unconditionally.
(d) Pre-push hygiene — verbatim block
Include this block verbatim (substitute placeholders). Each rule is a previously-paid rescue:
PRE-PUSH HYGIENE (non-negotiable):
1. If the project runs pre-push verification hooks (<hook-cost>): ALWAYS
`git fetch origin <integration-branch> && git rebase
origin/<integration-branch>` immediately before your FIRST push —
never push on a stale base to "see if CI passes". If a sibling PR
merged shared files while you worked, pushing on a stale base burns
that entire run and the hook rejects you anyway for being behind.
Rebase FIRST, then push — every time, including the first.
2. After every rebase, run `<lockfile-install-cmd>` (if the ecosystem
has one) so new transitive dependencies from sibling merges are present
before any local verification runs. Missing-dependency failures (any
"not found" / "cannot find module" error your toolchain emits for an
undeclared dep) are the most common cause of post-rebase pre-push
failures.
3. Never commit <derived-files> — they are regenerated by post-merge
automation; committing them causes constant merge conflicts. Do not
`git rm` them either (they regenerate); just never `git add` them.
Stage only your code and intentional doc edits.
4. A branch whose commits have never been on origin takes plain
`git push -u origin <branch>` — NOT force. Force-push is only
legitimate after rebasing an existing remote branch, and then only
`--force-with-lease` — unless <force-push-policy> reserves force
pushes for the orchestrator, in which case STOP and report so the
orchestrator performs the push (see driving-prs-to-merge).
(e) Scope and constraints
- Restate the acceptance criteria in your own words (this is the only sanctioned paraphrase — it is a checklist, not the spec).
- Concrete file paths IN scope.
- File areas explicitly OUT of scope, including a do-not-edit list for files owned by other operators' or agents' in-flight work.
- Conflict-awareness notes naming which sibling in-flight PRs touch related files, so the agent steers around them.
- For UI work: name
<design-source>artifacts the agent must read and match. - Name the
<test-layers>layer the behaviour should be covered at — the cheapest layer that actually exercises it — and, if the project uses<traceability-scheme>, the ID the test must carry. - Forbid writes to shared append-only files (team learnings logs, changelogs) unless the issue is about them — they are chronic rebase-conflict generators when every agent appends.
(f) Git discipline — destructive ops banned, STOP-and-report on surprises
Include verbatim:
GIT DISCIPLINE:
- Commit after each logical step — do not save a single large commit
for the end. Per-step commits mean a stalled agent's worktree can be
salvaged and resumed from the last commit in minutes rather than
replaying the whole task from scratch.
- Never run `git reset --hard`, `git rebase -i`, `git checkout <other-branch>`,
or any history-destroying command.
- If git state ever looks unexpected (wrong branch, commits you don't
recognize, dirty files you didn't touch): STOP and report. Do not
"clean up".
- Stay inside your worktree for the entire task.
Why the reset ban: a confused agent that runs git reset --hard to "clean up" unexpected state can silently destroy prior commits; recovery then needs git fsck --unreachable. Cheaper to ban the command than to fish objects out of the GC.
(g) Verification and PR procedure
1. Run the project's local verification (lint, typecheck, tests for the
touched packages AND their dependents; include any coverage flags CI
enforces) and confirm green BEFORE committing the final state.
2. Commit per <commit-convention>; body ends with `Closes #<N>` (one
line per bundled issue).
3. Rebase + `<lockfile-install-cmd>` + push, per the pre-push hygiene block.
4. gh pr create --base <integration-branch> --head <branch> \
--title "<conventional title>" --body "<structured body with Closes #<N>>" \
--assignee "$(gh api user --jq .login)"
Add any labels the project requires at creation time.
5. Verify the PR landed with the correct assignee and labels:
gh pr view <PR#> --json assignees,labels
Repair via the REST API if anything is missing — never via `gh pr edit`
(can exit 0 yet persist nothing).
6. Enable auto-merge immediately: <auto-merge-cmd>
7. Drive the PR to green per the driving-prs-to-merge skill: respond to
every review thread including <bot-reviewer>'s, fix CI, stay rebased.
The assignee is what --assignee @me filters on when multiple operators run concurrently — author is automatic, assignee is the ownership signal. Auto-merge at open means the PR merges the moment gates clear with no babysitting; verify which invocation the project's branch protection accepts, because a merge queue can reject a strategy flag and silently drop enrollment (a project's two docs can disagree for exactly this reason).
(h) Return contract
Require the agent to report back, explicitly:
- PR number and URL.
- Files modified.
- Tests added/changed (count and layer), and the
<traceability-scheme>ID used if applicable. - Confirmation that the assignee and required labels are set, and that auto-merge is enabled (state which command was used).
- Final
git status --shortoutput from the worktree (proves nothing is left uncommitted). - Anything that needs operator clarification.
The return contract gives the orchestrator a clean handle for completion verification (section 7) and for the close-on-merge tick. Without it, agents end with a confident prose summary and the orchestrator has to forensically reconstruct what actually happened.
5. Parallel dispatch
If two or more selected issues are file-disjoint AND logically independent, dispatch them in the same message with multiple Agent calls so they run concurrently — serial dispatch of independent work wastes wall-clock time.
Default guideline when the operator has not set <slot-count>: 3–5 concurrent sub-agents. Above that, the merge pipeline backs up and every merge invalidates the other branches' bases — rebase-thrash cost exceeds the parallelism win. The authoritative cap is operator policy; see the orchestrating-slots skill. The cap bounds agents, not processes: each agent multiplies build-tool and test-runner concurrency, so on constrained machines also cap tool-level workers, or the host OOMs (unbounded parallelism has frozen a multi-GB workstation more than once this way). Slot accounting and event-driven refill belong to the orchestrating-slots skill.
6. Stalled-agent recovery
Sub-agents stall: runtime watchdogs kill them after a no-progress timeout (e.g. ~600s, often a transient infrastructure blip) and report status: failed. A failed status does not mean lost work — the agent's worktree retains all local changes. Treating a stall as a total loss wastes a full implementation cycle, so always audit before re-dispatching.
Audit the worktree
git -C <worktree-dir>/<name> log --oneline origin/<integration-branch>..HEAD
git -C <worktree-dir>/<name> status --short
Decide
| Worktree state | Action |
|---|---|
| Local commits, clean tree | Orchestrator finishes the job itself: rebase, <lockfile-install-cmd>, plain push, gh pr create + auto-merge per section (g) |
| Uncommitted changes | Stage code only (exclude <derived-files>), commit, then as above |
| No commits, no changes, or worktree gone | Re-dispatch fresh on a -v2 branch (below) |
Before any salvage push: fetch + rebase onto the integration branch + <lockfile-install-cmd>, then plain push — the same hygiene the agent would have owed. If multiple agents stalled at once, parallelize the installs and pushes, but only after per-branch confirmation that each working tree actually has the code intact; batch-pushing unverified worktrees ships partial work.
-v2 re-dispatch for irretrievable attempts
When the first attempt left nothing salvageable:
git -C <repo-root> worktree add <worktree-dir>/<name>-v2 \
-b <branch>-v2 origin/<integration-branch>
Include in the new brief: "A prior agent on this issue stalled before pushing and its worktree was cleaned up. Start fresh." The -v2 suffix avoids collisions with remote ghosts of the dead branch; the note prevents the new agent from being confused by residue. Do not redo the implementation yourself in this case — dispatch a fresh agent so the audit trail stays clean.
7. Verify, then trust — completion checks
Agent completion reports are optimistic. Observed failure modes, each with its check:
- Truncation at the final push/PR-open step (heavy pre-push hooks, token exhaustion — agents end mid-"Now open the PR:"). Check
gh pr list --head <branch>; if no PR, audit the worktree per section 6 and self-handle push + PR. Re-dispatching hits the same wall. - Push "success" that never landed. With pre-push hooks,
git pushexit 0 is unreliable from background shells. Verifygit ls-remote origin <branch>matches the worktree's HEAD. - Committed-but-unpushed fixes behind resolved review threads. Verify
git -C <worktree> log origin/<branch>..HEADis empty before trusting a "resolved" state — the queue will otherwise merge pre-fix code. - Dropped assignee or labels. Roughly a quarter of agents drop the mandated
--assigneeflag even when the brief bolds it. After every dispatch:gh pr view <N> --json assignees,labelsand repair via the API if missing (the REST assignee endpoint works even on merged PRs). Note thatgh pr editcan exit 0 yet persist nothing — verify withgh pr view --json <field>after any edit. - Summary that reads like a review, not an implementation. An implementer describing its own work as a "security review" or "analysis" is a tell that real work is sitting uncommitted in the worktree. Check
git statusimmediately. - Wrong branch / primary checkout drift. Verify the commits are on the expected branch in the expected worktree, not on the integration branch or the primary checkout.
Only after these checks does the PR enter the merge-driving phase — see the driving-prs-to-merge skill — and the issue gets closed on merge per the issue-locking skill's release protocol.
8. Anti-patterns
Never do these; each is a previously-paid failure:
- Dispatch on a premium model on your own initiative. Premium is operator-only, via chat or the issue's control field — "this looks complex" self-judgment inflates cost; the operator decides per dispatch.
- Refuse an operator's explicit premium request (chat or control field). Both over- and under-escalation break the cost contract; the setting IS the instruction.
- Ignore the issue's model/effort control fields (
agent-model:/agent-effort:or their tracker equivalents). They are the persistent operator control plane. - Dispatch without locking first. Concurrent operators double-claim in exactly that window.
- Dispatch two agents into the same file area (or against a file an in-queue PR touches). Conflicts are checked at selection time, not discovered at merge time.
- Omit the toolchain prefix or pre-push hygiene blocks from the brief. The agent will fail the push and you will pay the rescue cost.
- Tell an agent to
--no-verifypast a failing hook. The hook is real; fix what it is flagging. - Tell an agent to
git rmderived files. They regenerate; the fix is to nevergit addthem. - Hardcode an operator login in the brief template. Resolve via
gh api user --jq .loginand verify on the opened PR — hardcodes rot and agents drop flags. - Pause the round to ask which model to use when resolution is ambiguous. Default to
<workhorse-model>and proceed. - Redo a stalled agent's implementation yourself when nothing is salvageable. Re-dispatch on
-v2; keep the audit trail clean. - Trust a completion report without the section-7 checks. Verify PR existence, remote HEAD, assignee, and worktree cleanliness every time.
Token discipline: caveman for ops, humanizer for prose
This skill runs in high-volume, repetitive orchestration loops where tokens compound across many rounds and many agents. Operate in caveman mode (load the caveman skill) to cut token use on all working output — status, reasoning, slot tables, completion reports, dispatch and coordination chatter.
Caveman compresses prose only. It must NEVER alter machine-precise content, which stays byte-exact: lock-comment markers, the RECON OK / RECON-ERROR contract lines, JQL, gh / Atlassian-MCP commands, label and field names/values, file:line references, code blocks, and acceptance-criteria checklists. Compress the narration, never the protocol.
Durable prose a human reads later — issue/ticket bodies and PR descriptions — is the exception: write those through the humanizer skill (see the issue-filing skill), not in caveman.
Offload mechanical ops to a cheap-tier subagent
The orchestrator's context is the expensive one — don't burn the workhorse/premium session on plumbing. Local mechanical work — ls/grep/git status, file/symbol lookups, listing issues or PRs, log triage, running a fixed command and parsing its output — goes to a cheap-tier subagent (the cheapest native model per platform: Haiku on Claude Code, Raptor Mini / GPT-mini on Copilot, free Auto on Cursor — see MODEL-DEFAULTS.md) that returns only the distilled, caveman-compressed answer. The main thread then spends a fraction of the tokens and keeps its context for judgement. The caveman plugin's caveman:cavecrew-investigator agent (read-only locator, caveman output) is one ready implementation; otherwise dispatch a sub-agent pinned to <cheap-model> for the lookup. Never escalate a mechanical sub-step to workhorse/premium "just in case" — a wrong answer there is obvious at a glance, which is exactly why the cheap tier is safe for it.