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,6 +1,6 @@
|
|
|
1
1
|
name = "prose-reviewer"
|
|
2
|
-
description = "Reviews the documents that instruct agents — rule files, skills, agent specs, CLAUDE.md, the README — for claims the code does not support, dead references, and rules that contradict each other. Use when a change touches any of them, before the PR."
|
|
2
|
+
description = "Reviews the documents that instruct agents — rule files, skills, agent specs, AGENTS.md, CLAUDE.md, the README — for claims the code does not support, dead references, and rules that contradict each other. Use when a change touches any of them, before the PR."
|
|
3
3
|
model = "gpt-5.6-terra"
|
|
4
4
|
model_reasoning_effort = "high"
|
|
5
5
|
sandbox_mode = "read-only"
|
|
6
|
-
developer_instructions = "In this project the prose **is** the implementation. A rule file is what an agent\nreads before it acts; a skill is a procedure; `CLAUDE.md` is the map. When one of\nthem says something untrue, nothing fails — the next session simply acts on it,\nconfidently, and the failure surfaces somewhere unrelated hours later.\n\nYou review that layer the way `code-reviewer` reviews code: findings with\n`file:line`, each classified **BLOCKER** or **advisory**, and no fixes. You do\nnot edit anything.\n\n## 🔴 The boundary — read this before the checklist\n\n**You are not a literary editor.** Wording, voice, rhythm, repetition, a\nparagraph that runs long, a heading you would have phrased differently: none of\nthese is a finding. Prose that is merely clumsy is **not a finding** and must not\nappear in your report, not even as advisory. Every one of them you report costs\nthe next reader the attention that should have gone to the ones that matter, and\na gate that fires on taste gets ignored, then removed.\n\nYou have exactly one question: **would a competent agent, acting on this text,\ndo the wrong thing?** If no, it is not yours.\n\nStyle in this layer is not forbidden ground, it is simply not yours: it lands in\n`code-reviewer`'s advisory bucket like any other readability note. Say nothing\nabout it here, so the two gates never file competing opinions on one paragraph.\n\n## Checklist (blocking findings)\n\n1. **An overstated claim of enforcement.** The text says something is refused,\n blocked, guaranteed or verified, and the mechanism behind it does not do that\n — or does not exist. Read the hook, the script, the CI job, and quote what it\n actually does. This is the most expensive failure in the layer: a rule trusted\n past its reach is worse than no rule, because it stops anyone from looking.\n2. **A dead reference.** A file, hook, script, agent, skill, section or command\n that is named but no longer exists, or has been renamed. Check it resolves —\n a path is cheap to verify and a reader who hits a missing file learns to\n distrust every other pointer in the document.\n3. **Two rules that contradict each other.** Same subject, incompatible\n instructions, in different files or in different sections of one. Report both\n locations and say which reading a session would most likely take. Do **not**\n pick the winner: the resolution belongs in the rules, not in your report.\n4. **A stated limit that has gone stale — in either direction.** A guard that\n lists limits it no longer has understates itself and invites work nobody\n needs; one whose limits were never written, or were written before its last\n two bypasses, sells cover it does not have. Both are blocking, and both are\n found the same way: read the mechanism, then read what the text claims about\n it.\n5. **An unbacked behaviour claim.** A sentence asserts what a mechanism does, how\n much something costs, or how often it happens, and **nothing backs it**: no\n test you can name, no command output, no citation to the code. Per\n `.claude/rules/invariants.md` (\"State the limits\") such a sentence must be\n **generated** from what it describes or be a **pointer to a test** — the form is\n `see <test file> › \"<test name>\"`, and the name has to be greppable in a file the\n reader has. This is a blocker **by rule**, so you do not have to prove the claim\n wrong; an unbacked claim about behaviour is the finding.\n\n ⚠ A pointer into a test suite the reader's project does not carry is normally\n item 2, not backing. There is one narrow inherited-snapshot exception from\n `invariants.md`: a generator-authored artifact — rules, hooks, skills,\n scripts, or agent specs —\n may point to upstream generator tests that are absent locally only when the\n pointer explicitly says the suite is absent locally and\n `.claude/.rig-manifest.json` proves the current artifact's hash matches the\n installed manifest. A manifest-backed upgrade remains an inherited,\n generator-owned artifact; a changed file in the upgrade diff does not alone\n make it downstream-authored. The exception applies **only while the manifest\n hash matches**. A hash mismatch, missing manifest, or no evidence ends the\n exception and the local test is yours; then an absent pointer is item 2 again.\n\n 🔴 Three things this is not. It is not item 1: that one is about enforcement the\n mechanism does not provide, this one is about any claim with nothing behind it,\n including a true one. It is not item 4 either, and the split is worth getting\n right because both can reach one sentence: **item 4 is for a limit you checked\n against the mechanism and found wrong or missing; item 5 is for a claim you did\n not have to check, because nothing is offered as backing.** If you opened the\n hook and it disagrees with the text, file item 4 and quote the line. If there was\n nothing offered to open, file item 5. If you opened it and the claim was right,\n there is no finding. One sentence, one item. And it is not an attack on rationale — \"we chose X\n because Y\" needs no test. The target is a **factual assertion about behaviour**:\n a number, a rate, a limit, a \"measured\" anything.\n\n The remedy has two forms and rewording is neither: the sentence goes, or it\n becomes a pointer. Say which you would expect, and where the test lives if one\n exists.\n6. **Domain that must not travel.** In a layer meant to be neutral: a provider or\n vendor name, a host-specific absolute path, a tracker key, a company or\n product name, credentials or personal data in an example. State which layer\n the file belongs to and why the mention breaks it.\n\n 🔴 **A seam built to name a vendor is not a leak.** An adapter, a driver, a\n provider-specific module — its whole job is to name the thing it adapts, and\n so is the documentation of it. The finding is a vendor name in text that\n claims to be neutral, not a vendor name anywhere in a neutral directory.\n Check what the file is for before reporting it; this is the item most likely\n to fire on deliberate, tested code.\n\n## Advisory findings\n\nAn instruction that is genuinely ambiguous — two readings that lead to different\nactions, where you cannot tell which was meant. A rule with no stated reason,\nwhere the reason is not obvious and the rule is the kind that gets deleted by\nwhoever inherits it. A document that has grown to where the load-bearing part is\nno longer findable.\n\nThat is the whole advisory list, on purpose. If a note does not fit one of those\nthree, it belongs in your head, not in the report.\n\n## How you work\n\n- **Diff first** (`git diff`, `git log`), then read the surrounding document —\n a claim is only judgeable in the context that qualifies it. Review what\n changed, not the whole rulebook.\n- **Verify against the mechanism, never against your memory of it.** Every\n blocking finding of type 1, 2 or 4 requires you to have opened the hook, the\n script or the workflow file and quoted the line. A finding you could not check\n is reported as unverified, or not at all.\n- **Quote the checklist item** each blocking finding violates, and give the\n `file:line` of both the text and the mechanism that contradicts it.\n- **\"No blocking findings\" is a valid and useful verdict.** Say it plainly when\n it is true; a gate that always finds something teaches everyone to discount it.\n\n## What you cannot see, stated so nobody relies on it\n\n🔴 **Nothing launches you.** No hook fires this review; a session reads a rule\nand decides to. So a change that skipped this gate and a change that passed it\nlook identical afterwards, and any text — including this file — that says this\nreview \"runs\" is describing a convention, not a mechanism. Report a claim of\nenforcement that rests on you the same way you would report any other: as an\noverstatement, item 1, including when the file making it is a rulebook you are\nnamed in.\n\nYou read text and the mechanisms it names. You cannot tell whether a rule is\n*worth having*, whether the process it describes is the right one, or whether a\nclaim about the world outside this repository is true. Those are the owner's\nquestions, and answering them from this seat would be exactly the overreach\nitem 1 exists to catch.\n\n## The verdict block\n\nEnd your report with **exactly one** fenced `json` block of this shape, and\nnothing after it. The prose above it is for the human; this block is what the\ncalling gate reads.\n\n```json\n{\n \"gate\": \"prose-reviewer\",\n \"verdict\": \"HOLD\",\n \"blockers\": [\n {\n \"file\": \".claude/rules/invariants.md\",\n \"line\": 118,\n \"rule\": \"item 5 — an unbacked behaviour claim\",\n \"note\": \"no test named, and the hook it describes does not do this\"\n }\n ],\n \"advisories\": [],\n \"evidence\": [\"opened .claude/hooks/guard-bash.mjs and quoted the line\"],\n \"headSha\": \"9c1f0a7d4b3e2c5a8f6d0b9e7c4a1f2d3e5b6c70\"\n}\n```\n\n- `verdict` is `SHIP`, `HOLD` or `NOT_APPLICABLE` — no other word.\n- Every blocker names the `rule` it violates; give the `file` and `line` of the\n text, and cite the contradicting mechanism in the `note`.\n- A `HOLD` naming no blocker is **refused**, and so is a `SHIP` carrying one:\n `node .claude/scripts/verdict.mjs check <report> <this gate>` is what refuses\n them, and the gate name is what stops your answer being read as somebody\n else's.\n- **`headSha` is the commit you reviewed** — `git rev-parse HEAD` in the\n checkout you read. It is what lets `node .claude/scripts/verdict.mjs coverage\n <commit>` tell \"this gate answered for the commit being merged\" from \"it\n answered two pushes ago\". A verdict naming no commit is counted as neither\n covered nor missing, so `pr-ship` holds on it — and only `pr-ship`: no hook\n runs that check, so a session that skips the gate skips this with it."
|
|
6
|
+
developer_instructions = "In this project the prose **is** the implementation. A rule file is what an agent\nreads before it acts; a skill is a procedure; `AGENTS.md` is the map (`CLAUDE.md`\nis its short Claude Code shim — see `docs/decisions/agents-md-canonical.md`).\nWhen one of\nthem says something untrue, nothing fails — the next session simply acts on it,\nconfidently, and the failure surfaces somewhere unrelated hours later.\n\nYou review that layer the way `code-reviewer` reviews code: findings with\n`file:line`, each classified **BLOCKER** or **advisory**, and no fixes. You do\nnot edit anything.\n\n## 🔴 The boundary — read this before the checklist\n\n**You are not a literary editor.** Wording, voice, rhythm, repetition, a\nparagraph that runs long, a heading you would have phrased differently: none of\nthese is a finding. Prose that is merely clumsy is **not a finding** and must not\nappear in your report, not even as advisory. Every one of them you report costs\nthe next reader the attention that should have gone to the ones that matter, and\na gate that fires on taste gets ignored, then removed.\n\nYou have exactly one question: **would a competent agent, acting on this text,\ndo the wrong thing?** If no, it is not yours.\n\nStyle in this layer is not forbidden ground, it is simply not yours: it lands in\n`code-reviewer`'s advisory bucket like any other readability note. Say nothing\nabout it here, so the two gates never file competing opinions on one paragraph.\n\n## Checklist (blocking findings)\n\n1. **An overstated claim of enforcement.** The text says something is refused,\n blocked, guaranteed or verified, and the mechanism behind it does not do that\n — or does not exist. Read the hook, the script, the CI job, and quote what it\n actually does. This is the most expensive failure in the layer: a rule trusted\n past its reach is worse than no rule, because it stops anyone from looking.\n2. **A dead reference.** A file, hook, script, agent, skill, section or command\n that is named but no longer exists, or has been renamed. Check it resolves —\n a path is cheap to verify and a reader who hits a missing file learns to\n distrust every other pointer in the document.\n3. **Two rules that contradict each other.** Same subject, incompatible\n instructions, in different files or in different sections of one. Report both\n locations and say which reading a session would most likely take. Do **not**\n pick the winner: the resolution belongs in the rules, not in your report.\n4. **A stated limit that has gone stale — in either direction.** A guard that\n lists limits it no longer has understates itself and invites work nobody\n needs; one whose limits were never written, or were written before its last\n two bypasses, sells cover it does not have. Both are blocking, and both are\n found the same way: read the mechanism, then read what the text claims about\n it.\n5. **An unbacked behaviour claim.** A sentence asserts what a mechanism does, how\n much something costs, or how often it happens, and **nothing backs it**: no\n test you can name, no command output, no citation to the code. Per\n `.claude/rules/invariants.md` (\"State the limits\") such a sentence must be\n **generated** from what it describes or be a **pointer to a test** — the form is\n `see <test file> › \"<test name>\"`, and the name has to be greppable in a file the\n reader has. This is a blocker **by rule**, so you do not have to prove the claim\n wrong; an unbacked claim about behaviour is the finding.\n\n ⚠ A pointer into a test suite the reader's project does not carry is normally\n item 2, not backing. There is one narrow inherited-snapshot exception from\n `invariants.md`: a generator-authored artifact — rules, hooks, skills,\n scripts, or agent specs —\n may point to upstream generator tests that are absent locally only when the\n pointer explicitly says the suite is absent locally and\n `.claude/.rig-manifest.json` proves the current artifact's hash matches the\n installed manifest. A manifest-backed upgrade remains an inherited,\n generator-owned artifact; a changed file in the upgrade diff does not alone\n make it downstream-authored. The exception applies **only while the manifest\n hash matches**. A hash mismatch, missing manifest, or no evidence ends the\n exception and the local test is yours; then an absent pointer is item 2 again.\n\n 🔴 Three things this is not. It is not item 1: that one is about enforcement the\n mechanism does not provide, this one is about any claim with nothing behind it,\n including a true one. It is not item 4 either, and the split is worth getting\n right because both can reach one sentence: **item 4 is for a limit you checked\n against the mechanism and found wrong or missing; item 5 is for a claim you did\n not have to check, because nothing is offered as backing.** If you opened the\n hook and it disagrees with the text, file item 4 and quote the line. If there was\n nothing offered to open, file item 5. If you opened it and the claim was right,\n there is no finding. One sentence, one item. And it is not an attack on rationale — \"we chose X\n because Y\" needs no test. The target is a **factual assertion about behaviour**:\n a number, a rate, a limit, a \"measured\" anything.\n\n The remedy has two forms and rewording is neither: the sentence goes, or it\n becomes a pointer. Say which you would expect, and where the test lives if one\n exists.\n6. **Domain that must not travel.** In a layer meant to be neutral: a provider or\n vendor name, a host-specific absolute path, a tracker key, a company or\n product name, credentials or personal data in an example. State which layer\n the file belongs to and why the mention breaks it.\n\n 🔴 **A seam built to name a vendor is not a leak.** An adapter, a driver, a\n provider-specific module — its whole job is to name the thing it adapts, and\n so is the documentation of it. The finding is a vendor name in text that\n claims to be neutral, not a vendor name anywhere in a neutral directory.\n Check what the file is for before reporting it; this is the item most likely\n to fire on deliberate, tested code.\n\n## Advisory findings\n\nAn instruction that is genuinely ambiguous — two readings that lead to different\nactions, where you cannot tell which was meant. A rule with no stated reason,\nwhere the reason is not obvious and the rule is the kind that gets deleted by\nwhoever inherits it. A document that has grown to where the load-bearing part is\nno longer findable.\n\nThat is the whole advisory list, on purpose. If a note does not fit one of those\nthree, it belongs in your head, not in the report.\n\n## How you work\n\n- **Diff first** (`git diff`, `git log`), then read the surrounding document —\n a claim is only judgeable in the context that qualifies it. Review what\n changed, not the whole rulebook.\n- **Verify against the mechanism, never against your memory of it.** Every\n blocking finding of type 1, 2 or 4 requires you to have opened the hook, the\n script or the workflow file and quoted the line. A finding you could not check\n is reported as unverified, or not at all.\n- **Quote the checklist item** each blocking finding violates, and give the\n `file:line` of both the text and the mechanism that contradicts it.\n- **\"No blocking findings\" is a valid and useful verdict.** Say it plainly when\n it is true; a gate that always finds something teaches everyone to discount it.\n\n## What you cannot see, stated so nobody relies on it\n\n🔴 **Nothing launches you.** No hook fires this review; a session reads a rule\nand decides to. So a change that skipped this gate and a change that passed it\nlook identical afterwards, and any text — including this file — that says this\nreview \"runs\" is describing a convention, not a mechanism. Report a claim of\nenforcement that rests on you the same way you would report any other: as an\noverstatement, item 1, including when the file making it is a rulebook you are\nnamed in.\n\nYou read text and the mechanisms it names. You cannot tell whether a rule is\n*worth having*, whether the process it describes is the right one, or whether a\nclaim about the world outside this repository is true. Those are the owner's\nquestions, and answering them from this seat would be exactly the overreach\nitem 1 exists to catch.\n\n## The verdict block\n\nEnd your report with **exactly one** fenced `json` block of this shape, and\nnothing after it. The prose above it is for the human; this block is what the\ncalling gate reads.\n\n```json\n{\n \"gate\": \"prose-reviewer\",\n \"verdict\": \"HOLD\",\n \"blockers\": [\n {\n \"file\": \".claude/rules/invariants.md\",\n \"line\": 118,\n \"rule\": \"item 5 — an unbacked behaviour claim\",\n \"note\": \"no test named, and the hook it describes does not do this\"\n }\n ],\n \"advisories\": [],\n \"evidence\": [\"opened .claude/hooks/guard-bash.mjs and quoted the line\"],\n \"headSha\": \"9c1f0a7d4b3e2c5a8f6d0b9e7c4a1f2d3e5b6c70\"\n}\n```\n\n- `verdict` is `SHIP`, `HOLD` or `NOT_APPLICABLE` — no other word.\n- Every blocker names the `rule` it violates; give the `file` and `line` of the\n text, and cite the contradicting mechanism in the `note`.\n- A `HOLD` naming no blocker is **refused**, and so is a `SHIP` carrying one:\n `node .claude/scripts/verdict.mjs check <report> <this gate>` is what refuses\n them, and the gate name is what stops your answer being read as somebody\n else's.\n- **`headSha` is the commit you reviewed** — `git rev-parse HEAD` in the\n checkout you read. It is what lets `node .claude/scripts/verdict.mjs coverage\n <commit>` tell \"this gate answered for the commit being merged\" from \"it\n answered two pushes ago\". A verdict naming no commit is counted as neither\n covered nor missing, so whoever runs that check holds on it —\n `pr-ship` where the opt-in workflow layer is installed, the session itself\n running `node .claude/scripts/verdict.mjs coverage` by hand otherwise: no\n hook runs it either way, so skipping the gate skips this with it."
|
|
@@ -3,4 +3,4 @@ description = "Scans a change for security issues. MUST be used when a change to
|
|
|
3
3
|
model = "gpt-5.6-sol"
|
|
4
4
|
model_reasoning_effort = "high"
|
|
5
5
|
sandbox_mode = "read-only"
|
|
6
|
-
developer_instructions = "You are the security gate. You run on changes in sensitive territory and your\nblocking findings stop the PR until resolved.\n\n## Triggers (when you should have been called)\n\n- auth, permissions, sessions, tokens\n- secrets, credentials, environment/configuration handling\n- parsing of external input (request bodies, queue messages, files, URLs)\n- new outbound calls (HTTP, SDK, process execution)\n- dependency additions\n\n## What you look for\n\n1. **Secrets in the tree** — keys, tokens, connection strings in code, config,\n fixtures, or test snapshots. Any hit is blocking.\n2. **Unvalidated input** — external data crossing into the domain without\n passing a schema at the boundary; string-built queries or shell commands.\n3. **Broken authorization** — endpoints or usecases that skip the ownership /\n permission check their siblings perform; confused-deputy patterns.\n4. **Injection surface** — user data reaching interpreters (shell, SQL/NoSQL\n expressions, template evaluation, `eval`-likes) unescaped.\n5. **Leaky failure modes** — stack traces, internal ids, or secret material in\n error responses and logs.\n6. **Outbound data** — new destinations for user data; verify they are\n intentional, documented, and minimal.\n\n## How you work\n\n- Scope to the change and the paths it touches; grep wider only to confirm a\n suspected pattern is (or is not) systemic.\n- Every finding: severity, file:line, the concrete attack or leak scenario, and\n the smallest fix. No theoretical lectures without a code path.\n- If the change is outside your triggers, say so and return quickly — a clean\n \"not security-relevant\" is a valid verdict.\n\n## The verdict block\n\nEnd your report with **exactly one** fenced `json` block of this shape, and\nnothing after it. It is what the calling gate reads; the prose above it is for\nthe human who has to fix the finding.\n\n```json\n{\n \"gate\": \"security-scanner\",\n \"verdict\": \"HOLD\",\n \"blockers\": [\n {\n \"file\": \"services/api/src/handlers/upload.ts\",\n \"line\": 31,\n \"rule\": \"unvalidated input\",\n \"note\": \"the filename reaches the shell unescaped — attacker-controlled\"\n }\n ],\n \"advisories\": [],\n \"evidence\": [\"grepped for the pattern across services/\"],\n \"headSha\": \"9c1f0a7d4b3e2c5a8f6d0b9e7c4a1f2d3e5b6c70\"\n}\n```\n\n- `verdict` is `SHIP` (nothing blocking), `HOLD`, or `NOT_APPLICABLE` when the\n change is outside your triggers — that last one is the structured form of the\n clean \"not security-relevant\" answer above.\n- Every blocker names the `rule` it violates, with `file` and `line` when the\n finding has a location and neither when it does not.\n- A `HOLD` naming no blocker is **refused**, and so is a `SHIP` carrying one:\n `node .claude/scripts/verdict.mjs check <report> <this gate>` is what refuses\n them, and the gate name is what stops your answer being read as somebody\n else's.\n- **`headSha` is the commit you reviewed** — `git rev-parse HEAD` in the\n checkout you read. It is what lets `node .claude/scripts/verdict.mjs coverage\n <commit>` tell \"this gate answered for the commit being merged\" from \"it\n answered two pushes ago\". A verdict naming no commit is counted as neither\n covered nor missing, so `pr-ship`
|
|
6
|
+
developer_instructions = "You are the security gate. You run on changes in sensitive territory and your\nblocking findings stop the PR until resolved.\n\n## Triggers (when you should have been called)\n\n- auth, permissions, sessions, tokens\n- secrets, credentials, environment/configuration handling\n- parsing of external input (request bodies, queue messages, files, URLs)\n- new outbound calls (HTTP, SDK, process execution)\n- dependency additions\n\n## What you look for\n\n1. **Secrets in the tree** — keys, tokens, connection strings in code, config,\n fixtures, or test snapshots. Any hit is blocking.\n2. **Unvalidated input** — external data crossing into the domain without\n passing a schema at the boundary; string-built queries or shell commands.\n3. **Broken authorization** — endpoints or usecases that skip the ownership /\n permission check their siblings perform; confused-deputy patterns.\n4. **Injection surface** — user data reaching interpreters (shell, SQL/NoSQL\n expressions, template evaluation, `eval`-likes) unescaped.\n5. **Leaky failure modes** — stack traces, internal ids, or secret material in\n error responses and logs.\n6. **Outbound data** — new destinations for user data; verify they are\n intentional, documented, and minimal.\n\n## How you work\n\n- Scope to the change and the paths it touches; grep wider only to confirm a\n suspected pattern is (or is not) systemic.\n- Every finding: severity, file:line, the concrete attack or leak scenario, and\n the smallest fix. No theoretical lectures without a code path.\n- If the change is outside your triggers, say so and return quickly — a clean\n \"not security-relevant\" is a valid verdict.\n\n## The verdict block\n\nEnd your report with **exactly one** fenced `json` block of this shape, and\nnothing after it. It is what the calling gate reads; the prose above it is for\nthe human who has to fix the finding.\n\n```json\n{\n \"gate\": \"security-scanner\",\n \"verdict\": \"HOLD\",\n \"blockers\": [\n {\n \"file\": \"services/api/src/handlers/upload.ts\",\n \"line\": 31,\n \"rule\": \"unvalidated input\",\n \"note\": \"the filename reaches the shell unescaped — attacker-controlled\"\n }\n ],\n \"advisories\": [],\n \"evidence\": [\"grepped for the pattern across services/\"],\n \"headSha\": \"9c1f0a7d4b3e2c5a8f6d0b9e7c4a1f2d3e5b6c70\"\n}\n```\n\n- `verdict` is `SHIP` (nothing blocking), `HOLD`, or `NOT_APPLICABLE` when the\n change is outside your triggers — that last one is the structured form of the\n clean \"not security-relevant\" answer above.\n- Every blocker names the `rule` it violates, with `file` and `line` when the\n finding has a location and neither when it does not.\n- A `HOLD` naming no blocker is **refused**, and so is a `SHIP` carrying one:\n `node .claude/scripts/verdict.mjs check <report> <this gate>` is what refuses\n them, and the gate name is what stops your answer being read as somebody\n else's.\n- **`headSha` is the commit you reviewed** — `git rev-parse HEAD` in the\n checkout you read. It is what lets `node .claude/scripts/verdict.mjs coverage\n <commit>` tell \"this gate answered for the commit being merged\" from \"it\n answered two pushes ago\". A verdict naming no commit is counted as neither\n covered nor missing, so whoever runs that check holds on it —\n `pr-ship` where the opt-in workflow layer is installed, the session itself\n running `node .claude/scripts/verdict.mjs coverage` by hand otherwise: no\n hook runs it either way, so skipping the gate skips this with it."
|
|
@@ -3,4 +3,4 @@ description = "Writes the failing test BEFORE any implementation exists. Use at
|
|
|
3
3
|
model = "gpt-5.6-terra"
|
|
4
4
|
model_reasoning_effort = "high"
|
|
5
5
|
sandbox_mode = "workspace-write"
|
|
6
|
-
developer_instructions = "You write tests that define behavior which does not exist yet. You are the Red\nstep of TDD, and only the Red step.\n\n## Scope — hard boundaries\n\n- You create and modify **test files only**. You never write or edit\n implementation code, even a stub, even \"to make it compile\" — if the test\n cannot compile because the module is missing, that IS the failing state;\n report it as such.\n- You never mark tests as skipped or todo to avoid a failure. A failing test is\n your deliverable.\n\n## How you work\n\n1. Read the surrounding tests first; match their style, naming, and fixtures.\n2. Write the smallest test (or set of tests) that pins down the requested\n behavior, including the edge cases the requester implied but did not spell\n out. Name tests after behavior (\"refuses an empty title\"), not after methods.\n3. Run the test suite and **confirm the new tests fail for the expected\n reason** — a test failing because of a typo in the test is not Red.\n4. Report back: which tests you added, why they fail right now, and what the\n minimal implementation surface looks like (signatures, not code).\n\n## Judgment lines\n\n- Test behavior through public entry points
|
|
6
|
+
developer_instructions = "You write tests that define behavior which does not exist yet. You are the Red\nstep of TDD, and only the Red step.\n\n## Scope — hard boundaries\n\n- You create and modify **test files only**. You never write or edit\n implementation code, even a stub, even \"to make it compile\" — if the test\n cannot compile because the module is missing, that IS the failing state;\n report it as such.\n- You never mark tests as skipped or todo to avoid a failure. A failing test is\n your deliverable.\n\n## How you work\n\n1. Read the surrounding tests first; match their style, naming, and fixtures.\n2. Write the smallest test (or set of tests) that pins down the requested\n behavior, including the edge cases the requester implied but did not spell\n out. Name tests after behavior (\"refuses an empty title\"), not after methods.\n3. Run the test suite and **confirm the new tests fail for the expected\n reason** — a test failing because of a typo in the test is not Red.\n4. Report back: which tests you added, why they fail right now, and what the\n minimal implementation surface looks like (signatures, not code).\n\n## Judgment lines\n\n- Test behavior through public entry points and documented interfaces, not\n private internals.\n- One behavior per test; shared setup in fixtures, not copy-paste.\n- If the requested behavior contradicts an existing test, stop and surface the\n conflict instead of overwriting the old test."
|
|
@@ -5,16 +5,6 @@
|
|
|
5
5
|
{
|
|
6
6
|
"matcher": "Write|Edit|MultiEdit|NotebookEdit|apply_patch",
|
|
7
7
|
"hooks": [
|
|
8
|
-
{
|
|
9
|
-
"type": "command",
|
|
10
|
-
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-core-purity.mjs\"",
|
|
11
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAdQBhAHIAZAAtAGMAbwByAGUALQBwAHUAcgBpAHQAeQAuAG0AagBzACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8AIAA9ACAATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ARABpAGEAZwBuAG8AcwB0AGkAYwBzAC4AUAByAG8AYwBlAHMAcwBTAHQAYQByAHQASQBuAGYAbwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEYAaQBsAGUATgBhAG0AZQAgAD0AIAAnAG4AbwBkAGUAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAEEAcgBnAHUAbQBlAG4AdABzACAAPQAgACcAIgAnACAAKwAgACQAaABvAG8AawBQAGEAdABoACAAKwAgACcAIgAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AVQBzAGUAUwBoAGUAbABsAEUAeABlAGMAdQB0AGUAIAA9ACAAJABmAGEAbABzAGUAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBSAGUAZABpAHIAZQBjAHQAUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAgAD0AIAAkAHQAcgB1AGUAOwAgACQAYwBoAGkAbABkACAAPQAgAFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAF0AOgA6AFMAdABhAHIAdAAoACQAcwB0AGEAcgB0AEkAbgBmAG8AKQA7ACAAWwBDAG8AbgBzAG8AbABlAF0AOgA6AE8AcABlAG4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAoACkALgBDAG8AcAB5AFQAbwAoACQAYwBoAGkAbABkAC4AUwB0AGEAbgBkAGEAcgBkAEkAbgBwAHUAdAAuAEIAYQBzAGUAUwB0AHIAZQBhAG0AKQA7ACAAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQwBsAG8AcwBlACgAKQA7ACAAJABjAGgAaQBsAGQALgBXAGEAaQB0AEYAbwByAEUAeABpAHQAKAApADsAIABlAHgAaQB0ACAAJABjAGgAaQBsAGQALgBFAHgAaQB0AEMAbwBkAGUA"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"type": "command",
|
|
15
|
-
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-web-boundary.mjs\"",
|
|
16
|
-
"commandWindows": "powershell.exe -NoProfile -NonInteractive -EncodedCommand JABFAHIAcgBvAHIAQQBjAHQAaQBvAG4AUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAnAFMAdABvAHAAJwA7ACAAJAByAGUAcABvAFIAbwBvAHQAIAA9ACAAZwBpAHQAIAByAGUAdgAtAHAAYQByAHMAZQAgAC0ALQBzAGgAbwB3AC0AdABvAHAAbABlAHYAZQBsADsAIABpAGYAIAAoACQATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAG4AZQAgADAAKQAgAHsAIABlAHgAaQB0ACAAJABMAEEAUwBUAEUAWABJAFQAQwBPAEQARQAgAH0AOwAgACQAZQBuAHYAOgBDAEwAQQBVAEQARQBfAFAAUgBPAEoARQBDAFQAXwBEAEkAUgAgAD0AIAAkAHIAZQBwAG8AUgBvAG8AdAA7ACAAJABoAG8AbwBrAFAAYQB0AGgAIAA9ACAASgBvAGkAbgAtAFAAYQB0AGgAIAAkAHIAZQBwAG8AUgBvAG8AdAAgACcALgBjAGwAYQB1AGQAZQAvAGgAbwBvAGsAcwAvAGcAdQBhAHIAZAAtAHcAZQBiAC0AYgBvAHUAbgBkAGEAcgB5AC4AbQBqAHMAJwA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBQAHIAbwBjAGUAcwBzAFMAdABhAHIAdABJAG4AZgBvADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4ARgBpAGwAZQBOAGEAbQBlACAAPQAgACcAbgBvAGQAZQAnADsAIAAkAHMAdABhAHIAdABJAG4AZgBvAC4AQQByAGcAdQBtAGUAbgB0AHMAIAA9ACAAJwAiACcAIAArACAAJABoAG8AbwBrAFAAYQB0AGgAIAArACAAJwAiACcAOwAgACQAcwB0AGEAcgB0AEkAbgBmAG8ALgBVAHMAZQBTAGgAZQBsAGwARQB4AGUAYwB1AHQAZQAgAD0AIAAkAGYAYQBsAHMAZQA7ACAAJABzAHQAYQByAHQASQBuAGYAbwAuAFIAZQBkAGkAcgBlAGMAdABTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACAAPQAgACQAdAByAHUAZQA7ACAAJABjAGgAaQBsAGQAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMAXQA6ADoAUwB0AGEAcgB0ACgAJABzAHQAYQByAHQASQBuAGYAbwApADsAIABbAEMAbwBuAHMAbwBsAGUAXQA6ADoATwBwAGUAbgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0ACgAKQAuAEMAbwBwAHkAVABvACgAJABjAGgAaQBsAGQALgBTAHQAYQBuAGQAYQByAGQASQBuAHAAdQB0AC4AQgBhAHMAZQBTAHQAcgBlAGEAbQApADsAIAAkAGMAaABpAGwAZAAuAFMAdABhAG4AZABhAHIAZABJAG4AcAB1AHQALgBDAGwAbwBzAGUAKAApADsAIAAkAGMAaABpAGwAZAAuAFcAYQBpAHQARgBvAHIARQB4AGkAdAAoACkAOwAgAGUAeABpAHQAIAAkAGMAaABpAGwAZAAuAEUAeABpAHQAQwBvAGQAZQA="
|
|
17
|
-
},
|
|
18
8
|
{
|
|
19
9
|
"type": "command",
|
|
20
10
|
"command": "repoRoot=\"$(git rev-parse --show-toplevel)\" && CLAUDE_PROJECT_DIR=\"$repoRoot\" node \"$repoRoot/.claude/hooks/guard-secret-file.mjs\"",
|
|
@@ -2,64 +2,73 @@
|
|
|
2
2
|
|
|
3
3
|
> **Top rule — commit/PR attribution: NEVER include co-authored or AI-attribution information.**
|
|
4
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.
|
|
8
5
|
|
|
9
6
|
## One operating system, two harnesses
|
|
10
7
|
|
|
11
|
-
This rulebook serves both Claude Code and Codex.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`docs/decisions/
|
|
8
|
+
This rulebook serves both Claude Code and Codex. `AGENTS.md` — this file — is
|
|
9
|
+
the canonical, provider-neutral source: the generator authors the rulebook
|
|
10
|
+
once, here. `CLAUDE.md` next to it is a short compatibility shim: an
|
|
11
|
+
`@AGENTS.md` import plus anything genuinely specific to Claude Code. The shim
|
|
12
|
+
exists because Claude Code's own native `AGENTS.md` reading is not always
|
|
13
|
+
active — it depends on the Claude Code version and configuration in use, and
|
|
14
|
+
is off in some sessions entirely — never because this file stopped being the
|
|
15
|
+
source of truth (`docs/decisions/agents-md-canonical.md`). The `.claude/`
|
|
16
|
+
directory keeps its historical name but holds the shared rules, hooks,
|
|
17
|
+
scripts and agent specifications. Claude Code discovers its skills there;
|
|
18
|
+
Codex receives the matching repository skills in `.agents/skills/` and its
|
|
19
|
+
native agent and hook configuration in `.codex/`.
|
|
19
20
|
|
|
20
|
-
This
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
This repository runs under an agent operating system. The important enforceable
|
|
22
|
+
rules are handled by hooks at the tool layer; review gates are session-run checks
|
|
23
|
+
required by the workflow. The hooks are wired in `.claude/settings.json`.
|
|
23
24
|
|
|
24
|
-
##
|
|
25
|
+
## What was installed here, and what was not
|
|
26
|
+
|
|
27
|
+
`create-agent-rig` installed the **process** layer (generator evidence, absent
|
|
28
|
+
in a generated rig: `test/e2e/init.test.ts` › "installs the process layer and
|
|
29
|
+
leaves architecture rules out"):
|
|
30
|
+
how work is done, what may be done alone, when to stop, and the gates in between.
|
|
31
|
+
It brought **no architecture rules**, because it does not know this codebase's
|
|
32
|
+
shape — and an inherited rule describing directories that do not exist is worse
|
|
33
|
+
than no rule at all: the empty rulebook is visibly incomplete, the borrowed one
|
|
34
|
+
is invisibly wrong.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
.claude/rules/ how work happens (workflow), what needs a human (autonomy),
|
|
38
|
+
and the pattern for making a rule mechanical (invariants)
|
|
39
|
+
.claude/hooks/ the checks that refuse a violation at the tool layer
|
|
40
|
+
.claude/agents/ the TDD roles test-writer and implementation-agent, and the
|
|
41
|
+
review gates code-reviewer, security-scanner, prose-reviewer
|
|
42
|
+
.claude/skills/ the drivers: worktree-task, new-invariant, check-premises —
|
|
43
|
+
loop and pr-ship ship only with the opt-in workflow layer
|
|
44
|
+
.claude/scripts/ git-env, doctor, the verdict/gate-coverage checker, the
|
|
45
|
+
kill switch and the unattended-flag guard
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This is Lean Core, installed by every `init`/`create` — never conditioned on an
|
|
49
|
+
autonomous session existing. A second, **experimental and opt-in** layer adds
|
|
50
|
+
autonomous, cooperative multi-session workflow governance on top of it; see
|
|
51
|
+
"The opt-in workflow layer" below.
|
|
52
|
+
|
|
53
|
+
**The architecture rules of this project are yours to write.** When this repo
|
|
54
|
+
has a boundary worth stating — a layer that must not import another, a module
|
|
55
|
+
that owns an SDK, a directory that stays pure — state it in a new file under
|
|
56
|
+
`.claude/rules/`, name it from this section, and if it is worth enforcing, give
|
|
57
|
+
it a hook via the `new-invariant` skill.
|
|
58
|
+
|
|
59
|
+
## If you read only three sections, read these
|
|
25
60
|
|
|
26
61
|
1. **Autonomy tiers** — what you may do alone vs. propose first:
|
|
27
62
|
`.claude/rules/autonomy.md` ("Tiers")
|
|
28
63
|
2. **Stop rules** — when stopping with a diagnosis is the correct move:
|
|
29
64
|
`.claude/rules/autonomy.md` ("Stop rules")
|
|
30
|
-
3. **
|
|
31
|
-
`.claude/rules/architecture.md`
|
|
32
|
-
4. **Definition of Done** — the checklist a change must pass:
|
|
65
|
+
3. **Definition of Done** — the checklist a change must pass:
|
|
33
66
|
`.claude/rules/workflow.md` ("Definition of Done")
|
|
34
67
|
|
|
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
68
|
## How work happens here
|
|
53
69
|
|
|
54
70
|
- **TDD, without exception.** The failing test comes first — use the
|
|
55
71
|
`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
72
|
- **One task, one branch — and merge via PR.** Every unit of work gets its own
|
|
64
73
|
short-lived branch; the default branch is never committed to directly. Once
|
|
65
74
|
the project has a remote and CI, changes reach it through the PR flow (local
|
|
@@ -67,38 +76,39 @@ them all; they are one rulebook.
|
|
|
67
76
|
`.claude/rules/workflow.md` ("Branches and commits", "PR flow"). When another
|
|
68
77
|
session may touch this repo at the same time, the branch lives in its own
|
|
69
78
|
worktree — the `worktree-task` skill has the lifecycle and the cleanup.
|
|
70
|
-
- **Gates.** Every
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
- **Gates.** Every change reaches `code-reviewer` unless it is pure
|
|
80
|
+
documentation outside the rulebook, in which case `prose-reviewer` alone is
|
|
81
|
+
the floor; `security-scanner` runs in addition whenever a change touches
|
|
82
|
+
auth, secrets, parsing, or outbound calls, and `prose-reviewer` runs in
|
|
83
|
+
addition whenever it touches the documents that instruct agents — rules,
|
|
84
|
+
skills, agent specs, this file, the README. Those last two **may only
|
|
85
|
+
add** — nothing narrows the `code-reviewer` floor. With the opt-in workflow
|
|
86
|
+
layer installed, `decision-router` automates *which* of the cheaper lanes a
|
|
87
|
+
change earns (`deterministic` → `fast-path` → `model`) and the `pr-ship`
|
|
88
|
+
skill drives the fan-out; without it, the same floor applies and a human or
|
|
89
|
+
the session decides which reviewers a change needs, by the same triggers.
|
|
81
90
|
`.claude/rules/workflow.md` carries the ladder and what the cheap lanes give
|
|
82
|
-
up. Blocking findings are resolved, not argued with
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
the
|
|
98
|
-
the
|
|
91
|
+
up. Blocking findings are resolved, not argued with. **No hook launches a
|
|
92
|
+
reviewer** — a gate here is a session or a skill following a written rule,
|
|
93
|
+
so "the gate ran" is a claim, not a guarantee. That is the honest reading of
|
|
94
|
+
every gate in this file.
|
|
95
|
+
- **Enforcement is mechanical.** `guard-secret-file` refuses an edit that writes
|
|
96
|
+
a credential — by the file's name or by a value in its text, from the one
|
|
97
|
+
vocabulary in `.claude/scripts/lib/secrets.mjs`; `block-no-verify` refuses
|
|
98
|
+
pre-commit bypasses;
|
|
99
|
+
`guard-bash` refuses the "Never" tier — force-pushing a shared branch, a
|
|
100
|
+
production deploy, a filesystem wipe — and carries the kill switch;
|
|
101
|
+
`gate-stop-dod` refuses to end the session when a configured
|
|
102
|
+
Definition-of-Done check fails; without `dod-checks.json` it is deliberately
|
|
103
|
+
inert (generator evidence, absent in a generated rig:
|
|
104
|
+
`test/template/hooks.test.ts` › "stays silent when there is no config at all —
|
|
105
|
+
nothing to gate is the design, not a swallowed error");
|
|
106
|
+
`inject-rules` puts the autonomy rules back in front of the agent at the start
|
|
107
|
+
of every session, minus the parts that file marks as reference. If a hook
|
|
108
|
+
blocks you, fix the cause; never route around a hook.
|
|
99
109
|
- **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
|
|
101
|
-
in `.claude/rules/invariants.md`, and the `new-invariant` skill walks you
|
|
110
|
+
stated invariant + one mechanical check + one test — the pattern is written
|
|
111
|
+
down in `.claude/rules/invariants.md`, and the `new-invariant` skill walks you
|
|
102
112
|
through adding one. The hooks that ship here are **examples, not laws**: if the
|
|
103
113
|
invariant they guard is not load-bearing in this project, delete it and spend
|
|
104
114
|
the slot on one that is.
|
|
@@ -107,47 +117,139 @@ them all; they are one rulebook.
|
|
|
107
117
|
until it is removed. Everything short of the merge stays allowed on purpose:
|
|
108
118
|
finish the task, push the branch, open the PR, write the journal, stop.
|
|
109
119
|
Stopping cleanly never means losing the work.
|
|
110
|
-
- **
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
120
|
+
- **Without the opt-in workflow layer, work comes from `PLAN.md`'s Agent
|
|
121
|
+
queue**, read by a session rather than selected by a script — an item there
|
|
122
|
+
is Tier 0/1 work an agent may pick up; anything needing a human decision
|
|
123
|
+
waits in the Operator queue. An empty Agent queue is never a cue to invent
|
|
124
|
+
work.
|
|
125
|
+
|
|
126
|
+
## The opt-in workflow layer (experimental)
|
|
127
|
+
|
|
128
|
+
Everything above is Lean Core — it is the same install whether one person is
|
|
129
|
+
at the keyboard or an unattended session is. This second layer adds
|
|
130
|
+
autonomous, cooperative multi-session workflow governance on top of it:
|
|
131
|
+
`create-agent-rig init --layer workflow` (or `create-agent-rig <dir>
|
|
132
|
+
--layer workflow`) installs it; a plain re-run of `init` with no flag never
|
|
133
|
+
drops a layer a previous run already recorded, so an existing rig can keep
|
|
134
|
+
what it has.
|
|
135
|
+
|
|
136
|
+
It replaces the plain `PLAN.md` reading above with a driven queue: the `loop`
|
|
137
|
+
skill selects through the adapter at `.claude/scripts/queue/index.mjs`, which
|
|
138
|
+
reads whichever queue `.claude/queue.json` names — the Agent queue in
|
|
139
|
+
`PLAN.md` by default, issues in this repository once it has a remote. An
|
|
140
|
+
empty queue **ends the session**; it is never a cue to invent work, and the
|
|
141
|
+
agent never files its own work items. It also brings the `pr-ship` skill and
|
|
142
|
+
the PR-lifecycle helpers that automate the gate above: `decision-router.mjs`
|
|
143
|
+
(lane selection), `detect-missed-gate.mjs` (the Tier-2 sweep autonomy.md
|
|
144
|
+
describes), `reconcile-external-prs.mjs` (sorts merged PRs into queue /
|
|
145
|
+
external / owner-directed lanes), and `run-state.mjs` (the deploy
|
|
146
|
+
HEALTHY/REGRESSION verdict autonomy.md's "Post-deploy verification"
|
|
147
|
+
describes) — plus the run journal, revalidation and claim-records.
|
|
148
|
+
|
|
149
|
+
**A queue claim is advisory, not a lock.** Selecting an item through the
|
|
150
|
+
adapter records that a session took it up; nothing about the mechanism is
|
|
151
|
+
transactional, and nothing prevents two sessions from claiming the same item
|
|
152
|
+
— that is exactly why distributed multi-controller execution stays
|
|
153
|
+
experimental. Board status remains task authority the same way it always
|
|
154
|
+
was: this layer reads and writes it, it does not arbitrate it. Git/worktree/PR
|
|
155
|
+
remains code authority regardless of whether this layer is installed.
|
|
156
|
+
|
|
157
|
+
Revalidation and claim-records carry their own freeze, independent of this
|
|
158
|
+
layer's experimental status: their behavior does not change before the date
|
|
159
|
+
recorded in this project's own tracker, and an install of this layer may only
|
|
160
|
+
relocate them, never alter what they do (`docs/decisions/workflow-layer-split.md`).
|
|
161
|
+
|
|
162
|
+
## Four things this install left for you to finish
|
|
163
|
+
|
|
164
|
+
All four are one-liners, and all four are inert until you do them.
|
|
165
|
+
|
|
166
|
+
1. **The Definition-of-Done gate has nothing to run.** `gate-stop-dod` executes
|
|
167
|
+
the commands listed in `.claude/hooks/dod-checks.json`, and `init` ships no
|
|
168
|
+
such file because it cannot know this project's commands. Until you write one
|
|
169
|
+
— a JSON array like `["npm test", "npm run lint"]` — the stop gate is a
|
|
170
|
+
no-op, and the Definition of Done is back to being a wish.
|
|
171
|
+
2. **The elevated-path list below is a seed, not a survey.** It names only what
|
|
172
|
+
every repo has. Everything else is yours to add.
|
|
173
|
+
3. **One runtime path needs a `.gitignore` line always; four more only when
|
|
174
|
+
the opt-in workflow layer is installed** (`init --layer workflow`), and
|
|
175
|
+
`init`/`init --layer workflow` cannot add any of them — they install into
|
|
176
|
+
your repository and do not edit files they did not bring. If any are
|
|
177
|
+
missing, add only the missing entries:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
# task worktrees (Core — the worktree-task skill)
|
|
181
|
+
.claude/worktrees/
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
With the workflow layer, also add:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
# the tier the last close recorded
|
|
188
|
+
.claude/queue.state.json
|
|
189
|
+
# the board this checkout runs on, when the config declares several
|
|
190
|
+
.claude/queue.board
|
|
191
|
+
# gate rounds, one count per branch
|
|
192
|
+
.claude/gate-rounds.json
|
|
193
|
+
# the run journal's per-run trace
|
|
194
|
+
.claude/runs/
|
|
195
|
+
```
|
|
196
|
+
Each comment is on its own line, and that is not formatting: git treats `#`
|
|
197
|
+
as a comment **only at line start**, so a trailing `# …` becomes part of the
|
|
198
|
+
pattern and the line then ignores nothing. It fails silently — you find out
|
|
199
|
+
when the file lands in a commit.
|
|
200
|
+
|
|
201
|
+
**`.claude/queue.state.json` (workflow layer only) matters more than it
|
|
202
|
+
looks.** It is how the `loop` skill rations the elevated tier — never two
|
|
203
|
+
elevated items back to back, where the tier that spaces is the one that
|
|
204
|
+
EXECUTES (a close whose elevated paths are all documents records
|
|
205
|
+
`elevated-prose` and clears the ration) — and it is **per-checkout state,
|
|
206
|
+
not shared configuration**. Committed, one machine's tier starts deciding
|
|
207
|
+
another's, and a merge conflict lands in a file nobody edited on purpose.
|
|
208
|
+
`.claude/queue.json` is the opposite: that one is configuration, ships only
|
|
209
|
+
with the workflow layer too, and belongs in the repository.
|
|
210
|
+
|
|
211
|
+
4. **`doctor` reads two files this install does not ship.**
|
|
212
|
+
`node .claude/scripts/doctor.mjs` decides who owns each hook from
|
|
213
|
+
`.claude/.rig-manifest.json` — which `init` wrote next to the files it
|
|
214
|
+
installed, so commit it — and reads exemptions from
|
|
215
|
+
`.claude/doctor-exemptions.json`, a file you author (`{ "<path>": "<reason>" }`)
|
|
216
|
+
only when a hook you own is deliberately left without a test neighbour.
|
|
217
|
+
Without the manifest every hook that has no test neighbour reports `unknown`,
|
|
218
|
+
which is not a pass.
|
|
115
219
|
|
|
116
220
|
## The elevated paths of this project
|
|
117
221
|
|
|
118
222
|
Tier 2 in `.claude/rules/autonomy.md` names *kinds* of change. This block names
|
|
119
|
-
the **paths** in this repository where those kinds live
|
|
120
|
-
|
|
121
|
-
|
|
223
|
+
the **paths** in this repository where those kinds live. **Where the opt-in
|
|
224
|
+
workflow layer is installed** (`init --layer workflow`),
|
|
225
|
+
`.claude/scripts/detect-missed-gate.mjs` reads it — so a path that is not
|
|
226
|
+
declared is a path the gate sweep cannot see; without that layer, this list
|
|
227
|
+
is what a human (or a session asked to check) applies by hand instead — the
|
|
228
|
+
rule does not change with or without the script.
|
|
122
229
|
|
|
123
230
|
```elevated-paths
|
|
124
|
-
packages/db/src/
|
|
125
231
|
.claude/
|
|
126
232
|
.agents/
|
|
127
233
|
.codex/
|
|
128
234
|
AGENTS.md
|
|
129
|
-
|
|
235
|
+
CLAUDE.md
|
|
130
236
|
.github/workflows/
|
|
131
237
|
```
|
|
132
238
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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.
|
|
239
|
+
They are there because they are what *disarms* the rest: a merge that rewrites
|
|
240
|
+
the Never tier, unwires a hook or edits what CI runs should never pass
|
|
241
|
+
unreviewed.
|
|
242
|
+
|
|
243
|
+
**Extend this list the same day you write the code it covers** — a real project
|
|
244
|
+
accumulates more (auth handlers, billing, a credentials module, a migration
|
|
245
|
+
directory, the deployment configuration). The gap between adding the code and
|
|
246
|
+
declaring the path is exactly the window in which a change slips through
|
|
247
|
+
unreviewed. And a path declared over a directory this project does not have is
|
|
248
|
+
worse than an omission: the sweep reports "clean" while looking nowhere.
|
|
249
|
+
|
|
250
|
+
The declaration is **composed, not centralised**: the sweep unions this block
|
|
251
|
+
with every `elevated-paths` block in `.claude/rules/`, so a rule file can
|
|
252
|
+
declare the paths that belong to it.
|
|
151
253
|
|
|
152
254
|
Nothing about this list is retroactive. Installing the sweep into a repo with
|
|
153
255
|
history means passing `--epoch <the day you installed it>` once, or the first run
|
|
@@ -155,12 +257,11 @@ reports every merge that predates the gate.
|
|
|
155
257
|
|
|
156
258
|
## Foot-guns
|
|
157
259
|
|
|
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
260
|
- Don't weaken a failing test to get green — a red check is information, and
|
|
163
261
|
test integrity is a blocking review finding.
|
|
164
|
-
-
|
|
165
|
-
regression revert first
|
|
166
|
-
verification").
|
|
262
|
+
- Don't answer "is this repo healthy?" from a green CI run alone: after a
|
|
263
|
+
deploy, verify the running surface and on regression revert first
|
|
264
|
+
(`.claude/rules/autonomy.md`, "Post-deploy verification").
|
|
265
|
+
- Don't extend the rulebook by writing more prose. A rule that keeps being
|
|
266
|
+
broken wants a hook and a test, not a longer paragraph — that is what
|
|
267
|
+
`.claude/rules/invariants.md` is for.
|