create-agent-rig 0.4.0 → 0.6.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 +316 -11
- package/README.md +58 -19
- package/package.json +2 -1
- package/packages/cli/dist/commands/create.js +8 -3
- package/packages/cli/dist/commands/init.js +85 -34
- package/packages/cli/dist/commands/upgrade.js +112 -30
- package/packages/cli/dist/index.js +81 -19
- package/packages/cli/dist/lib/copy-tree.js +35 -6
- package/packages/cli/dist/lib/init-settings.js +12 -0
- package/packages/cli/dist/lib/install-set.js +6 -8
- package/packages/cli/dist/lib/manifest.js +31 -9
- package/packages/cli/dist/lib/safe-path.js +30 -0
- package/scripts/prepare.mjs +1 -1
- package/templates/agent-os/init/AGENTS.md +199 -0
- package/templates/agent-os/init/CLAUDE.md +69 -9
- package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +105 -0
- package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +117 -0
- package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +41 -3
- package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +1 -1
- package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +41 -0
- package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +4 -0
- package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +29 -0
- package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +236 -0
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +958 -0
- package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +102 -0
- package/templates/agent-os/universal/.agents/skills/new-invariant/guard-invariant.example.mjs +78 -0
- package/templates/agent-os/universal/.agents/skills/new-invariant/guard-invariant.example.test.mjs +89 -0
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +396 -0
- package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +73 -0
- package/templates/agent-os/universal/.claude/agents/code-reviewer.md +40 -1
- package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +71 -1
- package/templates/agent-os/universal/.claude/agents/security-scanner.md +40 -0
- package/templates/agent-os/universal/.claude/hooks/gate-stop-dod.mjs +301 -26
- package/templates/agent-os/universal/.claude/hooks/guard-bash.mjs +43 -5
- package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +25 -11
- package/templates/agent-os/universal/.claude/hooks/guard-rulebook.mjs +127 -0
- package/templates/agent-os/universal/.claude/hooks/guard-secret-file.mjs +180 -0
- package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +32 -13
- package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +175 -7
- package/templates/agent-os/universal/.claude/hooks/lib/edit-input.mjs +503 -0
- package/templates/agent-os/universal/.claude/rules/autonomy.md +69 -1
- package/templates/agent-os/universal/.claude/rules/invariants.md +104 -19
- package/templates/agent-os/universal/.claude/rules/workflow.md +55 -5
- package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1260 -0
- package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +65 -2
- package/templates/agent-os/universal/.claude/scripts/doctor.mjs +351 -0
- package/templates/agent-os/universal/.claude/scripts/git-env.mjs +49 -0
- package/templates/agent-os/universal/.claude/scripts/lib/gate-coverage.mjs +306 -0
- package/templates/agent-os/universal/.claude/scripts/lib/revalidation-points.mjs +28 -0
- package/templates/agent-os/universal/.claude/scripts/lib/secrets.mjs +490 -0
- package/templates/agent-os/universal/.claude/scripts/lib/verdict.mjs +462 -0
- package/templates/agent-os/universal/.claude/scripts/preflight.mjs +33 -17
- package/templates/agent-os/universal/.claude/scripts/queue/as-of.mjs +51 -0
- package/templates/agent-os/universal/.claude/scripts/queue/checkout.mjs +149 -0
- package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +809 -28
- package/templates/agent-os/universal/.claude/scripts/queue/gate-rounds.mjs +160 -0
- package/templates/agent-os/universal/.claude/scripts/queue/github-issues.mjs +95 -16
- package/templates/agent-os/universal/.claude/scripts/queue/index.mjs +543 -15
- package/templates/agent-os/universal/.claude/scripts/queue/jira.mjs +457 -47
- package/templates/agent-os/universal/.claude/scripts/queue/plan-md.mjs +289 -25
- package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +197 -0
- package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +316 -0
- package/templates/agent-os/universal/.claude/scripts/revalidation-report.mjs +180 -0
- package/templates/agent-os/universal/.claude/scripts/run-journal.mjs +435 -0
- package/templates/agent-os/universal/.claude/scripts/run-state.mjs +539 -0
- package/templates/agent-os/universal/.claude/scripts/stop-flag.mjs +15 -8
- package/templates/agent-os/universal/.claude/scripts/unattended-flag.mjs +239 -0
- package/templates/agent-os/universal/.claude/scripts/verdict.mjs +198 -0
- package/templates/agent-os/universal/.claude/settings.json +11 -2
- package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +118 -7
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +667 -38
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +359 -26
- package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +4 -0
- package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +4 -0
- package/templates/agent-os/universal/.codex/agents/security-scanner.toml +4 -0
- package/templates/agent-os/universal/.codex/agents/test-writer.toml +4 -0
- package/templates/agent-os/universal/.codex/hooks.json +70 -0
- package/templates/agent-os/universal/AGENTS.md +166 -0
- package/templates/agent-os/universal/CLAUDE.md +49 -14
- package/templates/agent-os/universal/PLAN.md +7 -40
- package/templates/agent-os/universal/docs/decisions/closing-a-task.md +98 -0
- package/templates/agent-os/universal/docs/decisions/codex-adapter.md +108 -0
- package/templates/agent-os/universal/docs/decisions/fail-open-guards.md +43 -0
- package/templates/agent-os/universal/docs/decisions/gate-coverage.md +83 -0
- package/templates/agent-os/universal/docs/decisions/review-lanes.md +72 -0
- package/templates/agent-os/universal/docs/decisions/run-directory.md +44 -0
- package/templates/agent-os/universal/docs/decisions/spacing-rations-mechanisms.md +125 -0
- package/templates/agent-os/universal/docs/decisions/stop-conditions-in-a-file.md +46 -0
- package/templates/agent-os/universal/docs/decisions/two-empty-endings.md +74 -0
- package/templates/agent-os/universal/journal/README.md +101 -0
- package/templates/agent-os/universal/layers.json +45 -2
- package/templates/hash-history.json +310 -49
- package/templates/release-ledger.json +9 -0
- package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +34 -1
- package/templates/skeleton/aws-serverless/README.md +91 -9
- package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +9 -2
- package/templates/skeleton/aws-serverless/gitignore +37 -0
- package/templates/skeleton/aws-serverless/infra/bin/app.ts +73 -13
- package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +136 -4
- package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +14 -1
- package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +301 -0
- package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +137 -0
- package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +36 -20
- package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +15 -12
- package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +33 -6
- package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +18 -5
- package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +11 -0
- package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +120 -1
- package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +72 -1
- package/templates/skeleton/node-service/README.md +11 -1
- package/templates/skeleton/node-service/gitignore +34 -0
- package/templates/skeleton/node-service/packages/db/src/note-store.ts +47 -10
- package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +20 -0
- package/templates/skeleton/node-service/services/api/src/main.ts +2 -9
- package/templates/skeleton/node-service/services/api/src/server.ts +93 -10
- package/templates/skeleton/node-service/services/api/src/static-dir.ts +20 -0
- package/templates/skeleton/node-service/services/api/test/server.test.ts +98 -13
- package/templates/skeleton/node-service/services/api/test/static-dir.test.ts +28 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Why the fan-out is checked in `pr-ship`, and never in a hook
|
|
2
|
+
|
|
3
|
+
The check lives in the `pr-ship` skill, step 5 ("Coverage"), and its rule is one
|
|
4
|
+
sentence: *a merge is not gated by a fan-out whose reviewers did not all answer
|
|
5
|
+
for the commit being merged.* This file explains why that check sits in a skill
|
|
6
|
+
rather than in `guard-bash`. The hook version is the one that keeps being
|
|
7
|
+
proposed, and a refusal nobody wrote down gets proposed again. It is not loaded
|
|
8
|
+
into any session.
|
|
9
|
+
|
|
10
|
+
## The shape that was refused
|
|
11
|
+
|
|
12
|
+
The proposal: `guard-bash` denies a merge command unless the run journal holds a
|
|
13
|
+
`SHIP` from every reviewer the router named, for the PR's head commit. It is the
|
|
14
|
+
attractive version — mechanical, at the tool layer, impossible for a hurried
|
|
15
|
+
session to skip.
|
|
16
|
+
|
|
17
|
+
It was refused on four costs, each of them a rule this project already paid for.
|
|
18
|
+
|
|
19
|
+
**1. It needs to recognise a merge command while the brake is off.** The kill
|
|
20
|
+
switch can be coarse — it denies the network clients *as a class of binaries*,
|
|
21
|
+
reading no merge semantics at all, while still allowing the wind-down it asks
|
|
22
|
+
for — because a false block is cheap when the session is already stopped. `invariants.md` states that
|
|
23
|
+
directly: match a rule's precision to the cost of a false positive. A merge gate
|
|
24
|
+
runs during ordinary work, where a false block lands on the last step of finished
|
|
25
|
+
work. The one attempt at enumerating merge routes was reverted, and what it cost
|
|
26
|
+
is recorded where the attempt was made rather than restated here:
|
|
27
|
+
`.claude/hooks/guard-bash.mjs`, the comment above `NETWORK_CLIENTS`.
|
|
28
|
+
|
|
29
|
+
**2. It needs the head commit, inside a hook that must stay pure.** For
|
|
30
|
+
`gh pr merge <number>` the head is only knowable over the network, and
|
|
31
|
+
`guard-bash` records what an unbounded hook costs: killed by its own timeout, and
|
|
32
|
+
a killed hook does not block — so **every** rule silently switched off, not just
|
|
33
|
+
the new one.
|
|
34
|
+
|
|
35
|
+
**3. It needs to parse the journal in a guard that fails open.** The journal
|
|
36
|
+
reader refuses a malformed line by throwing, which is right for a reader and
|
|
37
|
+
fatal for a fail-open guard: the throw resolves to *allow*, again for every rule
|
|
38
|
+
at once. `stop-flag.mjs` is not the precedent it resembles — that is `existsSync`
|
|
39
|
+
over a capped list of fixed paths, not a parse.
|
|
40
|
+
|
|
41
|
+
**4. Its sweep half cannot exist.** The natural companion — audit merged PRs from
|
|
42
|
+
outside — has nothing to read: the run directory is gitignored, and the sweep
|
|
43
|
+
sees labels and PR bodies only.
|
|
44
|
+
|
|
45
|
+
## And the reason the four costs were not worth paying
|
|
46
|
+
|
|
47
|
+
Even fully built, the guard would read a file **the audited run wrote itself**.
|
|
48
|
+
For the threat model a hook actually has — drift, not an adversary — that is
|
|
49
|
+
tolerable, and it is why the skill-level check below is worth having at all. What
|
|
50
|
+
it is not is the *guarantee* the hook version promised, and the four costs above
|
|
51
|
+
were being paid for that word.
|
|
52
|
+
|
|
53
|
+
## What was built instead
|
|
54
|
+
|
|
55
|
+
`.claude/scripts/lib/gate-coverage.mjs` compares the three sets the journal already holds —
|
|
56
|
+
routed, launched, answered — and `pr-ship` runs it through
|
|
57
|
+
`verdict.mjs coverage <commit>` before its own verdict. It sits in the layer that
|
|
58
|
+
already knows the head commit, is allowed to run git, and is allowed to throw.
|
|
59
|
+
|
|
60
|
+
Two limits, and both are stated in the skill beside the step rather than only
|
|
61
|
+
here:
|
|
62
|
+
|
|
63
|
+
- with no `RIG_RUN_DIR` there is no journal, so the check says it was skipped and
|
|
64
|
+
exits 0 — an honest nothing, never a pass;
|
|
65
|
+
- a session that skips `pr-ship` entirely skips this with it. That is the gap the
|
|
66
|
+
hook version was reaching for, and it stays open.
|
|
67
|
+
|
|
68
|
+
So `CLAUDE.md` keeps its sentence unchanged: *no hook launches the gates, so "the
|
|
69
|
+
gate ran" is a claim, not a guarantee.* What changed is narrower and worth
|
|
70
|
+
having on its own — the driver can no longer accept a fan-out that did not
|
|
71
|
+
answer, or one that answered about a commit two pushes ago.
|
|
72
|
+
|
|
73
|
+
## The variant that removes self-report, and why it is not the default
|
|
74
|
+
|
|
75
|
+
Running the reviewers as CI check runs is the only shape where the evidence is
|
|
76
|
+
authored by something other than the audited run, and where the driver cannot
|
|
77
|
+
skip the gate at all. It is not refused on its merits.
|
|
78
|
+
|
|
79
|
+
It is refused **as a default for this layer**: everything under `.claude/` ships
|
|
80
|
+
into every project this rulebook generates, so making it the shape would require
|
|
81
|
+
a model credential in every generated project's CI and a per-PR cost, for
|
|
82
|
+
projects that never asked for either. A project that wants that guarantee should
|
|
83
|
+
adopt it deliberately; the check above is what every project gets.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Why the router's prose set and the gate sweep's inert set differ
|
|
2
|
+
|
|
3
|
+
The rule lives in `.claude/rules/workflow.md`, under "PR flow". This file
|
|
4
|
+
explains the one part of it that reads like an inconsistency and is not, so that
|
|
5
|
+
nobody "tidies" the two sets into agreement. It is not loaded into any session.
|
|
6
|
+
|
|
7
|
+
## The sets
|
|
8
|
+
|
|
9
|
+
Three different mechanisms each carry their own notion of "this file is only
|
|
10
|
+
words":
|
|
11
|
+
|
|
12
|
+
**The first two carve out the rulebook**, and only then differ; the third runs
|
|
13
|
+
*after* the sweep has already answered, so it sees only what survived:
|
|
14
|
+
|
|
15
|
+
| mechanism | rulebook exemption | inert / prose after it | consequence |
|
|
16
|
+
| ------------------------ | ------------------------------------------ | ------------------------------------------ | --------------------------------------------------- |
|
|
17
|
+
| the Tier-2 gate sweep | `isRulebook` in `detect-missed-gate.mjs` | `.md`, `.mdx`, non-provisioning test paths | does not escalate on the elevated-path ground alone |
|
|
18
|
+
| `decision-router.mjs` | `isRulebookPath`, checked before extension | `.md`, `.txt` | may route to the `fast-path` prose lane |
|
|
19
|
+
| the queue's elevated ration (`queue/state.mjs`) | none of its own — it classifies what `elevatedPathsIn` already returned, so only **rulebook** markdown ever reaches it | `.md` (`executesNothing`) | records `elevated-prose`, which does **not** space the next item |
|
|
20
|
+
|
|
21
|
+
The third row is the one added last, and its question is different again: not
|
|
22
|
+
"does this need the gate" nor "can a prose reviewer judge it alone", but **"can
|
|
23
|
+
a merge of this compound into a broken runtime overnight"**. That is why it
|
|
24
|
+
excludes `.mdx` where the sweep includes it — same reasoning as the router's,
|
|
25
|
+
one row below — and why it is `.md` only rather than the sweep's set. Its two
|
|
26
|
+
predicates live in `detect-missed-gate.mjs` side by side so *those two* cannot
|
|
27
|
+
drift; that is a statement about one file, **not** a rule that every markdown
|
|
28
|
+
test in the rig belongs there. The router's sets stay where they are, for the
|
|
29
|
+
reason this whole record exists.
|
|
30
|
+
|
|
31
|
+
**Neither row applies to a decision record, including this one.** Both
|
|
32
|
+
predicates recognise `CLAUDE.md` anywhere, everything under `.claude/`, and —
|
|
33
|
+
since these records were extracted — everything under `docs/decisions/`, through
|
|
34
|
+
the one shared `isDecisionRecord`. A change here escalates the sweep and takes
|
|
35
|
+
the `model` lane, exactly as the rule it explains would. The router's call is
|
|
36
|
+
not a redundant copy of the sweep's; deleting it silently drops this file to the
|
|
37
|
+
prose lane.
|
|
38
|
+
|
|
39
|
+
Without that exemption, declaring a path elevated was a no-op for every `.md`
|
|
40
|
+
under it — the defect that put it there — and it is why moving this rationale
|
|
41
|
+
out of `.claude/` needed a code change rather than only a declaration:
|
|
42
|
+
`isInert` is consulted first, so the declaration alone would have reported clean
|
|
43
|
+
over every record.
|
|
44
|
+
|
|
45
|
+
The **remaining** difference is the inert/prose column, and no set contains
|
|
46
|
+
another. That is deliberate, and every difference earns its keep. One more
|
|
47
|
+
asymmetry belongs to the router alone: it **folds case** before its rulebook
|
|
48
|
+
check, because there folding can only escalate, while a sweep that folded would
|
|
49
|
+
name a path the repository does not have.
|
|
50
|
+
|
|
51
|
+
## Why the sweep does not also take `.txt`
|
|
52
|
+
|
|
53
|
+
Widening the sweep to `.txt` would stop `requirements.txt` inside an elevated
|
|
54
|
+
directory from escalating. A dependency manifest is the opposite of inert — it
|
|
55
|
+
is one of the risk flags — and its extension happens to be `.txt`.
|
|
56
|
+
|
|
57
|
+
## Why neither the router nor the ration takes `.mdx`
|
|
58
|
+
|
|
59
|
+
Copying the sweep's `.mdx` into the router's prose set would put executable MDX
|
|
60
|
+
back on the prose lane. MDX carries components and imports; it is a program that
|
|
61
|
+
renders, not a document that is read. The ration reads it the same way and for
|
|
62
|
+
the same reason (`spacing-rations-mechanisms.md`): calling it prose there would
|
|
63
|
+
clear the spacing hold on a file this rig treats as a program, on the permissive
|
|
64
|
+
side.
|
|
65
|
+
|
|
66
|
+
## The shape of the mistake this prevents
|
|
67
|
+
|
|
68
|
+
Both edits look like clean-ups. Each removes an apparent inconsistency between
|
|
69
|
+
two lists that "obviously" mean the same thing, and each one silently downgrades
|
|
70
|
+
a real review. The lists mean different things because the questions differ:
|
|
71
|
+
"does this change need the elevated gate?" is not "can a prose reviewer judge
|
|
72
|
+
this alone?"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Why one run directory per run, and why nothing can enforce it
|
|
2
|
+
|
|
3
|
+
The rule lives in the `loop` skill, section 1 ("Declare the run directory here").
|
|
4
|
+
This file explains what the enforcement does and does not reach, so nobody
|
|
5
|
+
mistakes the warning for a guarantee. It is not loaded into any session.
|
|
6
|
+
|
|
7
|
+
## An undeclared run is not a run with a missing journal
|
|
8
|
+
|
|
9
|
+
`RIG_RUN_DIR` holds two unrelated things: the machine trace, and the run's
|
|
10
|
+
**stop conditions** — the escalation streak, the deploy verdict, the budget flag.
|
|
11
|
+
|
|
12
|
+
With `RIG_RUN_DIR` unset, the two verdicts a session writes by hand
|
|
13
|
+
(`run-state.mjs deploy …`, `run-state.mjs budget …`) refuse loudly, so it finds
|
|
14
|
+
out. **The escalation count does not.** It is recorded nowhere, silently, and
|
|
15
|
+
selection then hands out work after two walls in a row with nothing on stderr to
|
|
16
|
+
say why.
|
|
17
|
+
|
|
18
|
+
So an undeclared run is a run whose main brake is off, and which looks exactly
|
|
19
|
+
like a healthy one from the outside.
|
|
20
|
+
|
|
21
|
+
The trace's first call site is **selection**, which runs before every task.
|
|
22
|
+
Declared later, it misses everything that already happened — which is why the
|
|
23
|
+
declaration belongs in preflight or nowhere.
|
|
24
|
+
|
|
25
|
+
## What the reuse check catches
|
|
26
|
+
|
|
27
|
+
- Two writers landing on the same sequence number.
|
|
28
|
+
- A directory that already carries its run-end marker.
|
|
29
|
+
|
|
30
|
+
Both are refused. Selection still works and says so on stderr, and that run's
|
|
31
|
+
trace ends there — **loudly**, which is the good case.
|
|
32
|
+
|
|
33
|
+
## What it cannot catch
|
|
34
|
+
|
|
35
|
+
Two runs whose records happen not to collide.
|
|
36
|
+
|
|
37
|
+
A run that died before writing its end marker — and dying unexpectedly is
|
|
38
|
+
exactly the case the checkpoint discipline exists for — leaves an intact
|
|
39
|
+
sequence behind it. The next run pointed at that directory **continues it in
|
|
40
|
+
silence**: one seamless trace of two runs, with nothing in the file able to say
|
|
41
|
+
so.
|
|
42
|
+
|
|
43
|
+
Nothing detects this after the fact. A fresh directory per run is the only thing
|
|
44
|
+
that prevents it, and it is the session's to do.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Why the elevated ration counts mechanisms and not documents
|
|
2
|
+
|
|
3
|
+
The rule lives in the `loop` skill, section 2; the code is
|
|
4
|
+
`.claude/scripts/queue/state.mjs` (which tier a close records) and
|
|
5
|
+
`.claude/scripts/queue/core.mjs` (which tiers clear the ration). This file
|
|
6
|
+
explains why the elevated tier splits in two, why only one half spaces the next
|
|
7
|
+
item, and why an unrecognised tier holds. It is not loaded into any session.
|
|
8
|
+
|
|
9
|
+
## What the ration was bought for
|
|
10
|
+
|
|
11
|
+
The rule's own sentence names it: _one **unreviewed** schema or permissions
|
|
12
|
+
change is recoverable; a chain of them compounding overnight is not._ Two words
|
|
13
|
+
in it do the work. **Unreviewed** — the risk is an unattended run stacking
|
|
14
|
+
changes nobody read. **Compounding** — the second change lands on top of what the
|
|
15
|
+
first one did, so the damage is not additive but multiplied.
|
|
16
|
+
|
|
17
|
+
A rulebook document satisfies neither. It is reviewed on the model lane by two
|
|
18
|
+
cold readers, and it compounds into nothing overnight because no runtime
|
|
19
|
+
executes it. Yet in any repository whose rulebook lives under a declared
|
|
20
|
+
elevated path — every rig, by construction — a `.md` close recorded the same
|
|
21
|
+
`elevated` as a migration and held the next item exactly as hard.
|
|
22
|
+
|
|
23
|
+
Two measurements on this repository forced the change, and they are different
|
|
24
|
+
facts — the second is the mechanism's own report, the first is not:
|
|
25
|
+
|
|
26
|
+
- The `loop` run of 2026-08-17 hit `nothing-selectable` with **56 takeable items
|
|
27
|
+
held, 53 of them by spacing** — the count `queue/index.mjs next` printed, so
|
|
28
|
+
this one is the ration speaking. It holds on the item's **marker**, which is
|
|
29
|
+
what those 53 carried. ⚠ Not reproducible from this repository: the queue is
|
|
30
|
+
tracker-backed and the run's own record is under the gitignored
|
|
31
|
+
`.claude/runs/`, so this figure is a report, not a check anyone can re-run.
|
|
32
|
+
- Earlier, the AR-63 run recorded (journal, 2026-08) that of 58 selectable items
|
|
33
|
+
**56 were elevated in fact — by declared path** — 31 of them marked so and 25
|
|
34
|
+
marked `normal` while their own bodies named an elevated path. That is a
|
|
35
|
+
measurement of the queue, not of the ration: it says the pressure is not going
|
|
36
|
+
to ease, because a rig's rulebook lives under a declared path by construction.
|
|
37
|
+
|
|
38
|
+
Together: the ration was not pacing the project, it was halting it, and the halt
|
|
39
|
+
was indistinguishable from the rule working.
|
|
40
|
+
|
|
41
|
+
## The split, and where it does NOT apply
|
|
42
|
+
|
|
43
|
+
`recordCompletedTier` classifies the elevated paths a close actually crossed:
|
|
44
|
+
|
|
45
|
+
| what the close crossed | tier recorded | effect on the next elevated item |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| every elevated path is a document | `elevated-prose` | clears the ration |
|
|
48
|
+
| any elevated path is not | `elevated-mechanism` | spaces it |
|
|
49
|
+
| no elevated path at all | `normal` | clears the ration |
|
|
50
|
+
|
|
51
|
+
⚠ **"Elevated path" is the sweep's answer, not the diff's.** `elevatedPathsIn`
|
|
52
|
+
drops inert paths *before* this classification runs, and a non-rulebook `.md` is
|
|
53
|
+
inert — so `scripts/notes.md` under a declared directory records `normal`, not
|
|
54
|
+
`elevated-prose`. In practice the only markdown that ever reaches the split is
|
|
55
|
+
**rulebook** markdown: `CLAUDE.md` anywhere, everything under `.claude/`, and the
|
|
56
|
+
decision records. That is pre-existing sweep behaviour, restated here because the
|
|
57
|
+
table above reads more broadly than the code behaves.
|
|
58
|
+
|
|
59
|
+
The predicate is `executesNothing` — **`.md` only** — and it lives in
|
|
60
|
+
`detect-missed-gate.mjs` beside the sweep's own markdown test so the two cannot
|
|
61
|
+
drift apart.
|
|
62
|
+
|
|
63
|
+
**They are different tests on purpose, and `.mdx` is where they part.** The
|
|
64
|
+
sweep asks *does this need a reviewer* and calls both flavours inert. The ration
|
|
65
|
+
asks *can a merge of this compound overnight*, and MDX carries components and
|
|
66
|
+
imports — it is a program that renders, not a document that is read, which is why
|
|
67
|
+
`decision-router.mjs` already sends it down the code lane
|
|
68
|
+
(`review-lanes.md`). Calling it prose here would clear the spacing hold on a file
|
|
69
|
+
this same rig treats as a program, on the permissive side.
|
|
70
|
+
|
|
71
|
+
Two questions, two predicates, **one file** — that pairing is why they cannot
|
|
72
|
+
drift. It is not a rule that every markdown test in the rig belongs there:
|
|
73
|
+
`decision-router.mjs` keeps its own sets on purpose, and `review-lanes.md` — now
|
|
74
|
+
with a row for this ration — exists to stop anyone consolidating them.
|
|
75
|
+
|
|
76
|
+
**The known soft spot: a skill's `SKILL.md` is prose by this test**, and some
|
|
77
|
+
skills carry shell snippets an agent copies and runs. The ruling is that skills
|
|
78
|
+
stay prose for rationing — they are reviewed like the rules they are, and
|
|
79
|
+
rewriting a procedure is not the chain of unreviewed compounding changes the
|
|
80
|
+
ration was bought to stop. It is still the weakest ground the "no runtime
|
|
81
|
+
executes it" justification stands on, and the first place to look if the ration
|
|
82
|
+
turns out too loose.
|
|
83
|
+
|
|
84
|
+
**A mixed diff is a mechanism close.** The half that runs decides. Reading the
|
|
85
|
+
tier off the first path, or off "most of them are documents", would ship a ration
|
|
86
|
+
any diff can opt out of by also touching a `.md`.
|
|
87
|
+
|
|
88
|
+
The split is read by **exactly one** consumer: the ration. `elevated-prose` is
|
|
89
|
+
still an elevated change wherever it is *reviewed* — the model lane, the cold
|
|
90
|
+
readers, the `human-review` label, the gate sweep — and `recordCompletedTier`
|
|
91
|
+
still reports every elevated path it found, unchanged. Narrowing the ration must
|
|
92
|
+
not narrow the report: a prose merge that stopped listing its rulebook files
|
|
93
|
+
would look clean to the sweep that exists to catch exactly those merges.
|
|
94
|
+
|
|
95
|
+
## Unknown holds; absent does not
|
|
96
|
+
|
|
97
|
+
`core.mjs` releases on `normal`, on `elevated-prose`, and on an **absent** tier —
|
|
98
|
+
`null`/`undefined`, which is the honest statement that nothing has closed yet and
|
|
99
|
+
what a fresh checkout says. Everything else holds: the legacy `'elevated'` an
|
|
100
|
+
older state file carries, a word in the wrong case, a value that is not a string.
|
|
101
|
+
|
|
102
|
+
The tempting implementation is `tier === 'elevated-mechanism'`. It is wrong in
|
|
103
|
+
the one direction that matters: every unrecognised value would read as "nothing
|
|
104
|
+
elevated closed" and hand out the next elevated item — un-rationing the queue
|
|
105
|
+
silently, on state files this project itself wrote last week. The whole seam
|
|
106
|
+
exists because a filter whose input nobody supplies is indistinguishable from a
|
|
107
|
+
filter that agrees with you.
|
|
108
|
+
|
|
109
|
+
The legacy word stays *readable* for the same reason it must not be *permissive*:
|
|
110
|
+
a checkout that upgrades mid-run still has one on disk, and refusing it outright
|
|
111
|
+
would exit 1 on the next selection. `loadState` accepts four words and refuses
|
|
112
|
+
the rest — **for the state file only**. Selection falls back to a tier left in
|
|
113
|
+
`queue.json`, and `loadConfig` validates nothing but JSON syntax, so a word like
|
|
114
|
+
`banana` in the config reaches `selectNext` unrefused — measured: the CLI exits 0
|
|
115
|
+
with no refusal, and then **holds** the elevated item with `causes: ["spacing"]`.
|
|
116
|
+
It holds because `core.mjs` is the layer that reads every unrecognised value
|
|
117
|
+
restrictively — the same layer that holds when `selectNext` is called directly.
|
|
118
|
+
|
|
119
|
+
## What this does not fix
|
|
120
|
+
|
|
121
|
+
The livelock where *every* remaining item is elevated-by-mechanism still exists —
|
|
122
|
+
narrowed, not closed. Its operator-only remedy is filed and **not built**: no
|
|
123
|
+
such command exists in this repository today, so a run that hits the livelock
|
|
124
|
+
stops and says so rather than clearing its own tier. Spacing is also still per
|
|
125
|
+
checkout, so a second worktree does not get its own allowance.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Why the run's stop conditions are a file, not a memory
|
|
2
|
+
|
|
3
|
+
The rule lives in the `loop` skill, section 3 ("What keeps the loop running,
|
|
4
|
+
and what stops it"). This file records why the state was moved out of the
|
|
5
|
+
session, and why only one of the two written verdicts can be taken back. It is
|
|
6
|
+
not loaded into any session.
|
|
7
|
+
|
|
8
|
+
## The defect the file fixed
|
|
9
|
+
|
|
10
|
+
`escalations` and `lastDeployVerdict` now live in `<RIG_RUN_DIR>/state.json`,
|
|
11
|
+
written by `run-state.mjs`.
|
|
12
|
+
|
|
13
|
+
Before that existed, the CLI called `stopConditionOf` with the queue counts
|
|
14
|
+
alone. Every state-dependent branch therefore held its **default** on every real
|
|
15
|
+
selection — the runtime-regression stop, the two-escalations stop, the budget
|
|
16
|
+
stop. None of them could fire. The rules were enforced only by whichever session
|
|
17
|
+
happened to remember them.
|
|
18
|
+
|
|
19
|
+
Compaction is exactly the moment a long unattended run stops remembering, and a
|
|
20
|
+
long unattended run is the only situation these stops exist for. So the stops
|
|
21
|
+
were reliably absent precisely where they were needed.
|
|
22
|
+
|
|
23
|
+
## Why the escalation count has two writers, and both must be the documented one
|
|
24
|
+
|
|
25
|
+
- It **rises** through the adapter's `escalate()`. Hand-labelling an item
|
|
26
|
+
escalated marks the item and counts nothing, so the run grinds past the wall.
|
|
27
|
+
- It **resets** through the close step's `recordCompletedTier`, and only when
|
|
28
|
+
that call is passed `runDir` — see `docs/decisions/closing-a-task.md`.
|
|
29
|
+
|
|
30
|
+
Both halves fail quietly when done the undocumented way, and they fail in
|
|
31
|
+
opposite directions: one never stops a broken run, the other stops a healthy one.
|
|
32
|
+
|
|
33
|
+
## Why only the deploy verdict can be taken back
|
|
34
|
+
|
|
35
|
+
The asymmetry is deliberate.
|
|
36
|
+
|
|
37
|
+
`HEALTHY` names a **real later event** — the revert landed and the runtime was
|
|
38
|
+
re-verified. Without a way to record it, one bad deploy would end every later
|
|
39
|
+
selection in the run, however thoroughly it was fixed.
|
|
40
|
+
|
|
41
|
+
Spend only accumulates. Un-exhausting a budget would name no event at all — only
|
|
42
|
+
a decision to keep going, taken by the very run that declared the stop. That is
|
|
43
|
+
the shape of a stop condition a run can talk itself out of, which is not a stop
|
|
44
|
+
condition.
|
|
45
|
+
|
|
46
|
+
A new run starts from a clean state. That is the way back from both.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Why "queue empty" and "nothing selectable" are different endings
|
|
2
|
+
|
|
3
|
+
The rule lives in the `loop` skill, section 3. This file explains why the two
|
|
4
|
+
stops are reported separately, how the parked pile grows under each adapter, and
|
|
5
|
+
why a parked cause outranks a holding one. It is not loaded into any session.
|
|
6
|
+
|
|
7
|
+
## The two endings ask the owner for opposite things
|
|
8
|
+
|
|
9
|
+
- **Queue empty after the filters** — there is no work. Refilling it is the
|
|
10
|
+
owner's job. Expect this to be the most common ending: the queue is finite and
|
|
11
|
+
the loop drains it.
|
|
12
|
+
- **Nothing selectable** — the work is there and every piece of it is held back
|
|
13
|
+
by a condition that clears when _something else happens_: the elevated spacing
|
|
14
|
+
(a normal item lands — or an elevated one whose paths were all documents, see
|
|
15
|
+
`spacing-rations-mechanisms.md`), a blocker (its item closes), `in-progress`
|
|
16
|
+
(the other session finishes), a trigger (a human declares it), an owner (the
|
|
17
|
+
item is marked for another repository and a human moves or re-marks it —
|
|
18
|
+
AR-132), a `re-scope` item (a human rewrites it against the current code and
|
|
19
|
+
removes the label — AR-144), and a `deferred` item (it carries the `parked`
|
|
20
|
+
label and a human un-parks it — AR-144).
|
|
21
|
+
|
|
22
|
+
An empty queue wants refilling. A held one wants interleaving, time, or — for a
|
|
23
|
+
trigger or an owner — the human act the stop line names.
|
|
24
|
+
Reporting the second as the first sends the owner to write tickets that already
|
|
25
|
+
exist; reporting the first as the second tells them to wait for nothing.
|
|
26
|
+
|
|
27
|
+
## The parked pile is reported next to the verdict, never inside it
|
|
28
|
+
|
|
29
|
+
Parked items are out of play and waiting on a human. They are not work this run
|
|
30
|
+
can take, and they are not why the queue is empty — so they are named separately,
|
|
31
|
+
by cause and count. An `obsolete` item (AR-144) is one of them: it waits on a
|
|
32
|
+
human close with a comment naming the evidence, which the loop never writes.
|
|
33
|
+
|
|
34
|
+
⚠ "Parked" here is the pile, not the `parked` **label**. The label (AR-144) means
|
|
35
|
+
"valid work, deliberately not now" — takeable, held, freed by an un-park — so its
|
|
36
|
+
cause is spelled `deferred`, and it is never in this pile. The two were named
|
|
37
|
+
before each other existed; this note is the reconciliation rather than a rename,
|
|
38
|
+
because the pile word runs through the stop line, the tests and this record.
|
|
39
|
+
|
|
40
|
+
How that pile grows is the adapter's business, and the stop line does not guess:
|
|
41
|
+
|
|
42
|
+
| adapter | what lands in the parked pile |
|
|
43
|
+
| ---------------------------------------- | ----------------------------------------------------- |
|
|
44
|
+
| tracker-backed (`github-issues`, `jira`) | an escalated item, a filed proposal (both stay open), and an item labelled `obsolete` (AR-144) |
|
|
45
|
+
| `plan-md` | a `[triage]` or an `[obsolete]` line sitting in the Agent queue — nothing else, because a flat list has no per-item state |
|
|
46
|
+
|
|
47
|
+
Under `plan-md` a filed proposal goes to the Operator queue, where selection
|
|
48
|
+
never looks, and an escalation leaves **no mark on the queue at all** — a flat
|
|
49
|
+
list has no per-item state.
|
|
50
|
+
|
|
51
|
+
## That absence is not a safety
|
|
52
|
+
|
|
53
|
+
`plan-md`'s `escalate` writes nothing to the queue and returns `ok: false`,
|
|
54
|
+
handing back the instruction with it: move the item to the Operator queue in the
|
|
55
|
+
same edit. That move is the session's, and skipping it means the next run takes
|
|
56
|
+
the stuck item straight back.
|
|
57
|
+
|
|
58
|
+
It does still record the escalation into the run state, like every other
|
|
59
|
+
adapter. The two are different facts, which is why escalating must go through
|
|
60
|
+
the adapter rather than by hand-labelling: the count is what ends a run that has
|
|
61
|
+
hit the same wall twice.
|
|
62
|
+
|
|
63
|
+
## Why a parked cause outranks a holding one
|
|
64
|
+
|
|
65
|
+
An escalated item is left **claimed** on purpose, so it arrives carrying
|
|
66
|
+
`in-progress` as well as `escalated`.
|
|
67
|
+
|
|
68
|
+
Reading that as _held_ would report "another session will finish it" about an
|
|
69
|
+
item no session is on — and, worse, would make the empty verdict unreachable
|
|
70
|
+
from the first escalation onward. Reporting a working queue as empty is the
|
|
71
|
+
defect this distinction exists to prevent; reporting a parked one as working is
|
|
72
|
+
the same defect reversed.
|
|
73
|
+
|
|
74
|
+
Neither ending is an invitation to refill the queue or invent work.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# The journal
|
|
2
|
+
|
|
3
|
+
The human record of what sessions did here. **One file per month**, named
|
|
4
|
+
`journal/YYYY-MM.md` — the month is the filename's job, so entries themselves
|
|
5
|
+
stay date-free and their order carries the sequence.
|
|
6
|
+
|
|
7
|
+
**Newest-on-top inside each file.** A new entry goes directly under the month's
|
|
8
|
+
heading, so the file reads as a stack. Prune freely: this is operational memory,
|
|
9
|
+
not an archive.
|
|
10
|
+
|
|
11
|
+
**The shape of a month file**, stated because the first session of a new month
|
|
12
|
+
creates it and a shape nobody wrote down is one that has to be guessed:
|
|
13
|
+
|
|
14
|
+
- it **opens with a single `#` heading** naming the month;
|
|
15
|
+
- **every entry is a `###`** under that heading, and there is nothing at `##`
|
|
16
|
+
or any other level in between;
|
|
17
|
+
- a new entry is inserted directly beneath the `#` heading, above the previous
|
|
18
|
+
newest.
|
|
19
|
+
|
|
20
|
+
**What is mechanically checked, precisely — because this file ships into a
|
|
21
|
+
project and its checks do not.** The generator that produced this rig has tests
|
|
22
|
+
for the first two bullets and for the `YYYY-MM.md` filename; **this project has
|
|
23
|
+
none of them** unless you write them. That is the same arrangement
|
|
24
|
+
`.claude/rules/invariants.md` describes for the hooks, and the same caveat
|
|
25
|
+
applies: what is not tested here is convention, however firmly it is written.
|
|
26
|
+
|
|
27
|
+
The third bullet — *where* a new entry is inserted — is convention even in the
|
|
28
|
+
generator. Nothing checks entry order anywhere yet; making "newest" decidable
|
|
29
|
+
for date-free entries is its own piece of work. Do not read the presence of a
|
|
30
|
+
shape rule as a guarantee that a misordered file would be caught.
|
|
31
|
+
|
|
32
|
+
`README.md` is this document, not a month file. Other names: a file that does
|
|
33
|
+
not match `YYYY-MM.md` is never **read** as a month file — but do not read that
|
|
34
|
+
as permission, because in the generator any other `*.md` in this directory
|
|
35
|
+
**fails** the filename check. Keep archives and side notes out of this
|
|
36
|
+
directory, or somewhere with a non-`.md` extension.
|
|
37
|
+
|
|
38
|
+
An unattended run writes an entry at every stop **and** at checkpoints along the
|
|
39
|
+
way, because a run that dies unexpectedly must not take its history with it.
|
|
40
|
+
|
|
41
|
+
🔴 **This is not the run trace.** `.claude/runs/<run>/events.jsonl` and
|
|
42
|
+
`decisions.jsonl` are machine-readable, append-only and **oldest-first**, written
|
|
43
|
+
by `run-journal.mjs`. This file is the human record and is newest-on-top. They
|
|
44
|
+
answer different questions — the trace says what the run decided and on what
|
|
45
|
+
basis, this says what a reader needs to know afterwards — and reading one as the
|
|
46
|
+
other is how a reader concludes a run did nothing.
|
|
47
|
+
|
|
48
|
+
## The entry
|
|
49
|
+
|
|
50
|
+
The fields exist so an entry can be visibly **incomplete**. A journal with no
|
|
51
|
+
stated shape decays into a diary that reads fine and proves nothing.
|
|
52
|
+
|
|
53
|
+
Copy the block and drop the fields that do not apply — `unblocked` is the
|
|
54
|
+
exception, and it is stated even when the answer is "nothing".
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
### <one-line summary of the session>
|
|
58
|
+
|
|
59
|
+
- **done** — what landed, one line each, with the PR reference
|
|
60
|
+
- **escalated** — what stopped, and the diagnosis: what failed, what was tried,
|
|
61
|
+
the current hypothesis, and the one question whose answer unblocks it
|
|
62
|
+
- **reviewed** — changes that went through a reviewer gate, and what it returned
|
|
63
|
+
- **stopped at** — which stop condition ended the session (or "checkpoint,
|
|
64
|
+
still running")
|
|
65
|
+
- **unblocked** — what the session's closes released
|
|
66
|
+
- **queue hygiene** — queue state the session found unreliable and reported
|
|
67
|
+
- **cost** — the counts the session actually observed
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## The two fields that are most often got wrong
|
|
71
|
+
|
|
72
|
+
**`unblocked` is never dropped**, and it has **three** answers that do not
|
|
73
|
+
substitute for each other:
|
|
74
|
+
|
|
75
|
+
1. the items that were waiting, by name;
|
|
76
|
+
2. "nothing was waiting" — the queue carries dependency links and none pointed
|
|
77
|
+
here;
|
|
78
|
+
3. "this queue has no dependency links" — it cannot answer at all.
|
|
79
|
+
|
|
80
|
+
A flat-list queue is **absent, not satisfied**, and writing "nothing was waiting"
|
|
81
|
+
there claims a look that no query could perform. A missing line and an unpaid
|
|
82
|
+
debt read identically from outside, which is why the empty case has to be
|
|
83
|
+
written to mean anything.
|
|
84
|
+
|
|
85
|
+
**`cost` carries only what the session observed** — reviewer subagents run, CI
|
|
86
|
+
runs consumed (re-runs included, the cheapest signal that a task fought its
|
|
87
|
+
tests), deploys triggered.
|
|
88
|
+
|
|
89
|
+
## Never estimated — and this governs every field, not just `cost`
|
|
90
|
+
|
|
91
|
+
**Any** field the session cannot observe stays **visibly empty, never
|
|
92
|
+
estimated**. A plausible number will be believed, by the next reader and by the
|
|
93
|
+
next run reasoning about its own budget — and the same is true of a plausible
|
|
94
|
+
sentence: a guessed `reviewed` or an inferred `unblocked` is the identical
|
|
95
|
+
failure without the digits. Leave the gap; it is information.
|
|
96
|
+
|
|
97
|
+
## Queue hygiene is reported, never corrected in passing
|
|
98
|
+
|
|
99
|
+
A stale marker, a dependency already satisfied, an item describing work already
|
|
100
|
+
done — record it here. Quietly fixing the metadata destroys the evidence that the
|
|
101
|
+
metadata is unreliable.
|
|
@@ -14,21 +14,62 @@
|
|
|
14
14
|
".claude/hooks/guard-bash.mjs",
|
|
15
15
|
".claude/hooks/gate-stop-dod.mjs",
|
|
16
16
|
".claude/hooks/inject-rules.mjs",
|
|
17
|
+
".claude/hooks/guard-secret-file.mjs",
|
|
18
|
+
".claude/hooks/guard-rulebook.mjs",
|
|
19
|
+
".claude/hooks/lib/edit-input.mjs",
|
|
17
20
|
".claude/skills/pr-ship/SKILL.md",
|
|
18
21
|
".claude/skills/loop/SKILL.md",
|
|
19
22
|
".claude/skills/check-premises/SKILL.md",
|
|
20
23
|
".claude/skills/worktree-task/SKILL.md",
|
|
24
|
+
".agents/skills/new-invariant/SKILL.md",
|
|
25
|
+
".agents/skills/new-invariant/guard-invariant.example.mjs",
|
|
26
|
+
".agents/skills/new-invariant/guard-invariant.example.test.mjs",
|
|
27
|
+
".agents/skills/pr-ship/SKILL.md",
|
|
28
|
+
".agents/skills/loop/SKILL.md",
|
|
29
|
+
".agents/skills/check-premises/SKILL.md",
|
|
30
|
+
".agents/skills/worktree-task/SKILL.md",
|
|
31
|
+
".codex/agents/test-writer.toml",
|
|
32
|
+
".codex/agents/code-reviewer.toml",
|
|
33
|
+
".codex/agents/security-scanner.toml",
|
|
34
|
+
".codex/agents/prose-reviewer.toml",
|
|
21
35
|
".claude/scripts/detect-missed-gate.mjs",
|
|
36
|
+
".claude/scripts/decision-router.mjs",
|
|
22
37
|
".claude/scripts/reconcile-external-prs.mjs",
|
|
23
38
|
".claude/scripts/stop-flag.mjs",
|
|
39
|
+
".claude/scripts/unattended-flag.mjs",
|
|
40
|
+
".claude/scripts/git-env.mjs",
|
|
24
41
|
".claude/scripts/preflight.mjs",
|
|
42
|
+
".claude/scripts/doctor.mjs",
|
|
43
|
+
".claude/scripts/run-journal.mjs",
|
|
44
|
+
".claude/scripts/run-state.mjs",
|
|
45
|
+
".claude/scripts/verdict.mjs",
|
|
46
|
+
".claude/scripts/revalidate.mjs",
|
|
47
|
+
".claude/scripts/revalidation-report.mjs",
|
|
48
|
+
".claude/scripts/lib/gate-coverage.mjs",
|
|
49
|
+
".claude/scripts/lib/revalidation-points.mjs",
|
|
50
|
+
".claude/scripts/lib/verdict.mjs",
|
|
51
|
+
".claude/scripts/lib/secrets.mjs",
|
|
25
52
|
".claude/scripts/queue/core.mjs",
|
|
26
53
|
".claude/scripts/queue/plan-md.mjs",
|
|
27
54
|
".claude/scripts/queue/github-issues.mjs",
|
|
28
55
|
".claude/scripts/queue/jira.mjs",
|
|
29
56
|
".claude/scripts/queue/index.mjs",
|
|
57
|
+
".claude/scripts/queue/as-of.mjs",
|
|
58
|
+
".claude/scripts/queue/checkout.mjs",
|
|
59
|
+
".claude/scripts/queue/state.mjs",
|
|
60
|
+
".claude/scripts/queue/gate-rounds.mjs",
|
|
30
61
|
".claude/queue.json",
|
|
31
|
-
"PLAN.md"
|
|
62
|
+
"PLAN.md",
|
|
63
|
+
"journal/README.md",
|
|
64
|
+
"docs/decisions/gate-coverage.md",
|
|
65
|
+
"docs/decisions/fail-open-guards.md",
|
|
66
|
+
"docs/decisions/codex-adapter.md",
|
|
67
|
+
"docs/decisions/closing-a-task.md",
|
|
68
|
+
"docs/decisions/review-lanes.md",
|
|
69
|
+
"docs/decisions/run-directory.md",
|
|
70
|
+
"docs/decisions/spacing-rations-mechanisms.md",
|
|
71
|
+
"docs/decisions/stop-conditions-in-a-file.md",
|
|
72
|
+
"docs/decisions/two-empty-endings.md"
|
|
32
73
|
],
|
|
33
74
|
"architecture": [
|
|
34
75
|
".claude/rules/architecture.md",
|
|
@@ -37,6 +78,8 @@
|
|
|
37
78
|
],
|
|
38
79
|
"meta": [
|
|
39
80
|
".claude/settings.json",
|
|
40
|
-
"
|
|
81
|
+
".codex/hooks.json",
|
|
82
|
+
"CLAUDE.md",
|
|
83
|
+
"AGENTS.md"
|
|
41
84
|
]
|
|
42
85
|
}
|