create-agent-rig 0.9.0 → 0.10.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.
Files changed (237) hide show
  1. package/CHANGELOG.md +466 -3
  2. package/README.md +267 -299
  3. package/package.json +8 -14
  4. package/packages/cli/dist/commands/create.js +56 -88
  5. package/packages/cli/dist/commands/doctor.js +213 -0
  6. package/packages/cli/dist/commands/init.js +151 -54
  7. package/packages/cli/dist/commands/integrations.js +468 -0
  8. package/packages/cli/dist/commands/memory.js +63 -4
  9. package/packages/cli/dist/commands/setup-wizard.js +61 -0
  10. package/packages/cli/dist/commands/uninstall.js +1223 -0
  11. package/packages/cli/dist/commands/upgrade.js +489 -89
  12. package/packages/cli/dist/index.js +657 -49
  13. package/packages/cli/dist/integrations/declaration.js +158 -0
  14. package/packages/cli/dist/integrations/doctor-guards.js +126 -0
  15. package/packages/cli/dist/integrations/doctor-workflow.js +25 -0
  16. package/packages/cli/dist/integrations/mcp-json.js +107 -0
  17. package/packages/cli/dist/integrations/memory-doctor.js +124 -0
  18. package/packages/cli/dist/integrations/registry.js +22 -0
  19. package/packages/cli/dist/integrations/spawn.js +228 -0
  20. package/packages/cli/dist/integrations/spec-kit.js +280 -0
  21. package/packages/cli/dist/integrations/verify.js +193 -0
  22. package/packages/cli/dist/integrations/windows-job.js +275 -0
  23. package/packages/cli/dist/lib/elevated-paths.js +74 -0
  24. package/packages/cli/dist/lib/install-set.js +1 -44
  25. package/packages/cli/dist/lib/manifest.js +86 -9
  26. package/packages/cli/dist/lib/prompts.js +0 -23
  27. package/packages/cli/dist/lib/safe-path.js +193 -2
  28. package/packages/cli/dist/lib/safe-text.js +78 -0
  29. package/packages/cli/dist/lib/substitute.js +1 -52
  30. package/packages/cli/dist/lib/summary.js +5 -5
  31. package/packages/cli/dist/templates.js +4 -14
  32. package/scripts/prepare.mjs +28 -12
  33. package/templates/agent-os/subagent-routing.json +4 -4
  34. package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +13 -9
  35. package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +31 -6
  36. package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +5 -5
  37. package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +1 -1
  38. package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +3 -3
  39. package/templates/agent-os/universal/.claude/agents/code-reviewer.md +8 -6
  40. package/templates/agent-os/universal/.claude/agents/implementation-agent.md +41 -0
  41. package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +8 -4
  42. package/templates/agent-os/universal/.claude/agents/security-scanner.md +4 -2
  43. package/templates/agent-os/universal/.claude/agents/test-writer.md +2 -2
  44. package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +83 -4
  45. package/templates/agent-os/universal/.claude/rules/autonomy.md +55 -27
  46. package/templates/agent-os/universal/.claude/rules/invariants.md +9 -8
  47. package/templates/agent-os/universal/.claude/rules/workflow.md +47 -22
  48. package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1 -1
  49. package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +12 -9
  50. package/templates/agent-os/universal/.claude/scripts/doctor.mjs +100 -2
  51. package/templates/agent-os/universal/.claude/scripts/lib/claim-records.mjs +236 -6
  52. package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +43 -0
  53. package/templates/agent-os/universal/.claude/scripts/queue/jira.mjs +18 -1
  54. package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +2 -2
  55. package/templates/agent-os/universal/.claude/scripts/reconcile-external-prs.mjs +273 -35
  56. package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +16 -0
  57. package/templates/agent-os/universal/.claude/settings.json +0 -8
  58. package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +13 -9
  59. package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +31 -6
  60. package/templates/agent-os/universal/.claude/skills/new-invariant/SKILL.md +5 -5
  61. package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +1 -1
  62. package/templates/agent-os/universal/.claude/skills/worktree-task/SKILL.md +3 -3
  63. package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +2 -2
  64. package/templates/agent-os/universal/.codex/agents/implementation-agent.toml +6 -0
  65. package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +2 -2
  66. package/templates/agent-os/universal/.codex/agents/security-scanner.toml +1 -1
  67. package/templates/agent-os/universal/.codex/agents/test-writer.toml +1 -1
  68. package/templates/agent-os/universal/.codex/hooks.json +0 -10
  69. package/templates/agent-os/universal/AGENTS.md +208 -107
  70. package/templates/agent-os/universal/CLAUDE.md +15 -162
  71. package/templates/agent-os/universal/PLAN.md +17 -10
  72. package/templates/agent-os/universal/docs/decisions/agents-md-canonical.md +313 -0
  73. package/templates/agent-os/universal/docs/decisions/codex-adapter.md +15 -10
  74. package/templates/agent-os/universal/docs/decisions/review-lanes.md +12 -8
  75. package/templates/agent-os/universal/docs/decisions/session-start-wire-format.md +206 -0
  76. package/templates/agent-os/universal/docs/decisions/subagent-routing.md +6 -3
  77. package/templates/agent-os/universal/docs/decisions/workflow-layer-split.md +235 -0
  78. package/templates/agent-os/universal/layers.json +25 -30
  79. package/templates/hash-history.json +73 -24
  80. package/templates/release-ledger.json +3 -1
  81. package/packages/cli/dist/lib/composition.js +0 -20
  82. package/packages/cli/dist/lib/targets.js +0 -28
  83. package/packages/cli/dist/policy/benchmark/corpus.js +0 -165
  84. package/packages/cli/dist/policy/core/adapter.js +0 -18
  85. package/packages/cli/dist/policy/core/coverage.js +0 -253
  86. package/packages/cli/dist/policy/core/decision-record.js +0 -287
  87. package/packages/cli/dist/policy/core/declaration.js +0 -127
  88. package/packages/cli/dist/policy/core/evidence-matrix.js +0 -94
  89. package/packages/cli/dist/policy/core/probe.js +0 -442
  90. package/packages/cli/dist/policy/core/registry.js +0 -115
  91. package/packages/cli/dist/policy/core/validation.js +0 -275
  92. package/packages/cli/dist/policy/core/vocabulary.js +0 -123
  93. package/packages/cli/dist/policy/harness/claude.js +0 -47
  94. package/packages/cli/dist/policy/harness/codex.js +0 -87
  95. package/packages/cli/dist/policy/harness/index.js +0 -15
  96. package/packages/cli/dist/policy/harness/shared-hooks.js +0 -28
  97. package/packages/cli/dist/policy/index.js +0 -17
  98. package/templates/agent-os/init/AGENTS.md +0 -201
  99. package/templates/agent-os/init/CLAUDE.md +0 -201
  100. package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +0 -105
  101. package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +0 -117
  102. package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +0 -89
  103. package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +0 -105
  104. package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +0 -105
  105. package/templates/agent-os/stack/aws-cdk/.claude/skills/ro-debug/SKILL.md +0 -117
  106. package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +0 -6
  107. package/templates/agent-os/stack/node-ts/.claude/hooks/dod-checks.json +0 -1
  108. package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +0 -85
  109. package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +0 -89
  110. package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +0 -68
  111. package/templates/agent-os/universal/.claude/rules/architecture.md +0 -81
  112. package/templates/skeleton/aws-serverless/.github/workflows/ci.yml +0 -28
  113. package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +0 -90
  114. package/templates/skeleton/aws-serverless/README.md +0 -181
  115. package/templates/skeleton/aws-serverless/apps/web/next.config.mjs +0 -17
  116. package/templates/skeleton/aws-serverless/apps/web/package.json +0 -19
  117. package/templates/skeleton/aws-serverless/apps/web/src/app/layout.tsx +0 -17
  118. package/templates/skeleton/aws-serverless/apps/web/src/app/page.tsx +0 -96
  119. package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +0 -36
  120. package/templates/skeleton/aws-serverless/apps/web/src/lib/validate.ts +0 -23
  121. package/templates/skeleton/aws-serverless/apps/web/test/shared-validation.test.ts +0 -38
  122. package/templates/skeleton/aws-serverless/apps/web/tsconfig.json +0 -14
  123. package/templates/skeleton/aws-serverless/eslint.config.mjs +0 -20
  124. package/templates/skeleton/aws-serverless/gitignore +0 -56
  125. package/templates/skeleton/aws-serverless/infra/bin/app.ts +0 -79
  126. package/templates/skeleton/aws-serverless/infra/cdk.json +0 -3
  127. package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +0 -248
  128. package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +0 -45
  129. package/templates/skeleton/aws-serverless/infra/package.json +0 -18
  130. package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +0 -301
  131. package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +0 -137
  132. package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +0 -120
  133. package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +0 -44
  134. package/templates/skeleton/aws-serverless/package.json +0 -30
  135. package/templates/skeleton/aws-serverless/packages/core/package.json +0 -11
  136. package/templates/skeleton/aws-serverless/packages/core/src/events.ts +0 -14
  137. package/templates/skeleton/aws-serverless/packages/core/src/index.ts +0 -15
  138. package/templates/skeleton/aws-serverless/packages/core/src/note.ts +0 -69
  139. package/templates/skeleton/aws-serverless/packages/core/test/events.test.ts +0 -23
  140. package/templates/skeleton/aws-serverless/packages/core/test/note.test.ts +0 -101
  141. package/templates/skeleton/aws-serverless/packages/db/package.json +0 -14
  142. package/templates/skeleton/aws-serverless/packages/db/src/client.ts +0 -17
  143. package/templates/skeleton/aws-serverless/packages/db/src/index.ts +0 -2
  144. package/templates/skeleton/aws-serverless/packages/db/src/note-model.ts +0 -52
  145. package/templates/skeleton/aws-serverless/packages/db/test/note-model.test.ts +0 -91
  146. package/templates/skeleton/aws-serverless/packages/shared/package.json +0 -11
  147. package/templates/skeleton/aws-serverless/packages/shared/src/env.ts +0 -17
  148. package/templates/skeleton/aws-serverless/packages/shared/src/errors.ts +0 -33
  149. package/templates/skeleton/aws-serverless/packages/shared/src/index.ts +0 -3
  150. package/templates/skeleton/aws-serverless/packages/shared/src/logger.ts +0 -20
  151. package/templates/skeleton/aws-serverless/packages/shared/test/env.test.ts +0 -26
  152. package/templates/skeleton/aws-serverless/packages/shared/test/errors.test.ts +0 -28
  153. package/templates/skeleton/aws-serverless/packages/shared/test/logger.test.ts +0 -19
  154. package/templates/skeleton/aws-serverless/pnpm-lock.yaml +0 -2855
  155. package/templates/skeleton/aws-serverless/pnpm-workspace.yaml +0 -14
  156. package/templates/skeleton/aws-serverless/services/api/package.json +0 -15
  157. package/templates/skeleton/aws-serverless/services/api/src/adapters/sqs-publisher.ts +0 -26
  158. package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +0 -69
  159. package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +0 -37
  160. package/templates/skeleton/aws-serverless/services/api/src/list-main.ts +0 -12
  161. package/templates/skeleton/aws-serverless/services/api/src/main.ts +0 -21
  162. package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +0 -41
  163. package/templates/skeleton/aws-serverless/services/api/src/usecases/list-notes.ts +0 -14
  164. package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +0 -211
  165. package/templates/skeleton/aws-serverless/services/api/test/create-note.usecase.test.ts +0 -45
  166. package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +0 -122
  167. package/templates/skeleton/aws-serverless/services/api/test/sqs-publisher.test.ts +0 -22
  168. package/templates/skeleton/aws-serverless/services/worker/package.json +0 -12
  169. package/templates/skeleton/aws-serverless/services/worker/src/handlers/note-created.ts +0 -15
  170. package/templates/skeleton/aws-serverless/services/worker/src/main.ts +0 -7
  171. package/templates/skeleton/aws-serverless/services/worker/src/usecases/process-note-created.ts +0 -37
  172. package/templates/skeleton/aws-serverless/services/worker/test/note-created.test.ts +0 -61
  173. package/templates/skeleton/aws-serverless/tsconfig.base.json +0 -15
  174. package/templates/skeleton/aws-serverless/tsconfig.json +0 -16
  175. package/templates/skeleton/aws-serverless/vitest.config.ts +0 -14
  176. package/templates/skeleton/node-service/.github/workflows/ci.yml +0 -27
  177. package/templates/skeleton/node-service/.github/workflows/deploy.yml +0 -29
  178. package/templates/skeleton/node-service/README.md +0 -104
  179. package/templates/skeleton/node-service/apps/web/next.config.mjs +0 -17
  180. package/templates/skeleton/node-service/apps/web/package.json +0 -19
  181. package/templates/skeleton/node-service/apps/web/src/app/layout.tsx +0 -17
  182. package/templates/skeleton/node-service/apps/web/src/app/page.tsx +0 -96
  183. package/templates/skeleton/node-service/apps/web/src/lib/api.ts +0 -29
  184. package/templates/skeleton/node-service/apps/web/src/lib/validate.ts +0 -23
  185. package/templates/skeleton/node-service/apps/web/test/shared-validation.test.ts +0 -38
  186. package/templates/skeleton/node-service/apps/web/tsconfig.json +0 -14
  187. package/templates/skeleton/node-service/eslint.config.mjs +0 -20
  188. package/templates/skeleton/node-service/gitignore +0 -54
  189. package/templates/skeleton/node-service/package.json +0 -30
  190. package/templates/skeleton/node-service/packages/core/package.json +0 -11
  191. package/templates/skeleton/node-service/packages/core/src/events.ts +0 -14
  192. package/templates/skeleton/node-service/packages/core/src/index.ts +0 -15
  193. package/templates/skeleton/node-service/packages/core/src/note.ts +0 -69
  194. package/templates/skeleton/node-service/packages/core/test/events.test.ts +0 -23
  195. package/templates/skeleton/node-service/packages/core/test/note.test.ts +0 -101
  196. package/templates/skeleton/node-service/packages/db/package.json +0 -12
  197. package/templates/skeleton/node-service/packages/db/src/index.ts +0 -1
  198. package/templates/skeleton/node-service/packages/db/src/note-store.ts +0 -100
  199. package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +0 -100
  200. package/templates/skeleton/node-service/packages/shared/package.json +0 -11
  201. package/templates/skeleton/node-service/packages/shared/src/env.ts +0 -17
  202. package/templates/skeleton/node-service/packages/shared/src/errors.ts +0 -33
  203. package/templates/skeleton/node-service/packages/shared/src/index.ts +0 -3
  204. package/templates/skeleton/node-service/packages/shared/src/logger.ts +0 -20
  205. package/templates/skeleton/node-service/packages/shared/test/env.test.ts +0 -26
  206. package/templates/skeleton/node-service/packages/shared/test/errors.test.ts +0 -28
  207. package/templates/skeleton/node-service/packages/shared/test/logger.test.ts +0 -19
  208. package/templates/skeleton/node-service/pnpm-lock.yaml +0 -2402
  209. package/templates/skeleton/node-service/pnpm-workspace.yaml +0 -13
  210. package/templates/skeleton/node-service/scripts/build-artifact.mjs +0 -34
  211. package/templates/skeleton/node-service/services/api/package.json +0 -17
  212. package/templates/skeleton/node-service/services/api/src/adapters/spool-publisher.ts +0 -23
  213. package/templates/skeleton/node-service/services/api/src/handlers/create-note.ts +0 -40
  214. package/templates/skeleton/node-service/services/api/src/handlers/list-notes.ts +0 -23
  215. package/templates/skeleton/node-service/services/api/src/main.ts +0 -40
  216. package/templates/skeleton/node-service/services/api/src/server.ts +0 -172
  217. package/templates/skeleton/node-service/services/api/src/static-dir.ts +0 -20
  218. package/templates/skeleton/node-service/services/api/src/usecases/create-note.ts +0 -30
  219. package/templates/skeleton/node-service/services/api/src/usecases/list-notes.ts +0 -14
  220. package/templates/skeleton/node-service/services/api/test/artifact.test.ts +0 -92
  221. package/templates/skeleton/node-service/services/api/test/create-note.handler.test.ts +0 -64
  222. package/templates/skeleton/node-service/services/api/test/create-note.usecase.test.ts +0 -43
  223. package/templates/skeleton/node-service/services/api/test/list-notes.test.ts +0 -48
  224. package/templates/skeleton/node-service/services/api/test/package-manager.test.ts +0 -40
  225. package/templates/skeleton/node-service/services/api/test/package-manager.ts +0 -51
  226. package/templates/skeleton/node-service/services/api/test/server.test.ts +0 -208
  227. package/templates/skeleton/node-service/services/api/test/spool-publisher.test.ts +0 -32
  228. package/templates/skeleton/node-service/services/api/test/static-dir.test.ts +0 -29
  229. package/templates/skeleton/node-service/services/worker/package.json +0 -16
  230. package/templates/skeleton/node-service/services/worker/src/main.ts +0 -28
  231. package/templates/skeleton/node-service/services/worker/src/spool.ts +0 -60
  232. package/templates/skeleton/node-service/services/worker/src/usecases/process-note-created.ts +0 -38
  233. package/templates/skeleton/node-service/services/worker/test/process-note-created.test.ts +0 -34
  234. package/templates/skeleton/node-service/services/worker/test/spool.test.ts +0 -76
  235. package/templates/skeleton/node-service/tsconfig.base.json +0 -15
  236. package/templates/skeleton/node-service/tsconfig.json +0 -13
  237. package/templates/skeleton/node-service/vitest.config.ts +0 -12
@@ -28,7 +28,7 @@ same four steps with the diff as the code, and §4 carries what is different.
28
28
 
29
29
  **What "rulebook prose" means here is not a new list** — it is the set
30
30
  `.claude/rules/workflow.md` already uses for the `prose-reviewer` trigger: a rule
31
- file, a skill, an agent spec, a decision record, `CLAUDE.md`, the README. Where a
31
+ file, a skill, an agent spec, a decision record, `CLAUDE.md`, `AGENTS.md`, the README. Where a
32
32
  rulebook file exists twice (a template source and a generated copy), check the
33
33
  **source**; the copy is composed from it. A comment in a test or a hook is in scope
34
34
  too when it asserts behaviour — the file it lives in does not change what a claim is.
@@ -36,8 +36,8 @@ too when it asserts behaviour — the file it lives in does not change what a cl
36
36
  🔴 **`PREMISE FALSE` belongs to the first entry point only.** At the second one the
37
37
  claims are your own and the remedy is an edit, so a false one is not an escalation:
38
38
  it is `UNMEASURED`'s neighbour — delete or correct the sentence and carry on. Reading
39
- it as the escalation `loop` §6 defines would send a finished branch back to the queue
40
- over one sentence.
39
+ it as the escalation `loop` §6 (opt-in workflow layer) defines would send a
40
+ finished branch back to the queue over one sentence.
41
41
 
42
42
  ## Why it sits here and not in review
43
43
 
@@ -185,9 +185,13 @@ inside the block; both forms are the contract.
185
185
  actually says, and `file`/`line` is the citation §3 requires.
186
186
  - `PREMISES_HOLD` carries an empty `blockers` list; the other three name at
187
187
  least one. A stop verdict without one is not an answer the caller can act on,
188
- and the caller is what checks: the `loop` skill runs
189
- `node .claude/scripts/verdict.mjs check <report> check-premises` on what you
190
- return. Nothing in this skill runs it — this skill writes nothing at all.
188
+ and the caller is what checks: `node .claude/scripts/verdict.mjs check
189
+ <report> check-premises` on what you return — `verdict.mjs` is Core and runs
190
+ standalone, so the caller is whichever session invoked this skill (this is a
191
+ Core skill, meant to run with no queue and no loop); the `loop` skill (opt-in
192
+ workflow layer) runs the same command the same way when it is the one that
193
+ invoked you. Nothing in this skill runs it — this skill writes nothing at
194
+ all.
191
195
  - **`headSha` is the commit you read** — `git rev-parse HEAD` in the checkout
192
196
  you examined. A premise check answers about a tree, and the tree moves.
193
197
 
@@ -231,6 +235,6 @@ is invisible to every gate downstream.
231
235
  when a task starts building on an unchecked claim, and no artifact outlives the
232
236
  step — so a run that skipped it and a run that passed it look identical
233
237
  afterwards. That is the honest description of every rule of this shape here
234
- (the `loop` skill says the same about its own no-hand-feeding rule), and it is
235
- why the citation matters: a `file:line` in the report is the one part of this a
236
- later reader can re-check.
238
+ (the `loop` skill — opt-in workflow layer — says the same about its own
239
+ no-hand-feeding rule), and it is why the citation matters: a `file:line` in
240
+ the report is the one part of this a later reader can re-check.
@@ -12,7 +12,7 @@ decisions. This skill is the driver in between: what gets picked,
12
12
  what keeps the loop going, what stops it, and where the report goes.
13
13
 
14
14
  Per-task procedure: (worktree if another session may run) → `check-premises` on the
15
- item → failing test first → implement → **`check-premises` again, on your own prose**
15
+ item → failing test first (`test-writer`) → implement (`implementation-agent`) → **`check-premises` again, on your own prose**
16
16
  → `pr-ship` → merge on the named criterion → verify the deployed surface if one
17
17
  changed.
18
18
 
@@ -344,7 +344,7 @@ it only here. A tier outside that vocabulary **holds**, never releases
344
344
  (`docs/decisions/spacing-rations-mechanisms.md`).
345
345
 
346
346
  **The tier marker is a pre-filter, not the authority.** If an item passed as normal
347
- and the work turns out to touch an elevated path (`CLAUDE.md` →
347
+ and the work turns out to touch an elevated path (`AGENTS.md` →
348
348
  `elevated-paths`), run the gate anyway, record the verdict on the PR, and treat it
349
349
  as this run's elevated item for spacing.
350
350
 
@@ -842,8 +842,8 @@ unbounded improvement list is another diary, and three forces a choice. Each nam
842
842
  four things, and a proposal missing any of them is not ready to file:
843
843
 
844
844
  1. the finding it came from, cited as the journal line it appears on;
845
- 2. the part to change — a skill, an agent spec, a hook, a rule file, `CLAUDE.md`,
846
- the CI workflow;
845
+ 2. the part to change — a skill, an agent spec, a hook, a rule file, `AGENTS.md`,
846
+ `CLAUDE.md`, the CI workflow;
847
847
  3. the change, concretely enough to diff;
848
848
  4. how the next run would prove it worked — the observation that would differ.
849
849
 
@@ -858,7 +858,7 @@ node --input-type=module -e '
858
858
  const a = await import("./.claude/scripts/queue/plan-md.mjs"); // or github-issues / jira
859
859
  console.log(await a.proposeTriage({
860
860
  finding: "<the journal line it came from>",
861
- part: "<skill | agent | hook | rule | CLAUDE.md | workflow>",
861
+ part: "<skill | agent | hook | rule | AGENTS.md | CLAUDE.md | workflow>",
862
862
  change: "<concretely enough to diff>",
863
863
  proof: "<the observation that would differ next run>",
864
864
  // a pair: what the probe touched, and what is concluded from it. The
@@ -961,9 +961,34 @@ three poisons the only channel by which this project learns.
961
961
  underneath it:
962
962
 
963
963
  ```bash
964
- node .claude/scripts/revalidate.mjs --point BEFORE_CLOSE --ticket <item-id>
964
+ node .claude/scripts/revalidate.mjs --point BEFORE_CLOSE --ticket <item-id> \
965
+ --merge-commit "$(gh pr view <pr> --json mergeCommit -q .mergeCommit.oid)"
965
966
  ```
966
967
 
968
+ `--merge-commit` names the exact SHA the tracker's own PR metadata records as
969
+ THIS item's merge commit — one piece of evidence among several that let a
970
+ `targetSha` move which is nothing but that merge read as `CURRENT` instead
971
+ of `claim:scope` drift. Resolve it from the PR just merged, by name, never by
972
+ reading `git log` text, and only after the merge has landed and been
973
+ fetched. Omitting it (the item has not merged yet, or an older loop that
974
+ predates this flag) leaves any target movement holding exactly as it did
975
+ before this flag existed — it is purely additive to that default. Naming the
976
+ SHA is necessary but never sufficient: the exemption also requires the
977
+ target to have advanced by EXACTLY ONE commit — a genuine squash merge; a
978
+ merge commit or any multi-commit range still holds
979
+ (`test/template/revalidate.test.ts` (absent in a generated rig) › "a foreign
980
+ commit plus the real merge in the same range, --merge-commit correctly
981
+ naming the real one") — and it binds to THIS checkout: the named commit's
982
+ tree must equal `HEAD`'s tree here, and `HEAD` must still be the pre-merge
983
+ checkout, not one already fast-forwarded onto the merge
984
+ (`test/template/revalidate.test.ts` (absent in a generated rig) › "a single
985
+ FOREIGN commit named as --merge-commit does not exempt it — reproduces the
986
+ gate-hold attack and proves it now holds" and › "HEAD already at the merge
987
+ commit is vacuous, and still holds (a fast-forwarded checkout must not
988
+ self-satisfy the exemption)"). That binding stops a lazy or mistaken flag,
989
+ not an adversary who controls this run's own checkout — see
990
+ `isOwnMergeAdvance` in `claim-records.mjs` for the exact limit.
991
+
967
992
  It compares the tracked claim's `scope` and `commentary` fingerprint sets;
968
993
  commentary becomes hold-authoritative only here. Marker/take-up movement is
969
994
  retained in evidence but cannot decide drift. A missing claim is
@@ -94,9 +94,9 @@ is a booby trap: someone will hit it, not understand it, and route around it.
94
94
  - [ ] The rule is written down, with the hook named next to it
95
95
  - [ ] The hook guards **one** invariant, and its scope is as narrow as the rule
96
96
 
97
- ## A candidate that is already sitting there
97
+ ## Choosing a candidate
98
98
 
99
- The stack rules say service code logs through the shared structured logger, never
100
- `console.log` — and nothing enforces it. That is the invariant the shipped example
101
- encodes, so if the rule matters in your project, promoting the example into a real
102
- hook is a copy, a rename and a wiring line.
99
+ Start from a rule that already matters in this project and has been violated or
100
+ missed in review. Do not invent a sample architecture rule just to exercise this
101
+ skill: the hook must protect a real local invariant, and its test must demonstrate
102
+ the exact violation it blocks.
@@ -257,7 +257,7 @@ blockers.
257
257
  - `security-scanner` when the diff touches auth, secrets or configuration,
258
258
  input parsing, file handling, new outbound calls, dependency changes;
259
259
  - `prose-reviewer` when the diff touches a rule file, a skill, an agent spec,
260
- a decision record under `docs/decisions/`, `CLAUDE.md` or the README — a
260
+ a decision record under `docs/decisions/`, `CLAUDE.md`, `AGENTS.md` or the README — a
261
261
  rulebook that overstates its own enforcement fails silently and in the
262
262
  direction of false confidence;
263
263
  - an infrastructure review when it touches infrastructure (the stack layer
@@ -12,9 +12,9 @@ directories, with one `.git`. Without it, an unattended run and a hand-driven
12
12
  session share a working tree and overwrite each other's edits.
13
13
 
14
14
  **Use one when** anything else may touch this repo while you work — an
15
- unattended `loop` run, a colleague, a second Claude session. A single attended
16
- session on a quiet repo can just use a branch; the discipline that is never
17
- optional is the branch, not the worktree.
15
+ unattended `loop` run (opt-in workflow layer), a colleague, a second Claude
16
+ session. A single attended session on a quiet repo can just use a branch; the
17
+ discipline that is never optional is the branch, not the worktree.
18
18
 
19
19
  ## Start
20
20
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: code-reviewer
3
- description: Reviews a completed change against the checklist before a PR is opened or merged. Use after any non-trivial implementation work, and always before opening a PR the decision-router puts on its `model` lane, which is everything its two cheap lanes did not claim — code, a rulebook document, an unclassifiable path, a derived artifact git does not report as drift, or anything a risk flag escalated. Blocking findings must be resolved, not argued with.
3
+ description: Reviews a completed change against the checklist before a PR is opened or merged. Use after any non-trivial implementation work, and always before opening a PR that reaches the `model` lane — everything the two cheap lanes do not claim (code, a rulebook document, an unclassifiable path, a derived artifact git does not report as drift, or anything a risk flag escalated), decided by `decision-router.mjs` where the opt-in workflow layer is installed, or by the same rule applied by hand otherwise. Blocking findings must be resolved, not argued with.
4
4
  tools: Read, Grep, Glob, Bash
5
5
  model: claude-opus-5
6
6
  effort: high
@@ -11,9 +11,9 @@ references, and you classify every finding as **blocking** or **advisory**.
11
11
 
12
12
  ## Checklist (blocking findings)
13
13
 
14
- 1. **Boundary violations** — imports that cross layers the wrong way; storage
15
- or SDK access outside its owning module; handlers reaching past the usecase
16
- layer. See the architecture rules in `.claude/rules/`.
14
+ 1. **Boundary violations** — changes that bypass module ownership or layer
15
+ boundaries the repository itself declares. See any applicable architecture
16
+ rules in `.claude/rules/`.
17
17
  2. **Test integrity** — tests deleted, skipped, weakened, or rewritten to fit
18
18
  the implementation; implementation without a test that demonstrates it.
19
19
  3. **Error handling** — swallowed errors, bare catch-and-continue, failure
@@ -88,5 +88,7 @@ reads; a report that never writes one is read as whatever the caller expected.
88
88
  checkout you read. It is what lets `node .claude/scripts/verdict.mjs coverage
89
89
  <commit>` tell "this gate answered for the commit being merged" from "it
90
90
  answered two pushes ago". A verdict naming no commit is counted as neither
91
- covered nor missing, so `pr-ship` holds on it — and only `pr-ship`: no hook
92
- runs that check, so a session that skips the gate skips this with it.
91
+ covered nor missing, so whoever runs that check holds on it —
92
+ `pr-ship` where the opt-in workflow layer is installed, the session itself
93
+ running `node .claude/scripts/verdict.mjs coverage` by hand otherwise: no
94
+ hook runs it either way, so skipping the gate skips this with it.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: implementation-agent
3
+ description: Writes the minimum production code that makes an existing failing test pass — the Green step of TDD, and the Refactor that follows it. Use for ordinary implementation work once test-writer has produced the failing test.
4
+ tools: Read, Grep, Glob, Write, Edit, Bash
5
+ model: claude-sonnet-5
6
+ effort: high
7
+ ---
8
+
9
+ You make a failing test pass. You are the Green step of TDD, and the Refactor
10
+ that keeps it green — never the Red step, and never the reviewer of your own
11
+ work.
12
+
13
+ ## Scope — hard boundaries
14
+
15
+ - You start from a failing test that already exists. If there is none, stop
16
+ and say so: the test comes first, from `test-writer`.
17
+ - You never delete, skip, weaken or rewrite a test to make it pass. If a test
18
+ looks wrong, stop and surface the conflict instead of editing it.
19
+ - You change only what the task needs. Unrelated files, formatting sweeps and
20
+ speculative abstractions are out of scope.
21
+ - You do not commit, push, merge or open pull requests; the session that
22
+ dispatched you owns the branch and the gates.
23
+
24
+ ## How you work
25
+
26
+ 1. Read the failing test and the code around it; follow the repository's
27
+ rules in `AGENTS.md` and `.claude/rules/`.
28
+ 2. Write the smallest change that makes the test pass, in the style of the
29
+ surrounding code.
30
+ 3. Run the new test, then the suite, lint and typecheck the rules name.
31
+ Report a red check as information; never retry it until it passes.
32
+ 4. Refactor only with the tests green, then run them again.
33
+ 5. Report back: what you changed and why, which checks you ran with their
34
+ results, and anything you found but did not change.
35
+
36
+ ## Judgment lines
37
+
38
+ - When the change reaches an elevated area the task was not already tiered
39
+ for, stop and say so before changing it.
40
+ - When two rules in the repository conflict, stop and name both.
41
+ - Prefer deleting code to adding it when both satisfy the test.
@@ -1,13 +1,15 @@
1
1
  ---
2
2
  name: prose-reviewer
3
- description: Reviews the documents that instruct agents — rule files, skills, agent specs, CLAUDE.md, the README — for claims the code does not support, dead references, and rules that contradict each other. Use when a change touches any of them, before the PR.
3
+ description: Reviews the documents that instruct agents — rule files, skills, agent specs, AGENTS.md, CLAUDE.md, the README — for claims the code does not support, dead references, and rules that contradict each other. Use when a change touches any of them, before the PR.
4
4
  tools: Read, Grep, Glob, Bash
5
5
  model: claude-sonnet-5
6
6
  effort: high
7
7
  ---
8
8
 
9
9
  In this project the prose **is** the implementation. A rule file is what an agent
10
- reads before it acts; a skill is a procedure; `CLAUDE.md` is the map. When one of
10
+ reads before it acts; a skill is a procedure; `AGENTS.md` is the map (`CLAUDE.md`
11
+ is its short Claude Code shim — see `docs/decisions/agents-md-canonical.md`).
12
+ When one of
11
13
  them says something untrue, nothing fails — the next session simply acts on it,
12
14
  confidently, and the failure surfaces somewhere unrelated hours later.
13
15
 
@@ -177,5 +179,7 @@ calling gate reads.
177
179
  checkout you read. It is what lets `node .claude/scripts/verdict.mjs coverage
178
180
  <commit>` tell "this gate answered for the commit being merged" from "it
179
181
  answered two pushes ago". A verdict naming no commit is counted as neither
180
- covered nor missing, so `pr-ship` holds on it — and only `pr-ship`: no hook
181
- runs that check, so a session that skips the gate skips this with it.
182
+ covered nor missing, so whoever runs that check holds on it —
183
+ `pr-ship` where the opt-in workflow layer is installed, the session itself
184
+ running `node .claude/scripts/verdict.mjs coverage` by hand otherwise: no
185
+ hook runs it either way, so skipping the gate skips this with it.
@@ -78,5 +78,7 @@ the human who has to fix the finding.
78
78
  checkout you read. It is what lets `node .claude/scripts/verdict.mjs coverage
79
79
  <commit>` tell "this gate answered for the commit being merged" from "it
80
80
  answered two pushes ago". A verdict naming no commit is counted as neither
81
- covered nor missing, so `pr-ship` holds on it — and only `pr-ship`: no hook
82
- runs that check, so a session that skips the gate skips this with it.
81
+ covered nor missing, so whoever runs that check holds on it —
82
+ `pr-ship` where the opt-in workflow layer is installed, the session itself
83
+ running `node .claude/scripts/verdict.mjs coverage` by hand otherwise: no
84
+ hook runs it either way, so skipping the gate skips this with it.
@@ -31,8 +31,8 @@ step of TDD, and only the Red step.
31
31
 
32
32
  ## Judgment lines
33
33
 
34
- - Test behavior through public entry points (usecases, handlers), not private
35
- internals.
34
+ - Test behavior through public entry points and documented interfaces, not
35
+ private internals.
36
36
  - One behavior per test; shared setup in fixtures, not copy-paste.
37
37
  - If the requested behavior contradicts an existing test, stop and surface the
38
38
  conflict instead of overwriting the old test.
@@ -28,6 +28,22 @@
28
28
  // the whole file pays for it twice. That is harness behaviour, observable but
29
29
  // not pinned here. Where it does not hold, this is a plain subtraction — which
30
30
  // is why every ambiguity resolves toward injecting more.
31
+ //
32
+ // The output on stdout is a single JSON object —
33
+ // `{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":…}}`
34
+ // — not the plain text an earlier version of this hook wrote directly. Both
35
+ // Claude Code and Codex document that shape as valid SessionStart output
36
+ // (Claude Code: code.claude.com/docs/en/hooks; Codex:
37
+ // learn.chatgpt.com/docs/hooks), and Codex additionally documents plain text
38
+ // as accepted for `session_start` — this hook always emits the JSON form
39
+ // anyway, so one code path satisfies both without guessing which harness is
40
+ // asking. The change exists because Codex 0.154.0 on Windows was measured
41
+ // reporting this hook's OLD plain-text banner as invalid SessionStart JSON,
42
+ // so the rules refresh never reached the session; Claude Code was unaffected.
43
+ // The mechanism Codex used to reach that verdict is not published — a leading
44
+ // `[` is a plausible trigger, not a confirmed one. See
45
+ // `docs/decisions/session-start-wire-format.md` for what was measured and
46
+ // what each harness's own documentation says.
31
47
  import { readFileSync, realpathSync } from 'node:fs';
32
48
  import { fileURLToPath } from 'node:url';
33
49
  import { readHookInput } from './lib/hook-input.mjs';
@@ -187,15 +203,78 @@ function main() {
187
203
  ? 'This is `.claude/rules/autonomy.md` in full.\n\n'
188
204
  : 'This is `.claude/rules/autonomy.md` with the sections it marks as ' +
189
205
  'reference removed — read the file itself for those: how the Tier-2 ' +
190
- 'gate is swept from outside, how external work is reconciled, ' +
191
- 'post-deploy verification, and the escalation format.\n\n';
206
+ 'gate is swept from outside (opt-in workflow layer), how external ' +
207
+ 'work is reconciled, post-deploy verification, and the escalation ' +
208
+ 'format.\n\n';
209
+
210
+ const additionalContext =
211
+ `[agent-os] Autonomy rules refresh — in force regardless of compaction.\n${notice}${body}\n`;
192
212
 
213
+ // `hookSpecificOutput.additionalContext` is the JSON shape both harnesses'
214
+ // hooks documentation gives an example of for SessionStart output — see the
215
+ // file header and `docs/decisions/session-start-wire-format.md`. No leading
216
+ // or trailing byte outside the object, and no trailing newline: Claude Code's
217
+ // OWN documented detection reads "starts with `{` ends with `}`", literally
218
+ // (code.claude.com/docs/en/hooks) — Codex's JSON-vs-plain-text detection is
219
+ // not published, so this satisfies the one contract that IS written down
220
+ // rather than guessing at the one that is not.
221
+ // A reader that vanishes mid-write — a closed pipe, a harness that tears
222
+ // this process down before reading — turns the queued write into an EPIPE.
223
+ // That specific error is silenced: it means the reader is gone and there is
224
+ // nothing left to report to, so failing loudly would turn an absent reader
225
+ // into a noisy non-zero SessionStart exit for no one to read. Anything ELSE
226
+ // stdout can fail with (ENOSPC, EIO, a redirect to a full or broken device)
227
+ // is a real write failure with an actual reader still attached, and this
228
+ // file does not get to treat that as a healthy session: it is reported on
229
+ // stderr and the exit is marked non-zero, the same "say what happened"
230
+ // stance the excerpt path takes by injecting MORE rather than dropping
231
+ // content quietly. Measured (security review, RP-185 gate): a blanket
232
+ // handler here made a genuine stdout write failure (stdout redirected to
233
+ // /dev/full) exit 0 with nothing delivered and no diagnostic — exactly the
234
+ // silent-loss shape this whole file exists to avoid, just moved one write
235
+ // call over. Pinned in hooks.test.ts (absent in a generated rig) ›
236
+ // "silently exits 0 when the reader is gone before the write starts
237
+ // (EPIPE)" and › "reports a genuine stdout write failure on stderr and
238
+ // marks the exit non-zero, rather than looking like a healthy session".
239
+ process.stdout.on('error', (err) => {
240
+ if (err && err.code === 'EPIPE') return;
241
+ process.stderr.write(`inject-rules: stdout write failed: ${err}\n`);
242
+ process.exitCode = 1;
243
+ });
193
244
  process.stdout.write(
194
- `[agent-os] Autonomy rules refresh — in force regardless of compaction.\n${notice}${body}\n`,
245
+ JSON.stringify({
246
+ hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext },
247
+ }),
195
248
  );
196
249
  return 0;
197
250
  }
198
251
 
199
252
  if (invokedDirectly()) {
200
- process.exit(main());
253
+ // NOT process.exit(main()): exit() tears the process down without waiting
254
+ // for a queued stdout write to drain, and this hook's payload (the whole
255
+ // rules excerpt, wrapped in one JSON object) can be large enough to miss a
256
+ // pipe's buffer in one write. A write that process.exit() cuts off mid-object
257
+ // is not a short excerpt, the way the old plain-text form degraded — it is
258
+ // invalid JSON, which is exactly the failure this hook exists to avoid.
259
+ // Every path through main() returns 0, so setting exitCode changes nothing
260
+ // about the exit STATUS. What it does change is whether the process
261
+ // terminates AT ALL before the write finishes: exitCode lets the event
262
+ // loop drain naturally, and a reader that never drains at all no longer
263
+ // gets a fast, wrong exit 0 — it gets a hook that stays alive, waiting on
264
+ // the write, for as long as the harness lets it. A probe that refuses to
265
+ // read until the child would already have exited measurably DEADLOCKS this
266
+ // version where process.exit() would have terminated (truncated). Nothing
267
+ // in this file bounds that wait; the calling harness's own hook timeout
268
+ // does. Pinned in hooks.test.ts (absent in a generated rig) ›
269
+ // "delivers the whole envelope even when the reader does not drain until
270
+ // process.exit(main()) would already have torn the process down".
271
+ //
272
+ // That is the trade made on purpose — a loud hang, bounded by the
273
+ // harness's timeout, over a silent truncated "success" — and it is worth
274
+ // stating plainly rather than leaving to be discovered: not reachable at
275
+ // the size this hook ships today (a few KB, done in well under a second),
276
+ // but a real behaviour change on a project whose autonomy.md grows large
277
+ // enough, or whose harness stops reading a hook's stdout at all. See
278
+ // `docs/decisions/session-start-wire-format.md` for the fuller record.
279
+ process.exitCode = main();
201
280
  }
@@ -37,10 +37,10 @@ area *is* Tier 2 from that moment: run the gate, record the verdict on the PR,
37
37
  and say in the description that the tier changed mid-work.
38
38
 
39
39
  **Where the elevated paths of this project are written down:** the
40
- `elevated-paths` block in `CLAUDE.md`, plus any such block in `.claude/rules/` —
41
- the gate sweep reads them all and unions the result, so a stack layer declares the
42
- paths that exist only in its shape. A path declared in none of them is a path
43
- nothing checks.
40
+ `elevated-paths` block in `AGENTS.md` (the canonical rulebook), plus
41
+ any such block in `.claude/rules/` — the gate sweep reads them all and unions
42
+ the result, so a stack layer declares the paths that exist only in its shape.
43
+ A path declared in none of them is a path nothing checks.
44
44
 
45
45
  <!-- inject:skip -->
46
46
  <!-- `inject-rules` puts this WHOLE FILE into every session's context, minus
@@ -55,7 +55,13 @@ nothing checks.
55
55
  rules for whoever performs the sweep, which is not the run. If that stops
56
56
  being true, move them out rather than arguing with the marker. -->
57
57
 
58
- #### The gate is swept from outside, because a run cannot report this on itself
58
+ #### The gate is swept from outside (opt-in workflow layer), because a run cannot report this on itself
59
+
60
+ **`detect-missed-gate.mjs` and `reconcile-external-prs.mjs` below ship with
61
+ the opt-in workflow layer** (`init --layer workflow`) — see `AGENTS.md`'s "The
62
+ opt-in workflow layer" section. Without that layer, sweep merged PRs against
63
+ the elevated-paths block by hand; the rule they enforce — a Tier-2 change
64
+ needs a `human-review` label — does not change with or without the script.
59
65
 
60
66
  A run that continued past the Tier-2 gate is exactly the run that **will not
61
67
  report it** — a run that had known was a run that would have run the gate. So the
@@ -123,11 +129,16 @@ own cost figures are read next to the lane they do not cover.
123
129
  from proper-prefix widening". An entry
124
130
  outside the set — ordinary source — is not widening and is accepted. A second
125
131
  copy in prose is a copy that goes stale, and this one did. Mechanical:
126
- the hook refuses the edit while the unattended flag the `loop` skill writes
127
- at claim time is on disk (`.claude/scripts/unattended-flag.mjs`), and does
128
- nothing in an attended session. ⚠ It sees edit tool calls only — a
129
- shell redirect into a protected file is not one — and the flag, not
130
- the run, is what arms it; its header states the rest of its limits.
132
+ the hook refuses the edit while the unattended flag is on disk
133
+ (`.claude/scripts/unattended-flag.mjs`, Core — usable by hand on any rig),
134
+ and does nothing in an attended session. **On a Core-only rig nothing arms
135
+ this flag automatically** — the `loop` skill, opt-in workflow layer, is
136
+ what writes it at claim time; without that layer the flag is only ever set
137
+ by someone running `unattended-flag.mjs on` directly, so `guard-rulebook`'s
138
+ unattended-only refusal stays dormant unless an operator arms it by hand.
139
+ ⚠ It sees edit tool calls only — a shell redirect into a protected file is
140
+ not one — and the flag, not the run, is what arms it; its header states
141
+ the rest of its limits.
131
142
 
132
143
  ## Stop rules — by work-state, not by feelings
133
144
 
@@ -153,16 +164,23 @@ these lines is the failure mode:
153
164
  stop, write a short summary of state and intent, and **start fresh** from
154
165
  the summary. Resuming a stale session is how agents edit files that are not
155
166
  there anymore.
156
- - **A deploy that regressed.** A green pipeline is not a healthy runtime, so
157
- every deploy ends in a verdict and **both words get recorded**:
167
+ - **A deploy that regressed.** A green pipeline is not a healthy runtime:
168
+ verify runtime health after every deploy, and on a regression, **revert
169
+ first, diagnose second** — never fix-forward blind on a broken runtime.
170
+ **With the opt-in workflow layer installed** (`init --layer workflow`;
171
+ `run-state.mjs` ships only with it — a Core-only rig has no such file),
172
+ both words also get recorded as a mechanical verdict:
158
173
  `node .claude/scripts/run-state.mjs deploy HEALTHY` or `… deploy REGRESSION`.
159
- On a regression, **revert first, diagnose second**. `REGRESSION` is what
160
- makes the next selection refuse to build on it, and `HEALTHY` is the only
161
- thing that clears one — a run that reverts, redeploys, verifies and then
162
- stops at "healthy → done" has left the refusal latched behind it. The
163
- procedure behind the verdict is further down this file; the verdict is here
164
- because a compacted run has to carry it at the moment it is under the most
165
- pressure.
174
+ `REGRESSION` is what makes the next selection refuse to build on it, and
175
+ `HEALTHY` is the only thing that clears one — a run that reverts, redeploys,
176
+ verifies and then stops at "healthy → done" has left the refusal latched
177
+ behind it. Without the layer, there is no automated selection to gate, and
178
+ no journal either (workflow layer only, `PLAN.md`) — the verify-then-revert
179
+ rule still applies, and the record of it is whatever this project's own
180
+ operational notes are (a PR description, a commit message, telling the
181
+ human directly), never a file `queue/index.mjs next` reads. The procedure
182
+ behind the verdict is further down this file; the verdict is here because a
183
+ compacted run has to carry it at the moment it is under the most pressure.
166
184
 
167
185
  <!-- inject:skip -->
168
186
  <!-- Not carried into a session's context (see the note on the first marked
@@ -181,19 +199,29 @@ logs — the target's README says which). The verdict is binary:
181
199
  - Regression → **revert first**, diagnose second. Never fix-forward blind on a
182
200
  broken runtime.
183
201
 
184
- **Record the verdict where the next selection reads it**, or it stops nothing —
185
- an unattended run's memory of "the deploy went badly" does not survive a
186
- compaction, and the queue hands out the next item regardless:
202
+ **`run-state.mjs` and the mechanism below ship with the opt-in workflow
203
+ layer** (`init --layer workflow`). The rule — verify before calling a deploy
204
+ done, revert first on a regression — applies regardless; without this layer
205
+ there is no automated selection to gate, and no journal either (workflow
206
+ layer only, `PLAN.md`) — recording the verdict is whatever this project's own
207
+ operational notes are (a PR description, a commit message, telling the human
208
+ directly), never a file the next `queue/index.mjs next` reads.
209
+
210
+ **Record the verdict where the next selection reads it** (opt-in workflow
211
+ layer), or it stops nothing — an unattended run's memory of "the deploy went
212
+ badly" does not survive a compaction, and the queue hands out the next item
213
+ regardless:
187
214
 
188
215
  ```sh
189
216
  node .claude/scripts/run-state.mjs deploy REGRESSION # or HEALTHY
190
217
  ```
191
218
 
192
- It writes into the run directory the `loop` skill declared, and the next
193
- `queue/index.mjs next` refuses to select on a `REGRESSION` — which is what makes
194
- "start no new work on top of it" a mechanism rather than a resolution. In an
195
- attended session with no run directory the command refuses, and that is
196
- correct: there is no run for the verdict to belong to.
219
+ It writes into the run directory the `loop` skill (opt-in workflow layer)
220
+ declared, and the next `queue/index.mjs next` refuses to select on a
221
+ `REGRESSION` — which is what makes "start no new work on top of it" a
222
+ mechanism rather than a resolution. In an attended session with no run
223
+ directory the command refuses, and that is correct: there is no run for the
224
+ verdict to belong to.
197
225
 
198
226
  ## Escalation format
199
227
 
@@ -201,14 +201,15 @@ Two rules that follow from it:
201
201
  | the check | `.claude/hooks/block-no-verify.mjs` |
202
202
  | the test | the hook's blocking behaviour, under test |
203
203
 
204
- **Every one of them is an example, not a truth.** Take the rule a generated
205
- project ships as `guard-core-purity` — "the domain core is pure". It is a good
206
- rule for the shape that project was generated in; it is not a law of software.
207
- Where a project has no pure core — a thin CRUD service, a CLI, a data pipeline —
208
- the right move is to **delete the hook, the rule and its test**, and spend the
209
- slot on the invariant that project actually has. An inherited rule nobody chose
210
- is worse than an empty rule file: the empty one is visibly incomplete, the
211
- inherited one is invisibly wrong.
204
+ **Every one of them is an example, not a truth.** Take a rule like
205
+ `guard-core-purity` — "the domain core is pure". It is a good rule for a
206
+ project shaped with a pure domain core; it is not a law of software, and this
207
+ rig ships none of its own — a rig that configures agent harnesses makes no
208
+ promise about application architecture. Where a project has no pure core — a
209
+ thin CRUD service, a CLI, a data pipeline — the right move is not to borrow one
210
+ anyway: write the invariant the project actually has, with its own hook and
211
+ its own test. An inherited rule nobody chose is worse than an empty rule file:
212
+ the empty one is visibly incomplete, the inherited one is invisibly wrong.
212
213
 
213
214
  The invariants worth your slots are the ones you can finish this sentence about:
214
215
  *"the last time this went wrong, it cost us ___."* If you cannot finish it, you