Use this skill to make a change to an SDD project — triggered by a general change request like "add a start-mission skill to sdd", "implement the auth capability", "revise the gateway spec", or "work on <github issue url>". Opens a change request against the durable project spec and runs the mission loop (explore → deliver → handoff).
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Use this skill to make a change to an SDD project — triggered by a general change request like "add a start-mission skill to sdd", "implement the auth capability", "revise the gateway spec", or "work on <github issue url>". Opens a change request against the durable project spec and runs the mission loop (explore → deliver → handoff).
start-mission
The single user-facing entry for changing an SDD project. It opens a change request (CR) against the one durable project spec (.agents/specs/<project>/) and runs the mission loop over it. The session that runs this skill is the conductor — the user in the driver's seat, holding the user channel, grilling live, ratifying in-session. This skill is the in-session realization of the conductor role (the automaton agent is the headless realization for an unattended scheduler or a multi-CR fan-out).
Three realizations of the conductor.In-session interactive (default — the grill loop below); in-session plan-mode preview (Step 2 runs the preview branch — reasoning only, renders the drafted spec + suite into the plan file, ends at ExitPlanMode); headless automaton (unattended). The plan-mode branch is detected in-body from the harness plan-mode signal (only the plan file is writable) — never from the description, so a mission triggers on change-intent alone (plan mode or not) and never re-fires per turn: the branch is a fork inside an already-loaded explore phase, not a trigger.
A CR is the unit of change-intent (git-PR-shaped); the mission loop is the workflow that carries it. Whether the CR adds a capability, revises behavior, or reconciles overlap is decided during — not by a separate entry skill. A request with is and escapes the lifecycle (leave no SDD record).
explore
no suite-relevant behavior
not a CR
Advise a capable model (e.g. Opus) on entry. The explore grill runs in this session, so its quality tracks the session model. Surface this before the grill so the user can switch if needed. (The harness cannot switch the session model on your behalf.)
Load sdd:lifecycle-governance (status enum, the freeze re-open transition), sdd:ownership-governance (who writes each field), sdd:spec-format-governance + sdd:suite-format-governance (the node skeleton + suite bars), sdd:spec-producer-governance (the grilling procedure run inline), sdd:impl-producer-governance (what the spawned builder loads), sdd:gate-validation-governance (legal gate-state tuples), sdd:remediation-governance (how a producer answers a change verdict at either gate), and sdd:combat-log-governance (the provenance shapes). The autonomy bar is baked in (below).
Step 1 — intake: open the CR and scaffold the plan
Get the CR into the system and create its plan brief — the plan is a step-1 artifact, not something explore invents later.
Recover the request. From a general change prompt, name the change and the target. From a source URL (work on <github issue url>), fetch the issue and read it as the CR body.
Locate the project spec by running the discover-specs skill (the corpus/discovery engine) — it returns the TOON list of every project spec at the SDD spec locations (the three fixed conventions plus any declared extra anchors, ADR-0019) with its status and project-path. Resolve the CR's target to one spec by folder slug or project-path; an ambiguous match is disambiguated with the user, never guessed. One project is one spec — there is no spec fleet to pick from. If discover-specs finds no spec for the target project, that is the backfill path (load scaffold-project-spec).
Scaffold .agents/plans/<cr-ref>-<what>.plan.md — name the brief with a short kebab <what> slug naming what the CR does, even when the ref comes from an external source (github-34-rejudge-sweep.plan.md, not github-34.plan.md). The source name (github) is optional — most projects draw from one external source, so a bare 34-rejudge-sweep.plan.md is fine; keep the source prefix only when a project mixes sources. Fill from a basic template: frontmatter todos (ordered, status: pending, each content a short summary < 120 chars) + a ## NEXT anchor + the CR link. Keep the plan body concise — it is read by the agent each resume, so phrase for an agent first while staying human-legible (terse lead, no prose padding). This is the portable handoff brief pause-mission / resume-mission operate on. Safe-to-publish floor (the same one the combat log carries in combat-log-governance): the brief is tracked and committed, so it references only repo-relative paths — never an absolute path, $HOME/$USER, an OS username, or any machine-local location outside the repo. When the CR's design came from a plan-mode doc under a machine-local path (e.g. ~/.claude/plans/…), bring that content into the repo (a sibling <cr-ref>.design.md beside the brief) and reference it repo-relative — do not link the external absolute path. The check-plan-safety engine enforces this mechanically. When that brought-in content is a plan-mode preview (a drafted spec + scenario list from a prior ### Plan-mode preview run), the explore phase adopts it as the settled draft (see Step 2) rather than re-grilling from scratch.
Escape a non-CR. If the grill shows no suite-relevant behavior, escape: create no draft, invoke no gate, write no record. Independently, escape by tracking: for each artifact the request touches, run the resolve-tracking skill (intake/resolve-tracking's concrete engine) — node "<skill>/scripts/resolve-tracking.mts" --root . --path <path> [--artifact-type <type>] [--explicit tracked|ignored], passing --explicit when the requester stated tracking directly and --artifact-type when convention already makes it obvious. If every touched artifact resolves ignored, escape the whole request the same way. If the request is mixed, carve the tracked artifacts into the CR and escape the ignored ones (the same carve-and-escape shape already used for the no-behavior case). Escaping does not mean stopping: if the artifact-type has a producer with an escaped-request entry point (define-skill for skill), invoke it directly to do the work; only state "leaving the lifecycle" and stop when no such producer exists.
Step 2 — explore: grill the spec + suite, build to learn
Run authoring in-session as the conductor. Explore builds the implementation to learn (build-to-learn) — implementation is not deferred to deliver; the freeze is the boundary. The phase ends at the spec gate.
Mission statusline (opt-in). On entering explore, overwrite .agents/sdd/statusline with explore — a single-line, best-effort write; a missing file / no init-wired reader is not an error, just skip it. This is the runtime status value, distinct from the lifecycle status frontmatter field, and is written only while a mission is in flight (never at rest, no heartbeat). Skip this write during the Plan-mode preview branch below — it writes no repo files at all.
If plan mode is active, run the ### Plan-mode preview (end of this step) instead of the live grill loop — same reasoning, no repo writes, no build-to-learn spikes; the phase ends at ExitPlanMode, not the spec gate.
Resolution first. Run resolve-governances over only the project registry .agents/universal-plugin.json (never scan plugin dirs), passing the current project's anchors (--project, plus --project-root in a monorepo — you know the project from discover-specs / context). For each touched file'sartifact-type it names each production-chain role's agent (a plugin delegate or the SDD default) plus the resolved-actor bar candidates bucketed by tier (project / project-root / plugin / sdd). It does not compose — load each candidate and compose them yourself by precedence sdd-default < plugin < project-root < project (most-specific wins on conflict; a governance's own compose: replace supersedes its bar's lower-precedence candidates); the fixed-universal governances are loaded from the role/agent definition (the matcher does not emit them) — their names up front as a compact digest, each body lazily only at the gate/decision that invokes it (gate-validation/lifecycle at a gate, suite-format when authoring a .feature; sdd governance-resolution), so a one-line change never reads all six. A required role with no real delegate fails closed. A resolved delegate that recuses from a subject (produces nothing, declaring it outside its domain — e.g. a plugin bound by artifact-type meets a subject its lens does not fit) is not a fail-closed: re-resolve that one unit's chain to the SDD defaults (default producer + SDD-default bars + judge) and proceed, recording the recusal as a combat-log line (never a halt); other units keep their squad (sdd:lifecycle-governance). A domain claimed by two plugins → ask (answered live in-session).
For each unit the CR touches:
Locate or place the node — provisionally. If a spec.md / README.md already exists at the target → this is a revise (no scaffolding). Otherwise scaffold a new node and drop it in a plausible home under the layout the project declared in its root spec.md placement map — capability-first groups by what the project does, mirror-source mirrors the source tree. Placement is judged within that declaration, never against a preferred one (sdd:spec-structure-governance, "strategy is policy, homes are data"); where no strategy is declared, the capability-first default applies. A layered / framework-first top level stays discouraged under every strategy (it scatters a capability across folders, breaking node↔folder and degrading scheduling). Consult project-spec/place-node (--concept → candidate homes; --name → "belongs near X" duplicate-catch) and the placement-map routing table (root spec.md) for contested overlaps, but do not agonize: placement is provisional and finalized cheaply at handoff (step 4), where a scoped Warden pass relocates it to its blessed home in the same change (a pure rename — freeze survives, sdd:lifecycle-governance). If the user named no capability, propose a capability folder from the CR and confirm.
Classify the node (declared, never inferred): spec-type: behavioral (a testable unit → ## Use Cases + a <unit>.feature), reference (a shipped non-testable artifact → ## Subject, no .feature), or descriptive (an index → no marker). Tag the node's cross-cutting concept: (the concern it serves — e.g. lifecycle / resolution; a string or list, orthogonal to spec-type; it feeds project-spec/concept-index). Also classify each touched file's artifact-type (the squad key — resolved per file, not stored): by convention first (skill under skills/, subagent under agents/, …; the extension never decides). On a genuine ambiguity or a user-flagged path, consult and record the tiebreaker map .agents/sdd/artifact-types.toml and confirm — never guess (sdd:artifact-type model).
Scaffold the skeleton per sdd:spec-format-governance (sections per type; .feature form per sdd:suite-format-governance). Write no control frontmatter (status / project-path / approval / produced-by) — those live on the root spec.md and belong to the conductor and the gate.
Collect seed intent. For a new feature, ask 3–5 targeted questions — lead with the actors (who reaches this capability, and who is affected by its outcome without invoking it), then their goals, then the core problem, observable behavior, edge cases / non-goals, and reviewers who must be heard. Ask for the public interface last, and never first: an interface offered up front becomes the anchor the use cases get read off, which is the enumeration failure sdd:spec-format-governance exists to prevent. For backfill (behavior already in code), skip — the producer reads source, tests, history. For a revise, collect what changes and why and the parts it touches.
The grill loop (the user loop). You are the conductor. Run the spec-producer inline (load sdd:spec-producer-governance, or persona-load a plugin specialist for the artifact-types), dispatch the cold spec-judge each round — through the dispatch capability's intent seam when one is available (preferring its warm unit, context-cleared fresh via npx cyberlegion@0.3.1 unit clear <ref> before each round's judgment), else a portable cold subagent — and for build-to-learn dispatch the impl-producer builder the same way (its warm unit keeps its context across spikes; no reset) in explore mode against the non-frozen suite — spikes are thrown away; their learnings feed the live grill to steer the spec + suite. Set an iteration cap (default 3; honor a user-named cap), then loop:
Governance provenance relay. When you dispatch the cold spec-judge, forward the inline spec-producer's declared governances_loaded (sdd:spec-producer-governance) verbatim through the same dispatch channel, keyed producer_governances_declared — a brief field when the judge is a cold subagent, a mail envelope field when it runs through an agent pool. Forward it as-is, including an empty set — you render no opinion on which governances were actually required; that check is the spec-judge's own pre-flight (sdd:sdd-spec-judge).
Grill the user live with the node path, artifact-types, and the seed intent (or backfill / revise); write the draft spec.md + .feature.
Spawn the cold spec-judge; incorporate its verdict and any <!-- open: --> markers.
On convergence → exit to the spec gate.
On blocked, or the cap hit without converging → do not auto-accept. Present the failing scenarios and ask the user to accept as-is, keep looping (reset the count), or change direction.
Freeze re-open guard. A node at status: approved or implemented has a frozen .feature. The unfreeze trigger is risk, not phase (sdd:lifecycle-governance), so what you may do to that file depends on the edit class, not on it being frozen — read the edit class structurally, per named Scenario, never from a raw line diff (a step orphaned off a frozen scenario onto a new adjacent scenario shows no - line and would misread as additive): npx gherkin-cli@0.0.2 diff --base <baseref> <file> --format json (addOnly / only added ⇒ additive; any modified/removed ⇒ examine for narrowing), or the spec-gate's plugins/sdd/skills/spec-gate/scripts/classify-edit-class.mts which wraps this same structural diff plus git rename detection. An additive scenario (new behavior, nothing weakened) self-clears — it stays @frozen, needs no re-open; a pure move/rename (git mv, zero content delta) likewise preserves freeze and is not a gate-able edit. Only a narrowing or rewriting edit to an existing scenario is a re-open — a freeze transition and a status write you do not own, so confirm it was ratified (the lightweight async re-open flag) before touching that scenario's content. Never narrow or rewrite a frozen scenario without the ratified re-open; adding and relocating need none.
Route observations. Each production-chain producer (spec-, impl-, solution-producer) may surface typed OBSERVATIONS (architect | strategist); never act on them silently. When several producers surface observations in one segment, forward every producer's observations to the plan — drop or filter none of them — and spawn no spec of your own from them. A granularity / split observation becomes a new node or a project-spec operation (the plan's or the user's call) — never a marker grown into this node, and never a spawn you make here. An observation the plan or user then declines is dropped by that decision — an explicit call, not silent loss.
Plan-mode preview
Run only when plan mode is active (the harness blocks every write except the plan file). Run the explore reasoning in full but write no repo files — the plan file is the single output.
Reason as normal.resolve-governances; locate/place the node provisionally in-memory (no scaffold write); classify it (spec-type, concept:, per-file artifact-type); collect seed intent with the same 3–5 targeted questions (backfill reads source instead).
Draft, don't write. Compose the spec.md prose and the <unit>.featurescenario list per sdd:spec-format-governance / sdd:suite-format-governance, but render them into the plan file under ## Proposed Spec and ## Proposed Scenarios (scenario titles + Given/When/Then, grouped by # ── <stage> ──, @rubric/@trigger tags noted) — never to their repo paths.
Keep the cold spec-judge (read-only): spawn it over the in-memory draft as embedded in the plan; fold its verdict and any <!-- open: --> markers into the preview so unresolved gaps are visible.
Drop the build-to-learn spikes. Do not spawn the impl-producer — spikes mutate files / run builds (disallowed in plan mode) and are out of scope; note in the preview that the draft is un-spiked.
No gate, no writes. No spec gate, no @frozen, no status / approval / ledger writes. End the turn with ExitPlanMode presenting the drafted spec + scenario list.
Adoption on approval. On approve + exit plan mode, the next non-plan-mode explore run adopts this preview as the settled draft (via the intake <cr-ref>.design.md seam, Step 1): it writes spec.md + <unit>.feature from the preview, runs build-to-learn to validate, and proceeds to the spec gate without re-grilling seed intent. Guard: if the preview carried a failing spec-judge verdict or unresolved open markers, resolve those first — never blind-adopt a known-incomplete draft.
On entering the gate, overwrite the statusline file with spec gate (same opt-in, best-effort write as explore — skip when plan mode escaped this step via ExitPlanMode).
Run the spec gate as an internal step (not a user-invocable skill). Judge each touched unit suite against sdd:suite-format-governance (untagged scenarios boolean; @rubric well-formed) and the spec-format bars; load sdd:lifecycle-governance + sdd:ownership-governance + sdd:gate-validation-governance for the legal state tuple. Never advance with judge failures, open markers, or a suite that does not cover the spec. On a change verdict the findings are evidence, not a work order: substantiate each before acting, state the rule each instantiates and sweep for its other instances, re-derive every correction against the rule governing the artifact rather than against the finding alone, and account for each finding's provenance — a finding naming an artifact the previous round's commits changed is a regression, which stops the loop for a re-plan instead of another round (sdd:remediation-governance). ("Regression" here is finding provenance, distinct from the grill loop's convergence above.) On approve: freeze each touched .feature via its @frozen tag, record a per-CR gate line in your own shard in the ledger/ directory sibling to spec.md, and set status: approved. spec.md stays in sync, never frozen.
Step 3 — deliver: build to keep
On entering deliver, overwrite the statusline file with deliver.
Build-to-keep against the frozen suite. The deliver read-set is scoped (sdd deliver spec): the frozen <unit>.feature (the contract), the optional <unit>.solution.md, and the implementation files for the touched artifact-type (via produced-by / resolve-governances) — not the prose unit spec, which was explore's input and adds no constraint the frozen suite doesn't already carry. Dispatch the impl-producer builder (it loads sdd:impl-producer-governance; a named plugin / model-tuned producer runs at its own model + effort) — through the dispatch capability's intent seam when available, preferring the same warm builder unit reused from explore (it keeps its context; no reset) over a cold one-shot, else a portable cold subagent — to build the artifact and one verification per frozen scenario.
Rebase onto the target — the last deliver act, before the gate. Before running the impl gate, rebase the CR branch onto the current tip of the declared target (for a commit-to-main project, the equivalent pull --rebase onto the latest main), so the impl gate judges the merged tree that will actually land — keeping history linear and leaving handoff a pure consumer that never re-verifies. A textual conflict is resolved as deliver code work against the frozen .feature (never a .feature edit); the gate then runs on the resolved tree. A conflict you cannot resolve confidently is never guess-resolved — the frozen suite covers this CR's behavior, not the incoming change's, so a wrong resolution could still pass the gate and land broken; stop and escalate (in-session ask the user; headless return needs-input up the relay) and record a halt, never land a low-confidence resolution. Rebasing an unmerged CR branch is git-reversible (reflog), so it raises no new hard floor — but a conflict resolution that would narrow a frozen scenario still fires the existing Clearance floor, a semver class over the ceiling Compatibility, and a genuine contradiction Conflict (autonomy bar, below). The rebase-then-gate is optimistic: if the target advances again between the passing gate and the push (another CR merged in the window), re-rebase onto the new tip and re-run the impl gate — do not push until the gate passes on the re-rebased tree, looping until the push wins, so what lands is always a tree the gate saw green. The loop is bounded, not forced — if the target keeps advancing past a small cap of attempts, stop and escalate (record a halt) rather than spinning forever (a liveness stop, same as the unconfident-conflict halt).
The impl gate (Approved → Implemented, internal). On entering the gate, overwrite the statusline file with impl gate. Dispatch the cold impl-judge (sdd:sdd-impl-judge or the covering plugin's judge) — same seam-when-available wiring, preferring its warm unit context-cleared fresh via npx cyberlegion@0.3.1 unit clear <ref> for this judgment, else a portable cold subagent — to run the verification per frozen scenario plus an orthogonal structural/scope read. Advance to status: implementedonly when every impl-judge passes (a frozen scenario with no verification blocks the advance — impl-sync is this suite run, not a stored flag). The three actions: approve → implemented; change → fix the code (never the frozen .feature), under the same evidence-not-a-work-order remediation the spec gate uses (sdd:remediation-governance) — including the provenance account that stops a regressing loop; reject → redo, or a Oracle-lens revert (a frozen scenario proved fatal → unfreeze the .feature, return to draft — the only place a frozen .feature reopens).
Step 4 — handoff
On entering handoff, overwrite the statusline file with handoff. Clear the statusline file (delete .agents/sdd/statusline, not just blank it) once the mission lands — a clean handoff is one of the loop's exit paths, and the file is written only while a mission is in flight.
Land per the handoff unit. First finalize placement: run a Warden placement pass scoped to this mission's touched nodes, and relocate any provisionally-placed node to its blessed home (placement-map routing table) via git mv — a pure rename that preserves freeze (sdd:lifecycle-governance), logged as a detail-adjustment, so the delivery shows every node already in the right place (no follow-up formation CR). Then land per the declared delivery shape (branch → PR where the repo is PR-flow), decomposed by unit of work (one co-committable change per commit), conditional status write-back — when the CR's source closes by reference (a same-forge issue, e.g. GitHub/GitLab), write the auto-close reference (Closes #<n>, naming the source) into the PR body so the source auto-closes on merge; a source that does not close by reference (a bare prompt, or a cross-system source like Asana/Jira) gets no closing reference (direct-to-main work transitions it to done on push; a cross-system source is moved natively) — and a distilled public summary. Introduce no new hard floor; keep the combat log in the PR; keep the plan until the CR is done/merged and doctrine-distilled.
Follow-ups: record, classify, propose, drain — only the first always works. A follow-up (work the mission noticed but held out of scope) is carried through four stages. 1. Record — unconditional, first. Before anything else, and before any filing is attempted, append each identified follow-up as a kind: followup line to the CR's own ledger shard (sdd:combat-log-governance) — no permission, no forge, no human, so it cannot be denied; it goes to the ledger, never the combat log (the combat log is deleted from the tree at retro; the record must outlive the mission). 2. Classify — a proposal, not a verdict. Mark it blocking (it contradicts a completion claim the mission already made — name that claim in the line) or backlog (genuinely new territory); a finding that the mission's own frozen contract was wrong is not a follow-up at all — route it as an Oracle-lens revert inside this mission instead. 3. Propose, never admit. Emit the classified proposal plus its evidence; write no node or edge to the mission graph and spawn no mission for it — admission is the graph's single writer's act, out of scope here; filing an issue is not opening a CR, and a filed follow-up re-enters SDD only when a later mission is started from it. 4. Drain — permission-gated, class-agnostic. File one issue per outstanding follow-up, blocking and backlog alike (the class decides graph admission, never filing) — dedupe first against the forge's existing issues, open or closed (at least two keyword combinations: the full title, then the core noun/verb) — and on a mixed set file only the unmatched, skipping the matched, never all-or-nothing. Forge-conditional: a source with no issue forge files none; the records still stand. The followup line carries no filed-state — never edit it to mark it filed — so a later drain re-derives what is outstanding by that same dedupe, which is what makes a retry both correct and idempotent (a follow-up whose filed issue was since closed is a closed match, so it is skipped, not re-filed).
The denial path is first-class. Filing can be refused (an unattended mission has no channel to grant it). When refused: the ledger records stand, you report the refusal loudly, and you never report the follow-ups as filed — a fallback indistinguishable from success is the exact failure this doctrine exists to avoid. The drain retries later from the durable record, filing the still-outstanding follow-ups once permission is granted.
The issue body meets a stricter outward-publish floor than the committed record. Compose it self-contained — a reader who cannot see the mission's internal artifacts can act on it, with no "see the ledger line" and no gate/judge/leash prose — carrying no production-internal artifact reference: no ledger shard filename (it embeds a per-session hash), no combat-log reference, no plan-brief path — even though a repo-relative ledger shard filename passes the committed-record floor cleanly; this bar is stricter and excludes it anyway. Plus everything the committed-record floor already bans (absolute paths, $HOME/$USER, usernames, hostnames, secrets, code, raw numbers). Every filed follow-up also carries a marker identifying it as agent-filed and names the mission (<cr-ref>) it was discovered from, so intake can tell agent- from human-filed follow-ups and the loop's branching factor is measurable.
Before you close out, run the correction-line finalize backstop (autonomy bar, below): flush any correction whose combat-log line was never written, creating the plan's *.log.jsonl if absent.
Also run the plan-brief finalize backstop (autonomy bar, below): reconcile the plan brief's todos and its ## NEXT anchor to the landed state, in this same change — so the delivery never ships a landed mission described as in-progress.
Before closing out, reset the mission's warm units: npx cyberlegion@0.3.1 unit clear <ref> (context-clear, pane stays warm) or tear down every warm unit this mission dispatched — none carries this mission's context into the next.
Once landed, do not spawn the formation Warden. Surface a one-line nudge that a corpus-wide formation pass is due, pointing to sdd:manage ("audit the corpus structure" → formation-loop). The pass is on-demand — run deliberately, not auto-spawned on every landing; sdd:manage owns the trigger. Gate nothing on it.
Autonomy, provenance, and the hard floor (baked in)
Dispatch transport. Every spawn beyond this session states a dispatch intent — role, brief, expected verdict schema — never a pinned command. When a harness-agnostic dispatch capability is available (detected at runtime; the concrete case is the Legate's dispatch-governance composing cyberlegion primitives — agent resolve + unit spawn + mail await — with nodispatch CLI verb, the seam named in the SDD project spec's design/harness-spawning node, repo-only), route through its intent seam and let it pick subagent | channel | run-inline, preferring a warm unit over a cold one-shot spawn; with no capability present, fall back to the portable cold subagent (depth-1) default — grader independence intact either way. Warmth is a property of the unit/process; coldness of the context: a judge's fresh-context guarantee (ADR-0016) is transport-agnostic — satisfied by a newly spawned cold subagent or a warm unit context-cleared to a fresh context before each judgment (re-deriving its oracle, carrying none of a prior round's context). Clear a warm unit with npx cyberlegion@0.3.1 unit clear <ref> (<ref> = unit id / handle / worktree branch or CR ref) — it injects the harness's own fresh-context command (/clear on Claude/Codex/Copilot, /new-chat on Cursor; fail-loud on a harness with no honest reset) so the pane stays warm while the context goes cold; it tears nothing down. The impl-producer builder instead stays warm and keeps its context across the explore spikes and the deliver build (never cleared between those uses). Warm units stay warm for one mission — reused within it, then unit clear'd or torn down at handoff, never carrying this mission's context into the next.
Initial strategy (run start): assess blast radius + the other dimensions and emit a run-level kind: leash block to your own ledger shard (ledger/<cr-ref>.<hash>.jsonl — mint <hash> as 6 random hex once per session and reuse it for every line you append; sdd:combat-log-governance) — leash (auto-none | auto-spec | auto-all), by: derived | user, approach[]. It may be user-specified. This block is kind: leash, notstrategy — strategy is the doctrine Scanner's alone. Ledger lines carry no ts.
Per-gate verdict. At each gate, derive the leash against discovered state and either self-assert within leash (write approval.<gate>: { verdict: approve, by: agent, why }; the spec lands in the async review queue) or stop with a verdict packet for the human. Never advance when any judge fails, any open marker remains, or (at the impl gate) any frozen scenario's verification does not pass. Human ratification (by: <name>, advance status) is reserved to the in-session position holding the user channel — by default you, in-session; a headless automaton emits the verdict packet and stops, even when a coordinator relays "the user approved."
Combat log. Append report / correction lines (and the halt that stopped you) to the plan's *.log.jsonl (these carry a UTC ts); your run-start leash block, self-asserted gate lines, and the handoff followup records go to your own shard in the durable ledger/ directory sibling to spec.md — never another writer's shard, never a shared file (strategy there is the Scanner's alone). Free text is commit-message-grade — never code, prompts, secrets, or literal values.
Correction-line durability (combat-log-governance write duty). When a gate you self-assert was reached via a judge-reject→fix→pass, append the discrete correction line (correction-kind: judge-iteration, a matchable cause) to the combat log before you write the gate why — never leave the iteration recorded only in the why prose; a gate that passed clean appends none. At handoff/finalize, if any correction occurred whose combat-log line was never flushed, write it now — creating the plan's *.log.jsonl if it does not exist — so no correction is lost to the no-log mission class (a mission with no correction forces nothing). The forced line stays a combat-log correction, never a ledger line.
Cause-enum conformance (combat-log-governance write duty). Every time you write a cause — a correction's matchable cause or a gate line's stop cause — prefer an enum value; if none fits, write the off-enum string into cause anyway and flag the line cause-candidate: true, so it stays countable as a proposed enum-growth value instead of silently failing closed. A visibility nudge, never a write-blocking linter — the write always succeeds, and forcing an ill-fitting enum value would only relabel the silent drop. An absentcause still fails closed (the nudge governs only the no-value-fits case and licenses no omission). The gate stop-cause enum is dimension | clearance | ceiling; the correction matchable-cause enum is coverage-gap | design-overreach | spec-feature-contradiction | prose-impl-contradiction — both closed sets grown only by Council ratification, and a recurring cause-candidate value is the growth signal the Council reads.
Plan-brief durability (the execution-state sibling of the correction-line durability rule above). At handoff/finalize, a mission that lands reconciles its plan brief to the landed state — every todo set to its true terminal state, and the ## NEXT anchor rewritten to say what landed, naming no remaining resume action. It is a backstop: it does not depend on the loop having kept the brief current, so a brief untouched since intake is reconciled in full in one pass, and the reconciled brief lands in the same change as the work. Reconcile means to the landed state, not mark everything done — a todo whose work was genuinely held out of scope stays un-completed and rides the follow-up machinery instead; marking it completed would make the doctrine Scanner's todos-all-done ∧ source-closed cross-check agree wrongly and clear the brief for retirement, deleting the record of work never done. A brief already matching the landed state is left unmodified (the backstop writes what diverges and forces no minimum footprint). Scope is the brief and nothing else: nospec.mdstatus/approval, and no terminal value written into the plan-level status dispatch flag — that enum stays active | approved and terminal-ness stays derived, matching the Scanner's own never-writes-status guard. A mission that halts instead of landing is not reconciled: a halt is a pause-mission checkpoint of the true in-progress state, and reconciling it to "landed" would assert a landing that never happened.
Hard floors (mandatory stops):Clearance of a narrowing (weakening/deleting an acceptance scenario; pre-authorizable in the CR), Compatibility when the semver class exceeds the change-class ceiling (pre-authorizable), and Conflict of a logical contradiction in the suite (not pre-authorizable). An obvious stale-mistake contradiction is a conductor-served minor fix; escalate only when both sides are plausibly intended. Clear the statusline file on any abort/halt that ends the mission (a hard floor stop, an unconfident-conflict escalation, or any other terminal halt) — the same exit-path clear as handoff and pause; a mid-mission escalation the user resolves in-session (not a halt) is not an exit and leaves the file as-is.
Suspend and resume
A mission runs as segments (one autonomous sitting each). Position is derived from the artifacts (spec.md, the .feature, frontmatter, the plan), never a stored cursor. To checkpoint a mission into its plan, use pause-mission; to pick one up, resume-mission reads the .plan.md and continues this loop where it left off.
Clear the statusline file on pause too. A pause is an exit path like handoff — before (or as part of) invoking pause-mission, delete .agents/sdd/statusline. This is your write (the conductor's), not pause-mission's — its write scope stays boundaried to the plan brief (todos, ## NEXT, and, with --approve, status); it never touches the statusline file.