Skip to content

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.

  1. Resolve the issue set — by selector:
    • issue list — an explicit set of issue numbers the user named.
    • labelgh 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 is build-epic's job (it loops sprints).
  2. Order easiest → hardest and state the order. A CSS fix lands before a data-model migration.
  3. Per issue, in order: read it (gh issue view), gather code context with codegraph (codegraph_context, then one codegraph_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.
  4. Ask sequentially with AskUserQuestion, issue by issue. Keep one issue's questions together; never blend unrelated issues into one mega-prompt.
  5. 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 issue triage flagged "needs check-reasoning" in its brief (the durable agent-brief spec — docs/agents/agent-brief.md) — run check-reasoning over 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:

  1. Re-read the issue and its Plan decisions: comment.
  2. Understand the code via codegraph.
  3. 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-tests skill before you call an issue done.
  4. Implement to repo convention — validation in FormRequests, app/Data DTOs not arrays, Wayfinder for FE→BE calls, mobile-first UI, generic App naming (no "Tempo" in class names). See the fyi-tempo-domain skill.
  5. 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.
  6. One issue = one commit toward the sprint branch — named sprint/<slug> (never main directly — branch first; in hands-on, a task branch PR'd into the sprint branch), the message ending with a Closes #NN trailer and the Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> trailer. The sprint/<slug> name is a hard rule — the close-sprint-tasks Action keys its trigger off the sprint/ prefix, so an off-convention name silently disables Task close (ADR-0005).
  7. Never close the issue yourself. A Task closes when its work lands on the sprint branch — the close-sprint-tasks Action closes it from the Closes #NN reference, whether that arrives via a merged task PR (hands-on) or a direct commit (hands-off). Don't gh issue close by hand (docs/learnings/2026-06-04-issues-close-on-merge-not-commit.md).
  8. 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-everything hands-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:check is green. (A sprint once shipped its PR ahead of this gate and needed a follow-up qa-code pass — this closes that hole.) Write the PR body per docs/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.