/gaia-sprint-close

user-facing
Category:
Sprint Management
Lifecycle phase:
4 -- Implementation (close ceremony, post sprint-review PASSED)
Arguments:
<sprint-id>

What it does

/gaia-sprint-close is the sanctioned boundary-write replacement for any manual yq -i edits on sprint-status.yaml. It accepts the review → closed edge from a PASSED (or UNVERIFIED-bypass) /gaia-sprint-review verdict and finalizes the sprint with four ordered actions:

  1. Validate the dispatch sentinel written by /gaia-sprint-review and verify the verdict is PASSED (or UNVERIFIED with the bypass markers present).
  2. Write status: closed + closed_at: <ISO> atomically through sprint-state.sh transition (the sanctioned writer).
  3. Archive a snapshot of the closed yaml under .gaia/artifacts/implementation-artifacts/sprint-archive/.
  4. Append a sprint_closed lifecycle event to .gaia/memory/lifecycle-events.jsonl.

The skill is idempotent on already-closed sprints: re-running emits a warning and exits 0 with no yaml mutation, no new archive copy, and no new lifecycle event.

When to use it

  • /gaia-sprint-review returned a composite verdict of PASSED and you are ready to finalize the sprint.
  • /gaia-sprint-review returned an UNVERIFIED verdict, the PM signed off on the bypass explanation, and the second Val pass PASSED -- the UNVERIFIED-bypass marker is present in the sentinel.
  • You ran the retrospective (/gaia-retro) so the close-time precondition has a retro doc to point at.

Prerequisites

  • Sprint must be review. The legacy active → closed direct edge still works (Step 3a skips when the current status is active), but the canonical post-review path requires status: review.
  • Dispatch sentinel must be present. At least one of: .gaia/memory/checkpoints/sprint-review-<sprint_id>-val-dispatched.json or .gaia/memory/checkpoints/val-envelope-<sha256(<sprint_id>):0:16>.json.
    Sentinel payload schema. The sentinel JSON MUST carry the canonical Val-envelope shape: agent: "val" (literal lowercase string), status: "PASSED" | "FAILED" | "UNVERIFIED", summary: "<short prose>", and findings: […]. A sentinel that exists on disk but is missing any of these fields, or that has agent set to anything other than the literal string "val", is treated as MISSING and the skill refuses with the same HALT: sprint-close refused — sprint-review verdict is MISSING; run /gaia-sprint-review first error.
  • Retro doc path. The retro file MUST live at the EXACT path the close ceremony's glob walks: .gaia/artifacts/implementation-artifacts/retrospective-<sprint_id>-*.md (or the per-sprint subdir layout …/retrospective/retrospective-<sprint_id>-*.md). Both the date-only form retrospective-<id>-<date>.md and the clobber-avoidance form retrospective-<id>-<date>-<HHMM>.md emitted by /gaia-retro are accepted.
  • Sprint-review verdict must be PASSED (or UNVERIFIED with both pm_signoff and val_validation blocks recorded in review_justification:).
  • Retro doc must exist. The Step 1 precondition globs .gaia/artifacts/implementation-artifacts/retrospective-<sprint_id>-*.md -- run /gaia-retro first if absent.
  • All stories must be done. Override with --force-with-rollover <key1,key2,...> if specific stories are being rolled to the next sprint.
  • yq (mikefarah, Go v4) must be on PATH.

Arguments

NameTypeRequiredDefaultDescription
sprint-id Positional Yes -- The sprint identifier (e.g., sprint-12) to close.
--force-with-rollover Flag (comma-separated keys) No -- Closes the sprint even though the listed story keys are not done. The list MUST exactly match the non-done set; mismatches are rejected with canonical stderr.

Orchestration mode

/gaia-sprint-close declares orchestration_class: light-procedural. It is a thin orchestrator over sprint-state.sh transition, lifecycle-event.sh, and a copy-archive. No AskUserQuestion boundaries fire; no Val dispatch happens; the LLM does not classify the verdict. All decisions are mechanical in scripts/close.sh.

How to invoke

/gaia-sprint-close sprint-12

Replace sprint-12 with the sprint identifier returned in the /gaia-sprint-review handoff message.

What it does step by step

  1. Pre-condition: retro exists Globs .gaia/artifacts/implementation-artifacts/retrospective-<sprint_id>-*.md (accepts both -{date}.md and -{date}-{HHMM}.md clobber-avoidance variants). If empty, refuses with error: retro doc not found for <sprint_id>; run /gaia-retro first.
  2. Pre-condition: idempotency Reads top-level status: from sprint-status.yaml. If already closed, emits warning: sprint <id> already closed at <iso> to stderr and exits 0 with no further side effects.
  3. Pre-condition: all-done or force Parses stories[].status. If any story is not done: without --force-with-rollover, refuse and exit non-zero; with the flag, validate the comma-separated keys are exactly the non-done set (no extras, no missing) and reject mismatches.
  4. Pre-condition: review → closed sentinel verification When status: is review: reads the sprint-review verdict via review-gate.sh status --sprint <id> --gate sprint-review, verifies the dispatch sentinel exists, and decides:
    • PASSED -- permit transition via sprint-state.sh transition --sprint <id> --to closed.
    • UNVERIFIED with bypass -- read review_justification from the sentinel; when pm_signoff and val_validation are both present, permit transition through the same writer.
    • FAILED -- REFUSE with HALT: sprint-close refused -- sprint-review verdict is FAILED; run /gaia-correct-course first.
    • Missing sentinel -- REFUSE with HALT: sprint-close refused -- sprint-review verdict is MISSING; run /gaia-sprint-review first.
    When status: is active, this step is SKIPPED entirely -- the legacy direct edge still works.
  5. Yaml write On the legacy active → closed path only: yq -i '.status = "closed" | .closed_at = "<ISO 8601 UTC>"' sprint-status.yaml. On the new review → closed path, the equivalent write happens inside sprint-state.sh transition.
  6. Archive mkdir -p .gaia/artifacts/implementation-artifacts/sprint-archive/; cp sprint-status.yaml .gaia/artifacts/implementation-artifacts/sprint-archive/<sprint_id>-closed-<YYYY-MM-DD>.yaml. Date is today UTC; override via GAIA_SPRINT_CLOSE_DATE for deterministic tests.
  7. Lifecycle event Invokes lifecycle-event.sh --type sprint_closed --workflow gaia-sprint-close --data {...}. The JSONL line shape is {timestamp, event_type:"sprint_closed", workflow:"gaia-sprint-close", pid, data:{sprint_id, closed_at, total_points, stories_done, stories_rolled_over, rollover_target_sprint}}.
  8. Confirmation Emits a single-line confirmation to stdout: sprint <id> closed at <iso>; archive: <path>; lifecycle event recorded.

Inputs

Input Source Description
Sprint tracking file .gaia/state/sprint-status.yaml The sprint to close. Override the lookup with SPRINT_STATUS_YAML env if needed.
Sprint-review dispatch sentinel .gaia/memory/checkpoints/sprint-review-<sprint_id>-val-dispatched.json or val-envelope-<sha256>.json Written by /gaia-sprint-review Step 3 Track A; required when transitioning from review.
Retro artifact .gaia/artifacts/implementation-artifacts/retrospective-<sprint_id>-*.md Written by /gaia-retro; required by the Step 1 precondition.

Outputs

Output Location Description
Updated sprint tracking file .gaia/state/sprint-status.yaml status: closed + closed_at: <ISO> written atomically through the boundary writer.
Archived snapshot .gaia/artifacts/implementation-artifacts/sprint-archive/<sprint_id>-closed-<YYYY-MM-DD>.yaml Byte-for-byte copy of the yaml AFTER the close write -- the archived snapshot always reflects the closed state.
Lifecycle event .gaia/memory/lifecycle-events.jsonl Appended sprint_closed event with sprint id, close timestamp, total points, story counts, and rollover keys.

Examples

1. Canonical sequence -- sprint-review PASSED → sprint-close

> /gaia-sprint-review sprint-12
...
/gaia-sprint-review: composite verdict PASSED -- sprint sprint-12 ready to close;
  invoke /gaia-sprint-close to finalize.

> /gaia-retro sprint-12
...
Retro artifact written: retrospective-sprint-12-2026-05-29.md

> /gaia-sprint-close sprint-12

Pre-condition: retro doc found (retrospective-sprint-12-2026-05-29.md).
Pre-condition: sprint not already closed.
Pre-condition: 6 stories, all status: done.
Pre-condition: review -> closed sentinel verification:
  sprint-review verdict: PASSED
  dispatch sentinel: sprint-review-sprint-12-val-dispatched.json (present)
  permit transition.

Transition: review -> closed (sprint-state.sh, atomic).
Archive: .gaia/artifacts/implementation-artifacts/sprint-archive/sprint-12-closed-2026-05-29.yaml
Lifecycle event: sprint_closed appended to lifecycle-events.jsonl.

sprint sprint-12 closed at 2026-05-29T14:22:08Z;
  archive: sprint-archive/sprint-12-closed-2026-05-29.yaml;
  lifecycle event recorded

2. UNVERIFIED-bypass close

> /gaia-sprint-close sprint-13

Pre-condition: review -> closed sentinel verification:
  sprint-review verdict: UNVERIFIED
  review_justification.pm_signoff:   present (Derek, 2026-05-29T13:10:00Z)
  review_justification.val_validation: present (status: PASSED)
  bypass markers complete; permit transition.

Transition: review -> closed (UNVERIFIED-bypass marker recorded).
sprint sprint-13 closed at 2026-05-29T13:30:00Z; ...

3. Already closed (idempotent)

> /gaia-sprint-close sprint-12

warning: sprint sprint-12 already closed at 2026-05-29T14:22:08Z
# exit 0; no yaml write, no archive copy, no new lifecycle event

What to run next

  • /gaia-retro -- typically run BEFORE /gaia-sprint-close (the close skill requires the retro artifact). If you skipped retro on the previous sprint, run it now for retrospective continuity.
  • /gaia-action-items -- resolve any open action items from the retro before planning the next sprint.
  • /gaia-sprint-plan -- plan the next sprint. The prior-close guard in /gaia-sprint-plan requires the prior sprint be closed before a new sprint commits.

Troubleshooting

"HALT: sprint-close refused -- sprint-review verdict is MISSING"

The dispatch sentinel for the sprint-review run is absent. Either you have not run /gaia-sprint-review for this sprint yet, or the sentinel files under .gaia/memory/checkpoints/ were deleted. Re-run /gaia-sprint-review <sprint-id> to write a fresh sentinel.

"HALT: sprint-close refused -- sprint-review verdict is FAILED"

The last sprint-review verdict was FAILED. Closing a FAILED sprint is not permitted. Run /gaia-correct-course story_injection to inject rework stories, drive them to done, then re-run /gaia-sprint-review. Once the verdict turns PASSED, /gaia-sprint-close accepts the edge.

"error: retro doc not found for <sprint_id>"

The Step 1 precondition could not glob the retrospective artifact. Run /gaia-retro <sprint-id> first, then re-invoke /gaia-sprint-close.

"error: --force-with-rollover key mismatch"

The comma-separated keys supplied to --force-with-rollover do not exactly match the non-done story set in sprint-status.yaml (the error message lists both the actual non-done keys and the keys you supplied). Either correct the list to match, or drive the missing stories to done before retrying.

Sprint stuck at review after an UNVERIFIED verdict

The transition guard refused because either pm_signoff or val_validation is missing from the review_justification: block. Re-run /gaia-sprint-review Step 8 to collect the missing justification + Val pass, then retry.