Commit — Session-Isolated, Doc-Sync-Gated (gateway-inline)
Commits the changes this Claude session produced, leaving prior uncommitted work alone. The gateway runs the flow inline — it holds the session's diff, file list, and change intent, so the mechanics carry no closure a fresh container would hold. The doc-sync judgment runs warm in that same context: the diff, the change intent, and the session's read docs are the judgment's inputs, and the gateway already holds them all. Dispatch survives as the scope-overload valve — a scan scope past the ceiling moves whole to the cold doc-sync-scan agent rather than being truncated inline.
Execution (gateway-inline)
Session file list — from this conversation, the files this session edited/wrote. This is the session-isolation ground truth; a file you don't remember touching stays off it. Stage by explicit path only.
Gather state —
git status,git diff,git diff --staged(a staged path outside the §1 list is another session's — early warning only; §5's readback is the gate),git log --oneline -10(recent style).Doc-sync grep-gate — mechanical, no judgment:
- Deferred mode — check first (drain-worktree isolated commit): doc-sync belongs to the merge boundary — skip all of §3, go to §5.
- Frozen-provenance exemption — card lifecycle, history dimension: every changed path inside
docs/work/(card-thread appends, card deletions, work-README high-water bump), plus every changeddocs/outward/OUT-###.md(thread appends, entry deletions) and the outward README's high-water bump → skip the gate, go to the link check below then §5. Both are append-only threads, self-contained; cross-card ID mentions are frozen provenance, not behavior narration — sohitsandrefsleave everydocs/work/card thread and everydocs/outward/OUT-###.mdthread out of the scan scope too, whatever term they name or anchor they cite; each folder's standingREADME.mdnarrates its thread contract and stays in both lanes. A doc whose leading frontmatter declaresdimension: historyis frozen provenance the same way — a change to it yields no term (termsskips it),hitsandrefsleave it out of the scan scope, and the link check below still covers it. Mixed diff → run the gate on the other paths only. - Premise lane — product-anchor paths: the diff touches the product anchor (
docs/overview.md§ Problem / § User, or a dedicated product doc where the repo splits one out) → route the anchor portion through §3b — its closure set is the whole doc surface, so it already covers everything this gate would reach for the anchor; the rest of the diff continues through this gate. - Terms → grep hits — one script call each:
<skill-base>/assets/doc-links.sh terms <changed paths…>prints the gate's terms; scaffolding paths (bench, tests, fixtures, goldens, session ledgers), asset extensions, generic basenames, terms under four characters, and the machine state harness-bootstrap seeds under.claude/(the runway receipt,templates/) yield none. Nothing printed → the grep lane is empty, skip to the citer lookup. Otherwise<skill-base>/assets/doc-links.sh hits <terms…> | grep -vxF "$(printf '%s\n' <changed files>)"prints the doc-surface files mentioning a term in code shape — a whole word inside backticks, or a path segment — so bare prose stays out. Harness-seeded hub stems (overview,techstack,decisions, the runway receipt, the worktree template) count only as a bare token inside backticks: a path mention of a hub doc is a citation the anchored citer lane already reaches, not a narration. Hit files join the scan scope; the agent judges them cold (§4).hitswalks the markdown surface — a manifest description field the diff changes is read here directly. - Link-hit (reverse citers) — mechanical, beside the grep: for each changed
docs/**/ rootREADME.md/ plugin-README (plugins/*/README.md) path, take its post-image hunk ranges fromgit diff -U0 -- <path>(@@ -a,b +c,d @@→+c,d) and run<skill-base>/assets/doc-links.sh anchors <path> <ranges…>.(top)among the slugs means whole-file grain →<skill-base>/assets/doc-links.sh refs <path>; otherwiserefs <path>#<slug>…in one call of the same script, which prints the union. Exclude the changed files themselves. Every file returned is a declared citer of the changed truth — collect them as the citer read-set. - Link-target extraction (forward links) — mechanical, beside the reverse lookup: from the diff's added lines, extract every markdown link target (
grep -oE '\]\([^)]+\.md[^)]*\)'over+lines), resolve each relative to its linking file. Each target is a doc the new prose claims agreement with — add the target files to the scan scope. A target that is itself a changed file still joins: its unchanged sections are exactly where a same-commit contradiction hides. - Scope ceiling — count before judging: the scan scope is citers ∪ grep hits ∪ link-targets. At or under 8 docs → the gateway judges the scope warm-inline (§4). Above 8 → the scope moves whole to the cold
doc-sync-scandispatch (§4's fallback lane) — never truncated to fit inline. - Any grep hit OR any citer OR any link-target found → run the doc-sync judgment (§4) over the scan scope — citer read-set + grep-hit files + link-target files.
- Neither → the diff narrates nothing; go to §5.
- Link integrity (every non-deferred commit, exemption included): run
<skill-base>/assets/doc-links.sh checkfrom the repo root —<skill-base>is theBase directory for this skill:path surfaced at invocation; zero model tokens. Broken links (path or anchor) surface to the user with the commit: fix or explicitly acknowledge before landing; never silently skip. One class is exempt by construction — the consumed-card-link skip: a link from a card thread (docs/work/{BUG,DEBT,GAP}-###.md) to an absent card ID is consumed provenance — the sibling resolved — socheckskips it uncounted, while every other target from a card, and any dangling card link from a non-card doc, stays strict.
3b. Premise-closure lane (product-anchor diff) — a problem/ICP revision changes premise, not behavior; its closure is every doc whose framing leans on the anchor. Enumerate mechanically — <skill-base>/assets/doc-links.sh closure <anchor-path> prints the set: the doc surface minus consumables (per-item work files — docs/work/{BUG,DEBT}-*.md, docs/work/TEMPLATE.md) minus the anchor. Judgment runs only over the enumerated set — dispatch the premise-closure agent (Agent tool, subagent_type: "premise-closure"; prompt = the anchor diff hunks + the anchor path + the enumerated paths, no staleness leans): its sheet (holds / re-frame / dangling per doc + coverage line) returns here; resolve with the user before the commit lands — re-frame: update the doc to align / acknowledge still-accurate; dangling: drop / merge / defer. Never silently fix, never silently skip. Then continue §3 on the rest of the diff.
Doc-sync judgment (gate hit) — warm gateway-inline by default; the cold dispatch is the overload lane. Both lanes run the same procedure —
agents/doc-sync-scan.md§ Scan — and end in the same resolution.- Warm-inline (scope ≤ ceiling): the gateway applies § Scan itself, in its own context. Warm eyes are the point: hold the change intent and the session's reads beside the diff while judging. Every scope doc gets an outcome — a stale candidate (path + what's outdated + hunk) or read-and-confirmed-unchanged; a doc skimmed or skipped is an incomplete gate, not a
clean. - Cold dispatch (scope > ceiling):
Agent,subagent_type: "doc-sync-scan"; prompt = the diff (git diff+git diff --staged) + today's date + the scan scope. The agent judges the same procedure in its own window and returnsstale-docsorclean. - Either lane stays scoped — never a whole-surface re-derivation; whole-surface coverage belongs to
/super-bootstrap:check-docs-consistency. - Stale candidates → resolve each with the user (update / acknowledge-accurate / skip — never silently fix, never silently skip). Land approved doc edits (inline for bounded prose; dispatch by closure). Resolved docs join the stage list.
- Nothing stale → proceed.
- Warm-inline (scope ≤ ceiling): the gateway applies § Scan itself, in its own context. Warm eyes are the point: hold the change intent and the session's reads beside the diff while judging. Every scope doc gets an outcome — a stale candidate (path + what's outdated + hunk) or read-and-confirmed-unchanged; a doc skimmed or skipped is an incomplete gate, not a
Message + commit — draft a Conventional Commit (
<type>(<scope>): <subject>, imperative ≤72 chars, body only when the why isn't in the diff, matchgit logstyle; one logical change per commit — a diff spanning two unrelated changes splits).git add <explicit paths>— never-A/., never secrets (.env, keys).- Index readback — the gate between
git addandgit commit.git diff --cached --name-onlycompared against the §1 session file list: the index is shared across sessions in one checkout, so a concurrent session's staged paths ride into this commit unless read back. Any staged path outside the session list → stop and surface: the foreign paths, and the pick — unstage-and-continue (git restore --staged <foreign>, on the user's say-so only) or abort. Never commit through it. - Where a harness-audit stamp call sits between add and commit —
git add→ readback → stamp →git commit. The stamp is a set comparison: it matches only when its path set equals the commit's staged harness set. A foreign path stamped in widens that set, and the readback's own remedy (git restore --staged <foreign>) then narrows what commits — leaving a fingerprint that can never match, so the gate re-fires on a commit whose audit did run and §5 carries no re-stamp step. Stamp the set that commits. - Commit with HEREDOC formatting; after,
git show --name-only --format= HEADequals the session list — prior dirty state is sacred, so a clean tree is not the check. Pre-commit hooks run; on failure fix the cause, never bypass. Always a new commit — amend only if asked.
- Index readback — the gate between
Push (where a push surface exists) — probe first, ask second; the probe is a fact the gateway reads itself.
git remoteprints nothing → no push surface: §7's handoff line is the next and only output. A remote but no upstream for the branch (git rev-parse --abbrev-ref @{u}errors) → say so in one line and ask once: "Set upstream and push (git push -u <remote> <branch>)? (y / skip)" —<remote>is the sole remote, or the one the user names when several exist. Remote + upstream → present branch → upstream, commits ahead; ask "Push these now? (y / skip)". Push on explicit yes only; skip on silence or decline. Never force, never unannounced.Cycle handoff — one line from cycle facts (any
docs/work/{BUG,DEBT,GAP}-###.mdpresent; a card whose latest Plan block has steps the latest Progress doesn't report done = in-flight). Don't expand into a status table — that's/super-bootstrap:todo's job:
| Cycle facts | Handoff one-liner |
|---|---|
| No open cards | Cycle complete. Safe to /clear. Next session: /super-bootstrap:todo picks up next item. |
| In-flight card (Plan steps not all reported done in latest Progress) | Cycle complete. {ID} still in-flight — /clear then /super-bootstrap:todo to resume. |
| Open cards, none in-flight | Cycle complete. Open cards, none in-flight — /clear then /super-bootstrap:todo to pick next. |
Rules
- Gateway-inline, judgment included; two dispatch valves, each on its own gate. The gateway holds the diff, session list, intent, and session reads → mechanics and the doc-sync judgment stay inline (the judgment's inputs are exactly what the gateway holds). The cold doc-sync scan dispatches past the scope ceiling; the premise-closure judge dispatches on a product-anchor hit.
- Grep-gate is mechanical. Term extraction is path-structure only, never a judgment about which identifiers matter — a judgment gate gets omitted. Any hit triggers the doc-sync judgment (§4); conservative by design. A pure asset/binary diff with no narrated path is the skippable class.
- Session-isolated. The session list decides; prior dirty state is sacred. Explicit paths, never
-A— and the staged set is read back against that list before every commit, so isolation holds at the index, not only atgit add. - Doc-sync round-trip, never bypass — a
stale-docsreturn goes through the user before commit. - Whole-diff-once. Doc-sync runs at the integration boundary, on the whole diff, once. Drain-worktree defers it to merge; an implementer never owns doc-sync — a partial-slice view gives false confidence.
- Push asks only where a push surface exists, and only on explicit yes — §6's probe decides whether the question fires; committed work is safe locally either way.