ruvnet-brain 4.3.21 → 4.3.26
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/README.md +5 -5
- package/bin/install.mjs +275 -60
- package/console/app.js +189 -9
- package/console/index.html +70 -24
- package/console/scope.css +137 -0
- package/console/scope.html +144 -0
- package/console/scope.js +209 -0
- package/console/style.css +26 -0
- package/console/tips.html +1 -0
- package/kb/corpus-release-identity.mjs +239 -0
- package/kb/update-storage-transaction.mjs +20 -3
- package/package.json +9 -2
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/commands/checkpoint.md +61 -0
- package/plugin/hooks/codex-hooks.json +64 -1
- package/plugin/hooks/hook-contracts.json +299 -6
- package/plugin/hooks/hooks.json +81 -1
- package/plugin/mcp/server.mjs +23 -0
- package/plugin/scripts/advocacy-catalog.mjs +245 -0
- package/plugin/scripts/advocacy-route.mjs +460 -0
- package/plugin/scripts/continuation-gate.mjs +25 -2
- package/plugin/scripts/continuation-objective.mjs +7 -1
- package/plugin/scripts/continuity-hook-policy.mjs +190 -15
- package/plugin/scripts/coverage-integrity.mjs +7 -0
- package/plugin/scripts/gates.mjs +113 -10
- package/plugin/scripts/grounding-turn-gate.mjs +167 -0
- package/plugin/scripts/grounding-turn-mark.mjs +91 -0
- package/plugin/scripts/hook-shim.mjs +14 -0
- package/plugin/scripts/nightly-scheduler.mjs +37 -4
- package/plugin/scripts/project-progression-checkpoint.mjs +145 -0
- package/plugin/scripts/project-progression-contract.mjs +16 -0
- package/plugin/scripts/project-progression-hook.mjs +3 -0
- package/plugin/scripts/project-progression-producer.mjs +252 -0
- package/plugin/scripts/project-progression-reader.mjs +271 -0
- package/plugin/scripts/project-progression-session-start.mjs +93 -16
- package/plugin/scripts/project-progression-sources.mjs +220 -0
- package/plugin/scripts/project-progression-store.mjs +106 -13
- package/plugin/scripts/ruvnet-gate1-pattern.mjs +29 -0
- package/plugin/scripts/session-snapshot-hook.mjs +115 -7
- package/plugin/scripts/session-start-budget.mjs +59 -0
- package/plugin/scripts/session-start-core.mjs +234 -457
- package/plugin/scripts/session-start-fsutil.mjs +61 -0
- package/plugin/scripts/session-start-health.mjs +64 -0
- package/plugin/scripts/session-start-hook-description.mjs +45 -0
- package/plugin/scripts/session-start-issue-alert.mjs +77 -0
- package/plugin/scripts/session-start-repo-identity.mjs +54 -0
- package/plugin/scripts/session-start-signals.mjs +73 -0
- package/plugin/scripts/session-start-trace.mjs +86 -0
- package/plugin/scripts/session-start-update-plane.mjs +104 -0
- package/plugin/scripts/unprompted-runtime.mjs +32 -2
- package/plugin/skills/ruvnet-brain/PLAYBOOK.md +26 -2
- package/plugin/skills/ruvnet-brain/SKILL.md +67 -2
- package/scripts/adr-072-completion.mjs +1 -1
- package/scripts/agentdb-fleet-doctor.mjs +5 -1
- package/scripts/approved-runtime.mjs +197 -0
- package/scripts/brain-novice-50.mjs +16 -1
- package/scripts/brain-score.mjs +23 -5
- package/scripts/build-bundle.mjs +971 -530
- package/scripts/build-concepts.mjs +36 -116
- package/scripts/console-engine.test.mjs +8 -7
- package/scripts/console-runtime-identity.mjs +4 -0
- package/scripts/corpus-aggregates.mjs +94 -77
- package/scripts/corpus-candidate.mjs +475 -222
- package/scripts/corpus-next-seed.mjs +225 -0
- package/scripts/corpus-promotion.mjs +58 -0
- package/scripts/corpus-reconcile.mjs +411 -105
- package/scripts/doc-currency.mjs +16 -1
- package/scripts/dual-host-deliberation.mjs +25 -2
- package/scripts/dual-host-suggest.mjs +17 -1
- package/scripts/falsify.mjs +13 -3
- package/scripts/gist-receipts.mjs +482 -87
- package/scripts/github-health-watch.mjs +12 -2
- package/scripts/handoff-asset.mjs +34 -0
- package/scripts/hook-retirement-check.mjs +8 -1
- package/scripts/host-registry.mjs +1 -1
- package/scripts/ingest-gists.mjs +74 -101
- package/scripts/job-heartbeat.sh +77 -14
- package/scripts/learning-replay-execution.mjs +10 -4
- package/scripts/nightly-gists.sh +27 -13
- package/scripts/nightly-two-run-proof.mjs +1 -1
- package/scripts/nightly-watchdog.mjs +61 -4
- package/scripts/onboarding-console.mjs +364 -28
- package/scripts/oracle/produce-questions.mjs +293 -0
- package/scripts/oracle/producer-hosts.mjs +235 -0
- package/scripts/oracle/repo-recall.mjs +448 -0
- package/scripts/oracle/retrieval-accuracy.mjs +818 -0
- package/scripts/oracle/source-tree.mjs +165 -0
- package/scripts/oracle/source-units.mjs +391 -0
- package/scripts/oracle/spike-run.mjs +98 -0
- package/scripts/oracle/unit-inventory.mjs +141 -0
- package/scripts/oracle/unit-sampling.mjs +128 -0
- package/scripts/oracle/validate-labels.mjs +250 -0
- package/scripts/private-overlay.mjs +248 -0
- package/scripts/product-integrity-contract.mjs +1 -1
- package/scripts/proxy/claude-proxied.sh +6 -0
- package/scripts/proxy/proxy-revert.sh +5 -0
- package/scripts/proxy/proxy-up.sh +6 -0
- package/scripts/proxy/proxy-verify.mjs +4 -0
- package/scripts/public-inputs.mjs +409 -0
- package/scripts/public-verification-inputs.mjs +112 -26
- package/scripts/public-verification-lane.mjs +1 -1
- package/scripts/published-surface-probe.mjs +34 -4
- package/scripts/qe/card-lane-gate.mjs +16 -1
- package/scripts/qe/session-start-gate.mjs +16 -1
- package/scripts/rebuild-gists-from-receipts.mjs +58 -78
- package/scripts/record-lesson.mjs +4 -1
- package/scripts/rehearse-corpus-pipeline.mjs +994 -0
- package/scripts/release-abort-stale.mjs +5 -1
- package/scripts/release-authority.mjs +104 -12
- package/scripts/release-channel-kind.mjs +86 -0
- package/scripts/release-convergence-watchdog.mjs +7 -2
- package/scripts/release-projection.mjs +177 -72
- package/scripts/release-transaction-provider.mjs +47 -10
- package/scripts/release-transaction.mjs +40 -11
- package/scripts/release.mjs +252 -17
- package/scripts/retrieval-canary.mjs +87 -0
- package/scripts/rvf-index-audit.mjs +573 -13
- package/scripts/rvf-wire.mjs +269 -0
- package/scripts/seal-gist-receipt.mjs +65 -0
- package/scripts/selfcheck.mjs +42 -21
- package/scripts/source-coverage.mjs +253 -24
- package/scripts/status-honesty.mjs +25 -0
- package/scripts/sync-census.mjs +0 -0
- package/scripts/sync-version.mjs +2 -0
- package/scripts/trismart.mjs +42 -0
- package/scripts/updater-manifest.mjs +162 -0
- package/scripts/verify-channels.mjs +17 -5
- package/scripts/wired-check.mjs +48 -10
- package/tri-smart-skill/QUICKSTART.md +37 -0
- package/tri-smart-skill/README.md +92 -0
- package/tri-smart-skill/install.cmd +14 -0
- package/tri-smart-skill/install.command +13 -0
- package/tri-smart-skill/install.mjs +51 -0
- package/tri-smart-skill/install.sh +9 -0
- package/tri-smart-skill/tri-smart/SKILL.md +90 -0
- package/tri-smart-skill/tri-smart/evals/evals.json +25 -0
- package/tri-smart-skill/tri-smart/references/protocol.md +25 -0
- package/tri-smart-skill/tri-smart/references/provider-cli.md +18 -0
- package/tri-smart-skill/tri-smart/scripts/review.mjs +154 -0
- package/tri-smart-skill/tri-smart/scripts/setup.mjs +97 -0
- package/tri-smart-skill/tri-smart/scripts/verify-access.mjs +107 -0
- package/scripts/corpus-seed-publish.mjs +0 -110
|
@@ -48,12 +48,29 @@ export function treeIdentity(dir) {
|
|
|
48
48
|
fileCount: entries.filter((entry) => entry.type === 'file').length, entries };
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// SYMLINK POLICY (issues #130/#131, applied here 2026-09-11). This threw on ANY symbolic link, and
|
|
52
|
+
// the installed brain always carries one: npm's `node_modules/.bin/semver`. So the already-current
|
|
53
|
+
// path in forge-update.mjs (managedStorageInventory at :1141) died on every machine, and the same
|
|
54
|
+
// link inside a `kb.bak-*` sibling wedged its inventory. A link that cannot be a store file and
|
|
55
|
+
// stays inside the tree is inventory, reported as `symlinkCount`. Two cases still throw, because
|
|
56
|
+
// they are what the hardening exists for: a link standing in for a store file, and a link that
|
|
57
|
+
// escapes the tree (its target is what a receipt would then silently be measuring).
|
|
51
58
|
function trustedTreeSummary(dir, kind) {
|
|
52
59
|
const identity = treeIdentity(dir);
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
const root = path.resolve(dir);
|
|
61
|
+
let symlinkCount = 0;
|
|
62
|
+
for (const entry of identity.entries) {
|
|
63
|
+
if (entry.type !== 'symlink') continue;
|
|
64
|
+
const relative = entry.path.split('/').join(path.sep);
|
|
65
|
+
const link = path.join(dir, relative);
|
|
66
|
+
if (/\.rvf$/i.test(relative)) throw new Error(`managed ${kind} tree contains a symbolic link in place of a store file: ${link}`);
|
|
67
|
+
const resolved = path.resolve(root, path.dirname(relative), entry.target);
|
|
68
|
+
if (path.isAbsolute(entry.target) || !resolved.startsWith(`${root}${path.sep}`)) {
|
|
69
|
+
throw new Error(`managed ${kind} tree contains a symbolic link that escapes the tree: ${link} -> ${entry.target}`);
|
|
70
|
+
}
|
|
71
|
+
symlinkCount++;
|
|
55
72
|
}
|
|
56
|
-
return { kind, path: dir, sha256: identity.sha256, bytes: identity.bytes, fileCount: identity.fileCount };
|
|
73
|
+
return { kind, path: dir, sha256: identity.sha256, bytes: identity.bytes, fileCount: identity.fileCount, symlinkCount };
|
|
57
74
|
}
|
|
58
75
|
|
|
59
76
|
// Installer-retained paths are observations, not transaction-owned cleanup candidates. Count link
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.26",
|
|
4
4
|
"description": "One-command installer for RuvNet Brain — a portable, source-grounded brain over rUv's RuvNet building blocks, delivered as a Claude Code plugin so Claude uses the stack instead of fighting it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,10 +33,13 @@
|
|
|
33
33
|
"qe:ux": "node scripts/qe/ux-suite.mjs",
|
|
34
34
|
"test:cov": "vitest run tests/unit --coverage",
|
|
35
35
|
"coverage:source": "node scripts/source-coverage.mjs --check",
|
|
36
|
+
"private-overlay": "node scripts/private-overlay.mjs",
|
|
37
|
+
"seal-gist-receipt": "node scripts/seal-gist-receipt.mjs",
|
|
36
38
|
"test:all": "npm run test:unit && npm run test:mesh && npm run test:mutation && npm run test:regression && npm run test:integration && npm test",
|
|
37
39
|
"metaharness:receipts": "node scripts/metaharness-receipts.mjs",
|
|
38
40
|
"route:cheap": "node scripts/route-cheap.mjs",
|
|
39
41
|
"route:receipt": "node scripts/dispatch-receipt.mjs",
|
|
42
|
+
"trismart": "node scripts/trismart.mjs",
|
|
40
43
|
"metaharness:fix": "node scripts/fix-metaharness-memretrieve.mjs --apply",
|
|
41
44
|
"metaharness:check": "node scripts/fix-metaharness-memretrieve.mjs --check",
|
|
42
45
|
"eval": "node scripts/eval-brain.mjs",
|
|
@@ -64,7 +67,8 @@
|
|
|
64
67
|
"cap:report": "node scripts/rerank-cap-eval.mjs --report",
|
|
65
68
|
"cap:ab": "node scripts/rerank-cap-warm-ab.mjs",
|
|
66
69
|
"hooks:check": "node scripts/hook-retirement-check.mjs",
|
|
67
|
-
"release:qualify": "node scripts/release-qualification.mjs"
|
|
70
|
+
"release:qualify": "node scripts/release-qualification.mjs",
|
|
71
|
+
"rehearse:corpus": "node scripts/rehearse-corpus-pipeline.mjs"
|
|
68
72
|
},
|
|
69
73
|
"files": [
|
|
70
74
|
".claude-plugin/marketplace.json",
|
|
@@ -84,10 +88,12 @@
|
|
|
84
88
|
"LICENSE",
|
|
85
89
|
"console/",
|
|
86
90
|
"config/model-router/",
|
|
91
|
+
"tri-smart-skill/",
|
|
87
92
|
"data/model-catalog.json",
|
|
88
93
|
"scripts/",
|
|
89
94
|
"kb/verify-citation.mjs",
|
|
90
95
|
"kb/retrieval-result.mjs",
|
|
96
|
+
"kb/corpus-release-identity.mjs",
|
|
91
97
|
"kb/zip-extract.mjs",
|
|
92
98
|
"kb/brain-profile.mjs",
|
|
93
99
|
"kb/lifecycle-evidence-retention.mjs",
|
|
@@ -125,6 +131,7 @@
|
|
|
125
131
|
"@metaharness/darwin": "~0.9.2",
|
|
126
132
|
"@ruvector/rvf": "^0.3.4",
|
|
127
133
|
"@vitest/coverage-v8": "^4.1.10",
|
|
134
|
+
"mdast-util-from-markdown": "2.0.3",
|
|
128
135
|
"playwright": "^1.62.0",
|
|
129
136
|
"vitest": "^4.1.10"
|
|
130
137
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"description": "RuvNet brain transplant for Claude Code — grounds every RuvNet decision in real source across 77 rUv repositories, prefers Ruflo / RuVector-RVF / AgentDB over training-prior defaults (pgvector, Pinecone, hand-rolled cosine), and can pull in any RuvNet repo on demand. Ships
|
|
4
|
-
"version": "4.3.
|
|
3
|
+
"description": "RuvNet brain transplant for Claude Code — grounds every RuvNet decision in real source across 77 rUv repositories, prefers Ruflo / RuVector-RVF / AgentDB over training-prior defaults (pgvector, Pinecone, hand-rolled cosine), and can pull in any RuvNet repo on demand. Ships a UserPromptSubmit retrieve-and-inject grounding hook and a PreToolUse write gate that refuses ungrounded rUv-product code until search_ruvnet has been consulted (ADR-0012 / ADR-067).",
|
|
4
|
+
"version": "4.3.26",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Stuart Kerr"
|
|
7
7
|
},
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Write a full project checkpoint to this project's canonical AgentDB store — the goal, the acceptance contract, the decisions, what is done, what is blocked, and the exact next action — so the next session (in Claude Code or Codex) resumes from a verified record instead of from nothing. Prints a read-back receipt."
|
|
3
|
+
updated: 2026-09-11
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# RuvNet-Brain: checkpoint
|
|
7
|
+
|
|
8
|
+
The user is asking you to **persist the state of this project** so the next session can resume it.
|
|
9
|
+
|
|
10
|
+
Automatic capture already runs at Stop, PreCompact and SessionEnd, and it records everything that can
|
|
11
|
+
be READ from the machine: the git tree, their work ledger, their newest `project-state-current` note,
|
|
12
|
+
a bounded transcript reference. **It cannot read what only you know** — the acceptance contract you
|
|
13
|
+
are working to, the decision you just made and why, the exact next action. That is what this command
|
|
14
|
+
is for, and it is why a checkpoint is worth more than another automatic snapshot.
|
|
15
|
+
|
|
16
|
+
## Do this
|
|
17
|
+
|
|
18
|
+
**1. Write down the real state — from THIS session, not from a template.**
|
|
19
|
+
|
|
20
|
+
Build a JSON object with the fields you can honestly fill. Every field is optional; set at least one.
|
|
21
|
+
Empty is better than invented: a fabricated "next action" is worse than no next action, because the
|
|
22
|
+
next session will act on it.
|
|
23
|
+
|
|
24
|
+
| field | what goes in it |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `currentGoal` | one sentence: what this work is actually for |
|
|
27
|
+
| `acceptanceContract` | what would make it DONE — the conditions, not the vibe |
|
|
28
|
+
| `nextAction` | the single next concrete step, specific enough to start cold |
|
|
29
|
+
| `decisions` | decisions made and WHY; include the ones you'd otherwise have to re-derive |
|
|
30
|
+
| `completed` / `inProgress` / `blockers` | honest status; a blocker named is a blocker halved |
|
|
31
|
+
| `failures` | what was tried and did not work, so it is not tried again |
|
|
32
|
+
| `changedFiles` | the files this work touched |
|
|
33
|
+
| `proofArtifacts` | commands run, outputs seen, receipts — the evidence, not the claim |
|
|
34
|
+
| `untested` | what was built but NOT verified. Do not omit this one. |
|
|
35
|
+
|
|
36
|
+
**2. Store it.**
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/project-progression-checkpoint.mjs" --json '<your JSON>'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For anything longer than a line or two, write the JSON to a temp file first and use
|
|
43
|
+
`--json-file <path>` — a large single-quoted argument is how a shell mangles a checkpoint.
|
|
44
|
+
|
|
45
|
+
**3. Report the receipt, not a claim.**
|
|
46
|
+
|
|
47
|
+
The command prints the exact event key, the payload digest, and the digest of the row **read back
|
|
48
|
+
from the store by that exact key**. Tell the user it is stored only when `readbackVerified` is
|
|
49
|
+
`true`. If the command exits non-zero, say exactly what it printed — an unstored checkpoint that is
|
|
50
|
+
reported as stored is the specific failure this whole system exists to prevent.
|
|
51
|
+
|
|
52
|
+
If it reports `replayedPending`, say so: those were snapshots a previously interrupted session had
|
|
53
|
+
made durable but never committed, and this checkpoint settled them.
|
|
54
|
+
|
|
55
|
+
## What NOT to do
|
|
56
|
+
|
|
57
|
+
- **Do not** invent progress, decisions, or proof to make the checkpoint look complete.
|
|
58
|
+
- **Do not** write the user's secrets into it. Redaction runs anyway, but do not rely on it.
|
|
59
|
+
- **Do not** hand-write rows into `.swarm/memory.db` or call `ruflo memory store` yourself. This
|
|
60
|
+
command is the one writer; a second path is how two stores drift apart.
|
|
61
|
+
- **Do not** claim the next session "will remember" anything the receipt did not confirm.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "RuvNet Brain continuity plane for Codex. Broad legacy automatic gates remain retired.
|
|
2
|
+
"description": "RuvNet Brain continuity plane for Codex. Broad legacy automatic gates remain retired. Registrations here are MEASURED, not assumed: a probe hook was registered on all twelve event names the installed codex-cli 0.154.0 binary declares and a real `codex exec` run was observed (2026-09-11). SessionStart, UserPromptSubmit and SessionEnd FIRED and carry handlers. Stop keeps only the pre-existing, project-scoped continuation gate. PreCompact is DECLARED ABSENT here: the binary declares the event but the probe never observed it, and a capture registered on an unobserved event would look symmetrical while capturing nothing. All handlers are bounded and fail open. Amended 2026-09-11: UserPromptSubmit also runs ground-ruvnet (grounding injection, ADR-040 §Amendment). Amended 2026-09-12: the 2026-09-11 PreToolUse/PostToolUse \"not observed\" note was measured with a prompt (`codex exec \"reply OK\"`) that never invoked a tool, so neither event had anything to fire on — that was an untested path, not a failing one. Re-probed with prompts that actually call a tool: a real apply_patch write fired PreToolUse/PostToolUse with tool_name \"apply_patch\", and a real MCP call to this repo's own search_ruvnet server fired both with tool_name \"mcp__ruvnet_brain__search_ruvnet\". Both are now registered below: decision-gate's write route (matcher includes apply_patch, Codex's raw write-tool name) and grounding-stamp (unchanged matcher already recognizes the mcp__..__search_ruvnet shape). The bash route (exec_command) remains unregistered — today's measurement covered a write and an MCP call, not exec_command, and extending on that evidence would be the same unproven leap this note replaces. Also added 2026-09-12: grounding-turn-mark (UserPromptSubmit) and grounding-turn-gate (Stop), the \"answered without searching\" pair — a prompt-level grounding directive is advisory, so this records whether it fired and forces continuation at Stop if no search_ruvnet call was recorded since (reusing grounding-stamp's own stamp evidence). Both are registered on Codex identically to Claude: the Stop-block contract (hookSpecificOutput.additionalContext) already has a proven Codex translation via codex-hook-adapter.mjs's Stop branch (see tests/unit/codex-lifecycle-hooks.test.mjs), the same path continuation-gate already uses.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
@@ -20,10 +20,73 @@
|
|
|
20
20
|
"type": "command",
|
|
21
21
|
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 9000 continuation-gate",
|
|
22
22
|
"timeout": 10
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "command",
|
|
26
|
+
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 9000 grounding-turn-gate",
|
|
27
|
+
"timeout": 10
|
|
23
28
|
}
|
|
24
29
|
],
|
|
25
30
|
"matcher": "*"
|
|
26
31
|
}
|
|
32
|
+
],
|
|
33
|
+
"PreToolUse": [
|
|
34
|
+
{
|
|
35
|
+
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit|apply_patch)$",
|
|
36
|
+
"hooks": [
|
|
37
|
+
{
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 6500 decision-gate write",
|
|
40
|
+
"timeout": 8
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"PostToolUse": [
|
|
46
|
+
{
|
|
47
|
+
"matcher": "^(?:.*__)?search_ruvnet$",
|
|
48
|
+
"hooks": [
|
|
49
|
+
{
|
|
50
|
+
"type": "command",
|
|
51
|
+
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 4500 grounding-stamp",
|
|
52
|
+
"timeout": 5
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"UserPromptSubmit": [
|
|
58
|
+
{
|
|
59
|
+
"matcher": "*",
|
|
60
|
+
"hooks": [
|
|
61
|
+
{
|
|
62
|
+
"type": "command",
|
|
63
|
+
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 2500 unprompted-speech UserPromptSubmit",
|
|
64
|
+
"timeout": 3
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"type": "command",
|
|
68
|
+
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 9000 ground-ruvnet",
|
|
69
|
+
"timeout": 10
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "command",
|
|
73
|
+
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 4500 grounding-turn-mark",
|
|
74
|
+
"timeout": 5
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"SessionEnd": [
|
|
80
|
+
{
|
|
81
|
+
"matcher": "*",
|
|
82
|
+
"hooks": [
|
|
83
|
+
{
|
|
84
|
+
"type": "command",
|
|
85
|
+
"command": "node -e \"const f=require('node:fs'),o=require('node:os'),p=require('node:path'),c=require('node:child_process'),d=process.env.CODEX_HOME||p.join(o.homedir(),'.codex'),b=process.env.RUVNET_BRAIN_HOME||p.join(p.dirname(d),'.cache','ruvnet-brain'),w=p.join(b,'codex-hook.mjs');let s;try{s=f.statSync(w)}catch{}if(!s?.isFile())process.exit(0);const r=c.spawnSync(process.execPath,[w,...process.argv.slice(2)],{stdio:['inherit','pipe','pipe'],encoding:'utf8',env:process.env,timeout:Number(process.argv[1]),killSignal:'SIGKILL'});if(r.status===0||r.status===2){if(r.stdout)process.stdout.write(r.stdout);if(r.stderr)process.stderr.write(r.stderr)}process.exit(r.status===2?2:0)\" 9000 session-snapshot SessionEnd",
|
|
86
|
+
"timeout": 10
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
27
90
|
]
|
|
28
91
|
}
|
|
29
92
|
}
|
|
@@ -1,22 +1,280 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_note": "The legacy automatic gate collection remains retired.
|
|
3
|
-
"_version":
|
|
2
|
+
"_note": "The legacy automatic gate collection remains retired. What is permitted is the continuity plane below and nothing else: SessionStart restores the canonical project checkpoint; UserPromptSubmit runs the single unprompted-speech chokepoint; Stop may nudge one explicitly authorized project-scoped objective AND capture a project snapshot; PreCompact and SessionEnd capture a project snapshot. Version 3 of this file permitted exactly two handlers, which was not a safety property but a contradiction: it demanded a restore while forbidding any event that could WRITE the journal the restore reads, so the canonical store held zero progression rows. Adding to this list is still a deliberate act that must pass `npm run hooks:check`; what changed is that the shape can now express the plane that actually works. Amended 2026-09-11 (Stuart): the continuity-only charter had retired the ONLY enforcement of ADR-0012 — never write rUv-product code the brain has not seen — and the failure it exists to prevent recurred the day it was measured absent. The plane now also carries three grounding registrations: ground-ruvnet (UserPromptSubmit, grounding injection — a second owner of that event, scoped by ADR-040 §Amendment 2026-09-11 to directives rather than speech), decision-gate’s write route (PreToolUse, the one refuser, ADR-067), and grounding-stamp (PostToolUse on a successful search_ruvnet, the receipt that opens the write gate). Amended 2026-09-12: the 2026-09-11 claim that Codex PreToolUse/PostToolUse delivery had never been observed was measured with a prompt that never invoked a tool (`codex exec \"reply OK\"`), so it was an untested path, not a failing one. Re-measured with prompts that actually call a tool (a real apply_patch write, a real MCP search_ruvnet call against this repo's own server): both events FIRED on codex-cli 0.154.0 with real payloads. decision-gate's write route and grounding-stamp are now dual-host (see _codexCapture and contracts below); the bash route (exec_command) remains Claude-only — today's measurement did not exercise it. Also amended 2026-09-12: added grounding-turn-mark (UserPromptSubmit) and grounding-turn-gate (Stop), the \"answered without searching\" pair — ground-ruvnet's Gate 1 directive is advisory, so nothing previously checked whether the model complied before the turn ended. grounding-turn-mark records that Gate 1 fired for a turn; grounding-turn-gate forces continuation at Stop if grounding-stamp's own evidence shows no search_ruvnet call happened since. Both dual-host from the start (the Stop-block contract is already proven on Codex via continuation-gate).",
|
|
3
|
+
"_version": 7,
|
|
4
|
+
"_eventOwners": [
|
|
5
|
+
{
|
|
6
|
+
"event": "SessionStart",
|
|
7
|
+
"owner": "session-start",
|
|
8
|
+
"class": "continuity recovery",
|
|
9
|
+
"hosts": [
|
|
10
|
+
"claude",
|
|
11
|
+
"codex"
|
|
12
|
+
],
|
|
13
|
+
"responsibility": "Restore the newest coherent committed checkpoint. Reads only; ADR-073 §5 forbids replaying the outbox here because replay is a write and a write costs more than this boundary's whole budget."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"event": "UserPromptSubmit",
|
|
17
|
+
"owner": "unprompted-speech",
|
|
18
|
+
"class": "advisory delivery",
|
|
19
|
+
"hosts": [
|
|
20
|
+
"claude",
|
|
21
|
+
"codex"
|
|
22
|
+
],
|
|
23
|
+
"responsibility": "The sole writer of unprompted user-facing bytes (ADR-040 / DDD-0004). Producers run as candidates behind it; it alone applies policy and writes the envelope."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"event": "Stop",
|
|
27
|
+
"owner": "continuation-gate",
|
|
28
|
+
"class": "continuation nudge",
|
|
29
|
+
"hosts": [
|
|
30
|
+
"claude",
|
|
31
|
+
"codex"
|
|
32
|
+
],
|
|
33
|
+
"responsibility": "May request one continuation for one explicitly authorized, project-scoped objective read from the user's own work ledger (ADR-043). Never a refusal, never a second task store."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"event": "Stop",
|
|
37
|
+
"owner": "session-snapshot",
|
|
38
|
+
"class": "continuity capture",
|
|
39
|
+
"hosts": [
|
|
40
|
+
"claude"
|
|
41
|
+
],
|
|
42
|
+
"responsibility": "Append one project snapshot to the canonical store and commit any outbox debt a previously interrupted session left behind."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"event": "PreCompact",
|
|
46
|
+
"owner": "session-snapshot",
|
|
47
|
+
"class": "continuity capture",
|
|
48
|
+
"hosts": [
|
|
49
|
+
"claude"
|
|
50
|
+
],
|
|
51
|
+
"responsibility": "The boundary at which context is about to be lost — capture before it is."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"event": "SessionEnd",
|
|
55
|
+
"owner": "session-snapshot",
|
|
56
|
+
"class": "continuity capture",
|
|
57
|
+
"hosts": [
|
|
58
|
+
"claude",
|
|
59
|
+
"codex"
|
|
60
|
+
],
|
|
61
|
+
"responsibility": "The boundary at which the session is about to be gone — capture before it is."
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"event": "UserPromptSubmit",
|
|
65
|
+
"owner": "ground-ruvnet",
|
|
66
|
+
"class": "grounding injection",
|
|
67
|
+
"hosts": [
|
|
68
|
+
"claude",
|
|
69
|
+
"codex"
|
|
70
|
+
],
|
|
71
|
+
"responsibility": "Injects a grounding directive into the model’s context when the prompt names the rUv stack, reaches for a classical default, or asks to build: call search_ruvnet before you assert. Not speech — emits no advocacy, promotion, lesson or alarm and reads no dial; silenced by the brain switch (ADR-054); scoped by ADR-040 §Amendment 2026-09-11."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"event": "PreToolUse",
|
|
75
|
+
"owner": "decision-gate",
|
|
76
|
+
"class": "consequential-action authorization",
|
|
77
|
+
"hosts": [
|
|
78
|
+
"claude",
|
|
79
|
+
"codex"
|
|
80
|
+
],
|
|
81
|
+
"responsibility": "The ONE process that may refuse a Write/Edit/MultiEdit/NotebookEdit/apply_patch (ADR-067): composes protect-state, hijack-ruvnet, ground-before-write (ADR-0012) and adr-currency into one decision with one reason. Fails open on its own errors. apply_patch is Codex's raw write-tool name, added to the shared matcher 2026-09-12 after a real apply_patch call was measured to fire PreToolUse live (codex-cli 0.154.0); codex-hook-adapter.mjs normalizes it to the same Edit shape decision-gate.mjs's policies already read on Claude."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"event": "PostToolUse",
|
|
85
|
+
"owner": "grounding-stamp",
|
|
86
|
+
"class": "grounding receipt",
|
|
87
|
+
"hosts": [
|
|
88
|
+
"claude",
|
|
89
|
+
"codex"
|
|
90
|
+
],
|
|
91
|
+
"responsibility": "After a SUCCESSFUL search_ruvnet, records which rUv products were consulted (a 24h stamp per term named in the query). It is the key that opens ground-before-write; without it the write gate would refuse every rUv-product write forever. Extended to Codex 2026-09-12: a real MCP search_ruvnet call fired PostToolUse with tool_name mcp__ruvnet_brain__search_ruvnet, which the existing matcher already recognized unchanged."
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"event": "UserPromptSubmit",
|
|
95
|
+
"owner": "grounding-turn-mark",
|
|
96
|
+
"class": "grounding turn marker",
|
|
97
|
+
"hosts": [
|
|
98
|
+
"claude",
|
|
99
|
+
"codex"
|
|
100
|
+
],
|
|
101
|
+
"responsibility": "Records that ground-ruvnet's Gate 1 (the same regex, proven byte-identical by test) matched this turn's prompt, so grounding-turn-gate has something to check at Stop — Stop's own payload carries no prompt text. Writes only a marker file under ~/.cache/ruvnet-brain/grounding-turn/; never blocks, never speaks to the model."
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"event": "Stop",
|
|
105
|
+
"owner": "grounding-turn-gate",
|
|
106
|
+
"class": "answered-without-search enforcement",
|
|
107
|
+
"hosts": [
|
|
108
|
+
"claude",
|
|
109
|
+
"codex"
|
|
110
|
+
],
|
|
111
|
+
"responsibility": "The 'answered without searching' gate (2026-09-12): if grounding-turn-mark's marker shows Gate 1 fired this turn and grounding-stamp's own stamp evidence shows no search_ruvnet call happened since, forces continuation via the same hookSpecificOutput.additionalContext contract continuation-gate already uses on both hosts. A separate registration from continuation-gate — see grounding-turn-gate.mjs's header for why folding it into that file's ledger/cooldown semantics would corrupt them rather than extend them. Consumes its marker unconditionally so a stale one can never pressure an unrelated later turn."
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"_notInThisPlane": [
|
|
115
|
+
{
|
|
116
|
+
"id": "decision-gate (bash route)",
|
|
117
|
+
"class": "consequential-action authorization",
|
|
118
|
+
"adr": "ADR-067",
|
|
119
|
+
"reachability": "The bash sub-event (protect-state, identifier-preflight, spend-guard, degradation-watch, hijack-ruvnet, design-wall) stays reachable through hook-shim.mjs by explicit invocation and is not registered: the 2026-09-11 mandate was the WRITE path (ADR-0012), and no host has proven PreToolUse delivery for Bash under the plane’s measured-not-assumed rule. The write route IS in the plane — see contracts."
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"id": "execution-policy",
|
|
123
|
+
"class": "consequential-action authorization",
|
|
124
|
+
"adr": "ADR-075",
|
|
125
|
+
"reachability": "Reachable through `npm run execution-policy:check` and scripts/execution-policy.mjs at the host's consequential-execution boundary. It is an authorization decision point, not an automatic lifecycle registration."
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"_codexCapture": {
|
|
129
|
+
"state": "partial",
|
|
130
|
+
"measuredOn": "2026-09-12",
|
|
131
|
+
"host": "codex-cli 0.154.0",
|
|
132
|
+
"method": "2026-09-11: a probe hook was registered in a temporary CODEX_HOME on all twelve event names the installed binary declares, and a real `codex exec \"reply OK\"` was run against it — a prompt that never invokes a tool. 2026-09-12: re-probed with prompts that DO invoke a tool — a real apply_patch write, and a real MCP call to this repo's own plugin/mcp/server.mjs registered as `search_ruvnet` in the probe's CODEX_HOME config.toml.",
|
|
133
|
+
"fired": [
|
|
134
|
+
"SessionStart",
|
|
135
|
+
"UserPromptSubmit",
|
|
136
|
+
"SessionEnd",
|
|
137
|
+
"PreToolUse (apply_patch write; tool_input.command carried the raw patch)",
|
|
138
|
+
"PostToolUse (apply_patch write; tool_response = \"Exit code: 0 … Success. Updated the following files: A <path>\")",
|
|
139
|
+
"PreToolUse (MCP search_ruvnet; tool_name mcp__ruvnet_brain__search_ruvnet, tool_input.query preserved verbatim)",
|
|
140
|
+
"PostToolUse (MCP search_ruvnet; tool_response.content[0].text carried the \"Searched N RuvNet repos\" banner)"
|
|
141
|
+
],
|
|
142
|
+
"notObserved": {
|
|
143
|
+
"Stop": "The 2026-09-11 probe turn never completed, so run_turn_stop_hooks had no completion to fire on. The binary declares the event and StopCommandOutputWire, so this is not-proven rather than unsupported. Stop keeps only the pre-existing continuation gate; no capture handler was added to an event whose delivery has not been seen.",
|
|
144
|
+
"PreCompact": "A one-line turn never approaches a compaction threshold. The binary declares PreCompact and PreCompactCommandOutputWire. No capture handler registered."
|
|
145
|
+
},
|
|
146
|
+
"consequence": "Codex captures at SessionEnd only; Stop/PreCompact remain unproven and unregistered as above (unchanged by this measurement). PreToolUse/PostToolUse are now proven for a write (apply_patch) and an MCP tool call (search_ruvnet) specifically, and decision-gate's write route plus grounding-stamp are registered on Codex accordingly (see contracts below). Bash-class tool calls (exec_command) were not exercised by this measurement and remain unregistered — extending on unexercised evidence would repeat the exact mistake this record corrects."
|
|
147
|
+
},
|
|
4
148
|
"contracts": [
|
|
5
149
|
{
|
|
6
150
|
"id": "session-start",
|
|
7
151
|
"event": "SessionStart",
|
|
8
|
-
"hosts": [
|
|
152
|
+
"hosts": [
|
|
153
|
+
"claude",
|
|
154
|
+
"codex"
|
|
155
|
+
],
|
|
9
156
|
"mode": "advisory",
|
|
10
157
|
"offBehavior": "partial",
|
|
11
|
-
"matcher": "startup|resume|clear|compact|fork"
|
|
158
|
+
"matcher": "startup|resume|clear|compact|fork",
|
|
159
|
+
"timeout": 5
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "unprompted-speech",
|
|
163
|
+
"event": "UserPromptSubmit",
|
|
164
|
+
"hosts": [
|
|
165
|
+
"claude",
|
|
166
|
+
"codex"
|
|
167
|
+
],
|
|
168
|
+
"mode": "blocking",
|
|
169
|
+
"offBehavior": "silence",
|
|
170
|
+
"matcher": "*",
|
|
171
|
+
"timeout": 3
|
|
12
172
|
},
|
|
13
173
|
{
|
|
14
174
|
"id": "continuation-gate",
|
|
15
175
|
"event": "Stop",
|
|
16
|
-
"hosts": [
|
|
176
|
+
"hosts": [
|
|
177
|
+
"claude",
|
|
178
|
+
"codex"
|
|
179
|
+
],
|
|
180
|
+
"mode": "advisory",
|
|
181
|
+
"offBehavior": "run",
|
|
182
|
+
"matcher": "*",
|
|
183
|
+
"timeout": 10
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"id": "session-snapshot",
|
|
187
|
+
"event": "Stop",
|
|
188
|
+
"hosts": [
|
|
189
|
+
"claude"
|
|
190
|
+
],
|
|
191
|
+
"mode": "advisory",
|
|
192
|
+
"offBehavior": "run",
|
|
193
|
+
"matcher": "*",
|
|
194
|
+
"timeout": 10
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"id": "session-snapshot",
|
|
198
|
+
"event": "PreCompact",
|
|
199
|
+
"hosts": [
|
|
200
|
+
"claude"
|
|
201
|
+
],
|
|
202
|
+
"mode": "advisory",
|
|
203
|
+
"offBehavior": "run",
|
|
204
|
+
"matcher": "*",
|
|
205
|
+
"timeout": 10
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"id": "session-snapshot",
|
|
209
|
+
"event": "SessionEnd",
|
|
210
|
+
"hosts": [
|
|
211
|
+
"claude",
|
|
212
|
+
"codex"
|
|
213
|
+
],
|
|
17
214
|
"mode": "advisory",
|
|
18
215
|
"offBehavior": "run",
|
|
19
|
-
"matcher": "*"
|
|
216
|
+
"matcher": "*",
|
|
217
|
+
"timeout": 10
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"id": "ground-ruvnet",
|
|
221
|
+
"event": "UserPromptSubmit",
|
|
222
|
+
"hosts": [
|
|
223
|
+
"claude",
|
|
224
|
+
"codex"
|
|
225
|
+
],
|
|
226
|
+
"mode": "advisory",
|
|
227
|
+
"offBehavior": "silence",
|
|
228
|
+
"matcher": "*",
|
|
229
|
+
"timeout": 10
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"id": "decision-gate",
|
|
233
|
+
"event": "PreToolUse",
|
|
234
|
+
"hosts": [
|
|
235
|
+
"claude",
|
|
236
|
+
"codex"
|
|
237
|
+
],
|
|
238
|
+
"mode": "blocking",
|
|
239
|
+
"offBehavior": "run",
|
|
240
|
+
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit|apply_patch)$",
|
|
241
|
+
"timeout": 5
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "grounding-stamp",
|
|
245
|
+
"event": "PostToolUse",
|
|
246
|
+
"hosts": [
|
|
247
|
+
"claude",
|
|
248
|
+
"codex"
|
|
249
|
+
],
|
|
250
|
+
"mode": "advisory",
|
|
251
|
+
"offBehavior": "silence",
|
|
252
|
+
"matcher": "^(?:.*__)?search_ruvnet$",
|
|
253
|
+
"timeout": 5
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"id": "grounding-turn-mark",
|
|
257
|
+
"event": "UserPromptSubmit",
|
|
258
|
+
"hosts": [
|
|
259
|
+
"claude",
|
|
260
|
+
"codex"
|
|
261
|
+
],
|
|
262
|
+
"mode": "advisory",
|
|
263
|
+
"offBehavior": "silence",
|
|
264
|
+
"matcher": "*",
|
|
265
|
+
"timeout": 5
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"id": "grounding-turn-gate",
|
|
269
|
+
"event": "Stop",
|
|
270
|
+
"hosts": [
|
|
271
|
+
"claude",
|
|
272
|
+
"codex"
|
|
273
|
+
],
|
|
274
|
+
"mode": "advisory",
|
|
275
|
+
"offBehavior": "silence",
|
|
276
|
+
"matcher": "*",
|
|
277
|
+
"timeout": 10
|
|
20
278
|
}
|
|
21
279
|
],
|
|
22
280
|
"matcherAllowlist": [
|
|
@@ -27,12 +285,47 @@
|
|
|
27
285
|
"reason": "SessionStart is a lifecycle source matcher, not a tool matcher.",
|
|
28
286
|
"retiredBy": "continuity-only lifecycle plane"
|
|
29
287
|
},
|
|
288
|
+
{
|
|
289
|
+
"layer": "plugin",
|
|
290
|
+
"event": "UserPromptSubmit",
|
|
291
|
+
"matcher": "*",
|
|
292
|
+
"reason": "UserPromptSubmit is a prompt lifecycle event, not a tool matcher; the runtime is the sole writer of unprompted bytes (ADR-040/DDD-0004).",
|
|
293
|
+
"retiredBy": "continuity-only lifecycle plane"
|
|
294
|
+
},
|
|
30
295
|
{
|
|
31
296
|
"layer": "plugin",
|
|
32
297
|
"event": "Stop",
|
|
33
298
|
"matcher": "*",
|
|
34
299
|
"reason": "Stop is a lifecycle event; wildcard is the host contract.",
|
|
35
300
|
"retiredBy": "continuity-only lifecycle plane"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"layer": "plugin",
|
|
304
|
+
"event": "PreCompact",
|
|
305
|
+
"matcher": "*",
|
|
306
|
+
"reason": "PreCompact is a lifecycle event; wildcard is the host contract.",
|
|
307
|
+
"retiredBy": "continuity-only lifecycle plane"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"layer": "plugin",
|
|
311
|
+
"event": "SessionEnd",
|
|
312
|
+
"matcher": "*",
|
|
313
|
+
"reason": "SessionEnd is a lifecycle event; wildcard is the host contract.",
|
|
314
|
+
"retiredBy": "continuity-only lifecycle plane"
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"layer": "plugin",
|
|
318
|
+
"event": "PreToolUse",
|
|
319
|
+
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit|apply_patch)$",
|
|
320
|
+
"reason": "The write-class tools, anchored — the exact matcher ADR-067 shipped and hook-registry-lint’s matcher-semantics test models. Claude Code matchers are searches, so the anchors are load-bearing. apply_patch (Codex's raw write-tool name) was added 2026-09-12 after a real apply_patch call was measured to fire this event live on codex-cli 0.154.0 — a dead branch on Claude, which never names a tool apply_patch.",
|
|
321
|
+
"retiredBy": "not retired — registered 2026-09-11 (ADR-0012 / ADR-067, Stuart mandate); extended to Codex 2026-09-12"
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"layer": "plugin",
|
|
325
|
+
"event": "PostToolUse",
|
|
326
|
+
"matcher": "^(?:.*__)?search_ruvnet$",
|
|
327
|
+
"reason": "The grounding tool with or without an MCP server prefix (mcp__plugin_ruvnet-brain_ruvnet-brain__search_ruvnet, or Codex's mcp__ruvnet_brain__search_ruvnet, measured live 2026-09-12). Only a successful search may mint a stamp; the body checks the result banner.",
|
|
328
|
+
"retiredBy": "not retired — registered 2026-09-11 (ADR-0012); Codex host proven reachable 2026-09-12, matcher unchanged"
|
|
36
329
|
}
|
|
37
330
|
]
|
|
38
331
|
}
|