@sabaiway/agent-workflow-kit 14.21.0 → 14.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,52 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
4
4
  is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
5
5
  every `migrations/<version>-<slug>.md` newer than it, in semver order.
6
6
 
7
+ ## 14.22.0 — a story runs in four sessions, each step with one checked result; the advisor renders the new review loop (AD-170)
8
+
9
+ **Your project's rules now state the story flow the engine's canon (5.12.0) defines: four sessions — spec and plan,
10
+ tests, code, then diff review, release and record — with review on the spec with the plan's ledger and on the staged
11
+ diff.** The canon adds the epic's review by the review lens alone and the one commit after the diff review;
12
+ `/agent-workflow-kit procedures` renders both. Both rules templates' §2.6 (the lens) and §2.7
13
+ (Story sessions) carry the new bodies; the outgoing ones are priors, so an upgrade refreshes an unedited region and
14
+ keeps a custom edit, flagged.
15
+
16
+ - **`/agent-workflow-kit procedures` renders the loop the canon states.** One fold ask per member per round, carrying
17
+ all of its findings; round two with the folded artifact, the decided register and the fold diffs; a fold of the
18
+ last round re-read by its raiser; for `plan-execution`, the re-check of a staged tree that moves after a member's
19
+ last ship-class verdict. The round render, the cap triage and the red-proof instrument are gone from the
20
+ plan-authoring and plan-execution renders; `feedback-triage` keeps its round table. plan-authoring's agy review
21
+ reads the spec review file, and the unarmed flow line names no arming command. On a project that armed the flow
22
+ chain itself, `plan-execution` still renders the armed pre-fold line, a stated residual.
23
+ - **The epic by the lens.** `procedures epic` renders the lens review and, whatever `epic.review` resolves to, no
24
+ bridge wrapper, driving contract or grounding pre-step; the slot keys and the Slots line are unchanged.
25
+ `references/modes/agents.md` and the README say the lens is the whole review of an epic and never replaces the
26
+ review recipe of a plan or a diff; the `agents` report and `dispatch advise` say it never replaces a plan or diff
27
+ review recipe.
28
+ - **Cleanup after the commit.** The rules template's §1.3 Task Completion asks before committing first and runs the
29
+ plan's Phase: Cleanup after the commit.
30
+ - **One fold line.** Under a delegated execute slot the fold lane is one line: resume the run's session with
31
+ `codex-exec --resume <session id> --nonce <n> <prompt file>`, the id read from the run's exec receipt. The advisor
32
+ no longer reads the delegation ledger; `tools/held-session.mjs` drops `foldLaneLines`, which nothing else read.
33
+ - **`task.author` dispatches no slice.** `tools/carriers.mjs`: the orchestrator writes each row's prompt, so under
34
+ `subagent` `dispatchForm` prints the slot's sentence alone, without the executor dispatch lines; under `delegated`
35
+ the slot still renders `codex-exec` and its driving contract, which no step reads (display only, recorded debt).
36
+ `task.execute`'s slice is one prompt the orchestrator wrote from one ledger row; `references/modes/{agents,recipes,
37
+ set-recipe,procedures}.md` say the same.
38
+ - `tools/tier-guide.mjs`, `references/modes/tier.md` and the reference profile say four story sessions;
39
+ `references/templates/SPEC_TEMPLATE.md` says a draft exists at the spec review.
40
+ - Recorded debt (`docs/debt.md`): `recipes --active-line` (`→ codex-review`), the orchestration README default
41
+ sentence, the tier offer and `status` still render `epic.review` as a bridge review (`reviewed`), and `recipes
42
+ --active-line`, `procedures task` and the tier offer still name `codex-exec` for a delegated `task.author`; no
43
+ step reads either slot; display only.
44
+ - **The tier guide walks a story on this flow.** `tools/tier-guide.mjs` says a task is one plan row handed out in
45
+ one prompt from the task template, and the story commits once, after its diff review.
46
+ `references/authoring/TASK_TEMPLATE.md` is that prompt's form: Row, Files, Reads, Run and Do not run, seven keys;
47
+ a bridge prompt adds the contract block with a fresh nonce that the engine's *The task* names. The
48
+ guide's story stages are S1-S4: it reads each row's prompt at its canonical name, and a landed story's leftover
49
+ (read the staged diff, check the review state, the one commit, remove the plan) holds every other story and
50
+ every other epic's close until it is done, so the story commits before its epic closes. The guide no longer judges the plan, mints a checkpoint, stamps
51
+ or checks a brief, or commits per task; it prints `plan-shape-cli --check` as a step.
52
+
7
53
  ## 14.21.0 — the bridge model is one host setting: your choice, else the default, checked against the installed CLI before any run (AD-169)
8
54
 
9
55
  **Each bridge now runs the model you set, and `/agent-workflow-kit bridge-settings` shows and sets it.** The read-out
package/README.md CHANGED
@@ -252,7 +252,7 @@ file), or run the guarded `/agent-workflow-kit uninstall`.
252
252
  | `/agent-workflow-kit worktrees` | any time | **parallel feature worktrees** — run several features in DIFFERENT agent sessions on one repo, zero interference on working-tree files (the ONE exception is the dependency cache, below): `provision <slug> --plan <file>` creates a sibling git worktree on branch `aw/<slug>` and populates it (registry-derived footprint copy-if-missing — a tracked file is never overwritten; EXACTLY ONE seeded feature plan; the `handoff-<slug>.md` record from minute zero; `node_modules` symlinked where the link stays ignored — a shared MUTABLE dependency cache: writes through it hit MAIN's node_modules; for isolation run the printed isolated-install command (`--install` only PRINTS it; on `--resume` run the printed unlink-first recovery first — printed only for a link whose RAW TARGET is MAIN's `node_modules`, since a foreign or unreadable link is reported as such with no removal advised); absolute root-pinned gate commands rebased on untracked copies only, and only while their bytes equal the MAIN source or its rebased form — user-modified copies stay untouched); `list` is read-only (slug, branch, base, dirty, handoff); `prompt <slug>` is read-only too and re-prints the satellite's cold-start prompt — the same text `provision` ends its report with: where the worktree is, its ONE seeded plan, the handoff as the one channel back, MAIN's orientation (shared series index, landing) and, under its own heading because it is probed on the satellite, that checkout's install posture — every value derived LIVE rather than replayed from the frozen provision record, a recorded value that no longer matches NAMED as a divergence (with the cause its source makes likely) instead of printed as the runnable one, every offered command marked with WHO runs it (`MAIN $ …` for the landing, `HERE $ …` for this checkout's own install, a posture with nothing to run staying prose), and a control character in any rendered value a typed STOP rather than a forged prompt line; `land <slug> --prepare` locks the common git dir, fail-closes on divergence or incomplete satellite state, transfers the complete accepted satellite diff onto a CLEAN main, runs sync plus the declared gates, and reports HEAD/TRANSFER/PREPARED OIDs — the commit ALWAYS stays a dialogue ask; `cleanup <slug>` takes the same lock and removes a LANDED worktree only after live landed-verification against main HEAD, while `--abandon` is the ONE destructive arm (destroys unlanded work; **no preview step** on any writer). The parent dir is the `docs/ai/worktrees.json` `parentDir` setting (default: the repo's sibling parent); an unwritable parent degrades to printed maintainer-pasted commands, and the one-time host consent that makes it promptless surfaces via `recommendations`. Never commits, never pushes, never runs a subscription CLI. |
253
253
  | `/agent-workflow-kit uninstall` | opt-in, any time | **guarded teardown** — the inverse of `init` / `setup`. Removes only what's **provably ours** (managed skill dirs + bridge wrappers; in a project, the hidden-mode git-ignore block it added + the pre-commit hook it installed); **never deletes** your `docs/ai` / `AGENTS.md` (prints the exact `rm` to run by hand) or your `.claude/settings.json` (prints an **edit** — remove the attribution key, review any velocity `permissions.*` — never an `rm`). Always `--dry-run` first; preflight-then-mutate; never commits. |
254
254
  | `/agent-workflow-kit velocity` | Claude Code · opt-in | **onboarding velocity profile** — seeds a fixed, audited **read-only** allowlist into `.claude/settings.json` so routine read-only commands stop idling on approval prompts while you're away; opt-in `acceptEdits`; plus a **read-only advisory** of likely project gate commands to add by hand. Writes **only** `.claude/settings.json` — **never** allowlists commit/push/publish, never writes `settings.local.json`, never commits. A seeded entry is a **trust posture, not a sandbox** (a runtime residual remains at the settings level — its guard ships as the opt-in `hook` command); a direct commit/push/publish still asks. `--dry-run` first. |
255
- | `/agent-workflow-kit agents` | Claude Code · opt-in | **subagent vehicles** — places the five bundled subagent definitions into `.claude/agents/`: **four read-only vehicles + one full-tool `executor`**. **No read-only vehicle gets `Bash`**, and that is the load-bearing property: a read-only fan-out on a full-tool subagent shells out for facts it could have read, and every shelled command is an approval prompt you never needed to see. Three of the four ride a **cheap model** (haiku, low effort) for mechanical work — extraction sweeps, changelog fact-skeletons, gate-failure triage; the fourth, **`review-lens`**, is an ADDITIONAL independent read-only review opinion on code your configured backends have already seen (never a replacement for your review recipe, advisory like every review). The fifth, **`executor`** (all tools; model and effort from `docs/ai/vehicles.json`), is the ONE vehicle with a shell and the instrument behind the **Subagent** recipe: dispatched only for a bounded, file-disjoint execution / authoring / routine slice you verify afterwards — never for read-only work, never as a review backend, and it never commits. Its state (`placed` / `customized` / `unusable` / `missing`) is what a `subagent` slot's readiness resolves from. Writing code and running gates stay off the four read-only vehicles; the executor carries a bounded slice you re-verify on your main lane, and every vehicle's output is verified. Preview by default (`--apply` writes); an existing customized read-only vehicle or lens is **preserved, never overwritten**; the executor's body is re-derived from `docs/ai/vehicles.json` (a hand edit is replaced); never touches `settings*.json`, never commits. |
255
+ | `/agent-workflow-kit agents` | Claude Code · opt-in | **subagent vehicles** — places the five bundled subagent definitions into `.claude/agents/`: **four read-only vehicles + one full-tool `executor`**. **No read-only vehicle gets `Bash`**, and that is the load-bearing property: a read-only fan-out on a full-tool subagent shells out for facts it could have read, and every shelled command is an approval prompt you never needed to see. Three of the four ride a **cheap model** (haiku, low effort) for mechanical work — extraction sweeps, changelog fact-skeletons, gate-failure triage; the fourth, **`review-lens`**, is an ADDITIONAL independent read-only review opinion on code your configured backends have already seen (never a replacement for your plan or diff review recipe, advisory like every review; an epic is reviewed by the lens alone, whatever `epic.review` resolves to). The fifth, **`executor`** (all tools; model and effort from `docs/ai/vehicles.json`), is the ONE vehicle with a shell and the instrument behind the **Subagent** recipe: dispatched only for a bounded, file-disjoint execution / authoring / routine slice you verify afterwards — never for read-only work, never as a review backend, and it never commits. Its state (`placed` / `customized` / `unusable` / `missing`) is what a `subagent` slot's readiness resolves from. Writing code and running gates stay off the four read-only vehicles; the executor carries a bounded slice you re-verify on your main lane, and every vehicle's output is verified. Preview by default (`--apply` writes); an existing customized read-only vehicle or lens is **preserved, never overwritten**; the executor's body is re-derived from `docs/ai/vehicles.json` (a hand edit is replaced); never touches `settings*.json`, never commits. |
256
256
  | `/agent-workflow-kit hook` | Claude Code · opt-in | **gate-approval hook** — places a self-contained PreToolUse hook (`.claude/hooks/`) and wires it into `.claude/settings.json`: a Bash command **byte-identical** to a gate you declared in `docs/ai/gates.json` (run from the project root) is auto-approved — no prompt, no idle; a seeded read-only command carrying a runtime residual (output redirection, command substitution, `--output` writes) now **asks** even where an allow rule would have silently passed it (proven live — hook `ask` overrides an allow rule). Detection is a conservative string scan, so it over-asks on a byte that is ordinary text — searching for `=>`, or a read wearing `2>/dev/null`, prompts. That is a documented open limit: 4.1.0 built three mechanisms to narrow it and removed all three in review, each counterexample kept as a test (see Mode: hook). Exact matches only, never patterns; never `deny`; a broken `gates.json` only disables auto-approval, never the guard. An opt-in **read-lane** (`--read-lane` → `docs/ai/lanes.json`, a **separate** file from `gates.json`) additionally auto-approves *compounds* of seeded read-only commands carrying no shell metaprogramming; `--apply --read-lane` verifies the placed hook is current first (delete-to-reseed otherwise). Preview by default; never writes `settings.local.json`; never commits. |
257
257
  | `/agent-workflow-kit state-block-guard` | Claude Code · opt-in | **closing-block detector** — a `Stop` hook that reads the turn's final assistant message and warns when the closing state block is defective: the «what I need from you» slot answering *nothing* (a turn that ENDS always needs a resume, so the answer is false, not merely unhelpful), or a first-person promise of imminent work in a turn that is over. Judged on the slot's first clause, so a real ask followed by a clause break and "nothing else" passes, and a promise gated on something named passes; matching is word-bounded and Unicode-aware, quoted and fenced examples are stripped, and the last STARTED block decides — an incomplete tail counts as no block rather than falling back to an earlier one. A message carrying no block at all is silent unless you pass `--require-block` — this kit does not mandate the block, and a hook that runs every turn must not warn every turn. The judgement is lexical and the mode doc names every residual it leaves. **Detection, never prevention** — a `Stop` hook cannot un-send the message it judges; what it buys is that a silent recurrence becomes a visible one. Warns via `systemMessage` and **exits 0 on every path**: never `deny`, never blocks the stop, never re-enters the model. Reads nothing but the message, makes no network call, approves nothing. This mode is **read-only and has no writer** — it ships the self-contained hook and a paste-ready wiring block you merge into `.claude/settings.json` yourself. |
258
258
  | `/agent-workflow-kit bridge-settings` | opt-in, any time | **host-level bridge settings** — read or change the bridges' `KEY=VALUE` config file (`${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf`), the **one place a knob survives kit upgrades** (it lives outside every kit tree; a refresh never touches it, and now states loudly if it ever overwrote a local edit). The **model each bridge runs**: `CODEX_MODEL` + `CODEX_EFFORT` (default `gpt-6.1-sol` at `high`) and `AGY_MODEL` (default `Gemini 3.8 Flash (High)`) — the read-out shows the models each installed CLI offers, and a set one is checked against that list before anything is written. Other knobs: the **codex Fast tier** (`CODEX_SERVICE_TIER=priority` — "2x speed, **increased usage**" in the catalog's own words, quality-neutral, default off — a consented spend), the codex/agy hard timeouts, the codex review byte cap, and `AGY_REVIEW_MAX_TOTAL_BYTES` (the ceiling on what an oversized agy code review may feed before it refuses pre-spend). `AGY_REVIEW_ALLOW_ADDDIR` is a **retired** compatibility key: still recognized so an existing line never warns as unknown, but it arms nothing — the writer refuses to set it and `--unset` clears it. Allowed keys + value rules come from the bundled bridge manifests. **Previews by default**; refuses an unknown key, an out-of-range value, a model or effort the catalog does not offer, or a duplicate-carrying file; writes atomically (symlink/TOCTOU-safe). Never commits, never runs a model (only the read-only catalog commands). |
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: agent-workflow-kit
3
3
  description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow". New to the epic, story and task tier? Run `/agent-workflow-kit tier`. A typed decision with a confidence from Jev? Run `/agent-workflow-kit jev`.
4
4
  disable-model-invocation: true
5
5
  metadata:
6
- version: '14.21.0'
6
+ version: '14.22.0'
7
7
  ---
8
8
 
9
9
  # agent-workflow-kit
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "14.21.0",
6
+ "version": "14.22.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "14.21.0",
3
+ "version": "14.22.0",
4
4
  "description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -1,23 +1,18 @@
1
1
  # Task: {{TASK_NAME}}
2
- Story: {{STORY_ID}} of {{EPIC_ID}}
3
-
4
- ## Slice
5
2
  Plan: {{PLAN_PATH}}
6
- Row: {{ROW_ID}}
7
- Grouping: test, impl
8
- Files:
9
- - {{TEST_PATH}} :: test
10
- - {{MODULE_PATH}} :: impl
3
+
4
+ ## Row
5
+ {{ROW_LINE}}
6
+
7
+ ## Files
8
+ - {{FILE_PATH}}
11
9
 
12
10
  ## Reads
11
+ - {{SCENARIO_LINE}}
13
12
  - {{PLAN_PATH}}
14
13
 
15
- ## Acceptance
16
- - {{ACCEPTANCE_COMMAND}} :: {{EXPECTED_OUTCOME}}
17
-
18
- ## Negative cases
19
- - {{NEGATIVE_CASE}} :: {{NEGATIVE_OUTCOME}}
14
+ ## Run
15
+ - {{RUN_COMMAND}}
20
16
 
21
- ## Budget
22
- - {{TEST_PATH}} :: {{TEST_MAX_LINES}}
23
- - {{MODULE_PATH}} :: {{MODULE_MAX_LINES}}
17
+ ## Do not run
18
+ - {{FORBIDDEN_COMMAND}}
@@ -8,11 +8,11 @@ The opt-in **subagent-vehicle writer** — the family's second `.claude/` writer
8
8
  **Every READ-ONLY vehicle grants READ-ONLY tools and NO `Bash`** — that is the load-bearing property, not a detail. A read-only fan-out on a full-tool vehicle shells out for facts it could have read, and each shelled command is an approval prompt the maintainer never needed to see; a vehicle with no shell structurally cannot do that. Two lanes ride on it:
9
9
 
10
10
  - **cheap lane** (`model: haiku`, `effort: low`) — `mechanical-sweep`, `changelog-skeleton`, `gate-triage`: extraction sweeps, changelog fact-skeletons, gate-failure triage. Extraction/drafting only; the orchestrator applies judgment and verifies the output.
11
- - **review lens** (`review-lens`, review-capable model) — an ADDITIONAL independent read-only opinion on code the configured review backends have already seen. It exists because a third lens otherwise has **no vehicle at all**: the cheap vehicles are scoped away from judgment, and a review-capable full-tool subagent is the prompt-flood shape. It never replaces the configured review recipe, and it is advisory like every other review.
11
+ - **review lens** (`review-lens`, review-capable model) — an ADDITIONAL independent read-only opinion on code the configured review backends have already seen. It exists because a third lens otherwise has **no vehicle at all**: the cheap vehicles are scoped away from judgment, and a review-capable full-tool subagent is the prompt-flood shape. It never replaces the configured review recipe of a plan or a diff — an epic's rendered brief is reviewed by the lens alone, whatever `epic.review` resolves to — and it is advisory like every other review.
12
12
 
13
13
  Writing code, running gates, and user-facing copy never move to these four vehicles.
14
14
 
15
- **The fifth vehicle, `executor`, is the ONE full-tool one** (model and effort from `docs/ai/vehicles.json` — `opus` / `high` by default — and every tool, a shell included). It is the instrument behind the **Subagent** recipe, dispatched ONLY for a **bounded, file-disjoint slice** the orchestrator verifies afterwards by running its suites: a slice of execution (`plan-execution.execute`), a plan/contract authoring brief (`plan-authoring.author`), an authoring-round fold (`plan-authoring.fold`), a bounded chore (`routine.carrier`), an epic brief (`epic.author`), a task brief written from one ledger row (`task.author`), or one stamped task brief run inside its Files (`task.execute`). It **never commits** (no git write at all), is **never a review backend**, is **never a bridge substitute**, and is **never dispatched for read-only work** — a sweep, an inventory or a review rides a read-only vehicle instead.
15
+ **The fifth vehicle, `executor`, is the ONE full-tool one** (model and effort from `docs/ai/vehicles.json` — `opus` / `high` by default — and every tool, a shell included). It is the instrument behind the **Subagent** recipe, dispatched ONLY for a **bounded, file-disjoint slice** the orchestrator verifies afterwards by running its suites: a slice of execution (`plan-execution.execute`), a plan/contract authoring brief (`plan-authoring.author`), an authoring-round fold (`plan-authoring.fold`), a bounded chore (`routine.carrier`), an epic brief (`epic.author`), or one prompt the orchestrator wrote from one ledger row, run inside its Files (`task.execute`); `task.author` dispatches no slice, since the orchestrator writes each row's prompt itself. It **never commits** (no git write at all), is **never a review backend**, is **never a bridge substitute**, and is **never dispatched for read-only work** — a sweep, an inventory or a review rides a read-only vehicle instead.
16
16
 
17
17
  **Its readiness is the vehicle FILE.** `surveyExecutorVehicle` answers exactly one of four states: **`placed`** (bytes equal to the body derived from `docs/ai/vehicles.json` at `.claude/agents/executor.md`), **`customized`** (a readable regular file whose frontmatter names `executor` and whose tools are not read-only), **`unusable`** (a symlink, a non-regular or unreadable file, one failing that check, or an unreadable `docs/ai/vehicles.json` — with the reason), **`missing`**. `placed` and `customized` are dispatchable; on `unusable` or `missing` a `subagent` slot **degrades to Solo** with a reason naming this mode's apply command (and `docs/ai/vehicles.json` when that file is unreadable). `/agent-workflow-kit status` shows the state in its `agents` block and the deployment advisor raises it when a configured slot names `subagent` and the vehicle is `unusable` or `missing` — that item is **`executor-vehicle`** (attention-class: a configured declaration that is broken), a DIFFERENT capability from this mode's placement offer (`agents`), which converges the moment nothing is left to place and therefore can never observe a present-but-unusable vehicle. It is a claim about the FILE, never about the host: a Claude Code lane, like this mode itself.
18
18
 
@@ -2,16 +2,16 @@
2
2
 
3
3
  <!-- opt-in-capability: none — an inspection surface that configures nothing -->
4
4
 
5
- Read-only **activity-procedures advisor**. Answers *"what are the steps of this named activity, and which recipe applies at each slot here?"* It composes the orchestration recipes (`${CLAUDE_SKILL_DIR}/references/modes/recipes.md`) into **named activities** with **typed recipe slots**. It **never writes, never commits, never runs a subscription CLI** — the deterministic resolution lives in the kit; the orchestrator runs the resolved recipe via the bridge skills or the executor vehicle and **owns any commit when the activity has a commit boundary** (every other carrier never commits). Not every activity commits: `plan-authoring` ends at approval and produces no commit (plans are ephemeral, never committed); `plan-execution` commits per ledger row.
5
+ Read-only **activity-procedures advisor**. Answers *"what are the steps of this named activity, and which recipe applies at each slot here?"* It composes the orchestration recipes (`${CLAUDE_SKILL_DIR}/references/modes/recipes.md`) into **named activities** with **typed recipe slots**. It **never writes, never commits, never runs a subscription CLI** — the deterministic resolution lives in the kit; the orchestrator runs the resolved recipe via the bridge skills or the executor vehicle and **owns any commit when the activity has a commit boundary** (every other carrier never commits). Not every activity commits: `plan-authoring` ends at approval and produces no commit (plans are ephemeral, never committed); `plan-execution` commits the story once, after its diff review.
6
6
 
7
7
  The six activities (canon in the **installed engine**, `references/procedures.md`; the registry is `tools/carriers.mjs`):
8
8
 
9
- - **`plan-authoring`** (slots: `author`, `fold`, `review`) — research → draft (the resolved `author` carrier drafts: Solo writes it, Subagent drafts from the orchestrator's brief) → self-review with the readers sweep first → **review {recipe}** → consult, then fold/loop through the resolved `fold` carrier → present for approval; enforce the mandatory Cleanup.
10
- - **`plan-execution`** (slots: `execute`, `review`) — per ledger row: resolve the recipe → if Delegated, dispatch execution first; if Subagent, dispatch file-disjoint slices to the executor vehicle and verify each returned slice → implement → self-review → **review {recipe}** → gates → commit boundary; after the last row, the project-declared stages and Phase: Cleanup run as rows of their own.
9
+ - **`plan-authoring`** (slots: `author`, `fold`, `review`) — research → draft (the resolved `author` carrier drafts: Solo writes it, Subagent drafts from the orchestrator's brief) → self-review with the readers sweep first → **review {recipe}** of the spec, every contract the story revises and the plan's ledger in the same rounds, at most two → one fold ask per member per round, then fold through the resolved `fold` carrier, a fold of the last round re-read by its raiser → present the plan folded with the spec for approval; enforce the mandatory Cleanup.
10
+ - **`plan-execution`** (slots: `execute`, `review`) — per ledger row: resolve the recipe → if Delegated, dispatch execution first; if Subagent, dispatch file-disjoint slices to the executor vehicle and verify each returned slice → implement → self-review; then once, on the story's staged diff with every committable output (the project-declared stages' included) staged first: **review {recipe}** with the fold ask, the raiser's re-read and the re-check of a moved staged tree → gates → the one commit; Phase: Cleanup runs after it and changes nothing the review judged.
11
11
  - **`routine`** (slots: `carrier`, `parallel`) — name the chore and its file-disjoint slices → resolve → carry it (Solo, or Subagent: a read-only slice rides a placed read-only vehicle, a write-capable one rides the executor; `parallel` on → concurrently) → verify every returned slice; the commit boundary is unchanged.
12
12
  - **`feedback-triage`** (slot: `review`) — record → verify every claim by code on the stamped HEAD → `feedback-record-cli --check` → **review {recipe}** over the record, the excerpts as agy's `--facts` payload → `--rows` renders the queue rows and the ratchet line → fold only a false statement in shipped copy.
13
- - **`epic`** (slots: `author`, `review`) — brief → draft by the resolved `author` carrier → `epic-shape-cli --check` → **review {recipe}** over the rendered review brief (bridges in plan mode over it; one lens is the tier's roster) → fold through `--fold`, at most two rounds → land.
14
- - **`task`** (slots: `author`, `execute`) — mint a checkpoint → the resolved `author` carrier writes the brief from one ledger row, stamp and check it → the resolved `execute` carrier runs it inside its Files (Delegated: `dispatch open --checkpoint <oid> --task <brief>`, one session per task) → verify by its Acceptance → return into the story's row; no commit boundary or review of its own.
13
+ - **`epic`** (slots: `author`, `review`) — brief → draft by the resolved `author` carrier → `epic-shape-cli --check` → **review {recipe}**: one review-lens read over the rendered review brief, whatever `epic.review` resolves to (no bridge wrapper, driving contract or grounding pre-step renders under it) → fold through the fold ask and `--fold`, at most two rounds → land.
14
+ - **`task`** (slots: `author`, `execute`) — the orchestrator writes one prompt from one ledger row, whatever `author` resolves to → with the story's changes staged, the resolved `execute` carrier runs it inside its Files (Delegated: `codex-exec --nonce <n> <prompt file>`) → the read after the hand-out restores writes outside the Files from the index and the copied excluded paths from their copy, then the row's tests → return into the story's row, a fold resuming the run's session from its exec receipt; no commit boundary or review of its own.
15
15
 
16
16
  Value sets per slot type: `review` accepts `solo | reviewed | council`; `execute` (including `task.author` and `task.execute`) accepts `solo | delegated | subagent`; a carrier slot (`plan-authoring.author`, `plan-authoring.fold`, `routine.carrier`, `epic.author`) accepts `solo | subagent`; `parallel` is a **switch**, `on | off`, resolved outside the recipe lattice. Defaults when the config is silent: `review` → Reviewed if a review-capable backend is ready, else Solo; `author`, `fold`, `execute`, `carrier` → Solo (a placed executor never flips a default); `parallel` → on. The orchestrator owns every commit; every other carrier — a bridge or a subagent — never commits.
17
17
 
@@ -21,9 +21,9 @@ Run **`node ${CLAUDE_SKILL_DIR}/tools/procedures.mjs <activity> [--override <slo
21
21
  2. **Default resolution (config silent):** `review` → Reviewed if any review-capable backend is `ready`, else Solo (never Council by default); `execute`, `author`, `fold`, `carrier` → Solo (Delegated and Subagent are opt-in; a placed executor never flips a default); `parallel` → on. **Degradation:** a config/computed default degrades **gracefully with a stated reason** (Council → Reviewed → Solo; Delegated → Solo; Subagent → Solo when the executor vehicle is missing or unusable, the reason naming the apply command; a switch never degrades); a per-run **`--override <slot>=<value>`** that can't be satisfied degrades **loudly** (a flagged warning, so you tell the user) — but is **still exit 0** (a valid request that gracefully degraded).
22
22
  3. **Exit codes:** `0` success; `2` usage (unknown `<activity>` / bad `--override` — a bare `--override <recipe>`, an unknown slot, a value outside the slot's list, or a duplicate slot); `1` config error (malformed / schema-invalid / unreadable `orchestration.json`) **or** engine error (the installed engine is absent / invalid / **too old** to ship `references/procedures.md` — upgrade it with `npx @sabaiway/agent-workflow-engine@latest init`). A `1`/`2` failure is loud (`path: reason`), never a silent fallback. **Lagging-kit honesty:** a kit predating the `"flow"` key that reads a config carrying one fails this config load loudly (exit `1`, reddening its full gate matrix); the `set-flow` arming path now enforces the declared `kitMinVersion` floor with a null-guarded comparison (an unparseable version never passes), while tolerate-first ordering remains the only protection for readers older than the `"flow"` key itself — no in-config floor can reach a kit that dies on the unknown key.
23
23
 
24
- **The dispatch form (a slot resolved to `subagent`).** A carrier that is only NAMED is a name, not an instruction, so after such a slot's resolved-recipe line the advisor prints — indented under it, in place of the one-line vehicle mention — the form the dispatch must take, in five parts: (1) what a SLICE is for THIS slot — for `plan-execution.execute`, a set of file-disjoint ledger rows, wording copied verbatim where wording is a red line; for `plan-authoring.author`, a brief naming the goal, the governing spec(s) and the ledger constraints, whose returned draft the orchestrator reviews as its own; for `plan-authoring.fold`, the round's findings with their dispositions, whose edits the orchestrator follows with the self-consistency read; for `routine.carrier`, a bounded mechanical task, where a read-only chore (a sweep, gate triage) rides its placed read-only vehicle — or is carried solo with a stated reason when that vehicle is absent — a write-capable one (a regeneration, a fixture build) rides the executor, and the changelog stays the orchestrator's; for `epic.author`, a brief naming the intent, the value, the non-goals and the stories in order, from which the subagent drafts the epic file and the orchestrator runs the shape check on the draft as its own; for `task.author`, one ledger row of the plan with the contracts it reads, from which the subagent writes the task brief and the orchestrator stamps and checks it; for `task.execute`, one stamped brief, run inside its Files with the changed paths reported and the Acceptance commands run by the orchestrator; (2) the vehicle and its surveyed state — `.claude/agents/executor.md` (`placed` / `customized` / `unusable` / `missing`, from the same survey `status` and the advisor read) — dispatched **in the background**; (3) that the orchestrator **verifies every returned slice by running its suites itself**; (4) that the subagent is **never told to commit, never a review backend, never a bridge substitute**; (5) the **honest limit** — a Claude Code lane: on a host that cannot dispatch the vehicle, follow this form BY HAND and say so, never report it as a subagent dispatch. The wording is the kit's own (`tools/carriers.mjs`) and is printed, never re-worded. The dispatch-form branch is unchanged for a slot resolved to `solo` or `delegated`.
24
+ **The dispatch form (a slot resolved to `subagent`).** A carrier that is only NAMED is a name, not an instruction, so after such a slot's resolved-recipe line the advisor prints — indented under it, in place of the one-line vehicle mention — the form the dispatch must take, in five parts: (1) what a SLICE is for THIS slot — for `plan-execution.execute`, a set of file-disjoint ledger rows, wording copied verbatim where wording is a red line; for `plan-authoring.author`, a brief naming the goal, the governing spec(s) and the ledger constraints, whose returned draft the orchestrator reviews as its own; for `plan-authoring.fold`, the round's findings with their dispositions, whose edits the orchestrator follows with the self-consistency read; for `routine.carrier`, a bounded mechanical task, where a read-only chore (a sweep, gate triage) rides its placed read-only vehicle — or is carried solo with a stated reason when that vehicle is absent — a write-capable one (a regeneration, a fixture build) rides the executor, and the changelog stays the orchestrator's; for `epic.author`, a brief naming the intent, the value, the non-goals and the stories in order, from which the subagent drafts the epic file and the orchestrator runs the shape check on the draft as its own; for `task.author`, no slice the flow dispatches, since the orchestrator writes each row's prompt itself whatever the slot resolves to — that sentence renders alone, with none of the parts below; for `task.execute`, one prompt the orchestrator wrote from one ledger row, run inside the Files the prompt names with the changed paths reported and the row's tests run by the orchestrator; (2) the vehicle and its surveyed state — `.claude/agents/executor.md` (`placed` / `customized` / `unusable` / `missing`, from the same survey `status` and the advisor read) — dispatched **in the background**; (3) that the orchestrator **verifies every returned slice by running its suites itself**; (4) that the subagent is **never told to commit, never a review backend, never a bridge substitute**; (5) the **honest limit** — a Claude Code lane: on a host that cannot dispatch the vehicle, follow this form BY HAND and say so, never report it as a subagent dispatch. The wording is the kit's own (`tools/carriers.mjs`) and is printed, never re-worded. The dispatch-form branch is unchanged for a slot resolved to `solo` or `delegated`.
25
25
 
26
- **Fold lane (an execute slot the activity reads resolved to `delegated`).** `procedures plan-execution` reads `plan-execution.execute` and `task.execute`, `procedures task` reads `task.execute` alone, and `task.author` never counts; a per-run `--override` moves only the rendered activity's own slot. The lane renders once, immediately after the rendered activity's `execute` slot block (after its driving contract when that slot itself resolves to `delegated`), as `codex-exec --resume <held id> --nonce <nonce> <fold-brief>` under the populated `run:` prefix, with the audited ledger's held id shell-quoted. `<nonce>` and `<fold-brief>` stay placeholders. One `caveat:` line replaces the id in each no-id case: no ledger; no folded code session in the commit epoch; a recorded substitution; an unresolvable, unreadable, malformed or audit-refused ledger (the reader reason verbatim); a failed HEAD read; or an id a one-line render cannot carry. An unborn branch runs the judge and is not a caveat. The block is advisory and never changes the exit code; `foldLane` carries the identical lines under `--json`, and is `[]` for every other activity and whenever no slot the activity reads resolves to `delegated`. The sidecar is never read.
26
+ **Fold lane (an execute slot the activity reads resolved to `delegated`).** `procedures plan-execution` reads `plan-execution.execute` and `task.execute`, `procedures task` reads `task.execute` alone, and `task.author` never counts; a per-run `--override` moves only the rendered activity's own slot. The lane renders once, immediately after the rendered activity's `execute` slot block (after its driving contract when that slot itself resolves to `delegated`), as one line: a fold of code a bridge wrote resumes that run's session, `codex-exec --resume <session id> --nonce <n> <prompt file>`, the session id read from the `sessionId` of the run's exec receipt, with a new prompt and a fresh nonce. No delegation ledger and no HEAD are read, so the line is the same whatever a ledger holds. The block is advisory and never changes the exit code; `foldLane` carries the identical line under `--json`, and is `[]` for every other activity and whenever no slot the activity reads resolves to `delegated`.
27
27
 
28
28
  **`routine`'s `parallel` switch renders against the EFFECTIVE carrier.** The flag always renders with its source (`parallel: on` / `parallel: off`); the concurrency claim — *file-disjoint slices dispatch concurrently* — renders **only** while the resolved `carrier` is `subagent`. Under a `solo` carrier the line states its own inertness instead, `(no effect while the carrier is solo)`: a switch never degrades, so the flag keeps the value you set and the render simply stops promising a concurrency nothing can perform. That makes four cells (`on`/`off` x `subagent`/`solo`), and only the `subagent`+`on` cell claims concurrency.
29
29
 
@@ -10,7 +10,7 @@ The five recipes (defined over each bridge's `provides` roles — `codex`: execu
10
10
  - **Reviewed** — you execute; **one** backend reviews the result (advisory). Prefers `codex` when both are ready (`agy` carries a standing health caveat).
11
11
  - **Council** — **both** backends review independently; you synthesize the two opinions.
12
12
  - **Delegated** — you hand a **bounded** execution sub-task to a backend (`codex exec`), then review the returned diff and commit.
13
- - **Subagent** — a **full-tool frontier subagent**, dispatched from the placed executor vehicle (`.claude/agents/executor.md`), carries a **bounded, file-disjoint** slice — of execution, of plan/contract authoring, of an authoring fold, of routine work, of an epic brief (`epic.author`), of a task brief from one ledger row (`task.author`), or of one stamped task brief run inside its Files (`task.execute`); you verify the returned slice by running its suites yourself and you make the commit. It is **never a review backend**, **never a bridge substitute**, and is **never told to commit**; it **degrades to Solo** when the vehicle is `missing` or `unusable`, with the reason. Readiness here is the **vehicle FILE, never the host** — a **Claude Code lane**, like the `agents` writer itself: on a host that cannot dispatch the vehicle, the rendered dispatch form is an instruction you follow by hand and report as such, never as a subagent dispatch.
13
+ - **Subagent** — a **full-tool frontier subagent**, dispatched from the placed executor vehicle (`.claude/agents/executor.md`), carries a **bounded, file-disjoint** slice — of execution, of plan/contract authoring, of an authoring fold, of routine work, of an epic brief (`epic.author`), or of one prompt the orchestrator wrote from one ledger row, run inside its Files (`task.execute`; `task.author` dispatches no slice: the orchestrator writes each row's prompt itself); you verify the returned slice by running its suites yourself and you make the commit. It is **never a review backend**, **never a bridge substitute**, and is **never told to commit**; it **degrades to Solo** when the vehicle is `missing` or `unusable`, with the reason. Readiness here is the **vehicle FILE, never the host** — a **Claude Code lane**, like the `agents` writer itself: on a host that cannot dispatch the vehicle, the rendered dispatch form is an instruction you follow by hand and report as such, never as a subagent dispatch.
14
14
 
15
15
  1. Run **`node ${CLAUDE_SKILL_DIR}/tools/recipes.mjs`** (the read-only planner; `--json` for the structured form). It runs the backend detector, lists the five recipes, and prints — for the current environment — a **per-recipe dispatch plan that degrades with a stated reason** when a carrier isn't `ready` (Council → Reviewed → Solo; Delegated → Solo; Subagent → Solo when the executor vehicle is `missing`/`unusable`), plus advisory **quota/health notes** (each bridge runs the host posture the user set — a weaker model is the user's bridge setting, never a per-call choice; Council spends two backends' quota; `agy` may stall on substantive prompts — Issue-001, prefer `codex`).
16
16
  2. **Offer the choice** via **`AskUserQuestion` where your agent supports it** (`AskUserQuestion` in Claude Code) — one option per recipe, the `recommendRecipe` choice listed **first** — otherwise in prose. Then print `planRecipe(chosen, detection)` (the per-stage dispatch + degradation reasons + quota/health notes) so the user sees exactly what running it entails.
@@ -15,7 +15,7 @@ mapping their wording onto them is your job, not a shipped phrase list.
15
15
  | "both review" | `--set <activity>.review=council` | **disambiguate**: which activity? If both, pass `--set plan-authoring.review=council --set plan-execution.review=council`. |
16
16
  | "one reviewer" | `--set <activity>.review=reviewed` | per the named activity, else ask |
17
17
  | "delegate execution" | `--set plan-execution.execute=delegated` | execution only (a **bridge** runs the change) |
18
- | "let a subagent do it" | `--set <activity>.<slot>=subagent` | **disambiguate**: which work? `--set plan-execution.execute=subagent` (a slice of the change), `--set plan-authoring.author=subagent` (a plan/contract brief), `--set plan-authoring.fold=subagent` (the round's findings and dispositions), `--set routine.carrier=subagent` (a bounded chore), `--set epic.author=subagent` (an epic brief), `--set task.author=subagent` (a task brief), `--set task.execute=subagent` (one stamped task brief) |
18
+ | "let a subagent do it" | `--set <activity>.<slot>=subagent` | **disambiguate**: which work? `--set plan-execution.execute=subagent` (a slice of the change), `--set plan-authoring.author=subagent` (a plan/contract brief), `--set plan-authoring.fold=subagent` (the round's findings and dispositions), `--set routine.carrier=subagent` (a bounded chore), `--set epic.author=subagent` (an epic brief), `--set task.execute=subagent` (one row's prompt run inside its Files; `task.author` dispatches no slice) |
19
19
  | "one slice at a time" | `--set routine.parallel=off` | `routine` only — `parallel` is a **flag**, not a recipe |
20
20
  | "revert / do it myself" | `--unset <activity>.<slot>` | the named slot → its computed default |
21
21
 
@@ -8,7 +8,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/tier-guide.mjs --dir <project> --json`.
8
8
 
9
9
  Render the returned envelope compactly in the user's conversational language. Never paste the JSON. Keep every path and every command verbatim, each command on its own line so it runs as printed; translate only the prose around them.
10
10
 
11
- Keep this order: the tier text (what each level is, the five story sessions, the two templates, the glossary of their keys, the Recommendations pointer); then every rendered state with its reader, file, cause and next command; then per epic its stage, any placeholder left and the accepted check; then each story in hand with its stage, any placeholder left and its ordered actions; then the epic's own ordered actions (for example the check, the close, or the Cleanup a landed story left over). The first action printed is the next step. Several epics or stories each render; never pick one silently.
11
+ Keep this order: the tier text (what each level is, the four story sessions, the two templates, the glossary of their keys, the Recommendations pointer); then every rendered state with its reader, file, cause and next command; then per epic its stage, any placeholder left and the accepted check; then each story in hand with its stage, any placeholder left and its ordered actions; then the epic's own ordered actions (for example the check, the close, or the Cleanup a landed story left over). The first action printed is the next step. Several epics or stories each render; never pick one silently.
12
12
 
13
13
  Exit codes:
14
14
 
@@ -35,7 +35,7 @@ Run `node ${CLAUDE_SKILL_DIR}/tools/velocity-profile.mjs [--dry-run | --apply] [
35
35
  - `node ${CLAUDE_SKILL_DIR}/tools/release-scan.mjs <path>` (wildcard)
36
36
  - `node ${CLAUDE_SKILL_DIR}/tools/repo-search.mjs --pattern <literal> --path <p>` (wildcard — the LITERAL search lane; for a pattern carrying a shell-significant byte use `--pattern-file <p>` instead, and for a TARGET PATH carrying one use `--paths-file <p>` — either way the bytes never enter the command string. one of the TWO tier tools that carry hook residual coverage — see the honesty note below)
37
37
  - `node ${CLAUDE_SKILL_DIR}/tools/path-inventory.mjs --path <p>` (wildcard — the read-only inventory lane: exists / type / size / `wc -l` lines / one-level listing / small-file contents for N paths in ONE call, so small path questions never need a composed shell. `--paths-file <p>` is its out-of-band target lane; hook residual coverage as with repo-search)
38
- - `node ${CLAUDE_SKILL_DIR}/tools/review-rounds-cli.mjs --artifact <plan>` (wildcard — the read-only round table over the review receipts, the verdict half of the per-round emission the `procedures` advisor names every round; the path argument is resolved and compared, never opened as a pattern, so it rides the settings-level posture like the rest)
38
+ - `node ${CLAUDE_SKILL_DIR}/tools/review-rounds-cli.mjs --artifact <plan>` (wildcard — the read-only round table over the review receipts, which `procedures feedback-triage` renders over its record; the path argument is resolved and compared, never opened as a pattern, so it rides the settings-level posture like the rest)
39
39
  - `node ${CLAUDE_SKILL_DIR}/tools/control-bytes.mjs --check` (wildcard — the read-only control-byte gate over the work tree: read-only git queries and descriptor-bound reads, no write API; the agent's own hand run before the declared gate runs it)
40
40
  - `node ${CLAUDE_SKILL_DIR}/tools/robustness-brief.mjs --plan <plan>` (wildcard — the read-only executor-brief generator over a plan and the kit's shipped literal list; no write API and no process spawn)
41
41
  - `node ${CLAUDE_SKILL_DIR}/tools/run-gates.mjs --cwd ${PROJECT_ROOT}` — **EXACT byte-string only**, and honestly **project-exec, not read-only**: it runs YOUR declared `docs/ai/gates.json` commands — the same trust boundary the opt-in hook grants byte-exact per-cmd. A wildcard would be BROADER than that boundary (`--cwd <dir>` executes another project's declared gates), so the bare cwd-defaulting form, any other `--cwd`, `--only`, and **`--final`** forms all still prompt (`--final` WRITES the final-run receipt into the core-evidence store — a recording run is never auto-approved).
@@ -26,7 +26,7 @@
26
26
  "has": "The kit-owned checker gates are declared." },
27
27
  { "id": "session-close-rules",
28
28
  "story": "S5",
29
- "has": "The rules your project reads state the session-close value section and one task per session." },
29
+ "has": "The rules your project reads state the session-close value section and the four-session story flow." },
30
30
  { "id": "named-queue-row-seed",
31
31
  "story": "S5",
32
32
  "has": "A new work queue is seeded with the named row." },
@@ -21,7 +21,8 @@ revision: 1
21
21
  ## Contract
22
22
 
23
23
  What the feature accepts and returns, stated as invariants a test can pin. A `draft` spec is authored
24
- WITH the plan that lands the feature and exists at plan review; approval of that plan confirms the
24
+ in the session that writes the plan landing the feature and exists at its spec review; approval of
25
+ that plan confirms the
25
26
  contract (no separate stop). It becomes `live` on the plan's landing row; `revision` increments by one
26
27
  per live contract change; `retired` on the removal row — never backwards.
27
28
 
@@ -38,8 +38,8 @@ Before claiming "done":
38
38
  1. Run all quality gates (lint + type-check + tests) — all green.
39
39
  2. Update docs: `current_state.md` (feature ready), `changelog.md` (entry), `handover.md` (**REPLACE** the last-session block — session delta, never append; older deltas live in `changelog.md` → `history/`), `pages/<page>.md` (matches implementation), the governing spec (its revision lands with the code: `draft` -> `live` on the landing row). Only bump "Last Updated" when content actually changed.
40
40
  3. Run the docs cap-validator + index-freshness gate (the pre-commit hook also enforces it where installed). On failure: trim the offending file, or run the changelog rotation if the offender is `changelog.md`.
41
- 4. If the work executed a plan file — run that plan's final **Phase: Cleanup** (see the planning skill / §5). Without it the plan is not done.
42
- 5. **Ask before committing** (§4): report lint / type-check / test counts + docs status, then wait for explicit approval. DO NOT auto-commit.
41
+ 4. **Ask before committing** (§4): report lint / type-check / test counts + docs status, then wait for explicit approval. DO NOT auto-commit.
42
+ 5. If the work executed a plan file — after the commit, run that plan's final **Phase: Cleanup** (see the planning skill / §5); it changes nothing the review judged. Without it the plan is not done.
43
43
 
44
44
  ---
45
45
 
@@ -78,15 +78,15 @@ Apply this as part of §2 before any user-facing summary:
78
78
  ### 2.6. Planning, review & process-fidelity invariants
79
79
  Apply these when authoring a plan, reviewing, folding a finding, or editing code — the layer read **before any code change**. (Full canon: the project's planning / workflow-methodology + orchestration canon. This section is rendered from that canon and refreshed on upgrade; a custom edit is preserved verbatim, but flagged.)
80
80
  - **Fold by code, not prose.** Before folding a code-touching finding into a plan or change, read the cited `file:line` and cite it — a prose fold drifts from the code and seeds the next bug.
81
- - **Finding scope (plan-execution) — name the invariant BEFORE the edit.** During EXECUTION only — a plan under authoring has no shipped behaviour to call a live defect in, so plan-review carries none of this. Every finding names the invariant its fix would enforce, and where that invariant already lives decides the disposition: already an acceptance criterion of the phase → **fold here**; it would have to be ADDED → ship the **narrow fix** for the found site (red first, then green) and queue ONLY the generalization — a deferral row carries the invariant, the origin `file:line`, the narrow fix, its proof and a residual exposure declared NOT live; no correct narrow fix → **blocking**: the phase does not close, and it is **never queued**. Two bars declared before each round: a finding counts only if it changes a **WRITE/REMOVE decision** or is a false statement in shipped text; a repeat finding in one subarea **routes to SUBTRACTION**, not a fourth patch.
81
+ - **Finding scope (plan-execution) — name the invariant BEFORE the edit.** During EXECUTION only — a spec and its plan under authoring have no shipped behaviour to call a live defect in, so the spec review carries none of this. Every finding names the invariant its fix would enforce, and where that invariant already lives decides the disposition: already an acceptance criterion of the phase → **fold here**; it would have to be ADDED → ship the **narrow fix** for the found site (red first, then green) and queue ONLY the generalization — a deferral row carries the invariant, the origin `file:line`, the narrow fix, its proof and a residual exposure declared NOT live; no correct narrow fix → **blocking**: the phase does not close, and it is **never queued**. Two bars declared before each round: a finding counts only if it changes a **WRITE/REMOVE decision** or is a false statement in shipped text; a repeat finding in one subarea **routes to SUBTRACTION**, not a fourth patch.
82
82
  - **Right altitude.** Pin intent + invariants + acceptance criteria (named tests); leave fine code-mechanics to Execute, where prose cannot diverge from reality.
83
- - **Spec-first.** A plan names its GOVERNING spec(s) — zero, one or many, one per touched spec-covered slice (the feature spec under `docs/ai/specs/`; page-only coverage governs as an ADOPTION SHIM, with Out of scope + Revision stated inline in the plan). A ZERO names the adoption state it relies on — `not adopted` (no store) or `adopting` (a store with no live contract), either with a recorded decline, or `nothing spec-covered touched` (a store with live contracts) — a bare zero is never a licence; the store's own state is what `status` and the upgrade advisor report. Each cited spec's Out of scope bounds that slice's work and the plan's non-goals restate it per slice — no global union; a cross-spec conflict is resolved by a spec revision BEFORE approval, never by silent precedence. A NEW feature's draft spec exists AT plan review (a `create` row); a change to a governed contract rides the plan as its proposed revision (a `modify` row); approval confirms plan and contract atomically, and the revision lands with the code. Scenario bindings are per scenario: a new scenario is `unbound` until its test lands in the same plan, and a status never regresses for an extension.
83
+ - **Spec-first.** A plan names its GOVERNING spec(s) — zero, one or many, one per touched spec-covered slice (the feature spec under `docs/ai/specs/`; page-only coverage governs as an ADOPTION SHIM, with Out of scope + Revision stated inline in the plan). A ZERO names the adoption state it relies on — `not adopted` (no store) or `adopting` (a store with no live contract), either with a recorded decline, or `nothing spec-covered touched` (a store with live contracts) — a bare zero is never a licence; the store's own state is what `status` and the upgrade advisor report. Each cited spec's Out of scope bounds that slice's work and the plan's non-goals restate it per slice — no global union; a cross-spec conflict is resolved by a spec revision BEFORE approval, never by silent precedence. A NEW feature's draft spec exists AT the spec review (a `create` row); a change to a governed contract rides the plan as its proposed revision (a `modify` row); approval confirms plan and contract atomically, and the revision lands with the code. Scenario bindings are per scenario: a new scenario is `unbound` until its test lands in the same plan, and a status never regresses for an extension.
84
84
  - **No code-mechanics in the plan.** A ledger row carries its path and anchor, and Verification carries the exact commands (the plan-shape canon) — checked syntax: the plan's own Verification runs them against an explicit expected outcome or gate; the only other syntax a plan may carry is a literal fixture/schema fragment a named test copies or validates. Un-run, logic-bearing syntax — control-flow, a regex, a glob, a grammar, an algorithm body, a mini-DSL — never lives in plan prose, however plausible or shell-verified it looks: a fold or draft that wants one is the trigger to write the test instead.
85
85
  - **Test-as-spec.** Fold a code-touching finding into a red→green TEST, not a prose paragraph — the gate is the only deterministic checker; a paragraph cannot self-check.
86
86
  - **Characterize-first.** Before editing UNCOVERED code, pin its current behavior in a green test, then edit — any unintended change goes red. Never edit what has no checker; first give it one. Keep edits atomic/reversible; prefer SUBTRACTIVE folds.
87
87
  - **State table BEFORE the guard — enumerate by PROOF, never by exclusion.** The subtraction rule above fires on a repeat finding, which is a LATE signal: by then the review has paid for each miss. The EARLY signal is structural — a decision whose input has **several independent state dimensions** (is it tracked? do the bytes still match the source? does the neighbouring file exist?). Write the table first, admit the write with **ONE conjunction of proven facts**, and funnel every other cell into a single refusal; the table is then the table-driven test. An exclusion list (`if (bad1) return; if (bad2) return;`) fails **OPEN** on the first state nobody enumerated — and "unreadable" is a state, distinct from "absent". A reviewer cannot save you here: it judges the patch in front of it and can only name the NEXT missing state, one round at a time.
88
- - **Fold minimally — prose has no checker.** An ephemeral, gitignored plan is prose with no executable checker; fold **minimally, in ONE place** and run a **self-consistency** read across the plan before every re-review — a fold that drifts several prose spots is what turns a 2-round review into churn.
89
- - **Heavy review at the diff.** Plan-review settles architecture only (≤2 rounds, stop at the pre-existing→fold-induced crossover); the exhaustive per-row review runs against real compiling code + the full suite, where a regression fails a gate immediately. **Backend divergence** (one backend grounded-ships while another keeps revising mechanics) IS that crossover — resolve at altitude, don't exhaust the strictest backend; route an all-mechanics/CI or prose-only artifact to a **thin plan + diff-review**.
88
+ - **Fold minimally — prose has no checker.** A spec under the spec review, like the ephemeral plan beside it, is prose with no executable checker; fold **minimally, in ONE place** and run a **self-consistency** read across the spec before every re-review — a fold that drifts several prose spots is what turns a 2-round review into churn.
89
+ - **Heavy review at the diff.** The spec review settles the contract and reads the plan's ledger in the same rounds (≤2 rounds, stop at the pre-existing→fold-induced crossover); the plan has no rounds of its own and is checked by its shape gate, that reading and the approval; the exhaustive review runs against the staged diff of real compiling code + the full suite, where a regression fails a gate immediately. **Backend divergence** (one backend grounded-ships while another keeps revising mechanics) IS that crossover — resolve at altitude, don't exhaust the strictest backend; route an all-mechanics/CI or prose-only artifact to a **thin plan + diff-review**.
90
90
  - **Convergence bar.** A review loop is CLEAN only when one round returns **0 blockers + 0 majors** from EVERY backend the recipe names (nits + a ship verdict is the stop). Folding ≠ convergence — re-review after folding.
91
91
  - **Per-round emission.** Every review round emits **{round N · finding-origin tally · per-backend verdict}** so the crossover is a computed, visible signal, not a remembered rule.
92
92
  - **Recipe fidelity.** Council runs every backend the recipe names, **every round**; silently dropping a ready backend for quota/convenience is a forbidden downgrade — an unavailable backend is a LOUD, stated degrade, never a quiet drop.
@@ -94,7 +94,7 @@ Apply these when authoring a plan, reviewing, folding a finding, or editing code
94
94
  - **Cost lanes.** Route every step to the **cheapest adequate executor** — L0 deterministic script (the batched gate matrix over `gates.json`, the rotation `--check`s) · L1 cheap subagent (extraction/drafting only; the orchestrator verifies) · L2 subscription bridge · L3 frontier judgment. A step with **no named guardrail does not move down** a lane, and the **red lines never move down** (council review models · real code · ADR/handover/changelog-entry wording · persuasive copy · go/no-go · the approval asks). Own-error repair: salvage recorded state first (L0/L1, batched), never frontier re-derivation. **Prompt economy:** read-only fan-out (research/sweeps/extraction) runs ONLY on restricted-tool vehicles — a full-tool subagent for read-only work is a forbidden lane downgrade (invisible prompt-flood + blast radius), and a subagent is never told to shell out for facts obtainable read-only; the orchestrator's own shell form is ONE plain pipeline per call (a `;`/`&&` chain or env-prefixed invocation never matches a prefix allow rule); a fan-out launcher that gates per call yields to the agent-spawn lane — capability-gated: without restricted-tool vehicles (generic full-tool spawning does not count), read-only research stays in the orchestrator's own context, never a vehicle mandate a host cannot satisfy. Judgment, code, synthesis stay at the frontier lane (a task that genuinely runs/writes keeps a full-tool subagent); honest limit: no deterministic gate classifies a dispatch — canon at the point of use + placed vehicles + the retro loop. **Writer economy:** a stage's repeated WRITER commands batch — evidence declarations ride consecutive plain invocations of ONE allow-listed tool, other stage writers combine via one launcher per stage; never an unbatched writer scatter (each gated write is its own prompt).
95
95
 
96
96
  ### 2.7. Story sessions
97
- A story — one row of an epic's ledger, carried by one plan — runs as five sessions, each ending at its own review checkpoint: **spec** (the contract under `docs/ai/specs/`, drafted and reviewed on the `plan-authoring` recipe), **plan** (the ledger, same recipe), **tests** (one task per ledger row, red first), **code** (one task per row, to green), and **diff review, release and record** (the review of the staged tree on the `plan-execution` recipe, the release where the story ships one, then the changelog and handover entries and the plan's Phase: Cleanup). Tests and code never share a session, and a spec and its plan never share one either. A storyless plan runs the same five. **Exception — a split:** moving code and its existing cases into modules, with no new logic and no new case, is one session: a short spec (the Module list), the split, the diff review, the release, Cleanup. Inside the tests and code sessions it is one task per session: each task runs as its own carrier session — one brief, one run, never one run for a whole wave — and the orchestrator's session briefs, checks, verifies and folds.
97
+ A story — one row of an epic's ledger, carried by one plan — runs as four sessions, each step in them giving one checked result: **spec and plan** (every contract the story creates or revises and the plan's ledger beside them, checked by the spec gate, the plan-shape gate and one review of at most two rounds that reads both, then the plan's approval), **tests** (only tests, each new one failing for the reason its scenario or acceptance bullet states, or on the absence of a name the plan adds, imported inside the test; no code and no prototype), **code** (code until the tests and the pre-review gates pass; a wrong test is changed only back to what its scenario states), and **diff review, release and record** (every committable output, tracked records included, staged first, the review of the staged diff in at most two rounds, the final gates and the release where the story ships one, then the plan's Phase: Cleanup). Tests and code never share a session. A storyless plan runs the same four. **Exception — a split:** moving code and its existing cases into modules, with no new logic and no new case, is one session: a short spec (the Module list), the split, the diff review, the release, Cleanup. A bridge executor gets a task only when it writes new tests or code, from one prompt of the orchestrator; a file the orchestrator already wrote is laid down by the orchestrator, never relayed through a bridge.
98
98
 
99
99
  ---
100
100
 
@@ -112,8 +112,8 @@ export const SLICE_BY_SLOT = {
112
112
  'plan-execution.execute': 'a slice is a set of file-disjoint ledger rows; wording is copied verbatim where wording is a red line',
113
113
  'routine.carrier': "a slice is a bounded mechanical task; a read-only one (a sweep, gate triage) rides its placed read-only vehicle, or is carried solo with a stated reason when that vehicle is absent; a write-capable one (a regeneration, a fixture build) rides the executor; the changelog stays the orchestrator's",
114
114
  'epic.author': 'a slice is a brief naming the intent, the value, the non-goals and the stories in order; the subagent drafts the epic file from it, and the orchestrator runs the shape check on the draft as its own',
115
- 'task.author': 'a slice is one ledger row of the plan with the contracts it reads; the subagent writes the task brief from it, and the orchestrator stamps and checks the brief itself',
116
- 'task.execute': 'a slice is one stamped brief; the subagent runs it inside the Files the brief names and reports the paths it changed, and the orchestrator runs the Acceptance commands itself',
115
+ 'task.author': "no slice the flow dispatches: the orchestrator writes each row's prompt itself, whatever this slot resolves to",
116
+ 'task.execute': "a slice is one prompt the orchestrator wrote from one ledger row; the subagent runs it inside the Files the prompt names and reports the paths it changed, and the orchestrator runs the row's tests itself",
117
117
  };
118
118
 
119
119
  export const VEHICLE_STATE_TOKEN = '<state>';
@@ -139,12 +139,14 @@ export const SUBAGENT_SLOT_TYPES = Object.entries(SLOT_RECIPES)
139
139
 
140
140
  // dispatchForm({ activity, slot, state }) → the lines a `subagent`-resolved slot renders: the
141
141
  // slot's slice sentence, then the four shared lines with the surveyed vehicle state filled in.
142
- // A slot whose type cannot hold `subagent` (a review slot) and an unknown activity render nothing.
142
+ // A slot type that cannot hold `subagent` (review) and an unknown activity render nothing; a slot
143
+ // whose slice the flow never dispatches renders its sentence alone.
144
+ const UNDISPATCHED_SLOTS = new Set(['task.author']);
143
145
  export const dispatchForm = ({ activity, slot, state } = {}) => {
144
146
  const slice = SLICE_BY_SLOT[`${activity}.${slot}`];
145
147
  const slotType = ACTIVITIES[activity]?.slots?.[slot];
146
148
  if (!slice || !SUBAGENT_SLOT_TYPES.includes(slotType)) return [];
147
- return [slice, ...DISPATCH_LINES.map((line) => line.replace(VEHICLE_STATE_TOKEN, state ?? MISSING))];
149
+ return UNDISPATCHED_SLOTS.has(`${activity}.${slot}`) ? [slice] : [slice, ...DISPATCH_LINES.map((line) => line.replace(VEHICLE_STATE_TOKEN, state ?? MISSING))];
148
150
  };
149
151
 
150
152
  // parallelLine({ value, carrier }) → the `routine` switch line. The concurrency claim is TRUE only
@@ -94,7 +94,7 @@ const EXIT_USAGE = 2;
94
94
  // the internal-attestation evaluation consumes this sentence — a lens set claiming a configured
95
95
  // backend's slot without a then-active down-mark REFUSES, quoting it (substitution is recorded,
96
96
  // never silent).
97
- export const FALLBACK_LENS_ADDITIONAL_ONLY = 'review-lens is an ADDITIONAL read-only review opinion, not a replacement for your configured review recipe.';
97
+ export const FALLBACK_LENS_ADDITIONAL_ONLY = 'review-lens is an ADDITIONAL read-only review opinion, not a replacement for your plan or diff review recipe.';
98
98
 
99
99
  const USAGE = `usage: cheap-agents [--dry-run | --apply] [--cwd <dir>] [--help]
100
100
 
@@ -1,4 +1,4 @@
1
- import { escapeForDisplay, isRenderableLine, shellQuoteArg } from './repo-lex.mjs';
1
+ import { escapeForDisplay } from './repo-lex.mjs';
2
2
  import { wrapperCmdFor } from './detect-backends.mjs';
3
3
  import { DISPLAY_ALIASES } from './recipes.mjs';
4
4
  import { readsBaseline, TERMINAL_RETURN_OUTCOMES } from './dispatch-record.mjs';
@@ -9,7 +9,6 @@ const FOLD_KIND = 'fold';
9
9
  const RETURN_KIND = 'return';
10
10
  const DEGRADE_KIND = 'degrade';
11
11
  const EXECUTE_BACKEND = 'codex-cli-bridge';
12
- const UNPOPULATED_HELD_ID = '<held id>';
13
12
 
14
13
  export const HELD_RECEIPT_BACKEND = DISPLAY_ALIASES[EXECUTE_BACKEND];
15
14
  export const HELD_EXECUTE_WRAPPER = wrapperCmdFor(EXECUTE_BACKEND, 'execute');
@@ -184,34 +183,3 @@ export const decideHeldSession = (facts) => {
184
183
  const heldId = escapeForDisplay(facts.heldId);
185
184
  return { code: 0, reason: `held session "${heldId}" is continuous`, line: `held session: ${heldId} — ${facts.folds} fold(s) rode it` };
186
185
  };
187
-
188
- const describesLaneCaveat = (facts) => {
189
- if (facts.state === 'absent') return decideHeldSession(facts).reason;
190
- if (facts.state === 'error') return decideHeldSession(facts).reason;
191
- if (facts.substitution !== null) return decideHeldSession(facts).reason;
192
- if (facts.heldId === null) return decideHeldSession(facts).reason;
193
- if (!isRenderableLine(facts.heldId)) return 'the held session id cannot be rendered on one command line';
194
- return null;
195
- };
196
-
197
- const chainLaneLines = (facts, chain) => {
198
- const substitution = facts.threads.find((thread) => thread.chainKey === chain.key && thread.substituted) ?? null;
199
- const caveat = describesLaneCaveat({ state: facts.state, heldId: chain.heldId, substitution });
200
- const task = chain.key === null ? '' : ` (task ${escapeForDisplay(chain.key)})`;
201
- if (caveat !== null) return [` caveat: ${caveat}${task}`];
202
- return [` run: ${HELD_EXECUTE_WRAPPER} --resume ${shellQuoteArg(chain.heldId)} --nonce <nonce> <fold-brief>${task}`];
203
- };
204
-
205
- export const foldLaneLines = (facts) => {
206
- const lines = [
207
- 'Fold lane (execute = delegated) — a fold rides the delegate\'s HELD session:',
208
- ' the fold brief is a dispatch file carrying the finding and the accepted fold; dispatch open precedes the run, then dispatch return and fold follow it',
209
- ' the orchestrator runs the suites, verifies the returned diff, re-mints the red-proofs and owns the commit',
210
- ' a fresh session is a forbidden substitution; a retry of a failed thread or, for a head base, a recorded execute degrade is the exception (a checkpoint thread\'s substitution closes by its ledger degrade); the wrapper sidecar is never read',
211
- ];
212
- if (facts.chains !== undefined) return [...lines, ...facts.chains.flatMap((chain) => chainLaneLines(facts, chain))];
213
- const caveat = describesLaneCaveat(facts);
214
- const heldId = caveat === null ? shellQuoteArg(facts.heldId) : UNPOPULATED_HELD_ID;
215
- lines.splice(1, 0, ` run: ${HELD_EXECUTE_WRAPPER} --resume ${heldId} --nonce <nonce> <fold-brief>`);
216
- return caveat === null ? lines : [...lines, ` caveat: ${caveat}`];
217
- };