Ship
Two modes. Spec mode loops every ticket under a spec. Ticket mode ships one.
Merging is the maintainer's call. You open the PR and wait. gh pr merge is never yours to run.
Tracker operations: TRACKERS.md. Parallel worktree briefs: SUBAGENT-BRIEF.md.
Drift check — first thing, both modes
Before any ticket is touched:
gh issue view <spec> --json body
The stamp in the body carries both halves: <!-- prd-source: prd/features/<slug>.md@<blob-sha> -->. Read the path from it — never guess the slug from the issue title. Then:
git hash-object <the path from the stamp>
Compare that hash to the one in the stamp. On a mismatch the feature file moved and the spec issue is stale — re-render it with spec/SPEC-RENDER.md and gh issue edit <spec> --body, in place, same issue number. Then check whether the change invalidates any open ticket and tell the user which.
Skip nothing here. A stale spec makes every ticket below it a small bet that nothing changed.
Spec mode
git status --porcelain — dirty tree stops the run.
- Resolve the spec. No argument:
gh issue list --label type:spec --state open --limit 20, ask which.
- Drift check (above).
- Read the tickets:
gh issue view <spec> --json subIssues, then each one.
- Cluster and sort. Group by blocking edges. Within a cluster, the most load-bearing ticket goes first — one wrong ticket at the root invalidates the rest, and you want it wrong early while the context is fresh.
- Confirm the order with the user. This is the one stop in spec mode.
- For each ticket in order: check for an existing PR (
TRACKERS.md, resume check). Existing PR means ask resume / skip / redo. Otherwise run ticket mode, skipping its step 1 drift check and step 2 blocker check — both were settled here.
- After each merge, recompute the frontier and promote unblocked tickets to
status:ready-for-agent. Report anything the merge surprised you with; do not silently absorb it.
- Summary: shipped, skipped, needs a human.
A failing ticket does not stop the spec. Classify it — stale spec, failed CI, code issue, dependency, other — label it status:blocked with a comment saying which, and route around it. Ask the user only if the ticket is load-bearing for the rest.
Ticket mode
Read the ticket and its spec. gh issue view <n> --json title,body,labels,state,parent. The spec is the contract the work is measured against.
Drift-check the parent before reading it, using the section above — unless spec mode already did it for this run. A ticket measured against a stale spec fails in the way that is hardest to see: everything passes, against the wrong contract.
A ticket with no parent is measured against itself — say that out loud in the preflight so the user can correct you. Ambiguity in the spec is a question, not a guess.
Note the ticket's behaviours touched. That list is the entire test budget for this ticket.
Check blockers and prior runs. Both queries are in TRACKERS.md.
An open blocker stops the run: report which ticket gates this one and let the user decide whether to ship that first. Skip when spec mode ordered the run — the frontier was computed there.
An existing PR on this ticket means a previous run got partway. Ask resume / skip / redo rather than branching over the top of it.
Preflight and branch. git status --porcelain — a dirty tree stops the run. Then git fetch origin && git switch -c ticket/<short-kebab-summary> origin/main.
Branch from origin/main, not a local main that may be behind. Read the files at the seams the spec names — not the whole subsystem.
Look for a prefactor that makes the change easy. If you find one, it is a separate commit that lands first.
Implement. Dispatch /implement per unit. The review happens inside /implement, inline, using the review rules already in your context — there is no separate review dispatch.
PR. Dispatch /pr — it owns the commit format, the staging discipline, and the attribution guardrails. Give it the ticket number so the body carries Closes #<n>.
PRD edits this ticket produced are their own commit, docs(prd): <what>, in this same PR. Proposed behaviours.md entries go in the PR body, never in the file.
Gate. gh pr checks <pr> --required. Fix failures yourself. Do not hand it to a human red.
Ask the user to review. Then address comments and return to the gate.
Merged. git checkout main && git pull && git branch -d <branch>. Confirm the ticket closed.
PRD delta. What did this ticket establish that the PRD did not predict? A new term, a decision that was hard to reverse, a moved boundary. Dispatch /prd in update mode. Nothing to record is a valid answer — say it and stop.
If the ticket contradicted the spec, that is the most important thing you learned. Say so explicitly.
What this skill deliberately does not do
- No clash test. Checking
gh pr list --files for overlap guards a multi-developer repo. If that changes, it comes back.
- No separate
/review dispatch. The rubric is in your context; /implement applies it inline. /review stays available for reviewing something manually, outside a ticket.
- No harvest ritual. Step 9 replaces it, and it lands in the same PR rather than as a follow-up nobody writes.
Completion
Spec mode: every ticket merged, or explicitly blocked with a reason. Ticket mode: PR merged, ticket closed, branch deleted, PRD delta applied or explicitly skipped. Checkable: gh pr view <pr> --json state is MERGED and the local branch is gone.
1---2name: ship3description: Ship a spec or a single ticket from start to merged PR.4---56# Ship78Two modes. **Spec mode** loops every ticket under a spec. **Ticket mode** ships one.910**Merging is the maintainer's call.** You open the PR and wait. `gh pr merge` is never yours to run.1112Tracker operations: `TRACKERS.md`. Parallel worktree briefs: `SUBAGENT-BRIEF.md`.1314## Drift check — first thing, both modes1516Before any ticket is touched:1718```19gh issue view <spec> --json body20```2122The stamp in the body carries **both halves**: `<!-- prd-source: prd/features/<slug>.md@<blob-sha> -->`. Read the path from it — never guess the slug from the issue title. Then:2324```25git hash-object <the path from the stamp>26```2728Compare that hash to the one in the stamp. On a mismatch the feature file moved and the spec issue is stale — re-render it with `spec/SPEC-RENDER.md` and `gh issue edit <spec> --body`, in place, same issue number. Then check whether the change invalidates any open ticket and tell the user which.2930Skip nothing here. A stale spec makes every ticket below it a small bet that nothing changed.3132## Spec mode33341. `git status --porcelain` — dirty tree stops the run.352. Resolve the spec. No argument: `gh issue list --label type:spec --state open --limit 20`, ask which.363. Drift check (above).374. Read the tickets: `gh issue view <spec> --json subIssues`, then each one.385. **Cluster and sort.** Group by blocking edges. Within a cluster, the most load-bearing ticket goes first — one wrong ticket at the root invalidates the rest, and you want it wrong early while the context is fresh.396. Confirm the order with the user. This is the one stop in spec mode.407. For each ticket in order: check for an existing PR (`TRACKERS.md`, resume check). Existing PR means ask **resume / skip / redo**. Otherwise run ticket mode, skipping its step 1 drift check and step 2 blocker check — both were settled here.418. After each merge, recompute the frontier and promote unblocked tickets to `status:ready-for-agent`. Report anything the merge surprised you with; do not silently absorb it.429. Summary: shipped, skipped, needs a human.4344**A failing ticket does not stop the spec.** Classify it — stale spec, failed CI, code issue, dependency, other — label it `status:blocked` with a comment saying which, and route around it. Ask the user only if the ticket is load-bearing for the rest.4546## Ticket mode47481. **Read the ticket and its spec.** `gh issue view <n> --json title,body,labels,state,parent`. The spec is the contract the work is measured against.4950 **Drift-check the parent** before reading it, using the section above — unless spec mode already did it for this run. A ticket measured against a stale spec fails in the way that is hardest to see: everything passes, against the wrong contract.5152 A ticket with no parent is measured against itself — say that out loud in the preflight so the user can correct you. Ambiguity in the spec is a question, not a guess.5354 Note the ticket's **behaviours touched**. That list is the entire test budget for this ticket.55562. **Check blockers and prior runs.** Both queries are in `TRACKERS.md`.5758 An **open blocker** stops the run: report which ticket gates this one and let the user decide whether to ship that first. Skip when spec mode ordered the run — the frontier was computed there.5960 An **existing PR** on this ticket means a previous run got partway. Ask **resume / skip / redo** rather than branching over the top of it.61623. **Preflight and branch.** `git status --porcelain` — a dirty tree stops the run. Then `git fetch origin && git switch -c ticket/<short-kebab-summary> origin/main`.6364 Branch from `origin/main`, not a local `main` that may be behind. Read the files at the seams the spec names — not the whole subsystem.6566 Look for a prefactor that makes the change easy. If you find one, it is a separate commit that lands first.67684. **Implement.** Dispatch `/implement` per unit. The review happens inside `/implement`, inline, using the review rules already in your context — there is no separate review dispatch.69705. **PR.** Dispatch `/pr` — it owns the commit format, the staging discipline, and the attribution guardrails. Give it the ticket number so the body carries `Closes #<n>`.7172 PRD edits this ticket produced are their own commit, `docs(prd): <what>`, in this same PR. Proposed `behaviours.md` entries go in the **PR body**, never in the file.73746. **Gate.** `gh pr checks <pr> --required`. Fix failures yourself. Do not hand it to a human red.75767. **Ask the user to review.** Then address comments and return to the gate.77788. **Merged.** `git checkout main && git pull && git branch -d <branch>`. Confirm the ticket closed.79809. **PRD delta.** What did this ticket establish that the PRD did not predict? A new term, a decision that was hard to reverse, a moved boundary. Dispatch `/prd` in **update** mode. Nothing to record is a valid answer — say it and stop.8182 If the ticket contradicted the spec, that is the most important thing you learned. Say so explicitly.8384## What this skill deliberately does not do8586- **No clash test.** Checking `gh pr list --files` for overlap guards a multi-developer repo. If that changes, it comes back.87- **No separate `/review` dispatch.** The rubric is in your context; `/implement` applies it inline. `/review` stays available for reviewing something manually, outside a ticket.88- **No harvest ritual.** Step 9 replaces it, and it lands in the same PR rather than as a follow-up nobody writes.8990## Completion9192Spec mode: every ticket merged, or explicitly blocked with a reason. Ticket mode: PR merged, ticket closed, branch deleted, PRD delta applied or explicitly skipped. Checkable: `gh pr view <pr> --json state` is `MERGED` and the local branch is gone.