ruvnet-brain 4.3.20 → 4.3.25
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 +383 -78
- package/console/app.js +141 -9
- package/console/index.html +51 -24
- package/console/scope.css +137 -0
- package/console/scope.html +144 -0
- package/console/scope.js +209 -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/host-shell-boundary.mjs +43 -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/scripts/update-apply.mjs +2 -32
- 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 +319 -27
- 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 +23 -6
- 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
|
@@ -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
|
}
|
package/plugin/hooks/hooks.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "RuvNet Brain
|
|
2
|
+
"description": "RuvNet Brain lifecycle plane. The broad legacy routing, learning, and release interceptors remain retired. What is automatic is exactly: SessionStart restores the canonical project checkpoint; UserPromptSubmit runs the single unprompted-speech chokepoint AND the ground-ruvnet grounding injection (a directive to the model, not speech — ADR-040 §Amendment 2026-09-11); PreToolUse runs decision-gate's write route, the ONE process that may refuse a Write/Edit/MultiEdit/NotebookEdit/apply_patch (ADR-067, composing ground-before-write per ADR-0012) — apply_patch is Codex's own write tool name, added 2026-09-12 once a real apply_patch call was measured to fire this event live (codex-hooks.json carries the matching Codex registration; this is a dead branch on Claude, which never names a tool apply_patch); PostToolUse on a successful search_ruvnet mints the grounding stamp that opens that gate; grounding-turn-mark (UserPromptSubmit) records that the grounding directive fired this turn, and grounding-turn-gate (Stop) forces continuation if no search_ruvnet call was recorded since — the \"answered without searching\" gate, added 2026-09-12 (a directive alone is advisory; nothing previously checked whether the model actually complied); Stop also runs the ledger-scoped continuation handler and captures a project snapshot; PreCompact and SessionEnd capture a project snapshot. Every capture is bounded and fails open; only decision-gate may block on exit code, and it fails open on its own errors — grounding-turn-gate and continuation-gate force continuation via the Stop stdout envelope instead, which is advisory in the shim's own mode table but still keeps the agent working.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
@@ -13,6 +13,52 @@
|
|
|
13
13
|
]
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
|
+
"UserPromptSubmit": [
|
|
17
|
+
{
|
|
18
|
+
"matcher": "*",
|
|
19
|
+
"hooks": [
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" unprompted-speech UserPromptSubmit",
|
|
23
|
+
"timeout": 3
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"type": "command",
|
|
27
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" ground-ruvnet || true",
|
|
28
|
+
"timeout": 10
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"type": "command",
|
|
32
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" grounding-turn-mark || true",
|
|
33
|
+
"timeout": 5
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"PreToolUse": [
|
|
39
|
+
{
|
|
40
|
+
"matcher": "^(Write|Edit|MultiEdit|NotebookEdit|apply_patch)$",
|
|
41
|
+
"hooks": [
|
|
42
|
+
{
|
|
43
|
+
"type": "command",
|
|
44
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" decision-gate write",
|
|
45
|
+
"timeout": 5
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"PostToolUse": [
|
|
51
|
+
{
|
|
52
|
+
"matcher": "^(?:.*__)?search_ruvnet$",
|
|
53
|
+
"hooks": [
|
|
54
|
+
{
|
|
55
|
+
"type": "command",
|
|
56
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" grounding-stamp || true",
|
|
57
|
+
"timeout": 5
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
],
|
|
16
62
|
"Stop": [
|
|
17
63
|
{
|
|
18
64
|
"matcher": "*",
|
|
@@ -21,6 +67,40 @@
|
|
|
21
67
|
"type": "command",
|
|
22
68
|
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" continuation-gate || true",
|
|
23
69
|
"timeout": 10
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "command",
|
|
73
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" session-snapshot Stop || true",
|
|
74
|
+
"timeout": 10
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "command",
|
|
78
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" grounding-turn-gate || true",
|
|
79
|
+
"timeout": 10
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"PreCompact": [
|
|
85
|
+
{
|
|
86
|
+
"matcher": "*",
|
|
87
|
+
"hooks": [
|
|
88
|
+
{
|
|
89
|
+
"type": "command",
|
|
90
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" session-snapshot PreCompact || true",
|
|
91
|
+
"timeout": 10
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"SessionEnd": [
|
|
97
|
+
{
|
|
98
|
+
"matcher": "*",
|
|
99
|
+
"hooks": [
|
|
100
|
+
{
|
|
101
|
+
"type": "command",
|
|
102
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/hook-shim.mjs\" session-snapshot SessionEnd || true",
|
|
103
|
+
"timeout": 10
|
|
24
104
|
}
|
|
25
105
|
]
|
|
26
106
|
}
|
package/plugin/mcp/server.mjs
CHANGED
|
@@ -59,6 +59,29 @@ const SEARCH_TOOL = {
|
|
|
59
59
|
},
|
|
60
60
|
required: ['query'],
|
|
61
61
|
},
|
|
62
|
+
// ── WHY THIS TOOL IS DECLARED READ-ONLY ───────────────────────────────────────────────────────
|
|
63
|
+
// Its three siblings below (MANAGED_CLI_TOOLS) have carried annotations since they shipped; this
|
|
64
|
+
// one did not, and a host that must assume the worst therefore assumed it. Observed 2026-09-11:
|
|
65
|
+
// Claude Code's plan mode REFUSED search_ruvnet three times in one session ("Cannot call
|
|
66
|
+
// search_ruvnet while in plan mode") — so the one tool whose entire purpose is grounding a plan
|
|
67
|
+
// in rUv's real source was unavailable at exactly the moment a plan is written. An unannotated
|
|
68
|
+
// tool is not a neutral default; it is a claim of "may mutate", made by omission.
|
|
69
|
+
//
|
|
70
|
+
// The claim is checked, not asserted. Every write reachable from a search_ruvnet call was walked
|
|
71
|
+
// (kb/forge-mcp-all.mjs meterLog + markGroundingProven, kb/brain-alarm.mjs health.json,
|
|
72
|
+
// kb/telemetry-ping.mjs stamp/queue, and this file's refreshLease): all of them land under
|
|
73
|
+
// ~/.cache/ruvnet-brain — or $XDG_CACHE_HOME/ruvnet-brain — plus $RUVNET_BRAIN_STATE_DIR for the
|
|
74
|
+
// off-switch READ. Nothing is written into the user's project tree, nothing is deleted, and
|
|
75
|
+
// nothing outside this cache is touched; that property is not incidental, it is the fix issue #36
|
|
76
|
+
// (mamd69) landed after three writers had scattered hidden directories through project trees.
|
|
77
|
+
// Internal receipt/cache/telemetry writes under the user's cache dir are exactly what
|
|
78
|
+
// readOnlyHint is meant to tolerate — the hint is about the caller's world, not about whether the
|
|
79
|
+
// process ever calls write(2).
|
|
80
|
+
//
|
|
81
|
+
// idempotentHint: the same question over the same immutable corpus snapshot returns the same
|
|
82
|
+
// ranked documents — the cross-encoder is byte-for-byte deterministic for a fixed batch
|
|
83
|
+
// (evals/runs/2026-07-27-cross-encoder-pool-cap.md) and the pool order is stable by construction.
|
|
84
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
62
85
|
};
|
|
63
86
|
const FALLBACK_TOOLS = [SEARCH_TOOL, ...MANAGED_CLI_TOOLS];
|
|
64
87
|
|