lifecycle-kit

The iteration stage state machine for coding-agent-assisted delivery: stage skills, an evidence file of stamps whose last stamp is the current stage, and gates that fail the commit when a stage is skipped or claimed without running its skill. The stamp grammar, the queue’s iteration header and the configurable stage roster are SPEC.md §The state machine’s.

Why: a stateless agent session doesn’t reliably re-read process prose. So the process state lives in two files a gate can read, and every stage skill stamps its invocation as its first step (mechanized by the --enter-stage <stage> arm on the gate binary GATE_SDK_NATIVE_BIN names, so the misformat-prone hand ritual is one command). That stamp is the stage transition — there is no second copy of the cursor to keep in sync, and stage motion writes no queue at all. check-stage-evidence verifies the stamp file’s grammar and that every stamp belongs to the header’s iteration; check-stage-entry verifies the predecessor stamp, the drained queue at validate entry, and, at build entry, the cross-component audit trigger and no unrun inferred-claim marker. See SPEC.md for the full contracts.

This file ships in the installer payload; what that payload withholds, and where this page’s SPEC.md links then resolve, is gate-sdk/SPEC.md §Consumer payload.

The linear stage walk is the default; the gate-legal ways to leave it — abandon, split, reopen — compose existing mechanism with no new tooling (SPEC.md §Deviation transitions).

Install

Vendor the kit beside gate-sdk (required), then:

  1. Register the gates — add to your gates.list:

    check-stage-evidence
    check-stage-entry
    check-lesson-disposition
    check-lifecycle-registration
    check-stage-skill-coverage   # skill-shim trio: needs the skills dir (step 3)
    check-skill-binding
    check-shim-restatement
    check-merge-attrs            # multi-operator: needs the .gitattributes step (step 4)
    check-close-surfaces
    check-survey-record          # inert until a survey is filed (--emit file-survey)
    check-audit-roster           # inert until LIFECYCLE_KIT_AUDIT_ROSTER_FILE names a roster
    check-scratch-citation       # no permanent surface points a reader into per-iteration scratch
    check-gap-inbox-neutrality   # inert until a gap is filed (--emit file-gap)
    check-disposed-findings      # inert until a drain discards a finding
    check-stamp-subject          # commit-msg tier: a stamp commit's subject scope is its stage
    check-dispatch-entry         # commit-msg tier: inert until a lead declares a dispatch (--enter-stage --dispatch)
    

    They resolve through gate-sdk’s registry path (your gates dir first, then each kit’s checks/), and the hooks run those their # graph: manifests trigger, read at commit (check-stamp-subject and check-dispatch-entry in the commit-msg hook). --install-hooks on the gate binary GATE_SDK_NATIVE_BIN names places both hooks in a clone once, and a gate registered later is reached with no re-install.

  2. Give the queue file its header and each evidence file its skeleton — the stage-stamp file and the lesson-disposition file (LIFECYCLE_KIT_LESSON_EVIDENCE_FILE, both boundary-reset to their header). The queue header line:

    ## Iteration: —
    

    The stage-stamp skeleton:

    # contract: lifecycle-kit/SPEC.md §check-stage-evidence
    
    ---
    

    The lesson-disposition skeleton:

    # contract: lifecycle-kit/SPEC.md §check-lesson-disposition
    
  3. Adopt templates/stages/*.md in your agent-skill directory (e.g. .claude/commands/): by default make each skill a binding shim that references the template (SPEC.md §templates/stages/) — it tracks the kit, so a re-vendor reaches it and the shim gates hold it thin. Or, as the sanctioned fork, copy each in and fill its named slots (*<slot-name: …>*) with your project’s ritual — you then own the ritual prose, upgrades don’t reach it, and the shim gates don’t cover it (kept for legitimate structural divergence).

  4. Point your always-loaded agent file at the machine — run --install-lifecycle on the gate binary GATE_SDK_NATIVE_BIN names. It writes a marker-bounded registration block (the state machine, the stage roster as skill invocations, the SPEC link) into the file LIFECYCLE_KIT_AGENT_FILE names, the roster derived from your config so a reshape (step 5) flows in on a re-run. check-lifecycle-registration (step 1) holds the block in lockstep. The same run also writes the merge-attribute block into .gitattributes — a merge=iteration-scoped line per per-iteration state surface (these resolve to the arriving branch at a merge — SPEC.md §Multi-operator semantics) and a merge=union line for each committed inbox (their append-only bullets must survive a concurrent merge — SPEC.md §The committed gap inbox, §The consult inbox) — and registers the keep-ours driver in your clone’s git config (per-clone, the --install-hooks opt-in class; the git-native union driver needs no such step). check-merge-attrs (step 1) holds the block in parity with the derived supersede and union sets.

  5. Optional — narrow the hand-edit window: register the gate binary GATE_SDK_NATIVE_BIN names, under <project-dir>, as the command of a PreToolUse(Write|Edit) hook, with --hook workflow-state-guard as its args (guard-kit’s templates/settings-hooks.json carries the block, with <project-dir>, your harness’s project-directory variable, spelled for Claude Code, and the binary as a placeholder its note says how to replace). It refuses an agent write to the stage-stamp file, whose only sanctioned writer is the --enter-stage arm — the gates that would catch a hand-stamp all fire at commit, and an uncommitted one moves the cursor for a whole session (SPEC.md §check-stage-evidence). With LIFECYCLE_KIT_STAGE_SESSION_TYPES set, it also refuses a dispatched stage session’s write before that session’s stamp, and its write outside the scratch dir once the cursor has left its stage. Requires guard-kit vendored.

  6. Optional — reshape the machine: copy templates/lifecycle-config.knobs into your gates dir and set stages, predecessors, drain/audit stages, section names, or file paths, one NAME = value or NAME[] = element line each. Defaults are this repo’s own lifecycle; --emit knob-roster on the gate binary GATE_SDK_NATIVE_BIN names prints them.

After install the battery is red at check-stage-evidence until your first /scope session runs (it names the iteration and stamps the evidence file as its first step) — the bootstrap header is a stage like any other, fail-closed by design.

Use

Run these arms with the gate binary GATE_SDK_NATIVE_BIN names, where init places it. In PowerShell, spell each line ./scripts/checkwright-gates <arm> at the repository root, with .exe on native Windows:

gates="${GATE_SDK_NATIVE_BIN:-./scripts/checkwright-gates}"
"$gates" --enter-stage <stage>          # stamp a stage entry (the transition itself)
"$gates" --install-lifecycle    # (re)write the registration and merge-attribute blocks
"$gates" --emit file-gap "<gap>"   # route a work-shaped finding to the gap inbox
"$gates" --emit file-consult "<item>"   # route a ruling to reconsider or a request for advice to the consult inbox
"$gates" --emit consult-count           # one line counting the consult inbox, nothing when it is empty
"$gates" --emit file-survey "<question>" "<corpus>" "<oracle>" "<inferred>" "<finding>"
"$gates" --emit journal "<finding>"   # append to the resume journal of the stage you entered
"$gates" --emit journal --lead "<finding>"   # a lead session: append to the lead journal its opener opened
"$gates" --emit cite-survey "<heading-substring>"   # one carried survey, inline-ready
"$gates" --emit stage-contract <stage>           # a stage's contract for a reader with no skill and no write path
"$gates" --emit session-id                       # the canonical stamp id, by the derivation order
"$gates" --emit ruling-staleness ["<ruling name>"…]  # fired conditions, undeclared ones, citing sites

--emit session-id is SPEC.md §bin/session-id.sh’s derivation order, which --enter-stage reads for you: reach for it directly only where a session writes an id itself, as templates/lead.md’s session-role marker step does. It takes no argument and resolves no knob. The front-end route reads the cwd bin/run-gates.sh cds to — the git toplevel — so a caller standing elsewhere whose sessions dir is the cwd-slugged default invokes the binary’s --emit-session-id arm directly instead, which is what --enter-stage does.

The two survey arms are the capture and citation affordances of SPEC.md §The survey record. -- ends option processing for either, and a positional beginning with - without it, --help included, is a refusal that prints the arm’s usage at exit 2 (gate-sdk/SPEC.md §The bin/-tool contract).

Test

Run this arm the same way:

gates="${GATE_SDK_NATIVE_BIN:-./scripts/checkwright-gates}"
"$gates" --run-gate-tests lifecycle-kit/gate-tests lifecycle-kit/checks

License

Licensed under Apache-2.0, with the text in LICENSE beside this file in an installed copy and at the repository root in the source tree.