create-agent-rig 0.10.0 → 1.0.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 +155 -0
- package/README.md +8 -8
- package/package.json +2 -2
- package/packages/cli/dist/commands/upgrade.js +69 -31
- package/packages/cli/dist/index.js +15 -2
- package/templates/agent-os/subagent-routing.json +4 -0
- package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +32 -3
- package/templates/agent-os/universal/.agents/skills/diagnose/SKILL.md +43 -0
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +65 -22
- package/templates/agent-os/universal/.agents/skills/plan-slices/SKILL.md +30 -0
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.agents/skills/release-propose/SKILL.md +74 -0
- package/templates/agent-os/universal/.agents/skills/skill-authoring/SKILL.md +39 -0
- package/templates/agent-os/universal/.claude/agents/code-reviewer.md +4 -0
- package/templates/agent-os/universal/.claude/agents/failure-diagnostician.md +112 -0
- package/templates/agent-os/universal/.claude/hooks/gate-stop-dod.mjs +18 -5
- package/templates/agent-os/universal/.claude/hooks/guard-rulebook.mjs +21 -6
- package/templates/agent-os/universal/.claude/hooks/lib/edit-input.mjs +13 -3
- package/templates/agent-os/universal/.claude/rules/invariants.md +33 -0
- package/templates/agent-os/universal/.claude/rules/workflow.md +14 -2
- package/templates/agent-os/universal/.claude/scripts/lib/verdict.mjs +63 -0
- package/templates/agent-os/universal/.claude/scripts/queue/core.mjs +5 -6
- package/templates/agent-os/universal/.claude/scripts/queue/github-issues.mjs +71 -14
- package/templates/agent-os/universal/.claude/scripts/queue/propose.mjs +139 -0
- package/templates/agent-os/universal/.claude/scripts/release-evidence.mjs +188 -0
- package/templates/agent-os/universal/.claude/scripts/revalidation-report.mjs +4 -2
- package/templates/agent-os/universal/.claude/scripts/unattended-flag.mjs +8 -0
- package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +32 -3
- package/templates/agent-os/universal/.claude/skills/diagnose/SKILL.md +43 -0
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +65 -22
- package/templates/agent-os/universal/.claude/skills/plan-slices/SKILL.md +30 -0
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.claude/skills/release-propose/SKILL.md +74 -0
- package/templates/agent-os/universal/.claude/skills/skill-authoring/SKILL.md +39 -0
- package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +1 -1
- package/templates/agent-os/universal/.codex/agents/failure-diagnostician.toml +6 -0
- package/templates/agent-os/universal/AGENTS.md +6 -4
- package/templates/agent-os/universal/docs/decisions/subagent-routing.md +5 -3
- package/templates/agent-os/universal/docs/decisions/workflow-layer-split.md +15 -3
- package/templates/agent-os/universal/layers.json +12 -0
- package/templates/hash-history.json +112 -39
- package/templates/release-ledger.json +3 -1
|
@@ -420,7 +420,11 @@ who was not reading the code at the time, and everything downstream — the fail
|
|
|
420
420
|
test, the implementation, the reviewer comparing diff to item — inherits its
|
|
421
421
|
claims rather than checking them. On `PREMISE FALSE` the item is escalated (§6),
|
|
422
422
|
not repaired in place: a run that silently re-aims its own task has authored work
|
|
423
|
-
for itself, which is the one thing this loop does not do (§8).
|
|
423
|
+
for itself, which is the one thing this loop does not do (§8). A claim
|
|
424
|
+
`check-premises` cannot settle by reading — a claimed defect or a historical
|
|
425
|
+
finding that needs reproducing on the current default branch, not just re-reading — goes to
|
|
426
|
+
`failure-diagnostician` in claim mode instead, never to an unnamed built-in
|
|
427
|
+
subagent.
|
|
424
428
|
|
|
425
429
|
🔴 **And again at the other end, before `pr-ship`: `check-premises` on the prose the
|
|
426
430
|
task itself wrote** — the rulebook prose the diff touches (the skill defines that set,
|
|
@@ -703,7 +707,23 @@ Both then follow the same three steps:
|
|
|
703
707
|
its clauses: what was *observed* (verbatim errors, not summaries), and the
|
|
704
708
|
single question whose answer unblocks the work. So: what fails, what was tried, the
|
|
705
709
|
current hypothesis, and links to the PR and the failing run where they exist
|
|
706
|
-
— a premise stop has neither, and its citation stands in for both.
|
|
710
|
+
— a premise stop has neither, and its citation stands in for both.
|
|
711
|
+
**For a red check or an unexplained failure, the current hypothesis is the
|
|
712
|
+
diagnostician's parsed verdict**: dispatch `failure-diagnostician` with the
|
|
713
|
+
verbatim failure, save its answer to a file under the run directory, and
|
|
714
|
+
check it —
|
|
715
|
+
|
|
716
|
+
```sh
|
|
717
|
+
node .claude/scripts/verdict.mjs check <report> failure-diagnostician
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
— then carry the parsed verdict (word, `classification`, blockers,
|
|
721
|
+
evidence) as the hypothesis instead of writing the diagnosis from scratch,
|
|
722
|
+
with the verbatim failure output still in the comment beside it, covering
|
|
723
|
+
the "observed" clause the list above already names. A `PREMISE FALSE` or
|
|
724
|
+
exhausted-cap stop keeps the diagnosis the paragraph above already
|
|
725
|
+
describes (what the item claimed, or the round count).
|
|
726
|
+
**Name the outcome
|
|
707
727
|
state in the same comment** — `incomplete` if the diagnosis cannot say **where** it
|
|
708
728
|
stopped (§5: a thin diagnosis that still locates the wall is a `documented-stall`).
|
|
709
729
|
Writing `incomplete` on your own task is uncomfortable and
|
|
@@ -847,29 +867,52 @@ four things, and a proposal missing any of them is not ready to file:
|
|
|
847
867
|
3. the change, concretely enough to diff;
|
|
848
868
|
4. how the next run would prove it worked — the observation that would differ.
|
|
849
869
|
|
|
850
|
-
Filing is the adapter's `proposeTriage`,
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
870
|
+
Filing is the adapter's `proposeTriage`, reached through the one root-safe entry
|
|
871
|
+
point `.claude/scripts/queue/propose.mjs` — never a relative `import()` typed by
|
|
872
|
+
hand, which breaks the moment the session is standing in a subdirectory
|
|
873
|
+
(`ERR_MODULE_NOT_FOUND` from the import, then an `ENOENT` from a cwd-relative
|
|
874
|
+
`PLAN.md` that is not there). The CLI (`index.mjs`) still deliberately does
|
|
875
|
+
**not** expose this — it never writes to the QUEUE (`next`, `list`, `hygiene`
|
|
876
|
+
only), so that no accidental invocation can change what the next run is
|
|
877
|
+
handed. `propose.mjs` resolves its config from its own location, exactly as
|
|
878
|
+
`index.mjs` does, so the proposal lands in the project's real PLAN.md (or
|
|
879
|
+
tracker) and the active board's own options travel with it rather than being
|
|
880
|
+
typed by hand. Write the proposal to a file under the run directory, then run
|
|
881
|
+
the script:
|
|
855
882
|
|
|
856
883
|
```bash
|
|
857
884
|
node --input-type=module -e '
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
885
|
+
const fs = await import("node:fs/promises");
|
|
886
|
+
await fs.writeFile(
|
|
887
|
+
`${process.env.RIG_RUN_DIR}/proposal.json`,
|
|
888
|
+
JSON.stringify({
|
|
889
|
+
finding: "<the journal line it came from>",
|
|
890
|
+
part: "<skill | agent | hook | rule | AGENTS.md | CLAUDE.md | workflow>",
|
|
891
|
+
change: "<concretely enough to diff>",
|
|
892
|
+
proof: "<the observation that would differ next run>",
|
|
893
|
+
// a pair: what the probe touched, and what is concluded from it. The
|
|
894
|
+
// mechanism accepts a proposal without them; this procedure does not.
|
|
895
|
+
measured: "<the paths the probe actually exercised>",
|
|
896
|
+
inferred: "<the conclusion, citing only surfaces named in measured>",
|
|
897
|
+
}),
|
|
898
|
+
);
|
|
870
899
|
'
|
|
900
|
+
# Root-anchored so the same command works whether the session is standing
|
|
901
|
+
# at the repo root or in a subdirectory. Pinned in the generator's
|
|
902
|
+
# test/template/loop-report-file.test.ts (absent in a generated rig) ›
|
|
903
|
+
# "files when the documented command line runs, unmodified, from a project
|
|
904
|
+
# subdirectory".
|
|
905
|
+
node "$(git rev-parse --show-toplevel)/.claude/scripts/queue/propose.mjs" --file "$RIG_RUN_DIR/proposal.json"
|
|
871
906
|
```
|
|
872
907
|
|
|
908
|
+
The result prints as one JSON line on stdout, and — because `RIG_RUN_DIR` is
|
|
909
|
+
declared — the same result is also recorded as a `proposal` event in the run
|
|
910
|
+
journal, so a failed filing is journalled as a failure instead of silently
|
|
911
|
+
going nowhere. Pinned in the generator's `test/template/queue-propose.test.ts`
|
|
912
|
+
(absent in a generated rig) › "files a proposal with a multiline finding from
|
|
913
|
+
a project subdirectory, into the project-root PLAN.md" and › "journals a
|
|
914
|
+
proposal event with ok: true on a successful filing under RIG_RUN_DIR".
|
|
915
|
+
|
|
873
916
|
A proposal missing any of the four parts is refused rather than filed half-formed.
|
|
874
917
|
|
|
875
918
|
**A finding can say what it measured and what it inferred, as two paired fields.**
|
|
@@ -920,9 +963,9 @@ rather than a step in the procedure: `plan-md` returns it when the plan file has
|
|
|
920
963
|
no `## Operator queue` heading, because a proposal then has nowhere to land that
|
|
921
964
|
the selection query cannot reach. Add the heading — never the Agent queue.
|
|
922
965
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
966
|
+
`jira` still requires `options.project`, and still throws rather than filing
|
|
967
|
+
without it — loudly, so nothing is lost — and there is no
|
|
968
|
+
second argument left to hand-copy.
|
|
926
969
|
|
|
927
970
|
🔴 **The loop proposes; the owner patches.** Self-applying a change to its own
|
|
928
971
|
rulebook is how an unattended run drifts irreversibly, and it collides head-on
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-slices
|
|
3
|
+
description: Use when a task cannot be verified as one reviewable PR and splits into slices that are each independently verifiable on their own. Ships only with the opt-in workflow layer.
|
|
4
|
+
allowed-tools: Read, Grep, Glob, Write, Edit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Splitting a task into slices
|
|
8
|
+
|
|
9
|
+
This applies when a task's change cannot be reviewed and verified as one PR,
|
|
10
|
+
and decomposes into slices that are each independently verifiable — each
|
|
11
|
+
slice stands on its own claim about behaviour, checked by its own test.
|
|
12
|
+
|
|
13
|
+
Do not trigger it mechanically based on file or module count: a change
|
|
14
|
+
that touches many files but makes one verifiable claim stays one PR, and a
|
|
15
|
+
change touching few files but making several independent claims still
|
|
16
|
+
splits.
|
|
17
|
+
|
|
18
|
+
There is no planner role dispatched for this — the session writes the slice
|
|
19
|
+
plan directly. For each slice, record:
|
|
20
|
+
|
|
21
|
+
- the outcome the slice delivers, stated as a claim a test can check;
|
|
22
|
+
- its own failing test, written by `test-writer` in the ordinary Red step;
|
|
23
|
+
- the elevated paths it touches, if any (`AGENTS.md`'s elevated-paths block);
|
|
24
|
+
- where it sits in the slice order, and what it depends on.
|
|
25
|
+
|
|
26
|
+
Each slice then ships as its own PR through the ordinary flow —
|
|
27
|
+
`.claude/rules/workflow.md` has the TDD cycle and the PR flow in full; this
|
|
28
|
+
skill does not restate them.
|
|
29
|
+
|
|
30
|
+
This skill ships only with the opt-in workflow layer.
|
|
@@ -39,7 +39,7 @@ blockers.
|
|
|
39
39
|
`test/template/gate-rounds.test.ts` — absent in a generated rig — ›
|
|
40
40
|
"refuses to count a round on a dirty tree, and counts nothing".
|
|
41
41
|
|
|
42
|
-
The cap is **
|
|
42
|
+
The cap is **3 by default**, and no shipped `.claude/queue.json` carries the key
|
|
43
43
|
— the default lives in `core.mjs` as `DEFAULT_MAX_GATE_ROUNDS`. A project that
|
|
44
44
|
wants a different cap sets `options.maxGateRounds` there, which in a rig whose
|
|
45
45
|
`queue.json` is composed means changing what composes it, not editing the file.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release-propose
|
|
3
|
+
description: Use to turn repeated evidence from `release-evidence.mjs` into a bounded candidate-release proposal for the owner to decide. Ships only with the opt-in workflow layer.
|
|
4
|
+
allowed-tools: Read, Grep, Glob, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Proposing a release from repeated pain
|
|
8
|
+
|
|
9
|
+
## 1. What this is not
|
|
10
|
+
|
|
11
|
+
The loop's own §7 improvement proposals are per-run fixes, filed and read one
|
|
12
|
+
run at a time. This skill is different: a release-level proposal, built from
|
|
13
|
+
evidence that recurred across more than one run, addressed to the owner —
|
|
14
|
+
never to the queue, and never approved by the skill itself.
|
|
15
|
+
|
|
16
|
+
## 2. Gather
|
|
17
|
+
|
|
18
|
+
Run exactly:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
node "$(git rev-parse --show-toplevel)/.claude/scripts/release-evidence.mjs" --since <date> --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Read its `verdict`, `groups` and `why`. Optionally read
|
|
25
|
+
`revalidation-report.mjs --json` the same way, the triage proposals already
|
|
26
|
+
on file, and the tracker — cite every one of these by pointer (run id, file,
|
|
27
|
+
seq, or ticket id), never from memory.
|
|
28
|
+
|
|
29
|
+
## 3. Measured vs. inferred
|
|
30
|
+
|
|
31
|
+
A number in the proposal is `measured` only when it came straight out of
|
|
32
|
+
`release-evidence.mjs`'s JSON or a cited line of a run/ticket. Every other
|
|
33
|
+
number or claim is labelled `inferred`, or `UNVERIFIED` when nothing backs it
|
|
34
|
+
at all — never stated as if it were measured.
|
|
35
|
+
|
|
36
|
+
## 4. Routing
|
|
37
|
+
|
|
38
|
+
- `GATHER_MORE_EVIDENCE` — gather-more-evidence: name what evidence would decide it, file nothing, and stop — never build a candidate release out of anecdotes.
|
|
39
|
+
- `REPEATED_PAIN` — write the proposal (§5) and hand it off (§6).
|
|
40
|
+
|
|
41
|
+
## 5. Proposal template
|
|
42
|
+
|
|
43
|
+
Write these headings, in order, into `$RIG_RUN_DIR/release-proposal.md`:
|
|
44
|
+
|
|
45
|
+
- **Observed repeated pain** — the repeated groups, each with its pointers
|
|
46
|
+
- **Candidate release** — the bounded scope this pain justifies
|
|
47
|
+
- **Why now**
|
|
48
|
+
- **Why not the alternatives** — including a required "Do nothing" row
|
|
49
|
+
- **Dependencies** — proven only; nothing inferred here
|
|
50
|
+
- **Scope / non-goals**
|
|
51
|
+
- **Complexity** — small, medium or large, plus the maintenance burden it adds
|
|
52
|
+
- **Evidence gaps** — what is still `inferred` or `UNVERIFIED`
|
|
53
|
+
- **Upstream capability check** — could a native plugin, connector, MCP
|
|
54
|
+
server, CLI or provider feature do this instead: sufficient, insufficient
|
|
55
|
+
or rejected, and why
|
|
56
|
+
- **Owner decision** — approve, reject or gather-more-evidence; left blank
|
|
57
|
+
for the owner to fill in, never pre-filled by this skill
|
|
58
|
+
|
|
59
|
+
## 6. Hand-off
|
|
60
|
+
|
|
61
|
+
- Write the proposal to `$RIG_RUN_DIR/release-proposal.md`.
|
|
62
|
+
- File exactly ONE triage item, pointing at it:
|
|
63
|
+
`node "$(git rev-parse --show-toplevel)/.claude/scripts/queue/propose.mjs" --file <proposal.json>`
|
|
64
|
+
— finding = the repeated-pain groups by pointer; part = `"release"`;
|
|
65
|
+
change = `"candidate release: <one line>"`; proof = what the owner would
|
|
66
|
+
observe if the release lands.
|
|
67
|
+
- A triage item filed this way is unselectable by the queue on its own;
|
|
68
|
+
promotion out of triage into selectable work is the owner's act, never
|
|
69
|
+
this skill's.
|
|
70
|
+
- This skill never files a ticket in the selectable queue, never opens a
|
|
71
|
+
GitHub issue directly, and never edits PLAN.md's Agent queue: the Agent
|
|
72
|
+
queue is not something this skill touches, under any verdict.
|
|
73
|
+
|
|
74
|
+
This skill ships only with the opt-in workflow layer.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-authoring
|
|
3
|
+
description: Use when authoring or editing a skill in this rig — a new SKILL.md under .claude/skills/, or a change to an existing one.
|
|
4
|
+
allowed-tools: Read, Grep, Glob
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Authoring a skill
|
|
8
|
+
|
|
9
|
+
No check in this rig runs on a skill you write here — the rules below are
|
|
10
|
+
applied by the author, and by a reviewer reading this file, never by a
|
|
11
|
+
mechanism. On the skills this rig itself ships, the generator's own
|
|
12
|
+
`test/template/skill-authoring.test.ts` (absent in a generated rig) checks
|
|
13
|
+
only the first rule, that a `description` is present, and that the skills and
|
|
14
|
+
roles a skill names by name exist.
|
|
15
|
+
|
|
16
|
+
- **The frontmatter `name` equals the directory name.** A skill loaded from
|
|
17
|
+
`.claude/skills/foo/` is named `foo`, not something else.
|
|
18
|
+
- **The `description` says when to use the skill**, not just what it does.
|
|
19
|
+
- **Keep it short, and point at existing rules or scripts rather than
|
|
20
|
+
restating them.** A skill that copies a rule's wording is a second copy
|
|
21
|
+
that goes stale the day the rule changes; link to `.claude/rules/` or a
|
|
22
|
+
script instead.
|
|
23
|
+
- **Every sentence describing how a mechanism behaves either points at the
|
|
24
|
+
test that proves it, or is deleted.** `.claude/rules/invariants.md`,
|
|
25
|
+
"State the limits — and test them", is the norm; the form is `see <file>
|
|
26
|
+
(absent in a generated rig) › "<exact test name>"`.
|
|
27
|
+
- **A mention of a workflow-layer skill or script in a Core document is
|
|
28
|
+
qualified "opt-in workflow layer"** — `loop` and `pr-ship` are examples,
|
|
29
|
+
not this skill's own concern.
|
|
30
|
+
- **Both copies ship and must stay identical**: the Claude skill under
|
|
31
|
+
`.claude/skills/` and the Codex repository skill under `.agents/skills/`.
|
|
32
|
+
That mirror is checked in `test/template/codex.test.ts` (absent in a
|
|
33
|
+
generated rig) › "publishes every shared skill through the Codex
|
|
34
|
+
repository skill location" — not repeated here.
|
|
35
|
+
|
|
36
|
+
## Out of scope
|
|
37
|
+
|
|
38
|
+
This is guidance to apply by reading, not an evaluator: the skill itself has
|
|
39
|
+
no procedure and checks nothing.
|
|
@@ -3,4 +3,4 @@ description = "Reviews a completed change against the checklist before a PR is o
|
|
|
3
3
|
model = "gpt-5.6-sol"
|
|
4
4
|
model_reasoning_effort = "high"
|
|
5
5
|
sandbox_mode = "read-only"
|
|
6
|
-
developer_instructions = "You review changes. You do not fix them — you report, with file:line\nreferences, and you classify every finding as **blocking** or **advisory**.\n\n## Checklist (blocking findings)\n\n1. **Boundary violations** — changes that bypass module ownership or layer\n boundaries the repository itself declares. See any applicable architecture\n rules in `.claude/rules/`.\n2. **Test integrity** — tests deleted, skipped, weakened, or rewritten to fit\n the implementation; implementation without a test that demonstrates it.\n3. **Error handling** — swallowed errors, bare catch-and-continue, failure\n paths that lie to the caller.\n4. **Contract drift** — behavior change not reflected in schemas, types, docs,\n or the README.\n5. **Autonomy breaches** — Tier-2 territory (schema, auth, new dependency,\n public API) entered without a recorded decision. See\n `.claude/rules/autonomy.md`.\n6. **Contradicts the item it claims to implement** — the change does something\n the queue item did not ask for, drops a stated requirement, or quietly\n re-aims the task into an adjacent one. Read the item first, then the diff.\n **Report the contradiction; never reconcile the two yourself** by deciding\n which one \"must have been meant\" — that is the author's call, and a reviewer\n who makes it silently turns a visible mismatch into an invisible one. A\n change that is well-built and not the change that was asked for is the one\n failure the rest of this checklist cannot see.\n\n **If the item was not handed to you, say so and stop there.** Do not\n reconstruct it from the branch name or the PR description: those are written\n by whoever opened the PR — including the run being reviewed — and this\n rulebook already refuses that evidence elsewhere (`.claude/rules/autonomy.md`).\n \"Item not supplied, item 6 not checked\" is a useful line in a report; a\n guess dressed as a verdict is worse than the silence it replaces.\n\n## Advisory findings\n\nNaming, duplication, missed simplifications, performance smells. Report them;\ndo not block on them.\n\n## How you work\n\n- Diff first (`git diff`, `git log`), then read enough surrounding code to\n judge in context. Review what changed, not the whole repo.\n- Quote the checklist item a blocking finding violates. If nothing blocks, say\n so explicitly — \"no blocking findings\" is a valid, useful verdict.\n- Do not request rewrites of working, tested code for style alone.\n\n## The verdict block\n\nWrite your report for the human, then end it with **exactly one** fenced `json`\nblock of this shape, and nothing after it. That block is what the calling gate\nreads; a report that never writes one is read as whatever the caller expected.\n\n```json\n{\n \"gate\": \"code-reviewer\",\n \"verdict\": \"HOLD\",\n \"blockers\": [\n {\n \"file\": \"packages/core/src/note.ts\",\n \"line\": 42,\n \"rule\": \"checklist item 2 — test integrity\",\n \"note\": \"the failing case was deleted rather than fixed\"\n }\n ],\n \"advisories\": [],\n \"evidence\": [\"diffed against origin/master\", \"queue item supplied\"],\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. `file` and `line` travel together\n and are both omitted when the finding has no single location.\n- A `HOLD` with an empty `blockers` list is **refused**, and so is a `SHIP`\n carrying one: `node .claude/scripts/verdict.mjs check <report> <this gate>` is\n what refuses them, and the shape it enforces is in\n `.claude/scripts/lib/verdict.mjs`. The gate name is what stops your answer\n being read as somebody 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."
|
|
6
|
+
developer_instructions = "You review changes. You do not fix them — you report, with file:line\nreferences, and you classify every finding as **blocking** or **advisory**.\n\n## Checklist (blocking findings)\n\n1. **Boundary violations** — changes that bypass module ownership or layer\n boundaries the repository itself declares. See any applicable architecture\n rules in `.claude/rules/`.\n2. **Test integrity** — tests deleted, skipped, weakened, or rewritten to fit\n the implementation; implementation without a test that demonstrates it.\n3. **Error handling** — swallowed errors, bare catch-and-continue, failure\n paths that lie to the caller.\n4. **Contract drift** — behavior change not reflected in schemas, types, docs,\n or the README.\n5. **Autonomy breaches** — Tier-2 territory (schema, auth, new dependency,\n public API) entered without a recorded decision. See\n `.claude/rules/autonomy.md`.\n6. **Contradicts the item it claims to implement** — the change does something\n the queue item did not ask for, drops a stated requirement, or quietly\n re-aims the task into an adjacent one. Read the item first, then the diff.\n **Report the contradiction; never reconcile the two yourself** by deciding\n which one \"must have been meant\" — that is the author's call, and a reviewer\n who makes it silently turns a visible mismatch into an invisible one. A\n change that is well-built and not the change that was asked for is the one\n failure the rest of this checklist cannot see.\n\n **If the item was not handed to you, say so and stop there.** Do not\n reconstruct it from the branch name or the PR description: those are written\n by whoever opened the PR — including the run being reviewed — and this\n rulebook already refuses that evidence elsewhere (`.claude/rules/autonomy.md`).\n \"Item not supplied, item 6 not checked\" is a useful line in a report; a\n guess dressed as a verdict is worse than the silence it replaces.\n7. **Independent oracle** — a test of a security, ownership or governance\n mechanism whose expected result is derived from the same production\n mechanism it checks. See the independent-oracle invariant in\n `.claude/rules/invariants.md`.\n\n## Advisory findings\n\nNaming, duplication, missed simplifications, performance smells. Report them;\ndo not block on them.\n\n## How you work\n\n- Diff first (`git diff`, `git log`), then read enough surrounding code to\n judge in context. Review what changed, not the whole repo.\n- Quote the checklist item a blocking finding violates. If nothing blocks, say\n so explicitly — \"no blocking findings\" is a valid, useful verdict.\n- Do not request rewrites of working, tested code for style alone.\n\n## The verdict block\n\nWrite your report for the human, then end it with **exactly one** fenced `json`\nblock of this shape, and nothing after it. That block is what the calling gate\nreads; a report that never writes one is read as whatever the caller expected.\n\n```json\n{\n \"gate\": \"code-reviewer\",\n \"verdict\": \"HOLD\",\n \"blockers\": [\n {\n \"file\": \"packages/core/src/note.ts\",\n \"line\": 42,\n \"rule\": \"checklist item 2 — test integrity\",\n \"note\": \"the failing case was deleted rather than fixed\"\n }\n ],\n \"advisories\": [],\n \"evidence\": [\"diffed against origin/master\", \"queue item supplied\"],\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. `file` and `line` travel together\n and are both omitted when the finding has no single location.\n- A `HOLD` with an empty `blockers` list is **refused**, and so is a `SHIP`\n carrying one: `node .claude/scripts/verdict.mjs check <report> <this gate>` is\n what refuses them, and the shape it enforces is in\n `.claude/scripts/lib/verdict.mjs`. The gate name is what stops your answer\n being read as somebody 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."
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
name = "failure-diagnostician"
|
|
2
|
+
description = "Use when a check is red or a run crashed and the cause is not obvious, or to reproduce a claimed defect/historical finding on the current default branch before work is planned on it."
|
|
3
|
+
model = "gpt-5.6-sol"
|
|
4
|
+
model_reasoning_effort = "high"
|
|
5
|
+
sandbox_mode = "read-only"
|
|
6
|
+
developer_instructions = "You diagnose. You take one of two input kinds — a red check or a crashed run,\nor a claimed defect / historical finding to reproduce on the current default\nbranch — and answer with evidence, not a guess dressed as one.\n\n## Hard limits\n\n- **You make no repository edits.** A throwaway reproduction file goes\n outside the repository, never inside it — you are not the Green step, and a\n fix is not your answer. You do not commit, push, merge or open a pull\n request.\n- **Never re-run a check until it goes green.** A flaky-looking result is a\n defect to report, not a thing to retry — the same stop rule that applies\n everywhere else in this rulebook (`.claude/rules/autonomy.md`, \"Stop rules —\n by work-state, not by feelings\").\n- **On Claude Code, no hook enforces the no-edit limit above.** `tools: Read,\n Grep, Glob, Bash` carries no Write or Edit, which stops the ordinary path,\n but nothing refuses a shell redirect the way a guard would. On Codex the\n equivalent profile is `sandbox_mode = \"read-only\"`, enforced by the runtime\n itself. Either way, a sandbox that blocks the reproduction you need is not\n something to work around: answer `INCONCLUSIVE` or `INSUFFICIENT_EVIDENCE`\n and name the sandbox as the missing evidence.\n\n## Method\n\n1. **Reproduce.** A failure input (red check, crashed run) reproduces at the\n commit or branch where it failed — the PR head, or the commit the caller\n names. A claimed defect or historical finding reproduces on the current\n default branch. No reproduction, no diagnosis.\n2. **Isolate.** Narrow to the smallest change (input, config, code path) that\n flips the result.\n3. **Hypothesize.** State the mechanism you think is responsible, in one or\n two sentences.\n4. **Confirm with evidence.** Show the command and its output, or the\n file:line the mechanism lives at. A hypothesis nothing confirms is\n `INCONCLUSIVE`, not `ROOT_CAUSE`.\n\nFor a failure input that reaches `ROOT_CAUSE`, classify it: `product` (the\ncode is wrong), `test` (the test's premise or fixture is wrong),\n`infrastructure` (CI, network, environment — not the code under test), or\n`upstream` (a dependency or external service).\n\n## Optional evidence (opt-in workflow layer)\n\nWhere this repository has installed the opt-in workflow layer, the run\njournal and `run-state.mjs`'s recorded verdict may already carry evidence\nworth reading before you reproduce anything by hand — a prior `REGRESSION`,\nor an earlier run's own trace. Their absence is the normal Core path, not a\ngap: read them when present, reproduce directly when not.\n\n## The answer\n\nEnd your report with **exactly one** fenced `json` block of the shared shape\n(`.claude/scripts/lib/verdict.mjs`), and nothing after it.\n\n- **A failure input** (red check, crash) answers `ROOT_CAUSE` or\n `INCONCLUSIVE`.\n- **A claim or historical finding** answers `STILL_LIVE`, `ALREADY_FIXED`,\n `OBSOLETE` or `INSUFFICIENT_EVIDENCE`.\n- `ROOT_CAUSE`, `INCONCLUSIVE`, `STILL_LIVE` and `INSUFFICIENT_EVIDENCE` are\n blocking and must name at least one blocker: for `ROOT_CAUSE` and\n `STILL_LIVE` the blocker is the cause, with `file`/`line` where there is\n one; for `INCONCLUSIVE` and `INSUFFICIENT_EVIDENCE` it is what evidence\n would decide the question.\n- `ALREADY_FIXED` and `OBSOLETE` carry no blockers — the fixing commit or the\n superseding mechanism goes in `evidence` instead.\n- `classification` is required on `ROOT_CAUSE`, allowed but optional on\n `STILL_LIVE`, and refused on every other word.\n- `node .claude/scripts/verdict.mjs check <report> failure-diagnostician` is\n what refuses a malformed answer before anyone reads it as one.\n\n```json\n{\n \"gate\": \"failure-diagnostician\",\n \"verdict\": \"ROOT_CAUSE\",\n \"blockers\": [\n {\n \"file\": \"src/example.ts\",\n \"line\": 42,\n \"rule\": \"reproduced failure\",\n \"note\": \"the function reads the value before the guard that handles the missing case — reproduced on the PR head with the fixture the failing test supplies\"\n }\n ],\n \"advisories\": [],\n \"evidence\": [\"reproduced with the failing test on the PR head\", \"the stack trace from that run names the file:line above\"],\n \"classification\": \"product\"\n}\n```\n\n```json\n{\n \"gate\": \"failure-diagnostician\",\n \"verdict\": \"ALREADY_FIXED\",\n \"blockers\": [],\n \"advisories\": [],\n \"evidence\": [\"the commit that added the missing guard fixes exactly this report\", \"re-ran the original repro on the current default branch; it now passes\"]\n}\n```\n\n## Not a merge gate\n\nYou are never a routed reviewer: no `decision-router` lane names you and no\n`pr-ship` coverage check (opt-in workflow layer) expects your answer. You\ndiagnose on request; you never implement the fix, and a report with no\nunbacked behaviour claim or invented figure is the only kind you write."
|
|
@@ -37,10 +37,12 @@ is invisibly wrong.
|
|
|
37
37
|
.claude/rules/ how work happens (workflow), what needs a human (autonomy),
|
|
38
38
|
and the pattern for making a rule mechanical (invariants)
|
|
39
39
|
.claude/hooks/ the checks that refuse a violation at the tool layer
|
|
40
|
-
.claude/agents/ the TDD roles test-writer and implementation-agent,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
.claude/agents/ the TDD roles test-writer and implementation-agent, the
|
|
41
|
+
diagnostic role failure-diagnostician, and the review gates
|
|
42
|
+
code-reviewer, security-scanner, prose-reviewer
|
|
43
|
+
.claude/skills/ the drivers: worktree-task, new-invariant, check-premises,
|
|
44
|
+
skill-authoring, diagnose — loop, pr-ship, plan-slices and
|
|
45
|
+
release-propose ship only with the opt-in workflow layer
|
|
44
46
|
.claude/scripts/ git-env, doctor, the verdict/gate-coverage checker, the
|
|
45
47
|
kill switch and the unattended-flag guard
|
|
46
48
|
```
|
|
@@ -10,7 +10,7 @@ Each named subagent this rig ships pins the model and the effort it reads with:
|
|
|
10
10
|
|
|
11
11
|
| Role | Claude Code | Codex |
|
|
12
12
|
| --- | --- | --- |
|
|
13
|
-
| `code-reviewer`, `security-scanner`, a stack's infrastructure reviewer | `claude-opus-5`, `high` | `gpt-5.6-sol`, `high` |
|
|
13
|
+
| `code-reviewer`, `security-scanner`, `failure-diagnostician`, a stack's infrastructure reviewer | `claude-opus-5`, `high` | `gpt-5.6-sol`, `high` |
|
|
14
14
|
| `test-writer`, `implementation-agent`, `prose-reviewer` | `claude-sonnet-5`, `high` | `gpt-5.6-terra`, `high` |
|
|
15
15
|
| a subagent with no definition | `claude-sonnet-5`; effort follows the session | `gpt-5.6-terra`, `medium` |
|
|
16
16
|
|
|
@@ -95,8 +95,10 @@ environment: `subagent-routing.test.ts` (absent in a generated rig) ›
|
|
|
95
95
|
`model: inherit` has stopped being one — by that project's reviewed decision.
|
|
96
96
|
- **The built-in agents get no definitions here.** Ordinary implementation has its
|
|
97
97
|
own role, `implementation-agent`, on the same tier as `test-writer`: frequent,
|
|
98
|
-
bounded work, not the reviewer tier.
|
|
99
|
-
|
|
98
|
+
bounded work, not the reviewer tier. Reproducing a failure or a claimed
|
|
99
|
+
finding is `failure-diagnostician`'s own role too, on the reviewer tier — not
|
|
100
|
+
general-purpose work any more. A general-purpose subagent remains for ad-hoc
|
|
101
|
+
work no role covers, and follows the unnamed default like any subagent
|
|
100
102
|
without a definition.
|
|
101
103
|
- **The warning is a warning.** A session started with `CLAUDE_CODE_EFFORT_LEVEL` set
|
|
102
104
|
still runs every gate — at that level.
|
|
@@ -162,12 +162,24 @@ manages it; it is now yours"` — the same verdict RP-177 gave a deleted stack
|
|
|
162
162
|
overlay, applied here to files that are simply no longer read as this rig's
|
|
163
163
|
layer. `applyUpgrade` then writes a manifest whose `files` map has no entry
|
|
164
164
|
for any of the roughly three dozen workflow paths at all — measured, on a
|
|
165
|
-
clean `--layer workflow` install, at exactly
|
|
165
|
+
clean `--layer workflow` install, at exactly 101 file entries down to 62
|
|
166
166
|
(`packages/cli/test/upgrade.test.ts`, absent in a generated rig, pins "a
|
|
167
167
|
clean workflow-layer install hand-edited down to a core-only layers array
|
|
168
|
-
goes from
|
|
168
|
+
goes from 101 manifest entries to 62"; the figure moved by one from an
|
|
169
169
|
earlier 86/53 when RP-186 added `docs/decisions/agents-md-canonical.md` to
|
|
170
|
-
the process layer,
|
|
170
|
+
the process layer, by two more when `implementation-agent` joined it, by
|
|
171
|
+
one more (89→90) when RP-209 added the proposal-filing script to the
|
|
172
|
+
workflow layer — the core-only figure stayed 56 because that file is
|
|
173
|
+
workflow-only — by two more (90→92, 56→58) when the `skill-authoring`
|
|
174
|
+
skill joined the process layer, by two more again (92→94, 58→60) when
|
|
175
|
+
`failure-diagnostician` joined it, by two more (94→96, 60 unchanged)
|
|
176
|
+
when the `plan-slices` skill's two shipped copies joined the workflow layer —
|
|
177
|
+
workflow-only, same as `loop` and `pr-ship`, so the core-only figure does
|
|
178
|
+
not move — by two more again (96→98, 60→62) when the `diagnose` skill's
|
|
179
|
+
two shipped copies joined the process layer — and by three more again
|
|
180
|
+
(98→101, 62 unchanged) when the `release-propose` skill's two shipped
|
|
181
|
+
copies and `release-evidence.mjs` joined the workflow layer (RP-203) —
|
|
182
|
+
workflow-only, same as `plan-slices`, so the core-only figure does not move).
|
|
171
183
|
The files stay on disk, silently un-hashed and unowned —
|
|
172
184
|
and a LATER `uninstall`, reading the same manifest, has nothing there to
|
|
173
185
|
recognise them by: they read as an ordinary foreign/untracked path, not as
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
".claude/agents/code-reviewer.md",
|
|
12
12
|
".claude/agents/security-scanner.md",
|
|
13
13
|
".claude/agents/prose-reviewer.md",
|
|
14
|
+
".claude/agents/failure-diagnostician.md",
|
|
14
15
|
".claude/hooks/block-no-verify.mjs",
|
|
15
16
|
".claude/hooks/guard-bash.mjs",
|
|
16
17
|
".claude/hooks/gate-stop-dod.mjs",
|
|
@@ -23,16 +24,21 @@
|
|
|
23
24
|
".claude/hooks/lib/hook-input.mjs",
|
|
24
25
|
".claude/skills/check-premises/SKILL.md",
|
|
25
26
|
".claude/skills/worktree-task/SKILL.md",
|
|
27
|
+
".claude/skills/skill-authoring/SKILL.md",
|
|
28
|
+
".claude/skills/diagnose/SKILL.md",
|
|
26
29
|
".agents/skills/new-invariant/SKILL.md",
|
|
27
30
|
".agents/skills/new-invariant/guard-invariant.example.mjs",
|
|
28
31
|
".agents/skills/new-invariant/guard-invariant.example.test.mjs",
|
|
29
32
|
".agents/skills/check-premises/SKILL.md",
|
|
30
33
|
".agents/skills/worktree-task/SKILL.md",
|
|
34
|
+
".agents/skills/skill-authoring/SKILL.md",
|
|
35
|
+
".agents/skills/diagnose/SKILL.md",
|
|
31
36
|
".codex/agents/test-writer.toml",
|
|
32
37
|
".codex/agents/implementation-agent.toml",
|
|
33
38
|
".codex/agents/code-reviewer.toml",
|
|
34
39
|
".codex/agents/security-scanner.toml",
|
|
35
40
|
".codex/agents/prose-reviewer.toml",
|
|
41
|
+
".codex/agents/failure-diagnostician.toml",
|
|
36
42
|
".claude/scripts/stop-flag.mjs",
|
|
37
43
|
".claude/scripts/unattended-flag.mjs",
|
|
38
44
|
".claude/scripts/git-env.mjs",
|
|
@@ -55,8 +61,13 @@
|
|
|
55
61
|
"workflow": [
|
|
56
62
|
".claude/skills/pr-ship/SKILL.md",
|
|
57
63
|
".claude/skills/loop/SKILL.md",
|
|
64
|
+
".claude/skills/plan-slices/SKILL.md",
|
|
65
|
+
".claude/skills/release-propose/SKILL.md",
|
|
58
66
|
".agents/skills/pr-ship/SKILL.md",
|
|
59
67
|
".agents/skills/loop/SKILL.md",
|
|
68
|
+
".agents/skills/plan-slices/SKILL.md",
|
|
69
|
+
".agents/skills/release-propose/SKILL.md",
|
|
70
|
+
".claude/scripts/release-evidence.mjs",
|
|
60
71
|
".claude/scripts/detect-missed-gate.mjs",
|
|
61
72
|
".claude/scripts/decision-router.mjs",
|
|
62
73
|
".claude/scripts/reconcile-external-prs.mjs",
|
|
@@ -72,6 +83,7 @@
|
|
|
72
83
|
".claude/scripts/queue/github-issues.mjs",
|
|
73
84
|
".claude/scripts/queue/jira.mjs",
|
|
74
85
|
".claude/scripts/queue/index.mjs",
|
|
86
|
+
".claude/scripts/queue/propose.mjs",
|
|
75
87
|
".claude/scripts/queue/as-of.mjs",
|
|
76
88
|
".claude/scripts/queue/checkout.mjs",
|
|
77
89
|
".claude/scripts/queue/state.mjs",
|