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
@@ -0,0 +1,206 @@
1
+ # SessionStart hook output: one JSON wire format, both harnesses
2
+
3
+ Status: accepted for RP-185.
4
+
5
+ ## Decision
6
+
7
+ `inject-rules.mjs` (the SessionStart hook that re-injects the autonomy rules on
8
+ startup, resume and compaction) prints one JSON object to stdout, unconditionally,
9
+ for both Claude Code and Codex:
10
+
11
+ ```json
12
+ {"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"…"}}
13
+ ```
14
+
15
+ No trailing newline, no other top-level fields, no provider branching. The
16
+ `additionalContext` value carries exactly the text the hook used to write
17
+ directly to stdout (the `[agent-os] …` banner, the notice, the excerpted rules).
18
+
19
+ ## Why
20
+
21
+ Measured, 2026-09-17, Codex 0.154.0 on Windows: with the previous plain-text
22
+ output — stdout beginning with the literal characters `[agent-os] Autonomy
23
+ rules refresh …` — Codex printed `Hook failed └ hook returned invalid session
24
+ start JSON output`, and the autonomy refresh never reached the session's
25
+ context. Claude Code was unaffected by that same plain-text form. A second
26
+ SessionStart hook in the same measured session, one that already emitted
27
+ `{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":…}}`,
28
+ did reach the session — which is what pointed at the wire format rather than at
29
+ "Codex rejects plain text" as the fix.
30
+
31
+ That framing matters because it is not what Codex's own documentation says.
32
+ [Codex's hooks reference](https://learn.chatgpt.com/docs/hooks) states plainly
33
+ that plain text on stdout is accepted for `session_start` and is added as
34
+ developer context — so "Codex does not support plain-text SessionStart output"
35
+ would be false, and this file does not claim it. What the page does not
36
+ document is *how* Codex decides a given stdout is JSON rather than plain text,
37
+ or what happens when that decision goes the wrong way. The measured symptom —
38
+ an output whose first character is `[` reported as *invalid* JSON, rather than
39
+ silently read as plain text — is consistent with a sniff that treats a leading
40
+ `[` (or `{`) as a signal to attempt a JSON parse, and reports a failure rather
41
+ than falling back when that parse does not succeed. That mechanism is inferred
42
+ from the symptom, not read off the page, and is stated here as an inference,
43
+ not a documented fact.
44
+
45
+ ## Why the JSON envelope, not a reworded plain-text banner
46
+
47
+ The alternative fix — keep printing plain text, just not starting with `[` —
48
+ would have worked too, but it leaves the same undocumented sniffing behaviour
49
+ one character choice away from breaking again, for a reason nobody would think
50
+ to look for. The JSON form sidesteps the ambiguity entirely rather than
51
+ tip-toeing around it, and it turns out to need no provider branching, because
52
+ both harnesses already document the identical shape:
53
+
54
+ - **Codex** ([learn.chatgpt.com/docs/hooks](https://learn.chatgpt.com/docs/hooks)):
55
+ gives the worked example
56
+ `{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"Load the workspace conventions before editing."}}`
57
+ as JSON output for a `session_start` hook.
58
+ - **Claude Code** ([code.claude.com/docs/en/hooks](https://code.claude.com/docs/en/hooks)):
59
+ documents the same nested shape for `SessionStart` — `hookSpecificOutput`
60
+ with `hookEventName` (must equal `"SessionStart"`) and `additionalContext` —
61
+ and states that JSON is detected when stdout starts with `{` and ends with
62
+ `}`; anything else is treated as plain text and added to context the same
63
+ way. `systemMessage` and `terminalSequence` are also accepted fields there,
64
+ unused here because nothing today needs them.
65
+
66
+ One shape, honoured by both harnesses' own documentation, is what
67
+ `invariants.md` ("One mechanism, one implementation") asks for whenever a
68
+ single source can serve two consumers — the alternative, a provider check that
69
+ picks plain text for one harness and JSON for the other, would be exactly the
70
+ kind of guessed, undocumented branching this repository's rules warn against
71
+ ("never invent APIs or behavior").
72
+
73
+ ## What this does not claim
74
+
75
+ - Not that Codex rejects plain text in general — its own docs say otherwise.
76
+ - Not a documented account of Codex's JSON-vs-plain-text sniffing — that
77
+ mechanism is not published; only the fix (always emit the one documented
78
+ JSON shape) is asserted, not the internal reason it was needed.
79
+ - Not that `source: "startup"`, `"resume"` and `"compact"` are guaranteed
80
+ identical by either harness's spec beyond what each page states; both are
81
+ silent on any per-source difference in output handling, and the hook applies
82
+ the same output uniformly across all three because nothing in either
83
+ contract says to do otherwise.
84
+
85
+ ## The exit path: exitCode vs exit(), and what it trades
86
+
87
+ The envelope change alone re-armed the original defect at a different trigger.
88
+ `inject-rules.mjs` ended with `process.exit(main())`, and `process.exit()` tears
89
+ the process down without waiting for a queued `stdout.write()` to drain. Under
90
+ the old plain-text wire format a write a pipe's buffer could not hold in one
91
+ piece degraded to *partial rules text* — readable, if incomplete. Under the
92
+ JSON envelope the same truncation is *invalid JSON* — precisely the state
93
+ Codex was measured rejecting wholesale, just moved from "the output starts
94
+ with `[`" to "the output was cut off mid-object". Exit code 0 either way, so
95
+ nothing downstream reports it.
96
+
97
+ Reproduced independently by two review passes at HEAD before the fix: a
98
+ consumer that does not start reading until well after the child would have
99
+ exited loses everything past the pipe's buffer — at one measurement, a 74 KB
100
+ rules file delivered 0 bytes; at another, 65536 of 73893. Both parse as
101
+ `Unterminated string`.
102
+
103
+ The fix is `process.exitCode = main()` in place of `process.exit(main())`.
104
+ Every path through `main()` returns `0`, so the exit STATUS does not change.
105
+ What changes is whether the process terminates before the write finishes:
106
+ `exitCode` lets Node's event loop drain naturally, which is what lets a large
107
+ payload actually reach a reader. Verified against the same probe shape that
108
+ found the defect, at four payload sizes (7 083 B through 1 002 552 B) and
109
+ three consumer shapes (a non-draining reader, a slow reader at 4 KiB/50 ms,
110
+ and a plain file redirect): every case delivered the complete envelope and
111
+ parsed. Pinned in the generator's `hooks.test.ts` (absent in a generated rig)
112
+ › "delivers the whole envelope even when the reader does not drain until
113
+ process.exit(main()) would already have torn the process down", which goes
114
+ red (`Unterminated string`, at a byte count that is host-dependent — kernel
115
+ pipe buffer size and scheduler timing both vary) if the single line is
116
+ reverted. The pinned payload is sized for a deterministic kill rather than a
117
+ merely likely one: a smaller payload truncated on nearly every reversion run
118
+ on every host checked, but not every one, and a pin the defect can slip
119
+ through occasionally is a pin that will eventually be green on a real
120
+ revert. That pin's coverage is Linux-shaped: Node documents pipe writes as
121
+ synchronous on Windows and asynchronous on POSIX, so the same reversion is
122
+ expected to have little or nothing to catch on a Windows lane — the test's
123
+ own comment says so, so a future reader does not mistake a Linux-only kill
124
+ for cross-platform cover.
125
+
126
+ **What this trades away, stated plainly rather than left to be discovered:**
127
+ `process.exit()` also GUARANTEED teardown, and `exitCode` does not. A consumer
128
+ that never reads stdout at all no longer gets a fast, wrong exit 0 — it gets
129
+ a hook that stays alive indefinitely, waiting on the write. Measured: still
130
+ running 8 seconds in in one review's reproduction, at 74 KB and 1 MB payloads
131
+ with nobody draining; completing the instant a reader appeared. A probe built
132
+ to refuse reading until the child would already have exited measurably
133
+ DEADLOCKS this version, where `process.exit()` would have terminated
134
+ (truncated, but terminated). Nothing in this file bounds that wait — the
135
+ calling harness's own hook timeout does. Not reachable at the size this hook
136
+ ships today (a few KB, well under a second to write), but a real behaviour
137
+ change on a project whose `autonomy.md` grows large, or whose harness stops
138
+ reading a hook's stdout entirely. The trade is made on purpose: a loud hang
139
+ bounded by the harness's own timeout is preferred over a silent, truncated
140
+ "success" with no bound on how wrong it can be.
141
+
142
+ A second, smaller consequence of the same change: a reader that vanishes
143
+ MID-write (a closed pipe, a harness that kills this process before reading)
144
+ now surfaces as an unhandled `error` event on `process.stdout` — exit 1 with
145
+ a Node stack trace on stderr, where the old `process.exit()` path exited 0
146
+ silently in the same situation. The handler is narrow rather than blanket,
147
+ and the difference is measured, not theoretical: an earlier draft of this
148
+ fix silenced every stdout error unconditionally, and security review found
149
+ that with stdout redirected to `/dev/full` — a genuine write failure
150
+ (ENOSPC), with the reader still fully attached — that blanket form exited 0
151
+ with nothing delivered and no diagnostic, the exact silent-loss shape this
152
+ whole file exists to avoid, moved one write call over. The handler now
153
+ distinguishes the two: EPIPE (the reader is gone; there is nothing left to
154
+ report to) stays silent, and anything else is written to stderr and marks
155
+ the exit non-zero. Pinned in the generator's `hooks.test.ts` (absent in a
156
+ generated rig) › "silently exits 0 when the reader is gone before the write
157
+ starts (EPIPE)" and › "reports a genuine stdout write failure on stderr and
158
+ marks the exit non-zero, rather than looking like a healthy session".
159
+
160
+ **Left for a separate decision, not for this one:** seven sibling hooks in
161
+ this same directory still end in `process.exit(…)` with no wait for a
162
+ pending write — `block-no-verify.mjs`, `guard-rulebook.mjs`,
163
+ `guard-subagent-model.mjs`, `guard-bash.mjs`, `guard-secret-file.mjs`
164
+ (`process.exit(status)`), `gate-stop-dod.mjs` (`process.exit(code)`) and
165
+ `warn-subagent-routing.mjs` (the first four and the last end
166
+ `process.exit(main())`). Their payloads are short (a refusal message, not a
167
+ whole rules file), so the exposure is far smaller, but the reasoning above
168
+ now lives in one hook's comments only — `invariants.md`'s "one mechanism,
169
+ one implementation" would ask for the same pattern everywhere it applies.
170
+ This change deliberately does not touch the other seven: changing every
171
+ `process.exit()` call in the hooks directory in a PR whose stated purpose is
172
+ a SessionStart wire-format fix is exactly the scope creep `autonomy.md`'s
173
+ Tier-2 discipline exists to catch. Recorded here so the inconsistency is a
174
+ known, named backlog item rather than something the next reader has to
175
+ rediscover.
176
+
177
+ ## Risk and rollback
178
+
179
+ Tier 2 (`templates/agent-os/universal/.claude/hooks/` is a declared elevated
180
+ path) for both decisions this record carries, each with its own risk and its
181
+ own rollback:
182
+
183
+ **The wire format.** The blast radius is narrow: this hook's own stdout
184
+ contract, read only by the two harnesses' SessionStart machinery. If either
185
+ harness's documented shape turns out to differ from what was fetched here, or
186
+ a future harness version stops accepting it, rollback is reverting
187
+ `inject-rules.mjs` to write plain text again — a one-line change, the same
188
+ one this decision replaces. The old plain-text form is pinned by a regression
189
+ test precisely so it is not reintroduced by accident while chasing an
190
+ unrelated fix: the generator's `hooks.test.ts` (absent in a generated rig) ›
191
+ "never regresses to the old bare [agent-os]-prefixed plain-text stdout".
192
+
193
+ **The exit path** ("The exit path: exitCode vs exit(), and what it trades",
194
+ above). The blast radius is this hook's shutdown behaviour, not its output
195
+ shape: a consumer that never drains stdout at all now holds this process
196
+ alive rather than letting it exit truncated, bounded only by the calling
197
+ harness's own hook timeout. If that trade turns out to be wrong — a harness
198
+ with no such timeout, or one where a hung hook process is worse than a
199
+ truncated one — rollback is reverting the single `process.exitCode = main()`
200
+ line to `process.exit(main())`, independently of the wire-format decision
201
+ above; the two lines do not depend on each other. That reintroduces the
202
+ flush defect this record measures, so a revert of this line alone should
203
+ also remove or explicitly override the test that pins it: the generator's
204
+ `hooks.test.ts` (absent in a generated rig) › "delivers the whole envelope
205
+ even when the reader does not drain until process.exit(main()) would already
206
+ have torn the process down".
@@ -11,7 +11,7 @@ Each named subagent this rig ships pins the model and the effort it reads with:
11
11
  | Role | Claude Code | Codex |
12
12
  | --- | --- | --- |
13
13
  | `code-reviewer`, `security-scanner`, a stack's infrastructure reviewer | `claude-opus-5`, `high` | `gpt-5.6-sol`, `high` |
14
- | `test-writer`, `prose-reviewer` | `claude-sonnet-5`, `high` | `gpt-5.6-terra`, `high` |
14
+ | `test-writer`, `implementation-agent`, `prose-reviewer` | `claude-sonnet-5`, `high` | `gpt-5.6-terra`, `high` |
15
15
  | a subagent with no definition | `claude-sonnet-5`; effort follows the session | `gpt-5.6-terra`, `medium` |
16
16
 
17
17
  In this project the pins are the files themselves: `model:` and `effort:` in
@@ -93,8 +93,11 @@ environment: `subagent-routing.test.ts` (absent in a generated rig) ›
93
93
  In a generated project the definitions are the policy (next section), so an agent
94
94
  a project adds with a pin is a role, and a role whose definition is changed to
95
95
  `model: inherit` has stopped being one — by that project's reviewed decision.
96
- - **The built-in agents get no definitions here.** A general-purpose subagent follows
97
- the unnamed default like any subagent without a definition.
96
+ - **The built-in agents get no definitions here.** Ordinary implementation has its
97
+ own role, `implementation-agent`, on the same tier as `test-writer`: frequent,
98
+ bounded work, not the reviewer tier. A general-purpose subagent remains for
99
+ ad-hoc work no role covers, and follows the unnamed default like any subagent
100
+ without a definition.
98
101
  - **The warning is a warning.** A session started with `CLAUDE_CODE_EFFORT_LEVEL` set
99
102
  still runs every gate — at that level.
100
103
 
@@ -0,0 +1,235 @@
1
+ # Why the workflow layer is opt-in, and where the line falls
2
+
3
+ The rule lives in `CLAUDE.md`, under "The opt-in workflow layer (experimental)".
4
+ This file explains why `layers.json` (RP-180) draws the line where it does,
5
+ and why a few files that look like PR-lifecycle automation stayed in Lean Core
6
+ instead of moving with the rest of it.
7
+
8
+ ## What moved, and why
9
+
10
+ Before this split, `templates/agent-os/universal/layers.json` had one array,
11
+ and `init`/`create` installed all of it unconditionally — including the queue
12
+ adapter, the `loop` and `pr-ship` skills, run-state, the run journal,
13
+ revalidation, claim-records and the PR-lifecycle helpers named below. None of
14
+ that is required by Lean Core: a thin CRUD service or a solo-maintained
15
+ library gets the same review gates and stop rules with none of the
16
+ autonomous, cooperative machinery, and shipping it anyway made every fresh
17
+ rig carry queue-selection semantics it never asked for.
18
+
19
+ The workflow layer is what a project opts into with `init --layer workflow`:
20
+ the queue adapter (`.claude/scripts/queue/`, `.claude/queue.json`), the
21
+ `loop` and `pr-ship` skills, `run-state.mjs`, the run journal
22
+ (`run-journal.mjs` — see the one exception below —, `journal/README.md`),
23
+ revalidation and claim-records, and the PR-lifecycle helpers
24
+ `decision-router.mjs`, `detect-missed-gate.mjs` and
25
+ `reconcile-external-prs.mjs`.
26
+
27
+ ## The exception: why `verdict.mjs`, `lib/verdict.mjs`, `lib/gate-coverage.mjs`
28
+ ## and `run-journal.mjs` stayed in Lean Core
29
+
30
+ These four read as PR-lifecycle automation — the ticket's own wording groups
31
+ "PR-lifecycle helpers" with the workflow layer — and the first draft of this
32
+ split moved them too. It does not survive contact with what Lean Core
33
+ actually installs, for one mechanical reason: `check-premises` is a Lean Core
34
+ skill (a session runs it standalone, with no queue and no loop, "before the
35
+ Red step" and again "before the gate"), and its own second entry point tells
36
+ the reader to run `node .claude/scripts/verdict.mjs check <report>
37
+ check-premises` on its own output. `.claude/scripts/verdict.mjs` is a single
38
+ module with **static, top-level imports** of `./lib/gate-coverage.mjs` and
39
+ `./run-journal.mjs` — Node resolves the whole file before any subcommand
40
+ runs, so a core-only install that shipped `verdict.mjs` without those two
41
+ would break `check-premises`'s own documented command on the very first
42
+ `check` subcommand, not only on `coverage`.
43
+
44
+ The three reviewer agent specs (`code-reviewer.md`, `security-scanner.md`,
45
+ `prose-reviewer.md`) are Lean Core for the same reason `check-premises` is —
46
+ review applies to any PR, loop-driven or not — and all three cite
47
+ `.claude/scripts/verdict.mjs` as the shape their own report is checked
48
+ against.
49
+
50
+ So the dependency runs from Lean Core outward: `check-premises` (core) needs
51
+ `verdict.mjs` (core) to load at all, `verdict.mjs`'s own module graph needs
52
+ `lib/gate-coverage.mjs` and `run-journal.mjs`, and neither of those two
53
+ imports anything outside itself (`node:fs`, `node:path`, and in
54
+ `gate-coverage.mjs`'s case nothing at all — the mention of
55
+ `decision-router.mjs` in its header is a comment, not an import). Moving the
56
+ leaves and leaving the root behind was the option that did not exist;
57
+ `invariants.md`'s "a file a core guard imports must stay core" generalises
58
+ past hooks to this case on the same reasoning.
59
+
60
+ `decision-router.mjs` itself has no such pull: `lib/gate-coverage.mjs`
61
+ mentions it only in a comment, and the one real static import of it
62
+ (`.claude/hooks/lib/edit-input.mjs`) is also a comment, not code. It moved
63
+ with the rest of the workflow layer, and `workflow.md`'s "PR flow" section
64
+ states the Lean Core fallback when it is not installed: every change still
65
+ reaches `code-reviewer`, and a human or the session decides which additional
66
+ reviewers apply, by the same triggers `decision-router` would have read.
67
+
68
+ `docs/decisions/gate-coverage.md` stayed with `pr-ship` (workflow) rather
69
+ than `lib/gate-coverage.mjs` (core) for a different reason: nothing in Lean
70
+ Core cites the record, only `pr-ship`'s own skill file does. The module and
71
+ the rationale for *why it exists* travel separately on purpose — the module
72
+ is a dependency of a core skill's documented command, the essay about why a
73
+ hook version of the same check was rejected is not.
74
+
75
+ ## The freeze this split does not touch
76
+
77
+ RP-53 holds revalidation and claim-records' *behavior* frozen through the
78
+ RP-26 gate (2026-10-27): no feature expansion, no experiment restart, no bias
79
+ introduced by this or any other 0.10 change. This split moves their
80
+ *install-time layer* only — which `layers.json` array they sit in — and
81
+ changes not one line of `revalidate.mjs`, `revalidation-report.mjs`,
82
+ `lib/revalidation-evidence.mjs`, `lib/revalidation-points.mjs` or
83
+ `lib/claim-records.mjs` beyond that relocation. After the gate: GO retains
84
+ them in the optional workflow layer as they are today; NO-GO removes them in
85
+ a bounded follow-up. Missing evidence is not a NO-GO.
86
+
87
+ ## What the manifest records, and the direction that matters
88
+
89
+ `RigManifest.layers` records which layer(s) a rig installed, and `upgrade`
90
+ refreshes only what it names. The one detail worth restating here because
91
+ getting it backwards is silent and destructive: a manifest written **before**
92
+ this field existed recorded nothing about layers because there was only one
93
+ payload to record — so `parseManifest` reads that absence as `['process',
94
+ 'workflow']`, never as `['process']`. A fresh `init` with no
95
+ `--layer workflow` flag writes `['process']` explicitly. The two defaults
96
+ point in opposite directions on purpose, and swapping them would make the
97
+ very next `upgrade` on an existing dogfood repository report every workflow
98
+ file it already has as `retired` and stop managing it.
99
+
100
+ ## Interaction with `uninstall` (RP-181, merged after this split was written)
101
+
102
+ `uninstall` needs no separate awareness of `layers` at all, and gains none:
103
+ it walks `manifest.files` and `manifest.kept` directly (`commands/uninstall.ts`),
104
+ and both of those already name exactly the paths a given install wrote or
105
+ found, regardless of which `layers.json` array a path happens to live in. Three
106
+ cases, all covered by the same unmodified byte-hash check:
107
+
108
+ - **A Core-only rig** (no `--layer workflow`) never has a workflow-layer path in
109
+ `manifest.files` in the first place — `initManifest` only reads the layers
110
+ `effectiveLayers` resolved — so `uninstall` has nothing workflow-shaped to
111
+ remove and reports nothing about it.
112
+ - **A rig that opted into the workflow layer** has those paths in
113
+ `manifest.files` exactly like any process-layer path, and `uninstall` removes
114
+ or preserves them by the same pristine-bytes check as everything else it
115
+ owns.
116
+ - **An inherited pre-0.10 rig** (a manifest with no `layers` key at all) had its
117
+ workflow files recorded in `files` the only way any release before this one
118
+ ever wrote a manifest — there was no `kept`/`files` split by layer to begin
119
+ with — so `uninstall` already treats them as owned, the same as it always
120
+ has. Nothing here widens what `uninstall` is willing to remove, and nothing
121
+ narrows it: a manifest either names a path in `files`/`kept` with the right
122
+ hash, or `uninstall` leaves it alone, and that rule does not read `layers`.
123
+
124
+ Pinned in `packages/cli/test/uninstall.test.ts` (absent in a generated rig —
125
+ this is the generator's own test suite, not a payload path) › "removes an
126
+ installed workflow-layer file exactly like any Core file, when the rig opted
127
+ in", › "a workflow-layer file never installed here (Core-only rig) is simply
128
+ absent from the manifest, never reported \"not a path this release installs\"",
129
+ and › "an inherited pre-layers manifest (no `layers` key) still owns its
130
+ workflow files, exactly like any other installed path".
131
+
132
+ ## There is no opt-out short of `uninstall`
133
+
134
+ Once a rig has the workflow layer — `init --layer workflow`, or inherited
135
+ from before RP-180 — nothing in `init` or `upgrade` ever drops a layer a
136
+ READABLE manifest already recorded; `effectiveLayers` (`init.ts`) is
137
+ additive by construction, full stop. `detectLayersOnDisk` (`upgrade.ts`) is
138
+ a narrower claim: it only ever runs when there is NO readable manifest at
139
+ all, and even then it does not treat "a layer's files exist" as license to
140
+ keep them regardless of how many — it is additive in the same direction
141
+ (never narrows what a READABLE manifest said), but on the bootstrapped path
142
+ it decides per layer by quorum (`LAYER_ADOPTION_QUORUM`, more than half of
143
+ the layer's own files present), and can legitimately decide a layer is NOT
144
+ this rig's: a Core-only rig with one or a few stray files that happen to
145
+ share a workflow-layer path is left at Core, its stray files untouched and
146
+ unrecorded (round 4, blocker A — round 3's fix asked only "does at least one
147
+ file exist", which re-adopted the whole layer from a single stray path).
148
+ The only supported way back to Core-only for a rig the manifest genuinely
149
+ still names as having the workflow layer is `uninstall` (removing the
150
+ workflow files this rig owns) followed by a fresh `init` with no `--layer`
151
+ flag — see "The exact opt-out procedure, measured" below for what that
152
+ takes when `uninstall` had to preserve something.
153
+
154
+ **Hand-editing `layers` in `.claude/.rig-manifest.json` down to `["process"]`
155
+ is not that opt-out, and it does not do what it looks like it does.** The
156
+ files themselves are untouched by the edit itself — nothing deletes them —
157
+ but the next `upgrade` reads the manifest's `layers` as authoritative
158
+ (`upgrade.ts`'s `initInstallSet(repoDir, project, layers)`), so every
159
+ workflow path drops out of that plan's own install set and is reported
160
+ `retired`, reason `"no longer shipped by this release — the rig no longer
161
+ manages it; it is now yours"` — the same verdict RP-177 gave a deleted stack
162
+ overlay, applied here to files that are simply no longer read as this rig's
163
+ layer. `applyUpgrade` then writes a manifest whose `files` map has no entry
164
+ for any of the roughly three dozen workflow paths at all — measured, on a
165
+ clean `--layer workflow` install, at exactly 89 file entries down to 56
166
+ (`packages/cli/test/upgrade.test.ts`, absent in a generated rig, pins "a
167
+ clean workflow-layer install hand-edited down to a core-only layers array
168
+ goes from 89 manifest entries to 56"; the figure moved by one from an
169
+ earlier 86/53 when RP-186 added `docs/decisions/agents-md-canonical.md` to
170
+ the process layer, and by two more when `implementation-agent` joined it).
171
+ The files stay on disk, silently un-hashed and unowned —
172
+ and a LATER `uninstall`, reading the same manifest, has nothing there to
173
+ recognise them by: they read as an ordinary foreign/untracked path, not as
174
+ something this release ever installed, and are left alone. The manifest
175
+ itself does not warn about this because it has no opinion on why `layers`
176
+ changed; the tool trusts its own evidence file. This is measured behaviour,
177
+ not a guess: `packages/cli/test/upgrade.test.ts` (absent in a generated rig)
178
+ pins the `retired` verdict and the orphaning it causes in "hand-editing
179
+ `layers` down to `["process"]` on a rig that already has the workflow
180
+ layer retires every workflow file — on disk, unowned, never deleted".
181
+
182
+ **The mirror hand-edit — `layers: ["workflow"]` alone, dropping `process` —
183
+ does the identical thing in the other direction, on a still-readable
184
+ manifest.** `initInstallSet` reads exactly the array it is given; a `layers`
185
+ that never names `process` un-owns every Core file the same way dropping
186
+ `workflow` un-owns every workflow file: the next `upgrade` retires them from
187
+ the plan and drops them from `files`, silently, files untouched on disk.
188
+ (This is not the bootstrapped path's own normalisation — `detectLayersOnDisk`
189
+ always forces `process` into a layer set it INFERS from disk; a READABLE
190
+ manifest is trusted as written, `process` included, and nothing here
191
+ prevents an operator from writing one that omits it.)
192
+
193
+ ## The exact opt-out procedure, measured (RP-180 round 4, blocker B)
194
+
195
+ `uninstall --yes` followed by a fresh `init` (no `--layer` flag) reaches
196
+ Core-only in exactly ONE of the two cases that matter, and round 3 stated it
197
+ as though it always worked. Measured on the built CLI, both ways:
198
+
199
+ - **Nothing on the rig was ever edited.** `uninstall --yes` removes every
200
+ file it owns — Core and workflow alike — and, because nothing was left to
201
+ preserve, deletes the manifest too. A fresh `init` then finds no manifest
202
+ and no workflow files: Core-only, as documented. A fresh `init` then
203
+ installs Core only.
204
+ - **Anything was edited — one file is enough.** `uninstall --yes` preserves
205
+ that one file (and reports it) and, because something was preserved,
206
+ **keeps the manifest** — still recording `layers: ["process","
207
+ workflow"]`. The next plain `init` reads that surviving manifest
208
+ (`effectiveLayers` in `init.ts`: `previous?.layers.includes('workflow')`)
209
+ and reinstalls the entire workflow layer right back. `uninstall --yes` leaves
210
+ the one preserved file plus the manifest, and a plain `init` afterward
211
+ brings the whole workflow layer back, `layers` still both. The
212
+ "fresh `init`" instruction alone does NOT reach Core-only here — round 3
213
+ said it did.
214
+
215
+ **The procedure that actually reaches Core-only when something was
216
+ preserved: pass `--detach`.** `uninstall --yes --detach` performs the
217
+ identical safe removal and then deletes the manifest regardless of what is
218
+ left behind, handing the preserved file(s) over to the operator outright
219
+ (they stay on disk, no longer named by anything). The next plain `init`
220
+ then finds no manifest at all and installs Core only. A fresh `init` then installs
221
+ Core, leaves the preserved file untouched, and records `layers: ["process"]`. No new flag
222
+ was added for this — `--detach` already existed (RP-181) for the identical
223
+ reason: a manifest kept alive only by something it has no business
224
+ prescribing further action over.
225
+
226
+ Equivalently, without `--detach`: remove the file(s) `uninstall --yes`
227
+ reported as preserved, then remove `.claude/.rig-manifest.json` by hand,
228
+ then run a plain `init`. Both procedures were measured to reach the same
229
+ end state; `--detach` is the one to recommend because it is one command
230
+ instead of a report a human has to read and act on by hand.
231
+
232
+ Pinned end-to-end on the built CLI in `test/e2e/uninstall.test.ts` (absent in
233
+ a generated rig) › `describe('the opt-out procedure to Core-only, measured
234
+ (RP-180 round 4, blocker B)')`: both cases end in `layers: ["process"]` and
235
+ no un-preserved workflow file left on disk.
@@ -7,6 +7,7 @@
7
7
  ".claude/skills/new-invariant/guard-invariant.example.mjs",
8
8
  ".claude/skills/new-invariant/guard-invariant.example.test.mjs",
9
9
  ".claude/agents/test-writer.md",
10
+ ".claude/agents/implementation-agent.md",
10
11
  ".claude/agents/code-reviewer.md",
11
12
  ".claude/agents/security-scanner.md",
12
13
  ".claude/agents/prose-reviewer.md",
@@ -20,41 +21,52 @@
20
21
  ".claude/hooks/warn-subagent-routing.mjs",
21
22
  ".claude/hooks/lib/edit-input.mjs",
22
23
  ".claude/hooks/lib/hook-input.mjs",
23
- ".claude/skills/pr-ship/SKILL.md",
24
- ".claude/skills/loop/SKILL.md",
25
24
  ".claude/skills/check-premises/SKILL.md",
26
25
  ".claude/skills/worktree-task/SKILL.md",
27
26
  ".agents/skills/new-invariant/SKILL.md",
28
27
  ".agents/skills/new-invariant/guard-invariant.example.mjs",
29
28
  ".agents/skills/new-invariant/guard-invariant.example.test.mjs",
30
- ".agents/skills/pr-ship/SKILL.md",
31
- ".agents/skills/loop/SKILL.md",
32
29
  ".agents/skills/check-premises/SKILL.md",
33
30
  ".agents/skills/worktree-task/SKILL.md",
34
31
  ".codex/agents/test-writer.toml",
32
+ ".codex/agents/implementation-agent.toml",
35
33
  ".codex/agents/code-reviewer.toml",
36
34
  ".codex/agents/security-scanner.toml",
37
35
  ".codex/agents/prose-reviewer.toml",
38
- ".claude/scripts/detect-missed-gate.mjs",
39
- ".claude/scripts/decision-router.mjs",
40
- ".claude/scripts/reconcile-external-prs.mjs",
41
36
  ".claude/scripts/stop-flag.mjs",
42
37
  ".claude/scripts/unattended-flag.mjs",
43
38
  ".claude/scripts/git-env.mjs",
44
- ".claude/scripts/preflight.mjs",
45
39
  ".claude/scripts/doctor.mjs",
46
40
  ".claude/scripts/run-journal.mjs",
47
- ".claude/scripts/run-state.mjs",
48
41
  ".claude/scripts/verdict.mjs",
42
+ ".claude/scripts/lib/gate-coverage.mjs",
43
+ ".claude/scripts/lib/verdict.mjs",
44
+ ".claude/scripts/lib/secrets.mjs",
45
+ ".claude/scripts/lib/shell-tools.mjs",
46
+ "PLAN.md",
47
+ "docs/decisions/fail-open-guards.md",
48
+ "docs/decisions/codex-adapter.md",
49
+ "docs/decisions/subagent-routing.md",
50
+ "docs/decisions/review-lanes.md",
51
+ "docs/decisions/workflow-layer-split.md",
52
+ "docs/decisions/session-start-wire-format.md",
53
+ "docs/decisions/agents-md-canonical.md"
54
+ ],
55
+ "workflow": [
56
+ ".claude/skills/pr-ship/SKILL.md",
57
+ ".claude/skills/loop/SKILL.md",
58
+ ".agents/skills/pr-ship/SKILL.md",
59
+ ".agents/skills/loop/SKILL.md",
60
+ ".claude/scripts/detect-missed-gate.mjs",
61
+ ".claude/scripts/decision-router.mjs",
62
+ ".claude/scripts/reconcile-external-prs.mjs",
63
+ ".claude/scripts/preflight.mjs",
64
+ ".claude/scripts/run-state.mjs",
49
65
  ".claude/scripts/revalidate.mjs",
50
66
  ".claude/scripts/revalidation-report.mjs",
51
- ".claude/scripts/lib/gate-coverage.mjs",
52
67
  ".claude/scripts/lib/claim-records.mjs",
53
68
  ".claude/scripts/lib/revalidation-evidence.mjs",
54
69
  ".claude/scripts/lib/revalidation-points.mjs",
55
- ".claude/scripts/lib/verdict.mjs",
56
- ".claude/scripts/lib/secrets.mjs",
57
- ".claude/scripts/lib/shell-tools.mjs",
58
70
  ".claude/scripts/queue/core.mjs",
59
71
  ".claude/scripts/queue/plan-md.mjs",
60
72
  ".claude/scripts/queue/github-issues.mjs",
@@ -66,30 +78,13 @@
66
78
  ".claude/scripts/queue/gate-rounds.mjs",
67
79
  ".claude/queue.json",
68
80
  ".rig/revalidation.json",
69
- "PLAN.md",
70
81
  "journal/README.md",
71
82
  "docs/decisions/gate-coverage.md",
72
- "docs/decisions/fail-open-guards.md",
73
- "docs/decisions/codex-adapter.md",
74
- "docs/decisions/subagent-routing.md",
75
83
  "docs/decisions/closing-a-task.md",
76
84
  "docs/decisions/content-blind-revalidation.md",
77
- "docs/decisions/review-lanes.md",
78
85
  "docs/decisions/run-directory.md",
79
86
  "docs/decisions/spacing-rations-mechanisms.md",
80
87
  "docs/decisions/stop-conditions-in-a-file.md",
81
88
  "docs/decisions/two-empty-endings.md"
82
- ],
83
- "architecture": [
84
- ".claude/rules/architecture.md",
85
- ".claude/hooks/guard-core-purity.mjs",
86
- ".claude/hooks/guard-web-boundary.mjs"
87
- ],
88
- "meta": [
89
- ".claude/settings.json",
90
- ".codex/config.toml",
91
- ".codex/hooks.json",
92
- "CLAUDE.md",
93
- "AGENTS.md"
94
89
  ]
95
90
  }