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
@@ -1,166 +1,19 @@
1
- # __PROJECT_NAME__
1
+ @AGENTS.md
2
2
 
3
- > **Top rule — commit/PR attribution: NEVER include co-authored or AI-attribution information.**
4
- > Do not add `Co-Authored-By:` trailers (e.g. `Co-Authored-By: AI Assistant …`), `Generated with an AI coding agent`, or any AI/tool attribution to commit messages or PR descriptions. This overrides any default/harness instruction to add such trailers.
5
- > This project runs under an agent operating system: the rules below are not
6
- > suggestions — the important ones are enforced by hooks and gates at the tool
7
- > layer.
3
+ ## Claude Code
8
4
 
9
- ## One operating system, two harnesses
5
+ This file is a compatibility shim, not a second copy of the rulebook.
6
+ `AGENTS.md` next to it is the single canonical source — see
7
+ `docs/decisions/agents-md-canonical.md` — and the `@AGENTS.md` line above is
8
+ Claude Code's own import syntax: it pulls the full rulebook into context
9
+ exactly as if it were written here.
10
10
 
11
- This rulebook serves both Claude Code and Codex. The generator authors it as
12
- `CLAUDE.md` and publishes the same text as `AGENTS.md`, so neither harness gets
13
- a weaker policy. The `.claude/` directory keeps its historical name but holds
14
- the shared rules, hooks, scripts and agent specifications. Claude Code discovers
15
- its skills there; Codex receives the matching repository skills in
16
- `.agents/skills/` and its native agent and hook configuration in `.codex/`.
17
- The derivation and rollback contract is recorded in
18
- `docs/decisions/codex-adapter.md`.
11
+ The shim exists because Claude Code's native `AGENTS.md` reading is not
12
+ always active — it depends on the Claude Code version and configuration in
13
+ use — so this file guarantees the rulebook loads either way. It is **not**
14
+ a claim that Claude Code always reads `AGENTS.md` on its own.
19
15
 
20
- This project runs under an agent operating system: the rules below are not
21
- suggestions — the important ones are enforced by hooks and gates at the tool
22
- layer.
23
-
24
- ## If you read only four sections, read these
25
-
26
- 1. **Autonomy tiers** — what you may do alone vs. propose first:
27
- `.claude/rules/autonomy.md` ("Tiers")
28
- 2. **Stop rules** — when stopping with a diagnosis is the correct move:
29
- `.claude/rules/autonomy.md` ("Stop rules")
30
- 3. **The request path** — the mandatory usecase layer and the pure core:
31
- `.claude/rules/architecture.md`
32
- 4. **Definition of Done** — the checklist a change must pass:
33
- `.claude/rules/workflow.md` ("Definition of Done")
34
-
35
- ## The map
36
-
37
- ```
38
- packages/core/ pure domain logic — schemas + functions; no I/O, no clock,
39
- no randomness, no environment (hook-enforced)
40
- packages/shared/ logger, env loading, typed errors — cross-cutting, no domain
41
- packages/db/ the ONLY module that touches the storage SDK/driver
42
- services/ entrypoints; every request: payload → handler → usecase → model
43
- apps/web/ the frontend; imports core + shared ONLY, talks to services
44
- over HTTP (hook-enforced)
45
- ```
46
-
47
- The target-specific details (how to run, deploy, and verify runtime health)
48
- live in `README.md`. Alongside the universal rules, `.claude/rules/` carries
49
- the stack-specific conventions composed in for this project's target — read
50
- them all; they are one rulebook.
51
-
52
- ## How work happens here
53
-
54
- - **TDD, without exception.** The failing test comes first — use the
55
- `test-writer` agent for it. See `.claude/rules/workflow.md`.
56
- - **Check the premises at both ends.** A queue item is a claim about the code, and
57
- nothing downstream re-reads the file it was wrong about — the `check-premises`
58
- skill runs between taking the item and the failing test, and a false load-bearing
59
- claim stops the task instead of quietly re-aiming it. It runs **again before the
60
- gate**, on the prose the task itself wrote: a behaviour claim with nothing behind
61
- it is `UNMEASURED`, and it is deleted or turned into a pointer to its test rather
62
- than left for a reviewer to find.
63
- - **One task, one branch — and merge via PR.** Every unit of work gets its own
64
- short-lived branch; the default branch is never committed to directly. Once
65
- the project has a remote and CI, changes reach it through the PR flow (local
66
- checks → reviewer fan-out → merge on an explicit criterion). See
67
- `.claude/rules/workflow.md` ("Branches and commits", "PR flow"). When another
68
- session may touch this repo at the same time, the branch lives in its own
69
- worktree — the `worktree-task` skill has the lifecycle and the cleanup.
70
- - **Gates.** Every PR is routed before it is reviewed — the
71
- `decision-router` picks the cheapest lane the change earns
72
- (`deterministic` → `fast-path` → `model`), and risk flags escalate ahead of
73
- all three. `code-reviewer` runs on the `model` lane, which is **everything the
74
- two cheap lanes did not claim** — code, a rulebook document, an unclassifiable
75
- path, a derived artifact git does not report as drift, or anything a risk flag
76
- escalated;
77
- `security-scanner` when a change touches auth, secrets, parsing, or outbound
78
- calls; `prose-reviewer` when it touches the documents that instruct agents —
79
- rules, skills, agent specs, decision records, this file, the README. Those last two are
80
- **lane-independent and may only add** — the lane is a floor, never a ceiling.
81
- `.claude/rules/workflow.md` carries the ladder and what the cheap lanes give
82
- up. Blocking findings are resolved, not argued with, and the
83
- `pr-ship` skill drives the fan-out. **No hook launches them** — a gate here is
84
- a session following a written rule, so "the gate ran" is a claim, not a
85
- guarantee. The mechanical enforcement below is a different thing, and the
86
- difference is worth keeping straight.
87
- - **Enforcement is mechanical.** `guard-core-purity` catches an impure edit to
88
- the core the moment it lands; `guard-web-boundary` keeps the frontend off the
89
- backend; `guard-rulebook` refuses an edit to the rulebook itself from an
90
- unattended run outside the item's allow-list (a flag file the `loop` skill
91
- writes; attended sessions are untouched); `guard-secret-file` refuses an edit that writes a credential — by the
92
- file's name or by a value in its text, from the one vocabulary in
93
- `.claude/scripts/lib/secrets.mjs`; `block-no-verify` refuses pre-commit
94
- bypasses; `guard-bash` refuses
95
- the "Never" tier — force-pushing a shared branch, a production deploy, a
96
- filesystem wipe — and carries the kill switch; `gate-stop-dod` refuses to end
97
- the session while a Definition-of-Done check fails. If a hook blocks you, fix
98
- the cause; never route around a hook.
99
- - **Enforcement is a pattern you can apply again.** Each of those hooks is one
100
- stated invariant + one mechanical check + one test — the pattern is written down
101
- in `.claude/rules/invariants.md`, and the `new-invariant` skill walks you
102
- through adding one. The hooks that ship here are **examples, not laws**: if the
103
- invariant they guard is not load-bearing in this project, delete it and spend
104
- the slot on one that is.
105
- - **There is a brake, and it is a real file.** `touch
106
- ~/.claude/__PROJECT_NAME__-loop-STOP` and `guard-bash` denies every merge
107
- until it is removed. Everything short of the merge stays allowed on purpose:
108
- finish the task, push the branch, open the PR, write the journal, stop.
109
- Stopping cleanly never means losing the work.
110
- - **Work comes from the queue, through an adapter.** The `loop` skill selects via
111
- `.claude/scripts/queue/index.mjs`, which reads whichever queue
112
- `.claude/queue.json` names — the Agent queue in `PLAN.md` by default, issues in
113
- this repository once it has a remote. An empty queue **ends the session**; it is
114
- never a cue to invent work, and the agent never files its own work items.
115
-
116
- ## The elevated paths of this project
117
-
118
- Tier 2 in `.claude/rules/autonomy.md` names *kinds* of change. This block names
119
- the **paths** in this repository where those kinds live, and
120
- `.claude/scripts/detect-missed-gate.mjs` reads it — so a path that is not declared
121
- is a path the gate sweep cannot see.
122
-
123
- ```elevated-paths
124
- packages/db/src/
125
- .claude/
126
- .agents/
127
- .codex/
128
- AGENTS.md
129
- docs/decisions/
130
- .github/workflows/
131
- ```
132
-
133
- The entries that earn their place first are the ones that *disarm* the rest —
134
- wherever this project keeps its rulebook, its hooks and its CI definition. A
135
- merge that rewrites the Never tier, unwires a hook or edits what CI runs should
136
- never pass unreviewed. The rest of the block is whatever this particular shape
137
- has, so read the list above rather than this paragraph: the two are maintained
138
- separately, and a project that re-composes the block leaves prose describing
139
- somebody else's repository.
140
-
141
- **They are a seed, not a law — the list is yours to extend.** It is what every
142
- generated shape has; a real project accumulates more (auth handlers, billing, a
143
- credentials module, a migration directory). Add a path the same day you add the
144
- code, because the gap between the two is exactly the window in which a change
145
- slips through unreviewed.
146
-
147
- The declaration is **composed, not centralised**: the sweep unions this block with
148
- every `elevated-paths` block in `.claude/rules/`, so a stack layer declares the
149
- paths that only exist in its shape. A gate declared over a directory this project
150
- does not have would report "clean" while looking nowhere.
151
-
152
- Nothing about this list is retroactive. Installing the sweep into a repo with
153
- history means passing `--epoch <the day you installed it>` once, or the first run
154
- reports every merge that predates the gate.
155
-
156
- ## Foot-guns
157
-
158
- - Don't "simplify" a handler by calling a model directly — the usecase layer is
159
- mandatory even when it looks like ceremony.
160
- - Don't inline `Date.now()`/randomness into the core "just this once" — inject
161
- them; the hook will refuse anyway.
162
- - Don't weaken a failing test to get green — a red check is information, and
163
- test integrity is a blocking review finding.
164
- - After a deploy, CI-green ≠ runtime-healthy: verify per the README, and on
165
- regression revert first (`.claude/rules/autonomy.md`, "Post-deploy
166
- verification").
16
+ Add Claude-Code-only instructions below this line — provider-specific
17
+ wiring stays in `.claude/settings.json`, `.claude/agents/` and the other
18
+ provider-specific files the rulebook already names. Do not restate
19
+ rulebook content here, and do not remove the import above.
@@ -1,12 +1,17 @@
1
1
  # __PROJECT_NAME__ — plan and work queues
2
2
 
3
- Work in this project has a stated origin: one of the two queues below. An
4
- agent session picks from the **Agent queue** (see the `loop` skill); anything
5
- that needs a human decision waits in the **Operator queue**. An empty Agent
6
- queue means the session ends — it is never an invitation to improvise.
3
+ This file itself ships with Core — every rig has it, `--layer workflow` or
4
+ not. **What reads it automatically is workflow-layer only** (`init --layer
5
+ workflow`): with that layer, an agent session picks from the **Agent queue**
6
+ through the `loop` skill, and anything that needs a human decision waits in
7
+ the **Operator queue** — an empty Agent queue means the session ends, never
8
+ an invitation to improvise. **Without the workflow layer, this file is
9
+ manual**: a place to note or look up planned work by hand, read by a session
10
+ only when asked to, never selected from automatically.
7
11
 
8
12
  Keep entries one line each, most valuable first. Delete done items — the
9
- journal records history; the queues state only what is next.
13
+ journal (workflow layer only, below) records history; the queues state only
14
+ what is next.
10
15
 
11
16
  ## Agent queue
12
17
 
@@ -20,12 +25,14 @@ journal records history; the queues state only what is next.
20
25
  <!-- Decisions and Tier-2 work waiting on a human. State what is needed, e.g.:
21
26
  - decide: retention policy before real data (RemovalPolicy flip)
22
27
  -->
23
- ## Where the journal is
28
+ ## Where the journal is (workflow layer only)
24
29
 
25
- `journal/YYYY-MM.md` — one file per month, newest-on-top inside each. The
26
- convention and the field list are in `journal/README.md`.
30
+ `journal/README.md` and the `journal/YYYY-MM.md` files it describes ship with
31
+ the opt-in workflow layer (`init --layer workflow`) — a Core-only rig has
32
+ neither. Where they exist: one journal file per month, newest-on-top inside
33
+ each; the convention and the field list are in `journal/README.md`.
27
34
 
28
35
  The heading here is deliberately **not** `## Journal`: a pointer under that name
29
36
  still sends a session into this file to look, and keeping this file small is the
30
- point. `plan-md.mjs` resolves the two queue headings above by name and is not
31
- affected either way.
37
+ point. `plan-md.mjs` (workflow layer) resolves the two queue headings above by
38
+ name and is not affected either way.
@@ -0,0 +1,313 @@
1
+ # AGENTS.md is canonical; CLAUDE.md is a shim
2
+
3
+ The rule lives in `AGENTS.md`, under "One operating system, two harnesses".
4
+ This file explains the model behind it, what is and is not claimed about
5
+ Claude Code's own `AGENTS.md` support, and what an existing rig's upgrade does
6
+ with a `CLAUDE.md`/`AGENTS.md` pair it already has (RP-186).
7
+
8
+ ## The model
9
+
10
+ Before this change, `templates/agent-os/universal/CLAUDE.md` was the authored
11
+ source and `AGENTS.md` was a byte-identical Codex-facing projection of it,
12
+ mechanically generated by `scripts/sync-codex-adapter.mjs`. That inverted the
13
+ provider-neutral framing the rest of this rulebook states everywhere else:
14
+ the rules are not Claude Code's, and authoring them under a Claude-Code-named
15
+ file made `AGENTS.md` — a name several tools other than Claude Code already
16
+ read — the copy.
17
+
18
+ `AGENTS.md` is now the canonical, provider-neutral source: the full rulebook
19
+ text lives there, once, and the generator authors it in that file directly.
20
+ `CLAUDE.md` is a short compatibility shim: a Claude Code `@AGENTS.md` import
21
+ (see "Claude Code's own import syntax" below) plus anything genuinely
22
+ specific to Claude Code — nothing that duplicates the rulebook. Neither file
23
+ is generated from the other any more; both are authored tree files under
24
+ `templates/agent-os/universal/`, and `scripts/sync-agent-os.mjs` composes each
25
+ one (elevated paths and this repository's addendum go into `AGENTS.md` only)
26
+ independently.
27
+
28
+ ## What is claimed about Claude Code reading AGENTS.md — and what is not
29
+
30
+ **Verified against Anthropic's Claude Code documentation** (`docs.claude.com`
31
+ → `code.claude.com/docs/en/memory`, "AGENTS.md" section, read 2026-09-20):
32
+
33
+ - Claude Code can read a repository's `AGENTS.md` directly, without a
34
+ `CLAUDE.md`, starting with Claude Code v2.1.277.
35
+ - That support is conditional, not universal. Paraphrased from the docs (this
36
+ rulebook names no cloud provider — `test/template/composition.test.ts`):
37
+ in some sessions, such as ones on certain third-party model-hosting
38
+ providers or with telemetry disabled, Claude Code cannot read `AGENTS.md`
39
+ at all — and separately, whenever a `CLAUDE.md`
40
+ (or a same-named file nested under a project's `.claude` directory, or
41
+ `CLAUDE.local.md`) exists anywhere in the working directory or above it,
42
+ Claude Code reads that file **instead of** `AGENTS.md` by default (the
43
+ `claude-md-or-agents-md` project-instructions setting, the default).
44
+ - The documented remedy for exactly this situation is the pattern this
45
+ project ships: *"When Claude isn't reading your AGENTS.md directly, you can
46
+ still keep it as the one file every tool shares by putting an `@AGENTS.md`
47
+ import in a CLAUDE.md next to it… Add any Claude-specific instructions
48
+ below the import, and Claude reads the imported file first, then the
49
+ rest"* — with the worked example:
50
+
51
+ ```markdown
52
+ @AGENTS.md
53
+
54
+ ## Claude Code
55
+
56
+ Use plan mode for changes under `src/billing/`.
57
+ ```
58
+
59
+ This project's `CLAUDE.md` template follows that exact shape.
60
+
61
+ **What this project does NOT claim**, stated because the shim's own text and
62
+ this record both have to survive a reader who takes them literally:
63
+
64
+ - It does **not** claim Claude Code always reads `AGENTS.md` on its own. It
65
+ might, depending on version and configuration — the shim exists precisely
66
+ for the sessions and configurations where it does not, and costs nothing
67
+ when it does (the docs state the import is never read twice).
68
+ - It does **not** claim `AGENTS.md` appears in `/memory` or `/context` when
69
+ Claude reads it directly through the setting — the docs say it does not,
70
+ and point at the `AGENTS.md loaded` session-start line instead.
71
+ - The `@AGENTS.md` import syntax itself: relative and absolute paths are both
72
+ allowed, imports are expanded at launch, and recursive imports are capped
73
+ at four hops — none of which this project's shim relies on beyond the one,
74
+ first-line import.
75
+
76
+ ## The migration (RP-186)
77
+
78
+ A rig installed before this change has a `CLAUDE.md`/`AGENTS.md` pair that is
79
+ byte-identical and recorded as such in its manifest (`.claude/.rig-manifest.json`
80
+ — see `packages/cli/src/lib/manifest.ts`). Both files are ordinary
81
+ manifest-tracked paths (`MAPS` in `packages/cli/src/commands/init.ts`), so
82
+ `upgrade`/`uninstall` need no special-cased migration logic for the
83
+ *ordinary* per-file cases — the same hash-based verdict machinery that
84
+ decides `update` / `conflict` / `deleted` for every other tracked file
85
+ governs both, independently. One coupling IS special-cased: CLAUDE.md's own
86
+ verdict is never allowed to become `update` — writing the `@AGENTS.md`
87
+ shim — while the on-disk AGENTS.md cannot actually SERVE as the rulebook.
88
+
89
+ **Round 5 design ruling (replacing round 4's verdict-only rule, gate cycle 4
90
+ blocker 1): the hold condition is CONTENT, not verdict.** CLAUDE.md is held
91
+ back only when AGENTS.md is absent (`deleted`), or present but not a
92
+ readable rulebook — no fenced ` ```elevated-paths ` block at all, or one
93
+ that parses to nothing once comments and blank lines are stripped (see
94
+ `packages/cli/src/lib/elevated-paths.ts`'s `isReadableRulebook`, mirroring
95
+ the gate sweep's own `parseElevatedPaths` in
96
+ `templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs` — a
97
+ script that ships only with the opt-in workflow layer, so this Core rule is
98
+ implemented independently of it rather than importing it — kept in step by a
99
+ correspondence test). An AGENTS.md the user CUSTOMISED but that
100
+ still carries a non-empty `elevated-paths` block lets the shim through — the
101
+ shim then imports the user's own rulebook, which is the point of it — and
102
+ AGENTS.md itself stays a perfectly ordinary, QUIET `conflict`: the same
103
+ `edited since it was installed` line every other kept file gets, no rescue
104
+ file, no special wording anywhere. This matters because a customised
105
+ AGENTS.md is not a broken rulebook — it is this project's own SHIPPED,
106
+ DESIGNED steady state: `AGENTS.md` itself tells every project to extend its
107
+ `elevated-paths` block for its own paths. Round 4's rule kept AGENTS.md's
108
+ own *verdict* (`conflict` or `deleted`) as the trigger, which made every
109
+ customisation indistinguishable from a genuinely broken rulebook — measured
110
+ directly against the real pre-RP-186 payload with one added path line: every
111
+ `upgrade` said "the migration is NOT finished", wrote a rescue file that
112
+ carried NONE of the user's own lines, and closed on `mv AGENTS.md.rig-new
113
+ AGENTS.md` — following it would have deleted user-authored rulebook content,
114
+ and merging into it and `mv`-ing looped forever.
115
+
116
+ When genuinely held back, `upgrade` keeps CLAUDE.md as its current bytes,
117
+ verdict `conflict`, with a reason naming AGENTS.md's own state and pointing
118
+ at the rescue-file section below for the exact remedy (round 5, blocker 2:
119
+ the reason text never hardcodes `mv` — the actual remedy depends on the
120
+ rescue file's own status, decided separately, and a fixed `mv` promise here
121
+ survived even the case where `mv` would be wrong).
122
+
123
+ **Held back re-vouches, and that has an `uninstall` consequence (PR #241
124
+ round 3, blocker 2; measured correct in round 4).** Holding CLAUDE.md back
125
+ does not merely skip writing it — it also records `sha256` of its CURRENT
126
+ bytes into the next manifest (`nextFiles['CLAUDE.md']`), the same way an
127
+ ordinary `update` would record the new bytes. This is deliberate (see "The
128
+ remedy" below: it is what lets a LATER `upgrade` resolve cleanly instead of
129
+ falling through to "not a version this rig ever released" forever) — but it
130
+ means `uninstall`, which reads `manifest.files` exactly like every other
131
+ rig-owned path, now sees a held-back CLAUDE.md as rig-owned and unedited
132
+ since, and **removes it**, precisely as it would any other untouched file.
133
+ It does not "leave it in place" the way a genuine `conflict` (bytes the
134
+ manifest never vouched for) does. Pinned by `packages/cli/test/upgrade.test.ts`'s
135
+ test "uninstall removes a held-back CLAUDE.md — the re-vouch makes it
136
+ rig-owned again" (absent in a generated rig — `packages/cli/test/` ships no
137
+ test into the payload, so a mention of it is not a citation this rulebook's
138
+ own checker, `evidence-pointers.test.ts`, examines: it reads `test/` and
139
+ `templates/agent-os/`, never `packages/`).
140
+
141
+ **Round 4, blocker 2 (CLI-UX): that removal is now disclosed, not silent.**
142
+ Removing CLAUDE.md while AGENTS.md is not a clean removal (preserved as
143
+ edited, or already gone) — or the other way around — is exactly the moment
144
+ the rulebook could end up with no readable copy left at all, and a bare
145
+ `- CLAUDE.md` line did not say so. `UninstallAction` now carries an optional
146
+ `note` (distinct from `reason`, which stays `preserved`-only) for this one
147
+ case, set at PLAN time so `--dry-run` and a real run print it identically,
148
+ and carried in `--json` as a `notes` array alongside `preserved`. Pinned by
149
+ `packages/cli/test/uninstall.test.ts`'s tests "discloses that removing
150
+ CLAUDE.md leaves AGENTS.md, preserved as edited, as the only rulebook copy",
151
+ "discloses the same thing in the opposite direction when AGENTS.md is the
152
+ one being removed", "discloses when the sibling is already gone (absent),
153
+ not only when it is preserved as edited", "adds no note when both are a
154
+ clean removal", and "the disclosure is identical on --dry-run and a real
155
+ run — set at plan time, never at apply time" (absent in a generated rig,
156
+ same reason as above).
157
+
158
+ | Case | Upgrade outcome | Uninstall outcome |
159
+ | --- | --- | --- |
160
+ | Both untouched since install | Both `update`: `CLAUDE.md` becomes the shim, `AGENTS.md` becomes canonical | Both removed (rig-owned, unedited); no `note` — a clean removal on both sides |
161
+ | `CLAUDE.md` edited by the user, AGENTS.md untouched | `conflict`: kept exactly as the user left it, never force-shimmed; if the edited content is not already the `@AGENTS.md` shim, the reason also says it shadows AGENTS.md (Claude Code reads CLAUDE.md instead, by default) and names the fix; AGENTS.md upgrades independently | `CLAUDE.md` left in place — its own `conflict` verdict is never recorded in `manifest.files` (`upgrade.ts`, the per-file loop's `conflict` branch: "deliberately NOT recorded in `files`"), so `planUninstall` gives it no action at all; it is simply never touched. AGENTS.md removed WITH a `note`, measured verbatim: `this is the rig's own AGENTS.md — removing it leaves CLAUDE.md, which exists and is yours (untracked by this rig), as the only rulebook copy` — the untracked-but-present sibling wording, pinned by `packages/cli/test/uninstall.test.ts`'s test "when CLAUDE.md is the untracked sibling after a real upgrade dropped its conflict verdict from the manifest, the AGENTS.md removal note says it EXISTS — never "absent" (mirror direction)" (absent in a generated rig, same reason as above) |
162
+ | `AGENTS.md` **customised WITH a readable `elevated-paths` block**, CLAUDE.md untouched (round 5's central case — the shipped rulebook's own designed steady state) | AGENTS.md `conflict`, perfectly QUIET — the ordinary `edited since it was installed` line, nothing else. CLAUDE.md is **NOT held back**: verdict `update`, the shim IS adopted, and it imports the user's own customised rulebook | CLAUDE.md removed WITH a `note` (never held back, so never re-vouched — same as any ordinary untouched shim), measured verbatim: `this is the rig's own CLAUDE.md — removing it leaves AGENTS.md, which exists and is yours (untracked by this rig), as the only rulebook copy` — pinned by `packages/cli/test/uninstall.test.ts`'s test "when the sibling is untracked by the manifest (present on disk, never recorded), says it EXISTS — never "absent"" (absent in a generated rig, same reason as above). AGENTS.md itself is left in place — an ordinary, untracked `conflict`, never an uninstall action at all |
163
+ | `AGENTS.md` edited WITHOUT a readable `elevated-paths` block (no block at all, or one that parses to nothing), CLAUDE.md untouched | AGENTS.md `conflict`: kept exactly as the user left it, never overwritten with the canonical text. CLAUDE.md is **held back**: verdict `conflict` (not `update`), kept as its current (old, still-readable) bytes, never written as the shim | AGENTS.md left in place — untracked `conflict`, no uninstall action. **CLAUDE.md is REMOVED** — the hold re-vouches it, so it reads as rig-owned and unedited — WITH a `note`, measured verbatim: `this is the rig's own CLAUDE.md — removing it leaves AGENTS.md, which exists and is yours (untracked by this rig), as the only rulebook copy` — pinned by `packages/cli/test/uninstall.test.ts`'s test "when the sibling is untracked by the manifest (present on disk, never recorded), says it EXISTS — never "absent"" (absent in a generated rig, same reason as above) |
164
+ | `AGENTS.md` deleted by the user, CLAUDE.md untouched | AGENTS.md `deleted`: stays deleted. CLAUDE.md is **held back** the same way, for the same reason (there is no rulebook file at all otherwise) | AGENTS.md stays absent — a genuinely absent path the manifest still records a hash for (`upgrade.ts`'s `deleted` branch keeps `nextFiles['AGENTS.md']` pointing at the recognised, pre-deletion hash, so it stays a manifest-tracked path rather than dropping out the way an ordinary `conflict` does); the `upgrade` REPORT — not the manifest — is what labels it `you removed (left removed)`, in its own summary line (`index.ts`). **CLAUDE.md is REMOVED**, for the same re-vouching reason as the row above — WITH a `note`, measured verbatim: `this is the rig's own CLAUDE.md — removing it leaves AGENTS.md, which is already gone, as the only rulebook copy` — the genuinely-absent sibling wording, pinned by `packages/cli/test/uninstall.test.ts`'s test "discloses when the sibling is already gone (absent), not only when it is preserved as edited" (absent in a generated rig, same reason as above) |
165
+ | `CLAUDE.md` deleted by the user | `deleted`: stays deleted, never restored as the new shim; unaffected by AGENTS.md's own state | already absent |
166
+ | `AGENTS.md` deleted by the user, CLAUDE.md deleted too | Both `deleted`: stays deleted on both sides — there is nothing left to hold back | already absent |
167
+ | The migration already finished (CLAUDE.md is already the shim), THEN AGENTS.md is deleted on a later run | AGENTS.md `deleted`: stays deleted. CLAUDE.md's own verdict is `unchanged` — the held-back coupling above only overrides a verdict that would otherwise become `update`, and an already-adopted shim's verdict never is, so it is left exactly as it is rather than resurrected, rewritten, or held back a second time | CLAUDE.md (the shim) removed like any other untouched file — WITH a `note`, measured verbatim: `this is the rig's own CLAUDE.md — removing it leaves AGENTS.md, which is already gone, as the only rulebook copy` — pinned by `packages/cli/test/uninstall.test.ts`'s test "discloses when the sibling is already gone (absent), not only when it is preserved as edited" (absent in a generated rig, same reason as above); AGENTS.md already absent. Upgrade side pinned by `packages/cli/test/upgrade.test.ts`'s test "AGENTS.md deleted after the migration already finished: the already-adopted shim is left exactly alone" (absent in a generated rig, same reason as above) |
168
+ | A repo that had its own `CLAUDE.md` (or `AGENTS.md`) before `init` | `init` **refuses outright** (`InitError`, non-zero exit) rather than installing over it or recording it as `kept` — `MAPS` files are the one install-time exception to the generic "kept" path every other pre-existing process file gets. Pinned by `packages/cli/test/init.test.ts`'s tests "refuses to clobber an existing CLAUDE.md unless forced" and "refuses to clobber an existing AGENTS.md" — named by full path deliberately: `test/e2e/init.test.ts` (a different suite) shares the bare basename `init.test.ts`, and either mention is absent in a generated rig for the same reason as above regardless | N/A — `init` never installed here, so there is nothing for `uninstall` to have owned |
169
+
170
+ The round-5 rule was re-derived and pinned as a 4×3 grid — AGENTS.md's axis
171
+ split into `pristine` / `edited-with-block` / `edited-without-block` /
172
+ `deleted`, crossed with CLAUDE.md's `pristine` / `edited` / `deleted` — each
173
+ cell's expected verdicts and hold-back flag hand-derived from the rule
174
+ itself, never copied from `upgrade.ts`'s own branching, by
175
+ `packages/cli/test/upgrade.test.ts`'s parametrised test "AGENTS.md %s ×
176
+ CLAUDE.md %s" and its own central case "AGENTS.md customised WITH a readable
177
+ elevated-paths block: the shim is adopted, not held back, and no rescue file
178
+ appears" (absent in a generated rig, same reason as above). Verified AT THE
179
+ CLI BOUNDARY against a customised, still-readable AGENTS.md by
180
+ `packages/cli/test/cli-report.test.ts`'s test "fresh init, then a path line
181
+ added to elevated-paths: upgrade --yes is silent about it, exit 0, AGENTS.md
182
+ unchanged" (same absence), and against the real pre-RP-186 payload by
183
+ `test/e2e/agents-md-migration.test.ts` (absent in a generated rig) › "a
184
+ legacy rig whose AGENTS.md was customised (still a readable rulebook) before
185
+ upgrading: the shim is adopted in one run, and a second run is a no-op".
186
+
187
+ Round 4, blocker 1's rescue file (below) is invisible to the table above — it
188
+ is never a manifest-tracked path — so `uninstall` treats it out of band: a
189
+ byte-identical copy of what THIS release would render right now is
190
+ `remove`d like any other untouched file; anything else is the user's,
191
+ `preserved`. Pinned by `packages/cli/test/uninstall.test.ts`'s tests "treats
192
+ a byte-identical rescue file as removable" and "leaves a differing rescue
193
+ file alone, reported as preserved — not this release's own bytes" (absent
194
+ in a generated rig, same reason as above).
195
+
196
+ ## The remedy that actually works — measured, not assumed (PR #241 rounds 3–5)
197
+
198
+ AGENTS.md's own conflict names a fix, but three readings of it do not work,
199
+ and this project measured each rather than asserting any of them:
200
+
201
+ - **Copying the file the conflict's own `new version:` line points at.**
202
+ That path is the RAW template — still carrying the unsubstituted
203
+ per-project placeholder (`substituteContent` replaces it by exact match;
204
+ see `packages/cli/src/lib/substitute.ts` — spelled out here would itself
205
+ be substituted away by this repo's own dogfood sync, which is exactly why
206
+ it is not), because templates are substituted at install/upgrade time,
207
+ not at rest. Pasting it verbatim gives Claude Code the wrong project name.
208
+ (Round 5: the raw template DOES still carry a real, non-empty
209
+ `elevated-paths` block, so under the content-based hold rule it no longer
210
+ latches the hold the way it used to — but it is still the wrong remedy,
211
+ since it hands the project the wrong name throughout its own rulebook.)
212
+ - **Restoring "the exact bytes the rig installed".** Once AGENTS.md is
213
+ already a conflict, the manifest no longer records what those bytes were
214
+ (the generic rule: "a conflict is not recorded" — deliberately unchanged
215
+ by this ticket, see the top of this section) — there is nothing left on
216
+ disk or in the manifest to restore TO, and this record makes no claim
217
+ about whether any specific past release's bytes would be recognised
218
+ another way (that would need its own test, not an assertion here).
219
+ - **Round 3's own remedy: printing the rendered content to stdout for a
220
+ verbatim paste.** Gate cycle 3 measured this directly, with the built CLI,
221
+ and it does not work either: pasting the block verbatim, or de-indented,
222
+ left AGENTS.md at `conflict` and CLAUDE.md held back regardless — nothing
223
+ about a terminal's own line-wrapping and a human's own copy-paste survives
224
+ byte-for-byte reliably enough for `planUpgrade`'s exact-bytes comparison.
225
+ The dump was also ~270 lines sitting between the plan and the consent
226
+ prompt, scrolling the actionable lines off screen, and the run ended on
227
+ "Wrote N files." even while CLAUDE.md stayed held back — a bare success
228
+ line over an unfinished migration.
229
+ - **Round 4's own remedy: a rescue file keyed on AGENTS.md's verdict alone.**
230
+ Gate cycle 4 measured this against the real pre-RP-186 payload and found
231
+ it did the wrong thing for the project's own designed steady state (a
232
+ customised, still-readable AGENTS.md) — see "Round 5 design ruling" above
233
+ — and, separately, that its `differs` case still closed on `mv`: pasting a
234
+ hostile or merely stale pre-existing rescue file over AGENTS.md as if this
235
+ run had written or verified it.
236
+
237
+ **The fix that is always reachable, with no dependency on release history,
238
+ a terminal, or a human's paste at all — and that only ever appears in the
239
+ GENUINELY held-back state (round 5):** `create-agent-rig upgrade` WRITES the
240
+ already-rendered (substituted) content for AGENTS.md — the same bytes
241
+ `UpgradePlan.contents` carries — to a real sibling file, `AGENTS_MD_RESCUE`
242
+ (`AGENTS.md.rig-new`, `packages/cli/src/commands/upgrade.ts`), through the
243
+ same symlink-refusing write path (`resolveWritableInside`) every other file
244
+ in the plan goes through. It is never recorded in the manifest. The rescue
245
+ file's status is decided ENTIRELY AT PLAN TIME (round 5, blocker 3) —
246
+ `would-write` | `identical` | `differs` | `unsafe` — so a dry run and a real
247
+ run report the identical status, and `applyUpgrade` refuses `unsafe`
248
+ (a symlink, a directory, or similar sitting at the path) BEFORE touching
249
+ anything else at all, including the ordinary payload writes and the
250
+ manifest — closing gate cycle 4's own finding that a symlinked rescue file
251
+ used to leave other files rewritten and the manifest stale, and that a
252
+ directory there crashed with an uncaught `EISDIR`.
253
+
254
+ The closing instruction is printed as a short, delimited block, LAST, after
255
+ the plan, after any wiring hand-over, after "Wrote N files." — the previous
256
+ remedy's placement between the plan and the consent prompt is exactly why
257
+ cycle 3 found "Wrote N files." reading as success while the migration was
258
+ not finished. **`mv` is printed ONLY for `would-write` and `identical`** —
259
+ bytes this run either just wrote or independently verified byte-identical to
260
+ its own rendering. **For `differs`, the remedy is `rm` (or restoring
261
+ AGENTS.md some other way), never `mv`** (round 5, blocker 2: printing `mv`
262
+ there installs bytes this run never wrote or verified as the live rulebook
263
+ the moment the instruction is followed literally). A leftover, byte-identical
264
+ rescue file is cleaned up once AGENTS.md resolves and the rig is NOT held
265
+ back; unrelated clutter at the path (a stray directory or symlink) on an
266
+ otherwise healthy rig is never touched and never even mentioned (round 5,
267
+ blocker 3's own "must not affect upgrade at all").
268
+
269
+ Verified AT THE CLI BOUNDARY — the spawned, built binary, never
270
+ `plan.contents` as the oracle for "the bytes are right" (that circularity was
271
+ cycle 3's finding about round 3's own test) — by
272
+ `packages/cli/test/cli-report.test.ts`'s describe block "AGENTS.md.rig-new —
273
+ the CLI-boundary remedy for a GENUINELY held-back AGENTS.md", including "the
274
+ rescue file is byte-identical to an independently-rendered AGENTS.md for the
275
+ same project — not `plan.contents`" (the independent oracle is a SEPARATE
276
+ `initProject` call, forced to the same project name), "never overwrites a
277
+ pre-existing AGENTS.md.rig-new that differs from the rendered bytes, and
278
+ NEVER prints `mv` for it", "a symlinked AGENTS.md.rig-new in the held-back
279
+ state: exit 1, a clean message, zero files changed", and "a directory at
280
+ AGENTS.md.rig-new in the held-back state: exit 1, a clean message, no
281
+ EISDIR crash" (absent in a generated rig, same reason as above). The
282
+ plan-time state machine itself is pinned at the `planUpgrade`/`applyUpgrade`
283
+ level by `packages/cli/test/upgrade.test.ts`'s describe blocks "the
284
+ AGENTS.md.rig-new rescue file — GENUINELY held back only (round 5)" and
285
+ "AGENTS.md.rig-new clutter on a HEALTHY (never held back) rig must not
286
+ affect upgrade at all" (same absence). And the whole remedy is followed end
287
+ to end against the real pre-RP-186 payload — not a fixture — by
288
+ `test/e2e/agents-md-migration.test.ts` (absent in a generated rig) › "a
289
+ legacy rig whose AGENTS.md was edited before upgrading: CLAUDE.md is held
290
+ back, never shimmed over an unreadable rulebook — and the rescue file
291
+ resolves it end to end".
292
+
293
+ Also see the byte-identity tests this ticket replaced, listed in the PR
294
+ description as an old-test → new-test table.
295
+
296
+ ## What did not change
297
+
298
+ - Provider-specific wiring stays provider-specific: `.claude/settings.json`,
299
+ `.claude/agents/`, `.codex/hooks.json`, `.codex/config.toml` are untouched
300
+ by this ticket and are never duplicated into either rulebook file.
301
+ - The `elevated-paths` block moved with the canonical text: it is declared in
302
+ `AGENTS.md` now, not `CLAUDE.md`. Every mechanical reader of that block —
303
+ `readDeclaredPaths`, and through it the PR-lane router and the queue's own
304
+ tier bookkeeping, all of them part of the opt-in workflow layer and named
305
+ by the core rulebook only to describe what that layer adds — reads
306
+ `AGENTS.md` first and `CLAUDE.md` second, so a not-yet-migrated rig (or a
307
+ test fixture that still writes the block into a `CLAUDE.md`) is not
308
+ silently un-declared.
309
+ - Zero new dependencies; the project-name token this generator substitutes
310
+ everywhere else is unaffected (it is not written literally here — this
311
+ file is itself substituted); no application skeleton, benchmark, agent-bus
312
+ or mandatory Memory
313
+ came back.
@@ -4,15 +4,20 @@ Status: accepted for AR-113; subagent routing extended for RP-166.
4
4
 
5
5
  ## Decision
6
6
 
7
- Claude-shaped files remain the authoring surface. The generator derives the
8
- Codex rulebook (`AGENTS.md`), skills (`.agents/`), custom agents and hook
9
- wiring (`.codex/`); the generated files are checked for drift in the generator
10
- repository and are materialised into a
11
- generated project as its local, versioned operating system. A generated
12
- project does not ship the generator's projector. Its Claude and Codex files are
13
- versioned snapshots: a downstream project that deliberately changes one side
14
- must either make the equivalent local change on the other side or take a newer
15
- generated release. There is no downstream automatic drift check.
7
+ Claude-shaped files remain the authoring surface for skills, custom agents and
8
+ hook wiring. The generator derives the Codex skills (`.agents/`), custom
9
+ agents and hook wiring (`.codex/`) from them; the generated files are checked
10
+ for drift in the generator repository and are materialised into a generated
11
+ project as its local, versioned operating system. The rulebook itself is the
12
+ one exception, since RP-186: `AGENTS.md` is the canonical, authored,
13
+ provider-neutral source — not derived from `CLAUDE.md` — and `CLAUDE.md` is a
14
+ short, separately authored compatibility shim (`@AGENTS.md` import plus
15
+ Claude-Code-specific notes; see `docs/decisions/agents-md-canonical.md`). A
16
+ generated project does not ship the generator's projector for the derived
17
+ files. Its Claude and Codex files are versioned snapshots: a downstream
18
+ project that deliberately changes one side must either make the equivalent
19
+ local change on the other side or take a newer generated release. There is no
20
+ downstream automatic drift check.
16
21
 
17
22
  ## Why
18
23
 
@@ -26,7 +31,7 @@ table, and the projector refuses a missing or orphaned agent profile. It also
26
31
  refuses duplicate source-agent names across layers, since one profile name
27
32
  cannot route two definitions.
28
33
 
29
- Frequent bounded work (`test-writer`, `prose-reviewer`) uses `gpt-5.6-terra`;
34
+ Frequent bounded work (`test-writer`, `implementation-agent`, `prose-reviewer`) uses `gpt-5.6-terra`;
30
35
  correctness, security, and infrastructure gates use `gpt-5.6-sol`. Every named
31
36
  gate uses `high` reasoning effort. Unnamed subagents inherit repository defaults
32
37
  of `gpt-5.6-terra` and `medium` from `.codex/config.toml`. `xhigh` is not a
@@ -4,10 +4,13 @@ The rule lives in `.claude/rules/workflow.md`, under "PR flow". This file
4
4
  explains the one part of it that reads like an inconsistency and is not, so that
5
5
  nobody "tidies" the two sets into agreement. It is not loaded into any session.
6
6
 
7
- ## The sets
7
+ ## The sets (opt-in workflow layer)
8
8
 
9
- Three different mechanisms each carry their own notion of "this file is only
10
- words":
9
+ All three mechanisms below — the gate sweep, the router, and the queue's
10
+ elevated ration — ship with the opt-in workflow layer (`init --layer
11
+ workflow`); a Core-only rig applies the same rulebook exemptions by hand,
12
+ since none of these scripts exist for it to run. Three different mechanisms
13
+ each carry their own notion of "this file is only words":
11
14
 
12
15
  **The first two carve out the rulebook**, and only then differ; the third runs
13
16
  *after* the sweep has already answered, so it sees only what survived:
@@ -29,7 +32,7 @@ test in the rig belongs there. The router's sets stay where they are, for the
29
32
  reason this whole record exists.
30
33
 
31
34
  **Neither row applies to a decision record, including this one.** Both
32
- predicates recognise `CLAUDE.md` anywhere, everything under `.claude/`, and —
35
+ predicates recognise `CLAUDE.md` and `AGENTS.md` anywhere, everything under `.claude/`, and —
33
36
  since these records were extracted — everything under `docs/decisions/`, through
34
37
  the one shared `isDecisionRecord`. A change here escalates the sweep and takes
35
38
  the `model` lane, exactly as the rule it explains would. The router's call is
@@ -58,10 +61,11 @@ is one of the risk flags — and its extension happens to be `.txt`.
58
61
 
59
62
  Copying the sweep's `.mdx` into the router's prose set would put executable MDX
60
63
  back on the prose lane. MDX carries components and imports; it is a program that
61
- renders, not a document that is read. The ration reads it the same way and for
62
- the same reason (`spacing-rations-mechanisms.md`): calling it prose there would
63
- clear the spacing hold on a file this rig treats as a program, on the permissive
64
- side.
64
+ renders, not a document that is read. The ration (workflow layer, like the
65
+ mechanism it rations) reads it the same way and for the same reason
66
+ (`spacing-rations-mechanisms.md`, also workflow layer): calling it prose there
67
+ would clear the spacing hold on a file this rig treats as a program, on the
68
+ permissive side.
65
69
 
66
70
  ## The shape of the mistake this prevents
67
71