ruvnet-brain 4.0.36 → 4.2.2-dev
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 +28 -5
- package/bin/install.mjs +405 -23
- package/data/model-catalog.json +104 -15
- package/package.json +2 -1
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/commands/brain-console.md +72 -9
- package/plugin/commands/configure.md +67 -21
- package/plugin/commands/rvcb.md +72 -9
- package/plugin/hooks/codex-hooks.json +40 -33
- package/plugin/hooks/hook-contracts.json +14 -24
- package/plugin/hooks/hooks.json +7 -42
- package/plugin/mcp/server.mjs +23 -6
- package/plugin/scripts/adr-currency-gate.mjs +150 -0
- package/plugin/scripts/capability-registry.mjs +10 -1
- package/plugin/scripts/codex-hook-adapter.mjs +121 -19
- package/plugin/scripts/codex-hook-wrapper.mjs +61 -4
- package/plugin/scripts/continuation-gate.mjs +148 -8
- package/plugin/scripts/decision-gate.mjs +428 -0
- package/plugin/scripts/decision-outcomes.mjs +231 -0
- package/plugin/scripts/degradation-watch.mjs +271 -0
- package/plugin/scripts/ground-ruvnet.sh +51 -11
- package/plugin/scripts/hijack-ruvnet.sh +11 -3
- package/plugin/scripts/hook-registry.mjs +48 -3
- package/plugin/scripts/hook-shim.mjs +58 -3
- package/plugin/scripts/identifier-preflight.mjs +134 -0
- package/plugin/scripts/learn-capture.sh +50 -1
- package/plugin/scripts/learn-flush.mjs +5 -5
- package/plugin/scripts/lesson-bridge.mjs +343 -0
- package/plugin/scripts/lesson-hooks.sh +26 -0
- package/plugin/scripts/lesson-promote.mjs +50 -0
- package/plugin/scripts/lesson-store.mjs +6 -1
- package/plugin/scripts/mcp-readiness.mjs +107 -0
- package/plugin/scripts/protect-brain-state.sh +9 -0
- package/plugin/scripts/runtime-preferences.mjs +40 -0
- package/plugin/scripts/session-snapshot-hook.mjs +15 -6
- package/plugin/scripts/spend-guard.mjs +125 -0
- package/plugin/scripts/unprompted-runtime.mjs +12 -2
- package/plugin/scripts/update-apply.mjs +7 -2
- package/plugin/skills/ruvnet-brain/PLAYBOOK.md +20 -5
- package/plugin/skills/ruvnet-brain/SKILL.md +3 -3
- package/scripts/brain-score.mjs +261 -0
- package/scripts/brain-stamp.mjs +5 -1
- package/scripts/build-bundle.mjs +38 -4
- package/scripts/card-from-source.mjs +114 -0
- package/scripts/console-engine.mjs +1 -1
- package/scripts/corpus-candidate.mjs +294 -0
- package/scripts/corpus-reconcile.mjs +273 -0
- package/scripts/corpus-seed-publish.mjs +110 -0
- package/scripts/health-repair.mjs +11 -2
- package/scripts/ingest-new-repos.mjs +122 -0
- package/scripts/ingest-repo.mjs +66 -6
- package/scripts/learning-replay-cli.mjs +8 -3
- package/scripts/learning-replay-fixture.mjs +25 -6
- package/scripts/learning-replay-proof.mjs +38 -0
- package/scripts/nightly-wrapper.sh +55 -7
- package/scripts/onboarding-console.mjs +21 -1
- package/scripts/org-repo-count.mjs +119 -0
- package/scripts/rebuild-gists-from-receipts.mjs +246 -0
- package/scripts/release-transaction.mjs +30 -2
- package/scripts/release.mjs +147 -0
- package/scripts/repo-count-detector.mjs +62 -0
- package/scripts/restore-local-ingests.mjs +116 -0
- package/scripts/rvf-generation.mjs +44 -0
- package/scripts/selfcheck.mjs +9 -1
- package/scripts/stabilization-receipt.mjs +11 -1
- package/scripts/sync-census.mjs +0 -0
- package/scripts/sync-commands.mjs +117 -0
package/data/model-catalog.json
CHANGED
|
@@ -18,17 +18,65 @@
|
|
|
18
18
|
"providers": {
|
|
19
19
|
"anthropic": {
|
|
20
20
|
"label": "Claude (Anthropic)",
|
|
21
|
-
"detect_env": [
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
"detect_env": [
|
|
22
|
+
"ANTHROPIC_API_KEY",
|
|
23
|
+
"CLAUDE_CODE_ENTRYPOINT",
|
|
24
|
+
"CLAUDECODE"
|
|
25
|
+
],
|
|
26
|
+
"frontier": {
|
|
27
|
+
"model": "claude-fable-5",
|
|
28
|
+
"in": 10,
|
|
29
|
+
"out": 50,
|
|
30
|
+
"released": "2026-06-09",
|
|
31
|
+
"rank": "AA Intelligence #1 (60) · Arena #1 (1508 Elo)",
|
|
32
|
+
"source": "independent (AA + Arena)"
|
|
33
|
+
},
|
|
34
|
+
"mid": {
|
|
35
|
+
"model": "claude-sonnet-5",
|
|
36
|
+
"in": 2,
|
|
37
|
+
"out": 10,
|
|
38
|
+
"released": "2026-06-30",
|
|
39
|
+
"rank": "AA 53; intro price $2/$10 → $3/$15 after 2026-08-31",
|
|
40
|
+
"source": "independent (AA)"
|
|
41
|
+
},
|
|
42
|
+
"cheap": {
|
|
43
|
+
"model": "claude-haiku-4.5",
|
|
44
|
+
"in": 1,
|
|
45
|
+
"out": 5,
|
|
46
|
+
"released": "2025-10-15",
|
|
47
|
+
"rank": "cheap tier (AA index low; cost-cascade prefers a cross-provider value pick when an OpenRouter key is present)",
|
|
48
|
+
"source": "catalog"
|
|
49
|
+
}
|
|
25
50
|
},
|
|
26
51
|
"openai": {
|
|
27
52
|
"label": "ChatGPT (OpenAI)",
|
|
28
|
-
"detect_env": [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
53
|
+
"detect_env": [
|
|
54
|
+
"OPENAI_API_KEY"
|
|
55
|
+
],
|
|
56
|
+
"frontier": {
|
|
57
|
+
"model": "openai/gpt-5.6-sol",
|
|
58
|
+
"in": 2.5,
|
|
59
|
+
"out": 15,
|
|
60
|
+
"released": "2026-07-09",
|
|
61
|
+
"rank": "AA Intelligence #2 (59) · AA Coding Index leader (80) · Terminal-Bench 2.1 SOTA · ~1/3 Fable 5's cost/task",
|
|
62
|
+
"source": "independent (AA)"
|
|
63
|
+
},
|
|
64
|
+
"mid": {
|
|
65
|
+
"model": "openai/gpt-5.6-terra",
|
|
66
|
+
"in": 2,
|
|
67
|
+
"out": 12,
|
|
68
|
+
"released": "2026-07-09",
|
|
69
|
+
"rank": "AA Coding 77.4 — beats prev-gen flagship GPT-5.5 (76.4) at lower live catalog pricing",
|
|
70
|
+
"source": "independent (AA)"
|
|
71
|
+
},
|
|
72
|
+
"cheap": {
|
|
73
|
+
"model": "openai/gpt-5.6-luna",
|
|
74
|
+
"in": 0.2,
|
|
75
|
+
"out": 1.2,
|
|
76
|
+
"released": "2026-07-09",
|
|
77
|
+
"rank": "AA 51 · Coding 74.6 — beats most last-gen mid-tier",
|
|
78
|
+
"source": "independent (AA)"
|
|
79
|
+
}
|
|
32
80
|
},
|
|
33
81
|
"codex": {
|
|
34
82
|
"label": "Codex (OpenAI)",
|
|
@@ -38,17 +86,58 @@
|
|
|
38
86
|
},
|
|
39
87
|
"google": {
|
|
40
88
|
"label": "Gemini (Google)",
|
|
41
|
-
"detect_env": [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
89
|
+
"detect_env": [
|
|
90
|
+
"GEMINI_API_KEY",
|
|
91
|
+
"GOOGLE_API_KEY"
|
|
92
|
+
],
|
|
93
|
+
"frontier": {
|
|
94
|
+
"model": "google/gemini-3.1-pro-preview",
|
|
95
|
+
"in": 2,
|
|
96
|
+
"out": 12,
|
|
97
|
+
"released": "2026-02-19",
|
|
98
|
+
"rank": "AA Intelligence 46 — BELOW the Anthropic/OpenAI/xAI frontier cluster (54–60); still preview-named. Honest: Gemini is not frontier-competitive on independent indices right now.",
|
|
99
|
+
"source": "independent (AA) — vendor's GPQA-D 94.3% / ARC-AGI-2 77.1% are Google's own, uncorroborated"
|
|
100
|
+
},
|
|
101
|
+
"mid": {
|
|
102
|
+
"model": "google/gemini-3.5-flash",
|
|
103
|
+
"in": 1.5,
|
|
104
|
+
"out": 9,
|
|
105
|
+
"released": "2026",
|
|
106
|
+
"rank": "AA 50 — out-scores Google's own 3.1 Pro on this index (real anomaly, not a typo)",
|
|
107
|
+
"source": "independent (AA)"
|
|
108
|
+
},
|
|
109
|
+
"cheap": {
|
|
110
|
+
"model": "google/gemini-3.1-flash-lite",
|
|
111
|
+
"in": 0.25,
|
|
112
|
+
"out": 1.5,
|
|
113
|
+
"released": "2026",
|
|
114
|
+
"rank": "budget",
|
|
115
|
+
"source": "catalog"
|
|
116
|
+
}
|
|
45
117
|
},
|
|
46
118
|
"xai": {
|
|
47
119
|
"label": "Grok (SpaceXAI)",
|
|
48
|
-
"detect_env": [
|
|
120
|
+
"detect_env": [
|
|
121
|
+
"XAI_API_KEY",
|
|
122
|
+
"GROK_API_KEY"
|
|
123
|
+
],
|
|
49
124
|
"note": "xAI's live lineup has no distinct budget SKU below Grok 4.3 as of 2026-07-15 (the 'grok-4.1-fast' I first wrote does not exist in the live catalog — the verify gate caught it). A Grok shop's cheap tasks route to Grok 4.3 or a cross-provider value pick.",
|
|
50
|
-
"frontier": {
|
|
51
|
-
|
|
125
|
+
"frontier": {
|
|
126
|
+
"model": "x-ai/grok-4.5",
|
|
127
|
+
"in": 2,
|
|
128
|
+
"out": 6,
|
|
129
|
+
"released": "2026-07-08",
|
|
130
|
+
"rank": "AA Intelligence 54 (#8) at ~1/3 Opus 4.7's blended price — the frontier VALUE standout; 'Opus-class, faster, cheaper' (Musk)",
|
|
131
|
+
"source": "independent (AA)"
|
|
132
|
+
},
|
|
133
|
+
"mid": {
|
|
134
|
+
"model": "x-ai/grok-4.3",
|
|
135
|
+
"in": 1.25,
|
|
136
|
+
"out": 2.5,
|
|
137
|
+
"released": "2026-04-30",
|
|
138
|
+
"rank": "AA 38 — also xAI's cheapest verified stable tier",
|
|
139
|
+
"source": "independent (AA)"
|
|
140
|
+
}
|
|
52
141
|
}
|
|
53
142
|
}
|
|
54
143
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.2-dev",
|
|
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": {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"substitution:check": "node scripts/no-silent-substitution.mjs",
|
|
39
39
|
"catalog:verify": "node scripts/verify-model-catalog.mjs",
|
|
40
40
|
"catalog:refresh": "node scripts/refresh-model-catalog.mjs",
|
|
41
|
+
"orgcount:refresh": "node scripts/org-repo-count.mjs --record",
|
|
41
42
|
"falsify": "node scripts/falsify.mjs",
|
|
42
43
|
"sbom": "npx --yes @cyclonedx/cyclonedx-npm --omit dev --output-file sbom/ruvnet-brain.cdx.json --mc-type application --validate",
|
|
43
44
|
"learning:replay": "node scripts/learning-replay.mjs",
|
|
@@ -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
|
|
4
|
-
"version": "4.
|
|
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 an enforced UserPromptSubmit retrieve-and-inject grounding hook that sharply reduces drift.",
|
|
4
|
+
"version": "4.2.2-dev",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Stuart Kerr"
|
|
7
7
|
},
|
|
@@ -3,14 +3,77 @@ description: "Brain Console — RuvNet Brain Console (same console as /rvbc, /br
|
|
|
3
3
|
updated: 2026-07-20
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
Launch the **RuvNet Brain Console** for the user. Same console as `/ruvnet-brain:configure`,
|
|
7
|
+
`/rvcb`, and `/brain-console` — every spelling lands here, so never tell the user they typed it wrong.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
2. Use `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
11
|
-
A current-repository copy is allowed only for an explicit developer checkout.
|
|
12
|
-
3. Run `node <resolved-script> --serve --open` in the background.
|
|
13
|
-
4. Give the URL immediately. Never promise a duration; the page reports its own progress.
|
|
9
|
+
## The contract you are keeping
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
The page **opens immediately and scans itself while they watch.** The server never blocks: a cold or
|
|
12
|
+
new-project read is answered in milliseconds with "measuring…", the page keeps its skeletons and
|
|
13
|
+
narrates the wait, and each card fills in as its own measurement lands. A chip in the header says how
|
|
14
|
+
old the picture is and re-measures when clicked.
|
|
15
|
+
|
|
16
|
+
So there is nothing to wait for and nothing to warn them about. **Your entire job is: say one
|
|
17
|
+
sentence, start the server in the background, hand over the URL, and get out of the way.**
|
|
18
|
+
|
|
19
|
+
## 1. SPEAK FIRST — one short sentence, before any tool call
|
|
20
|
+
|
|
21
|
+
Your FIRST output — before any tool call, any file read, any search — is one warm line saying you are
|
|
22
|
+
opening it now and it will scan itself live in their browser. Something in the spirit of:
|
|
23
|
+
|
|
24
|
+
> "Opening your console now — it'll come up right away and scan your setup live while you watch."
|
|
25
|
+
|
|
26
|
+
Say it like a person, not a status bar. **Do not** promise 20 seconds, a minute, or any duration: the
|
|
27
|
+
page carries its own timing now, and a number invented here is a number the page will contradict.
|
|
28
|
+
|
|
29
|
+
## 2. Find the installed runtime
|
|
30
|
+
|
|
31
|
+
Use `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
32
|
+
A current-repository copy is allowed only in an explicit developer checkout. Never guess a
|
|
33
|
+
`~/Code/ruvnet-brain` path: the installer persists this runtime for clean users.
|
|
34
|
+
|
|
35
|
+
## 3. Start it in the BACKGROUND and open the browser
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
node <repo>/scripts/onboarding-console.mjs --serve --open
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**`run_in_background: true`, ALWAYS — never in the foreground.** This is a server: it does not exit,
|
|
42
|
+
so a foreground run hangs the tool call until the 120-second timeout and turns an instant page into
|
|
43
|
+
two minutes of dead air. It binds `127.0.0.1` only and prints `http://127.0.0.1:7411/` within about a
|
|
44
|
+
third of a second.
|
|
45
|
+
|
|
46
|
+
**Then post the URL immediately.** Do not poll the log, do not wait for a scan, do not check whether
|
|
47
|
+
the data has landed — the page reports its own progress and none of it is visible from here.
|
|
48
|
+
|
|
49
|
+
**If it reports it is already running**, that is a success, not an error: open the URL yourself with
|
|
50
|
+
`open "http://127.0.0.1:<port>/"`. One honest caveat, worth half a sentence if it comes up — a
|
|
51
|
+
console that is already running is serving the project it was *launched* from, so if they want this
|
|
52
|
+
project's view they can stop that one (`^C` in its terminal) and run this again.
|
|
53
|
+
|
|
54
|
+
## 4. Hand it over and stop
|
|
55
|
+
|
|
56
|
+
Give them the URL as a clickable line, and one warm sentence: the page is **read-only until you
|
|
57
|
+
click**, every machine change is **explained first and reversible**, and Settings save at the user
|
|
58
|
+
level only. Worth naming once: the brain's on/off switch is the first card on the page, and the
|
|
59
|
+
header chip says how fresh the reading is and re-measures if they click it.
|
|
60
|
+
|
|
61
|
+
## 5. If it errors
|
|
62
|
+
|
|
63
|
+
Report it plainly — the real error, not a guess — and offer to fix it. Never leave them staring at
|
|
64
|
+
a dead tab wondering whether it is still loading.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Things NOT to do before the page is open
|
|
69
|
+
|
|
70
|
+
Each of these has cost a real user real minutes of silence, and not one of them is needed to open a
|
|
71
|
+
local web page:
|
|
72
|
+
|
|
73
|
+
- **No knowledge search, no memory recall, no source grounding, no repo exploration.** A cold
|
|
74
|
+
embedding-model load alone is allowed up to 180 seconds.
|
|
75
|
+
- **No model selection or routing work.**
|
|
76
|
+
- **No reading this repo to "check" anything first.** Find the script, run it.
|
|
77
|
+
|
|
78
|
+
Do **not** narrate the machine yourself afterwards; the page is the mirror. Your job is to open it,
|
|
79
|
+
say one sentence, and get out of the way.
|
|
@@ -1,33 +1,79 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Open the RuvNet Brain Onboarding Console — a local web page that mirrors YOUR machine's RuvNet setup, explains it in plain English, and lets you safely configure and fix it. Read-only until you click; every machine change is explained first and is reversible.
|
|
3
|
-
updated: 2026-07-
|
|
3
|
+
updated: 2026-07-20
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Launch the **RuvNet Brain
|
|
7
|
-
|
|
6
|
+
Launch the **RuvNet Brain Console** for the user. Same console as `/ruvnet-brain:configure`,
|
|
7
|
+
`/rvcb`, and `/brain-console` — every spelling lands here, so never tell the user they typed it wrong.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## The contract you are keeping
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
The page **opens immediately and scans itself while they watch.** The server never blocks: a cold or
|
|
12
|
+
new-project read is answered in milliseconds with "measuring…", the page keeps its skeletons and
|
|
13
|
+
narrates the wait, and each card fills in as its own measurement lands. A chip in the header says how
|
|
14
|
+
old the picture is and re-measures when clicked.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
So there is nothing to wait for and nothing to warn them about. **Your entire job is: say one
|
|
17
|
+
sentence, start the server in the background, hand over the URL, and get out of the way.**
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
node <repo>/scripts/onboarding-console.mjs --serve --open
|
|
20
|
-
```
|
|
19
|
+
## 1. SPEAK FIRST — one short sentence, before any tool call
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
Your FIRST output — before any tool call, any file read, any search — is one warm line saying you are
|
|
22
|
+
opening it now and it will scan itself live in their browser. Something in the spirit of:
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
the page is **read-only until you click**, everything it can change to your computer is **explained
|
|
27
|
-
in plain English and confirmed first**, and **Settings save at your user level**
|
|
28
|
-
(`~/.claude/ruvnet-brain/config.json`) without touching how anything else on your machine runs.
|
|
24
|
+
> "Opening your console now — it'll come up right away and scan your setup live while you watch."
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
Say it like a person, not a status bar. **Do not** promise 20 seconds, a minute, or any duration: the
|
|
27
|
+
page carries its own timing now, and a number invented here is a number the page will contradict.
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
## 2. Find the installed runtime
|
|
30
|
+
|
|
31
|
+
Use `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
32
|
+
A current-repository copy is allowed only in an explicit developer checkout. Never guess a
|
|
33
|
+
`~/Code/ruvnet-brain` path: the installer persists this runtime for clean users.
|
|
34
|
+
|
|
35
|
+
## 3. Start it in the BACKGROUND and open the browser
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
node <repo>/scripts/onboarding-console.mjs --serve --open
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**`run_in_background: true`, ALWAYS — never in the foreground.** This is a server: it does not exit,
|
|
42
|
+
so a foreground run hangs the tool call until the 120-second timeout and turns an instant page into
|
|
43
|
+
two minutes of dead air. It binds `127.0.0.1` only and prints `http://127.0.0.1:7411/` within about a
|
|
44
|
+
third of a second.
|
|
45
|
+
|
|
46
|
+
**Then post the URL immediately.** Do not poll the log, do not wait for a scan, do not check whether
|
|
47
|
+
the data has landed — the page reports its own progress and none of it is visible from here.
|
|
48
|
+
|
|
49
|
+
**If it reports it is already running**, that is a success, not an error: open the URL yourself with
|
|
50
|
+
`open "http://127.0.0.1:<port>/"`. One honest caveat, worth half a sentence if it comes up — a
|
|
51
|
+
console that is already running is serving the project it was *launched* from, so if they want this
|
|
52
|
+
project's view they can stop that one (`^C` in its terminal) and run this again.
|
|
53
|
+
|
|
54
|
+
## 4. Hand it over and stop
|
|
55
|
+
|
|
56
|
+
Give them the URL as a clickable line, and one warm sentence: the page is **read-only until you
|
|
57
|
+
click**, every machine change is **explained first and reversible**, and Settings save at the user
|
|
58
|
+
level only. Worth naming once: the brain's on/off switch is the first card on the page, and the
|
|
59
|
+
header chip says how fresh the reading is and re-measures if they click it.
|
|
60
|
+
|
|
61
|
+
## 5. If it errors
|
|
62
|
+
|
|
63
|
+
Report it plainly — the real error, not a guess — and offer to fix it. Never leave them staring at
|
|
64
|
+
a dead tab wondering whether it is still loading.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Things NOT to do before the page is open
|
|
69
|
+
|
|
70
|
+
Each of these has cost a real user real minutes of silence, and not one of them is needed to open a
|
|
71
|
+
local web page:
|
|
72
|
+
|
|
73
|
+
- **No knowledge search, no memory recall, no source grounding, no repo exploration.** A cold
|
|
74
|
+
embedding-model load alone is allowed up to 180 seconds.
|
|
75
|
+
- **No model selection or routing work.**
|
|
76
|
+
- **No reading this repo to "check" anything first.** Find the script, run it.
|
|
77
|
+
|
|
78
|
+
Do **not** narrate the machine yourself afterwards; the page is the mirror. Your job is to open it,
|
|
79
|
+
say one sentence, and get out of the way.
|
package/plugin/commands/rvcb.md
CHANGED
|
@@ -3,14 +3,77 @@ description: "RvCB — RuvNet Brain Console (same console as /rvbc, /brain-conso
|
|
|
3
3
|
updated: 2026-07-20
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
Launch the **RuvNet Brain Console** for the user. Same console as `/ruvnet-brain:configure`,
|
|
7
|
+
`/rvcb`, and `/brain-console` — every spelling lands here, so never tell the user they typed it wrong.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
2. Use `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
11
|
-
A current-repository copy is allowed only for an explicit developer checkout.
|
|
12
|
-
3. Run `node <resolved-script> --serve --open` in the background.
|
|
13
|
-
4. Give the URL immediately. Never promise a duration; the page reports its own progress.
|
|
9
|
+
## The contract you are keeping
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
The page **opens immediately and scans itself while they watch.** The server never blocks: a cold or
|
|
12
|
+
new-project read is answered in milliseconds with "measuring…", the page keeps its skeletons and
|
|
13
|
+
narrates the wait, and each card fills in as its own measurement lands. A chip in the header says how
|
|
14
|
+
old the picture is and re-measures when clicked.
|
|
15
|
+
|
|
16
|
+
So there is nothing to wait for and nothing to warn them about. **Your entire job is: say one
|
|
17
|
+
sentence, start the server in the background, hand over the URL, and get out of the way.**
|
|
18
|
+
|
|
19
|
+
## 1. SPEAK FIRST — one short sentence, before any tool call
|
|
20
|
+
|
|
21
|
+
Your FIRST output — before any tool call, any file read, any search — is one warm line saying you are
|
|
22
|
+
opening it now and it will scan itself live in their browser. Something in the spirit of:
|
|
23
|
+
|
|
24
|
+
> "Opening your console now — it'll come up right away and scan your setup live while you watch."
|
|
25
|
+
|
|
26
|
+
Say it like a person, not a status bar. **Do not** promise 20 seconds, a minute, or any duration: the
|
|
27
|
+
page carries its own timing now, and a number invented here is a number the page will contradict.
|
|
28
|
+
|
|
29
|
+
## 2. Find the installed runtime
|
|
30
|
+
|
|
31
|
+
Use `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
|
|
32
|
+
A current-repository copy is allowed only in an explicit developer checkout. Never guess a
|
|
33
|
+
`~/Code/ruvnet-brain` path: the installer persists this runtime for clean users.
|
|
34
|
+
|
|
35
|
+
## 3. Start it in the BACKGROUND and open the browser
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
node <repo>/scripts/onboarding-console.mjs --serve --open
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**`run_in_background: true`, ALWAYS — never in the foreground.** This is a server: it does not exit,
|
|
42
|
+
so a foreground run hangs the tool call until the 120-second timeout and turns an instant page into
|
|
43
|
+
two minutes of dead air. It binds `127.0.0.1` only and prints `http://127.0.0.1:7411/` within about a
|
|
44
|
+
third of a second.
|
|
45
|
+
|
|
46
|
+
**Then post the URL immediately.** Do not poll the log, do not wait for a scan, do not check whether
|
|
47
|
+
the data has landed — the page reports its own progress and none of it is visible from here.
|
|
48
|
+
|
|
49
|
+
**If it reports it is already running**, that is a success, not an error: open the URL yourself with
|
|
50
|
+
`open "http://127.0.0.1:<port>/"`. One honest caveat, worth half a sentence if it comes up — a
|
|
51
|
+
console that is already running is serving the project it was *launched* from, so if they want this
|
|
52
|
+
project's view they can stop that one (`^C` in its terminal) and run this again.
|
|
53
|
+
|
|
54
|
+
## 4. Hand it over and stop
|
|
55
|
+
|
|
56
|
+
Give them the URL as a clickable line, and one warm sentence: the page is **read-only until you
|
|
57
|
+
click**, every machine change is **explained first and reversible**, and Settings save at the user
|
|
58
|
+
level only. Worth naming once: the brain's on/off switch is the first card on the page, and the
|
|
59
|
+
header chip says how fresh the reading is and re-measures if they click it.
|
|
60
|
+
|
|
61
|
+
## 5. If it errors
|
|
62
|
+
|
|
63
|
+
Report it plainly — the real error, not a guess — and offer to fix it. Never leave them staring at
|
|
64
|
+
a dead tab wondering whether it is still loading.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Things NOT to do before the page is open
|
|
69
|
+
|
|
70
|
+
Each of these has cost a real user real minutes of silence, and not one of them is needed to open a
|
|
71
|
+
local web page:
|
|
72
|
+
|
|
73
|
+
- **No knowledge search, no memory recall, no source grounding, no repo exploration.** A cold
|
|
74
|
+
embedding-model load alone is allowed up to 180 seconds.
|
|
75
|
+
- **No model selection or routing work.**
|
|
76
|
+
- **No reading this repo to "check" anything first.** Find the script, run it.
|
|
77
|
+
|
|
78
|
+
Do **not** narrate the machine yourself afterwards; the page is the mirror. Your job is to open it,
|
|
79
|
+
say one sentence, and get out of the way.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "RuvNet Brain lifecycle hooks for Codex. Every command enters through a generation-independent wrapper and adapts the shared Brain hook bodies to Codex contracts.",
|
|
2
|
+
"description": "RuvNet Brain lifecycle hooks for Codex. Every command enters through a generation-independent wrapper and adapts the shared Brain hook bodies to Codex contracts.\n\nSCHEMA WARNING, MEASURED 2026-08-14 ON A LIVE CODEX 0.147.0 SESSION: this file accepts EXACTLY two top-level keys, `description` and `hooks`. Anything else and Codex logs `warning: failed to parse hooks config ...: unknown field `X`, expected `description` or `hooks`` and DROPS THE WHOLE FILE — all 16 hooks silently stop, on a warning line nobody reads. A structured `hostParity` object was written here first and did exactly that; the record below lives in this string because this string is the only place it can live.\n\nHOST PARITY (ADR-067). PreToolUse refusal routes through decision-gate.mjs on BOTH hosts, so decision-gate.mjs REFUSAL_POLICIES is the single list of policies and neither host can gain or lose one silently. This file deliberately does NOT restate that list: it used to name policies one by one, which is exactly why identifier-preflight, degradation-watch and adr-currency (added 2026-08-13) went live on Claude Code and were unreachable on Codex — a new policy had to be remembered twice, and nothing failed when it was not.\n\nDECLARED ABSENT — swarm-slot-recycler (Claude Code event TeammateIdle). Codex 0.147.0 has no TeammateIdle hook event. Its complete event set, read from the binary rather than assumed, is pre_tool_use, permission_request, post_tool_use, pre_compact, post_compact, session_start, session_end, user_prompt_submit, subagent_start, subagent_stop, stop. There is nothing to register against.\n\nOUTPUT CONTRACT. PreToolUse/PostToolUse/SessionStart/UserPromptSubmit stdout is PARSED by Codex (\"hook returned invalid post-tool-use JSON output\"); SessionEnd has no output schema at all and PreCompact carries no additionalContext. codex-hook-adapter.mjs enforces this per event.\n\nSESSIONEND IS HARD-CAPPED AT 3s BY THE HOST, measured on a live Codex 0.147.0 session which says so itself: `warning: clamping SessionEnd hook timeout to 3s`. A larger number here is not a longer budget, it is a lie the host silently corrects. learn-flush needs 18s (measured 18342/18347/18384 ms with a real queue and real ruflo), so codex-hook-wrapper.mjs DETACHES it: the cap governs how long the host WAITS, not how long work may take.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
@@ -13,6 +13,18 @@
|
|
|
13
13
|
]
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
|
+
"PreCompact": [
|
|
17
|
+
{
|
|
18
|
+
"matcher": ".*",
|
|
19
|
+
"hooks": [
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"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 session-snapshot PreCompact",
|
|
23
|
+
"timeout": 5
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
],
|
|
16
28
|
"UserPromptSubmit": [
|
|
17
29
|
{
|
|
18
30
|
"hooks": [
|
|
@@ -31,41 +43,31 @@
|
|
|
31
43
|
],
|
|
32
44
|
"PreToolUse": [
|
|
33
45
|
{
|
|
34
|
-
"matcher": "^(
|
|
46
|
+
"matcher": "^(Edit|Write|MultiEdit|apply_patch)$",
|
|
35
47
|
"hooks": [
|
|
36
48
|
{
|
|
37
49
|
"type": "command",
|
|
38
|
-
"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)\"
|
|
39
|
-
"timeout":
|
|
50
|
+
"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",
|
|
51
|
+
"timeout": 8
|
|
40
52
|
}
|
|
41
53
|
]
|
|
42
54
|
},
|
|
43
55
|
{
|
|
44
|
-
"matcher": "
|
|
56
|
+
"matcher": "^(Bash|exec_command|functions\\.exec_command|functions__exec_command)$",
|
|
45
57
|
"hooks": [
|
|
46
58
|
{
|
|
47
59
|
"type": "command",
|
|
48
|
-
"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)\"
|
|
49
|
-
"timeout":
|
|
60
|
+
"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 bash",
|
|
61
|
+
"timeout": 8
|
|
50
62
|
}
|
|
51
63
|
]
|
|
52
64
|
},
|
|
53
65
|
{
|
|
54
|
-
"matcher": "^(
|
|
66
|
+
"matcher": "^(Agent|spawn_agent)$",
|
|
55
67
|
"hooks": [
|
|
56
68
|
{
|
|
57
69
|
"type": "command",
|
|
58
|
-
"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
|
|
59
|
-
"timeout": 5
|
|
60
|
-
},
|
|
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)\" 4500 protect-state",
|
|
64
|
-
"timeout": 5
|
|
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)\" 4500 unprompted-speech PreToolUse-write",
|
|
70
|
+
"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 route-dispatch",
|
|
69
71
|
"timeout": 5
|
|
70
72
|
}
|
|
71
73
|
]
|
|
@@ -77,16 +79,6 @@
|
|
|
77
79
|
"type": "command",
|
|
78
80
|
"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 verify-interface",
|
|
79
81
|
"timeout": 5
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"type": "command",
|
|
83
|
-
"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 design-wall",
|
|
84
|
-
"timeout": 5
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"type": "command",
|
|
88
|
-
"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 unprompted-speech PreToolUse-bash",
|
|
89
|
-
"timeout": 5
|
|
90
82
|
}
|
|
91
83
|
]
|
|
92
84
|
}
|
|
@@ -103,7 +95,7 @@
|
|
|
103
95
|
]
|
|
104
96
|
},
|
|
105
97
|
{
|
|
106
|
-
"matcher": "^(Bash|Edit|Write|exec_command|functions\\.exec_command|functions__exec_command|apply_patch)$",
|
|
98
|
+
"matcher": "^(Bash|Edit|Write|MultiEdit|exec_command|functions\\.exec_command|functions__exec_command|apply_patch)$",
|
|
107
99
|
"hooks": [
|
|
108
100
|
{
|
|
109
101
|
"type": "command",
|
|
@@ -113,7 +105,7 @@
|
|
|
113
105
|
]
|
|
114
106
|
},
|
|
115
107
|
{
|
|
116
|
-
"matcher": "^(Edit|Write|apply_patch)$",
|
|
108
|
+
"matcher": "^(Edit|Write|MultiEdit|apply_patch)$",
|
|
117
109
|
"hooks": [
|
|
118
110
|
{
|
|
119
111
|
"type": "command",
|
|
@@ -131,15 +123,30 @@
|
|
|
131
123
|
"timeout": 5
|
|
132
124
|
}
|
|
133
125
|
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"matcher": "^(Agent|spawn_agent)$",
|
|
129
|
+
"hooks": [
|
|
130
|
+
{
|
|
131
|
+
"type": "command",
|
|
132
|
+
"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 routing-outcome",
|
|
133
|
+
"timeout": 5
|
|
134
|
+
}
|
|
135
|
+
]
|
|
134
136
|
}
|
|
135
137
|
],
|
|
136
138
|
"SessionEnd": [
|
|
137
139
|
{
|
|
138
|
-
"matcher": "
|
|
140
|
+
"matcher": ".*",
|
|
139
141
|
"hooks": [
|
|
140
142
|
{
|
|
141
143
|
"type": "command",
|
|
142
|
-
"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)\"
|
|
144
|
+
"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)\" 2800 session-snapshot SessionEnd",
|
|
145
|
+
"timeout": 3
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"type": "command",
|
|
149
|
+
"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)\" 2800 learn-flush",
|
|
143
150
|
"timeout": 3
|
|
144
151
|
}
|
|
145
152
|
]
|