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.
- package/CHANGELOG.md +466 -3
- package/README.md +267 -299
- package/package.json +8 -14
- package/packages/cli/dist/commands/create.js +56 -88
- package/packages/cli/dist/commands/doctor.js +213 -0
- package/packages/cli/dist/commands/init.js +151 -54
- package/packages/cli/dist/commands/integrations.js +468 -0
- package/packages/cli/dist/commands/memory.js +63 -4
- package/packages/cli/dist/commands/setup-wizard.js +61 -0
- package/packages/cli/dist/commands/uninstall.js +1223 -0
- package/packages/cli/dist/commands/upgrade.js +489 -89
- package/packages/cli/dist/index.js +657 -49
- package/packages/cli/dist/integrations/declaration.js +158 -0
- package/packages/cli/dist/integrations/doctor-guards.js +126 -0
- package/packages/cli/dist/integrations/doctor-workflow.js +25 -0
- package/packages/cli/dist/integrations/mcp-json.js +107 -0
- package/packages/cli/dist/integrations/memory-doctor.js +124 -0
- package/packages/cli/dist/integrations/registry.js +22 -0
- package/packages/cli/dist/integrations/spawn.js +228 -0
- package/packages/cli/dist/integrations/spec-kit.js +280 -0
- package/packages/cli/dist/integrations/verify.js +193 -0
- package/packages/cli/dist/integrations/windows-job.js +275 -0
- package/packages/cli/dist/lib/elevated-paths.js +74 -0
- package/packages/cli/dist/lib/install-set.js +1 -44
- package/packages/cli/dist/lib/manifest.js +86 -9
- package/packages/cli/dist/lib/prompts.js +0 -23
- package/packages/cli/dist/lib/safe-path.js +193 -2
- package/packages/cli/dist/lib/safe-text.js +78 -0
- package/packages/cli/dist/lib/substitute.js +1 -52
- package/packages/cli/dist/lib/summary.js +5 -5
- package/packages/cli/dist/templates.js +4 -14
- package/scripts/prepare.mjs +28 -12
- package/templates/agent-os/subagent-routing.json +4 -4
- package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.claude/agents/code-reviewer.md +8 -6
- package/templates/agent-os/universal/.claude/agents/implementation-agent.md +41 -0
- package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +8 -4
- package/templates/agent-os/universal/.claude/agents/security-scanner.md +4 -2
- package/templates/agent-os/universal/.claude/agents/test-writer.md +2 -2
- package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +83 -4
- package/templates/agent-os/universal/.claude/rules/autonomy.md +55 -27
- package/templates/agent-os/universal/.claude/rules/invariants.md +9 -8
- package/templates/agent-os/universal/.claude/rules/workflow.md +47 -22
- package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1 -1
- package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +12 -9
- package/templates/agent-os/universal/.claude/scripts/doctor.mjs +100 -2
- package/templates/agent-os/universal/.claude/scripts/lib/claim-records.mjs +236 -6
- package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +43 -0
- package/templates/agent-os/universal/.claude/scripts/queue/jira.mjs +18 -1
- package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +2 -2
- package/templates/agent-os/universal/.claude/scripts/reconcile-external-prs.mjs +273 -35
- package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +16 -0
- package/templates/agent-os/universal/.claude/settings.json +0 -8
- package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.claude/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.claude/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/implementation-agent.toml +6 -0
- package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/security-scanner.toml +1 -1
- package/templates/agent-os/universal/.codex/agents/test-writer.toml +1 -1
- package/templates/agent-os/universal/.codex/hooks.json +0 -10
- package/templates/agent-os/universal/AGENTS.md +208 -107
- package/templates/agent-os/universal/CLAUDE.md +15 -162
- package/templates/agent-os/universal/PLAN.md +17 -10
- package/templates/agent-os/universal/docs/decisions/agents-md-canonical.md +313 -0
- package/templates/agent-os/universal/docs/decisions/codex-adapter.md +15 -10
- package/templates/agent-os/universal/docs/decisions/review-lanes.md +12 -8
- package/templates/agent-os/universal/docs/decisions/session-start-wire-format.md +206 -0
- package/templates/agent-os/universal/docs/decisions/subagent-routing.md +6 -3
- package/templates/agent-os/universal/docs/decisions/workflow-layer-split.md +235 -0
- package/templates/agent-os/universal/layers.json +25 -30
- package/templates/hash-history.json +73 -24
- package/templates/release-ledger.json +3 -1
- package/packages/cli/dist/lib/composition.js +0 -20
- package/packages/cli/dist/lib/targets.js +0 -28
- package/packages/cli/dist/policy/benchmark/corpus.js +0 -165
- package/packages/cli/dist/policy/core/adapter.js +0 -18
- package/packages/cli/dist/policy/core/coverage.js +0 -253
- package/packages/cli/dist/policy/core/decision-record.js +0 -287
- package/packages/cli/dist/policy/core/declaration.js +0 -127
- package/packages/cli/dist/policy/core/evidence-matrix.js +0 -94
- package/packages/cli/dist/policy/core/probe.js +0 -442
- package/packages/cli/dist/policy/core/registry.js +0 -115
- package/packages/cli/dist/policy/core/validation.js +0 -275
- package/packages/cli/dist/policy/core/vocabulary.js +0 -123
- package/packages/cli/dist/policy/harness/claude.js +0 -47
- package/packages/cli/dist/policy/harness/codex.js +0 -87
- package/packages/cli/dist/policy/harness/index.js +0 -15
- package/packages/cli/dist/policy/harness/shared-hooks.js +0 -28
- package/packages/cli/dist/policy/index.js +0 -17
- package/templates/agent-os/init/AGENTS.md +0 -201
- package/templates/agent-os/init/CLAUDE.md +0 -201
- package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +0 -89
- package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +0 -6
- package/templates/agent-os/stack/node-ts/.claude/hooks/dod-checks.json +0 -1
- package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +0 -85
- package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +0 -89
- package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +0 -68
- package/templates/agent-os/universal/.claude/rules/architecture.md +0 -81
- package/templates/skeleton/aws-serverless/.github/workflows/ci.yml +0 -28
- package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +0 -90
- package/templates/skeleton/aws-serverless/README.md +0 -181
- package/templates/skeleton/aws-serverless/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/aws-serverless/apps/web/package.json +0 -19
- package/templates/skeleton/aws-serverless/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/aws-serverless/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +0 -36
- package/templates/skeleton/aws-serverless/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/aws-serverless/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/aws-serverless/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/aws-serverless/eslint.config.mjs +0 -20
- package/templates/skeleton/aws-serverless/gitignore +0 -56
- package/templates/skeleton/aws-serverless/infra/bin/app.ts +0 -79
- package/templates/skeleton/aws-serverless/infra/cdk.json +0 -3
- package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +0 -248
- package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +0 -45
- package/templates/skeleton/aws-serverless/infra/package.json +0 -18
- package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +0 -301
- package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +0 -137
- package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +0 -120
- package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +0 -44
- package/templates/skeleton/aws-serverless/package.json +0 -30
- package/templates/skeleton/aws-serverless/packages/core/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/core/src/events.ts +0 -14
- package/templates/skeleton/aws-serverless/packages/core/src/index.ts +0 -15
- package/templates/skeleton/aws-serverless/packages/core/src/note.ts +0 -69
- package/templates/skeleton/aws-serverless/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/aws-serverless/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/aws-serverless/packages/db/package.json +0 -14
- package/templates/skeleton/aws-serverless/packages/db/src/client.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/db/src/index.ts +0 -2
- package/templates/skeleton/aws-serverless/packages/db/src/note-model.ts +0 -52
- package/templates/skeleton/aws-serverless/packages/db/test/note-model.test.ts +0 -91
- package/templates/skeleton/aws-serverless/packages/shared/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/aws-serverless/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/aws-serverless/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/aws-serverless/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/aws-serverless/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/aws-serverless/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/aws-serverless/pnpm-lock.yaml +0 -2855
- package/templates/skeleton/aws-serverless/pnpm-workspace.yaml +0 -14
- package/templates/skeleton/aws-serverless/services/api/package.json +0 -15
- package/templates/skeleton/aws-serverless/services/api/src/adapters/sqs-publisher.ts +0 -26
- package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +0 -69
- package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +0 -37
- package/templates/skeleton/aws-serverless/services/api/src/list-main.ts +0 -12
- package/templates/skeleton/aws-serverless/services/api/src/main.ts +0 -21
- package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +0 -41
- package/templates/skeleton/aws-serverless/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +0 -211
- package/templates/skeleton/aws-serverless/services/api/test/create-note.usecase.test.ts +0 -45
- package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +0 -122
- package/templates/skeleton/aws-serverless/services/api/test/sqs-publisher.test.ts +0 -22
- package/templates/skeleton/aws-serverless/services/worker/package.json +0 -12
- package/templates/skeleton/aws-serverless/services/worker/src/handlers/note-created.ts +0 -15
- package/templates/skeleton/aws-serverless/services/worker/src/main.ts +0 -7
- package/templates/skeleton/aws-serverless/services/worker/src/usecases/process-note-created.ts +0 -37
- package/templates/skeleton/aws-serverless/services/worker/test/note-created.test.ts +0 -61
- package/templates/skeleton/aws-serverless/tsconfig.base.json +0 -15
- package/templates/skeleton/aws-serverless/tsconfig.json +0 -16
- package/templates/skeleton/aws-serverless/vitest.config.ts +0 -14
- package/templates/skeleton/node-service/.github/workflows/ci.yml +0 -27
- package/templates/skeleton/node-service/.github/workflows/deploy.yml +0 -29
- package/templates/skeleton/node-service/README.md +0 -104
- package/templates/skeleton/node-service/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/node-service/apps/web/package.json +0 -19
- package/templates/skeleton/node-service/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/node-service/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/node-service/apps/web/src/lib/api.ts +0 -29
- package/templates/skeleton/node-service/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/node-service/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/node-service/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/node-service/eslint.config.mjs +0 -20
- package/templates/skeleton/node-service/gitignore +0 -54
- package/templates/skeleton/node-service/package.json +0 -30
- package/templates/skeleton/node-service/packages/core/package.json +0 -11
- package/templates/skeleton/node-service/packages/core/src/events.ts +0 -14
- package/templates/skeleton/node-service/packages/core/src/index.ts +0 -15
- package/templates/skeleton/node-service/packages/core/src/note.ts +0 -69
- package/templates/skeleton/node-service/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/node-service/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/node-service/packages/db/package.json +0 -12
- package/templates/skeleton/node-service/packages/db/src/index.ts +0 -1
- package/templates/skeleton/node-service/packages/db/src/note-store.ts +0 -100
- package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +0 -100
- package/templates/skeleton/node-service/packages/shared/package.json +0 -11
- package/templates/skeleton/node-service/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/node-service/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/node-service/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/node-service/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/node-service/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/node-service/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/node-service/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/node-service/pnpm-lock.yaml +0 -2402
- package/templates/skeleton/node-service/pnpm-workspace.yaml +0 -13
- package/templates/skeleton/node-service/scripts/build-artifact.mjs +0 -34
- package/templates/skeleton/node-service/services/api/package.json +0 -17
- package/templates/skeleton/node-service/services/api/src/adapters/spool-publisher.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/handlers/create-note.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/handlers/list-notes.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/main.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/server.ts +0 -172
- package/templates/skeleton/node-service/services/api/src/static-dir.ts +0 -20
- package/templates/skeleton/node-service/services/api/src/usecases/create-note.ts +0 -30
- package/templates/skeleton/node-service/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/node-service/services/api/test/artifact.test.ts +0 -92
- package/templates/skeleton/node-service/services/api/test/create-note.handler.test.ts +0 -64
- package/templates/skeleton/node-service/services/api/test/create-note.usecase.test.ts +0 -43
- package/templates/skeleton/node-service/services/api/test/list-notes.test.ts +0 -48
- package/templates/skeleton/node-service/services/api/test/package-manager.test.ts +0 -40
- package/templates/skeleton/node-service/services/api/test/package-manager.ts +0 -51
- package/templates/skeleton/node-service/services/api/test/server.test.ts +0 -208
- package/templates/skeleton/node-service/services/api/test/spool-publisher.test.ts +0 -32
- package/templates/skeleton/node-service/services/api/test/static-dir.test.ts +0 -29
- package/templates/skeleton/node-service/services/worker/package.json +0 -16
- package/templates/skeleton/node-service/services/worker/src/main.ts +0 -28
- package/templates/skeleton/node-service/services/worker/src/spool.ts +0 -60
- package/templates/skeleton/node-service/services/worker/src/usecases/process-note-created.ts +0 -38
- package/templates/skeleton/node-service/services/worker/test/process-note-created.test.ts +0 -34
- package/templates/skeleton/node-service/services/worker/test/spool.test.ts +0 -76
- package/templates/skeleton/node-service/tsconfig.base.json +0 -15
- package/templates/skeleton/node-service/tsconfig.json +0 -13
- package/templates/skeleton/node-service/vitest.config.ts +0 -12
|
@@ -1,166 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
@AGENTS.md
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
that
|
|
6
|
-
|
|
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
|
|
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`
|
|
26
|
-
|
|
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
|
|
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
|
|
8
|
-
|
|
9
|
-
wiring (`.codex/`); the generated files are checked
|
|
10
|
-
repository and are materialised into a
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|