/ticket-fleet — Headless Ticket Fleet
Resolve N well-scoped GitHub tickets in parallel: each ticket gets its own headless
claude -p session in an isolated git worktree of the owning repo (so the repo's
CLAUDE.md governs it), produces a PR, self-runs a Codex review, and reports
uncertainties. The orchestrator (you, the main session) does a second review leg per
PR, relays uncertainties to the user, and handles merges + conflicts.
Proven: 2026-07-03→04, 23 tickets across 10 repos, 29 PRs merged, 0 rejected;
cross-model review caught 2 criticals + 1 high the authoring model missed; survived a
mid-flight spend-limit outage via --continue resume.
Usage
/ticket-fleet <ticket-list> — e.g. verdandi#9 skuld#3 heimdall#104 or "all open from:grimnir tickets"
Assets
scripts/run-ticket.sh <repo_dir> <issue_no> <model> <prompt_file> <log_file> — creates
worktree ~/repos/.wt/<repo>-t<issue> on branch ticket/<issue>-headless from
origin/<default>, runs the headless session with the gated allowlist, logs everything.
scripts/continue-ticket.sh <worktree_dir> <model> <log_file> — resumes an interrupted
session in its worktree via claude -p --continue (conversation context + partial edits
survive).
scripts/run-ticket-m5.sh / scripts/continue-ticket-m5.sh — M5-enabled variants
(proven 2026-07-04, 4/4 tickets): add mcp__m5__ask/mcp__m5__list_models to the allowlist
plus optional per-ticket extra tools as trailing args (e.g. "Bash(curl:*)" for live-seam
tickets). Use these when sessions should offload bounded sub-tasks to the M5 box; include an
M5-offload paragraph in the prompt's EXTRA section requiring the session to VERIFY every M5
output before use, and add an M5: line to the FINAL REPORT format. Reliability data so
far (2026-07-04): qwen3-coder review legs were clean and correct on 3 TypeScript diffs but
confabulated 5-of-6 findings on a shell/docs diff — trust the M5 review leg on TS, treat its
shell/docs findings as hypotheses to verify, and always verify its codegen with tests.
templates/ticket-prompt.md — the per-ticket prompt. Fill {ISSUE}, {TITLE},
{EXTRA_TASK_SPECIFIC_GUIDANCE} (2–6 sentences: concrete scope, files, constraints,
known traps). The EXTRA section is where quality is won — be specific per ticket.
Workflow
1. Triage the tickets
Group by repo. Well-scoped, self-contained tickets only — split or skip anything needing
production access, cross-repo edits, or the user's judgment mid-flight. Per-ticket model:
sonnet for mechanical/clear-spec, opus for architectural/security. If a repo has a
concurrent active session (dirty main checkout), schedule its tickets LAST and say so in
the prompt ("do not touch <branch/area>").
2. Write prompts, launch in waves
One prompt file per ticket from the template. Launch each via run-ticket.sh as a
background Bash task (no 10-min cap; you get a notification per completion).
Wave size ~6–8; mechanical wave first (validates the pipeline cheaply), harder wave
after. Pilot one ticket end-to-end before the first fan-out.
3. Permission posture (hard-learned)
--dangerously-skip-permissions will be refused by the auto-mode classifier —
correctly. The scripts use --permission-mode acceptEdits + a scoped --allowedTools
list (git/gh/npm/node/python3/codex/shellcheck/bash/sh/make + read-only utils).
- Include
Bash(bash:*) and Bash(sh:*) — without them sessions detour through
python3 subprocess to run test scripts.
- Sessions are told: PR only — no deploys, no service restarts, no ssh, no STATUS.md.
4. Per-completion processing (orchestrator loop)
On each completion notification:
tail -c 3000 <log> — read the FINAL REPORT (PR / TESTS / CODEX / UNCERTAINTIES / STATUS).
- Second review leg: fetch the PR diff (bounded), independently verify the riskiest
claim yourself (grep the worktree — it still exists), optionally pipe the diff to a
local model for a first-pass (see §7). Post findings as a PR comment, never an
approval — the classifier blocks orchestrator self-approval of its own spawn's PR,
and it's right; the formal stamp stays with the human.
- Relay the session's UNCERTAINTIES to the user (they're consistently the highest-value
output). File follow-up tickets for real discoveries (owning repo,
from:<sender>
label, board).
5. Interrupts & failures
- Spend-limit / API death mid-flight: sessions die with partial work in their
worktrees. Do NOT delete and relaunch —
continue-ticket.sh resumes with full context.
Check git log @{u}.. + status --porcelain per worktree first to see what survived.
- Same-repo PR collisions (e.g. two tickets both add a
make test target): rebase in
the ticket worktree, merge the hunks (union), re-run the full suite, push --force-with-lease. Expect this whenever >1 ticket touches one repo.
- After resolving rebase conflicts,
grep -c '^<<<<<<<' EVERY conflicted file before
rebase --continue — a truncated conflict listing hides hunks (bit us once).
6. Merge & cleanup
- Merge only on the user's word.
--squash --delete-branch; check mergeStateStatus
(BEHIND → gh pr update-branch; UNSTABLE → CI running, use gh pr merge --auto).
- Check merge gates from the reports before merging (e.g. "env var X must exist in
prod first") — verify read-only via ssh, don't assume.
- After merges: remove worktrees (
git worktree remove, clean-only — keep any backing an
unmerged PR), delete merged local branches, pull every local repo before any deploy
(stale-checkout trap — see the deploy skill).
7. Local-model review leg (optional, cost-saving)
Pipe each PR diff to the m5 box (mcp__m5__ask, qwen3-coder) via a haiku pipe-agent that
reads the diff file and inlines it into the ask prompt — the diff never enters root
context. Never call ask with the diff "attached" but not actually in the prompt —
you'll get a worthless NO FINDINGS on empty input (bit us once). If the box times out
(load/cold-swap), fall back without ceremony and say so in the PR comment.
Report format to the user
Running scoreboard per wave: PR / tests / Codex verdict / your leg. Consolidate at the
end: totals, criticals caught, grouped uncertainties as decision buckets (activation
steps, policy blessings, filed follow-ups, recurring fleet themes), pending user actions.
1---2name: ticket-fleet3description: Resolve a batch of GitHub tickets via parallel headless Claude Code sessions — one isolated git worktree per ticket, gated permissions, triple review (Codex + local-model first-pass + orchestrator comment), interrupt-resume, and merge orchestration. Use when the user wants many well-scoped tickets solved autonomously across one or more repos.4---56# /ticket-fleet — Headless Ticket Fleet78Resolve N well-scoped GitHub tickets in parallel: each ticket gets its own headless9`claude -p` session in an isolated git worktree of the owning repo (so the repo's10CLAUDE.md governs it), produces a PR, self-runs a Codex review, and reports11uncertainties. The orchestrator (you, the main session) does a second review leg per12PR, relays uncertainties to the user, and handles merges + conflicts.1314**Proven:** 2026-07-03→04, 23 tickets across 10 repos, 29 PRs merged, 0 rejected;15cross-model review caught 2 criticals + 1 high the authoring model missed; survived a16mid-flight spend-limit outage via `--continue` resume.1718## Usage1920- `/ticket-fleet <ticket-list>` — e.g. `verdandi#9 skuld#3 heimdall#104` or "all open from:grimnir tickets"2122## Assets2324- `scripts/run-ticket.sh <repo_dir> <issue_no> <model> <prompt_file> <log_file>` — creates25 worktree `~/repos/.wt/<repo>-t<issue>` on branch `ticket/<issue>-headless` from26 `origin/<default>`, runs the headless session with the gated allowlist, logs everything.27- `scripts/continue-ticket.sh <worktree_dir> <model> <log_file>` — resumes an interrupted28 session in its worktree via `claude -p --continue` (conversation context + partial edits29 survive).30- `scripts/run-ticket-m5.sh` / `scripts/continue-ticket-m5.sh` — **M5-enabled variants**31 (proven 2026-07-04, 4/4 tickets): add `mcp__m5__ask`/`mcp__m5__list_models` to the allowlist32 plus optional per-ticket extra tools as trailing args (e.g. `"Bash(curl:*)"` for live-seam33 tickets). Use these when sessions should offload bounded sub-tasks to the M5 box; include an34 M5-offload paragraph in the prompt's EXTRA section requiring the session to VERIFY every M535 output before use, and add an `M5:` line to the FINAL REPORT format. **Reliability data so36 far (2026-07-04):** qwen3-coder review legs were clean and correct on 3 TypeScript diffs but37 confabulated 5-of-6 findings on a shell/docs diff — trust the M5 review leg on TS, treat its38 shell/docs findings as hypotheses to verify, and always verify its codegen with tests.39- `templates/ticket-prompt.md` — the per-ticket prompt. Fill `{ISSUE}`, `{TITLE}`,40 `{EXTRA_TASK_SPECIFIC_GUIDANCE}` (2–6 sentences: concrete scope, files, constraints,41 known traps). The EXTRA section is where quality is won — be specific per ticket.4243## Workflow4445### 1. Triage the tickets46Group by repo. Well-scoped, self-contained tickets only — split or skip anything needing47production access, cross-repo edits, or the user's judgment mid-flight. Per-ticket model:48`sonnet` for mechanical/clear-spec, `opus` for architectural/security. If a repo has a49concurrent active session (dirty main checkout), schedule its tickets LAST and say so in50the prompt ("do not touch <branch/area>").5152### 2. Write prompts, launch in waves53One prompt file per ticket from the template. Launch each via `run-ticket.sh` as a54**background Bash task** (no 10-min cap; you get a notification per completion).55Wave size ~6–8; mechanical wave first (validates the pipeline cheaply), harder wave56after. **Pilot one ticket end-to-end before the first fan-out.**5758### 3. Permission posture (hard-learned)59- `--dangerously-skip-permissions` **will be refused** by the auto-mode classifier —60 correctly. The scripts use `--permission-mode acceptEdits` + a scoped `--allowedTools`61 list (git/gh/npm/node/python3/codex/shellcheck/bash/sh/make + read-only utils).62- Include `Bash(bash:*)` and `Bash(sh:*)` — without them sessions detour through63 `python3 subprocess` to run test scripts.64- Sessions are told: PR only — no deploys, no service restarts, no ssh, no STATUS.md.6566### 4. Per-completion processing (orchestrator loop)67On each completion notification:681. `tail -c 3000 <log>` — read the FINAL REPORT (PR / TESTS / CODEX / UNCERTAINTIES / STATUS).692. **Second review leg:** fetch the PR diff (bounded), independently verify the riskiest70 claim yourself (grep the worktree — it still exists), optionally pipe the diff to a71 local model for a first-pass (see §7). Post findings as a PR **comment, never an72 approval** — the classifier blocks orchestrator self-approval of its own spawn's PR,73 and it's right; the formal stamp stays with the human.743. Relay the session's UNCERTAINTIES to the user (they're consistently the highest-value75 output). File follow-up tickets for real discoveries (owning repo, `from:<sender>`76 label, board).7778### 5. Interrupts & failures79- **Spend-limit / API death mid-flight:** sessions die with partial work in their80 worktrees. Do NOT delete and relaunch — `continue-ticket.sh` resumes with full context.81 Check `git log @{u}..` + `status --porcelain` per worktree first to see what survived.82- **Same-repo PR collisions** (e.g. two tickets both add a `make test` target): rebase in83 the ticket worktree, merge the hunks (union), re-run the full suite, `push84 --force-with-lease`. Expect this whenever >1 ticket touches one repo.85- After resolving rebase conflicts, `grep -c '^<<<<<<<'` EVERY conflicted file before86 `rebase --continue` — a truncated conflict listing hides hunks (bit us once).8788### 6. Merge & cleanup89- Merge only on the user's word. `--squash --delete-branch`; check `mergeStateStatus`90 (BEHIND → `gh pr update-branch`; UNSTABLE → CI running, use `gh pr merge --auto`).91- Check merge **gates** from the reports before merging (e.g. "env var X must exist in92 prod first") — verify read-only via ssh, don't assume.93- After merges: remove worktrees (`git worktree remove`, clean-only — keep any backing an94 unmerged PR), delete merged local branches, **pull every local repo before any deploy**95 (stale-checkout trap — see the deploy skill).9697### 7. Local-model review leg (optional, cost-saving)98Pipe each PR diff to the m5 box (`mcp__m5__ask`, qwen3-coder) via a haiku pipe-agent that99reads the diff file and inlines it into the ask prompt — the diff never enters root100context. **Never call `ask` with the diff "attached" but not actually in the prompt** —101you'll get a worthless NO FINDINGS on empty input (bit us once). If the box times out102(load/cold-swap), fall back without ceremony and say so in the PR comment.103104## Report format to the user105106Running scoreboard per wave: PR / tests / Codex verdict / your leg. Consolidate at the107end: totals, criticals caught, grouped uncertainties as decision buckets (activation108steps, policy blessings, filed follow-ups, recurring fleet themes), pending user actions.