/gaia-sprint-close
user-facingWhat 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:
-
Validate the dispatch sentinel written by
/gaia-sprint-reviewand verify the verdict is PASSED (or UNVERIFIED with the bypass markers present). -
Write
status: closed+closed_at: <ISO>atomically throughsprint-state.sh transition(the sanctioned writer). -
Archive a snapshot of the closed yaml under
.gaia/artifacts/implementation-artifacts/sprint-archive/. -
Append a
sprint_closedlifecycle 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-reviewreturned a composite verdict of PASSED and you are ready to finalize the sprint. -
/gaia-sprint-reviewreturned 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 legacyactive → closeddirect edge still works (Step 3a skips when the current status isactive), but the canonical post-review path requiresstatus: review. -
Dispatch sentinel must be present. At least one
of:
.gaia/memory/checkpoints/sprint-review-<sprint_id>-val-dispatched.jsonor.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>", andfindings: […]. A sentinel that exists on disk but is missing any of these fields, or that hasagentset to anything other than the literal string"val", is treated as MISSING and the skill refuses with the sameHALT: sprint-close refused — sprint-review verdict is MISSING; run /gaia-sprint-review firsterror. -
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 formretrospective-<id>-<date>.mdand the clobber-avoidance formretrospective-<id>-<date>-<HHMM>.mdemitted by/gaia-retroare accepted. -
Sprint-review verdict must be PASSED (or
UNVERIFIED with both
pm_signoffandval_validationblocks recorded inreview_justification:). -
Retro doc must exist. The Step 1 precondition
globs
.gaia/artifacts/implementation-artifacts/retrospective-<sprint_id>-*.md-- run/gaia-retrofirst 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
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
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
-
Pre-condition: retro exists
Globs
.gaia/artifacts/implementation-artifacts/retrospective-<sprint_id>-*.md(accepts both-{date}.mdand-{date}-{HHMM}.mdclobber-avoidance variants). If empty, refuses witherror: retro doc not found for <sprint_id>; run /gaia-retro first. -
Pre-condition: idempotency
Reads top-level
status:fromsprint-status.yaml. If alreadyclosed, emitswarning: sprint <id> already closed at <iso>to stderr and exits 0 with no further side effects. -
Pre-condition: all-done or force
Parses
stories[].status. If any story is notdone: 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. -
Pre-condition: review → closed sentinel verification
When
status:isreview: reads the sprint-review verdict viareview-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_justificationfrom the sentinel; whenpm_signoffandval_validationare 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.
status:isactive, this step is SKIPPED entirely -- the legacy direct edge still works. - PASSED -- permit transition via
-
Yaml write
On the legacy
active → closedpath only:yq -i '.status = "closed" | .closed_at = "<ISO 8601 UTC>"' sprint-status.yaml. On the newreview → closedpath, the equivalent write happens insidesprint-state.sh transition. -
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 viaGAIA_SPRINT_CLOSE_DATEfor deterministic tests. -
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}}. -
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-planrequires the prior sprint beclosedbefore 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.