Appearance
build-sprint
build-sprint
buildwriteseither
Use this when: you want to plan then build out a sprint's issues
Problem it solves — A loop that stops at every issue to ask something is a conversation wearing a loop's clothes. This front-loads every decision in an interactive PLAN sweep, then executes the whole sprint autonomously — one gated commit per task.
Used in workflows: Idea → shipped · Build the epic · Build the sprint
Build sprint
Front-load the thinking, then go heads-down. Every question lives in the PLAN phase; EXECUTE asks nothing. A loop that stops at each issue to ask something isn't a grind — it's a conversation wearing a loop's clothes.
Phase 1 — PLAN (interactive)
End this phase with zero unknowns, recorded where the execute phase will find them.
- Resolve the issue set — by selector:
- issue list — an explicit set of issue numbers the user named.
- label —
gh issue list --label <label> --state open. - sprint — a typed Sprint issue: take its child Task sub-issues as the batch (
gh issue view <sprint>→ its sub-issues). Executing a whole epic isbuild-epic's job (it loops sprints).
- Order easiest → hardest and state the order. A CSS fix lands before a data-model migration.
- Per issue, in order: read it (
gh issue view), gather code context with codegraph (codegraph_context, then onecodegraph_explore— not a grep/read loop), and surface only decisions that are genuinely the user's: scope, force-vs-fill-gaps, UX forks, data-model tradeoffs. Settle everything else from the code or a sensible default — don't ask what you can decide. - Ask sequentially with AskUserQuestion, issue by issue. Keep one issue's questions together; never blend unrelated issues into one mega-prompt.
- Record the answers back onto the issue as a comment headed
Plan decisions:. This comment is the contract Phase 2 reads — an undocumented decision did not happen. Include an explicit Out of scope line for anything deliberately not in this batch, so EXECUTE has a drift guard — a "related feature" that isn't listed doesn't get built.
Cadence — ask once (front-load): hands-on (a task PR + your review per issue) or hands-off (tasks auto-merge into the sprint branch on a green gate; one Sprint PR at the end). Always run under be-caveman + be-complete.
This is the skill. A sloppy plan phase yields an execute phase that either stalls on a question or ships the wrong thing. Spend disproportionate effort here; the loop is mechanical by comparison.
Gate — write no code until every target issue carries a
Plan decisions:comment. For a consequential or architectural batch — and always on any issuetriageflagged "needs check-reasoning" in its brief (the durable agent-brief spec —docs/agents/agent-brief.md) — runcheck-reasoningover the plan first (its independence gate red-teams the decomposition before EXECUTE locks it in); fix or consciously accept each FAIL before proceeding.
Failure branch: if a decision needs information you don't have (an API contract, a credential, a design asset), don't guess and don't freeze the whole batch — record the blocker on the issue, drop it from this run, and tell the user what you need to unblock it.
Phase 2 — EXECUTE (autonomous)
Boot only after the gate clears. Build each issue under be-complete — ship the whole change (every file the issue needs), never a skeleton you'll "finish later." For each issue, easiest first, ask nothing — the plan settled it:
- Re-read the issue and its
Plan decisions:comment. - Understand the code via codegraph.
- Test-first in Pest, designed against the ZOMBIES + CORRECT lenses (happy and sad paths). Visual/CSS-only changes are exempt — say so rather than forcing a hollow test. Run the
qa-testsskill before you call an issue done. - Implement to repo convention — validation in FormRequests,
app/DataDTOs not arrays, Wayfinder for FE→BE calls, mobile-first UI, genericAppnaming (no "Tempo" in class names). See thefyi-tempo-domainskill. - Pre-commit gate:
vendor/bin/pint --dirty --format agent→ the affected tests →composer ci:check(PHPStan L7, coverage ≥ 80, mutation ≥ 90). Never lower a threshold — a surviving mutant means add a test, not relax the gate. - One issue = one commit toward the sprint branch — named
sprint/<slug>(nevermaindirectly — branch first; in hands-on, a task branch PR'd into the sprint branch), the message ending with aCloses #NNtrailer and theCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>trailer. Thesprint/<slug>name is a hard rule — theclose-sprint-tasksAction keys its trigger off thesprint/prefix, so an off-convention name silently disables Task close (ADR-0005). - Never close the issue yourself. A Task closes when its work lands on the sprint branch — the
close-sprint-tasksAction closes it from theCloses #NNreference, whether that arrives via a merged task PR (hands-on) or a direct commit (hands-off). Don'tgh issue closeby hand (docs/learnings/2026-06-04-issues-close-on-merge-not-commit.md). - Report one line:
#NN ✓ <what shipped> (<sha>), then move to the next issue.
Don't batch commits across issues — one issue, one commit (the issue closes later, on merge).
Parallelising (hands-off only)
Hands-off mode only — hands-on stays sequential (you review each). For disjoint, backend-heavy issues, fan out following the orchestration contract in docs/agents/orchestration.md — the capable model orchestrates in-thread; cheap-model workers (Workflow tool, or the worktree-builder agent at model: sonnet; falls back to general-purpose if absent) build one issue each in isolated worktrees; you integrate sequentially and re-run the whole gate yourself (a worker's green is partial). That doc is the source of truth for the when-to-fan-out gate, the guardrails, and the worker prompt recipe — don't re-spell them here.
Sprint-specific deltas on top of that contract:
- Keep front-end-overlapping issues (shared Vue files, routes) sequential — parallel branches on shared files just create merge conflicts.
- Decompose by the sprint's issues — one issue per worker, easiest → hardest integration order.
Windows / Herd
Run php / artisan / pest / composer through PowerShell. Pass test file paths, not --filter pipes. Freeze the clock per-test in arrange (Carbon::setTestNow). Every external API (Todoist, Google, Notion, Anthropic) is mocked — never touch the network in a test.
Pre-PR QA gate — QA the changes before the PR, not after
A green ci:check is necessary but not sufficient — it can't see a lazy N+1, an over-broad catch, a missing-cardinality assertion, a doc that drifted. So once every issue is on the sprint branch, before opening the Sprint PR, run qa-everything over the branch diff (git diff main...) — the audits judge the whole, settled change, not each issue in isolation. The order is QA (code + tests + changes) → iterate → green gate → PR, never green → PR.
- Hands-off: run
qa-everythinghands-off — let it QA the changes made, apply the clear-cut fixes and re-run the affected tests itself, escalating only genuine judgment calls (the same posture EXECUTE already uses: act on what's settled, stop only on a real fork). This is the heart of the gate — it fixes, it doesn't just collect findings. - Hands-on: keep
qa-everything's per-finding pause so you review each. - Open the Sprint PR only once QA is clean and
ci:checkis green. (A sprint once shipped its PR ahead of this gate and needed a follow-upqa-codepass — this closes that hole.) Write the PR body perdocs/agents/pr-writing.md— plain lead, a> [!IMPORTANT]decision alert when the sprint made a decision, emoji-anchored##headings, and footnote attribution (never an inline "🤖 Generated with Claude Code" line).
Output contract
Per issue: a commit + a one-line report — not a closed issue (the close-sprint-tasks Action closes the Task when its work lands on the sprint branch — ADR-0005). At sprint end: open one Sprint PR with base main (the epic is a tracking parent, not a branch), its body carrying a Closes #<sprint> trailer so the Sprint issue closes natively on merge to main. Hands-on: a task PR + your review per issue along the way; hands-off: tasks auto-merge into the sprint branch on a green gate. Don't merge the Sprint PR yourself unless asked. Then report what shipped, what was deferred (with the blocker), and any new follow-up issues that surfaced — file those as issues (see docs/agents/issue-tracker.md), don't fix them inline.