ruvnet-brain 4.0.1 → 4.0.4

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.
Files changed (195) hide show
  1. package/.claude-plugin/marketplace.json +1 -0
  2. package/README.md +4 -4
  3. package/bin/install.mjs +303 -24
  4. package/console/CONTRACT.md +172 -0
  5. package/console/activity.js +753 -0
  6. package/console/app.js +4189 -0
  7. package/console/architecture.html +1221 -0
  8. package/console/assets/depth-1.webp +0 -0
  9. package/console/assets/depth-2.webp +0 -0
  10. package/console/assets/depth-3.webp +0 -0
  11. package/console/assets/harness-vs-plain.svg +259 -0
  12. package/console/assets/hero.webp +0 -0
  13. package/console/assets/memory.webp +0 -0
  14. package/console/assets/metaharness.svg +247 -0
  15. package/console/index.html +777 -0
  16. package/console/install-architecture.html +162 -0
  17. package/console/install-mockup.html +543 -0
  18. package/console/style.css +2144 -0
  19. package/console/tips.css +926 -0
  20. package/console/tips.html +858 -0
  21. package/console/tips.js +128 -0
  22. package/docs/RELEASE-NOTES-4.0.md +88 -0
  23. package/kb/model-requirements.mjs +37 -6
  24. package/keys/ruvnet-brain-signing.pub.pem +3 -0
  25. package/package.json +8 -22
  26. package/plugin/.claude-plugin/marketplace.json +1 -0
  27. package/plugin/.claude-plugin/plugin.json +2 -3
  28. package/plugin/.codex-plugin/plugin.json +1 -1
  29. package/plugin/commands/brain-console.md +2 -2
  30. package/plugin/commands/configure.md +3 -2
  31. package/plugin/commands/rvbc.md +4 -3
  32. package/plugin/commands/rvcb.md +2 -2
  33. package/plugin/commands/whats-new.md +6 -6
  34. package/plugin/docs/RELEASE-NOTES-4.0.md +88 -0
  35. package/plugin/hooks/hooks.json +1 -2
  36. package/plugin/mcp/managed-cli-interface.mjs +47 -4
  37. package/plugin/mcp/server.mjs +90 -32
  38. package/plugin/scripts/detach.mjs +14 -0
  39. package/plugin/scripts/first-session-worker.mjs +38 -0
  40. package/plugin/scripts/ground-ruvnet.sh +16 -6
  41. package/plugin/scripts/hook-shim.mjs +34 -29
  42. package/plugin/scripts/learn-capture.sh +22 -3
  43. package/plugin/scripts/learn-flush.mjs +21 -4
  44. package/plugin/scripts/runtime-preferences.mjs +269 -0
  45. package/plugin/scripts/session-start-core.mjs +503 -0
  46. package/plugin/scripts/session-start.sh +3 -858
  47. package/plugin/scripts/whats-new.mjs +42 -0
  48. package/plugin/skills/brain-console/SKILL.md +4 -2
  49. package/plugin/skills/release-proof/SKILL.md +98 -0
  50. package/plugin/skills/release-proof/agents/openai.yaml +4 -0
  51. package/plugin/skills/release-proof/references/receipt-contract.md +44 -0
  52. package/plugin/skills/release-proof/scripts/release-proof.mjs +286 -0
  53. package/plugin/skills/ruvnet-brain/PLAYBOOK.md +5 -1
  54. package/plugin/skills/ruvnet-brain/SKILL.md +22 -7
  55. package/plugin/skills/rvbc/SKILL.md +9 -6
  56. package/plugin/skills/whats-new/SKILL.md +4 -4
  57. package/scripts/adr-backfill.mjs +107 -0
  58. package/scripts/advocacy-outcomes.mjs +808 -0
  59. package/scripts/agentdb-context.mjs +216 -0
  60. package/scripts/agentdb-fleet-doctor.mjs +101 -0
  61. package/scripts/ascii-drift.mjs +236 -0
  62. package/scripts/behavioral-l1-l4.mjs +210 -0
  63. package/scripts/brain-capability-check.mjs +72 -0
  64. package/scripts/brain-grade-groundtruth.mjs +100 -0
  65. package/scripts/brain-latency-50.mjs +227 -0
  66. package/scripts/brain-novice-50.mjs +189 -0
  67. package/scripts/brain-stamp.mjs +94 -0
  68. package/scripts/brain-state.mjs +212 -0
  69. package/scripts/build-bundle.mjs +531 -0
  70. package/scripts/build-concepts.mjs +132 -0
  71. package/scripts/build-l2.mjs +71 -0
  72. package/scripts/build-primer.mjs +73 -0
  73. package/scripts/build-symbols.mjs +68 -0
  74. package/scripts/calibrate-router.mjs +97 -0
  75. package/scripts/capability-audit.mjs +321 -0
  76. package/scripts/capability-registry.mjs +876 -0
  77. package/scripts/check-indexation.mjs +108 -0
  78. package/scripts/check-legibility.mjs +189 -0
  79. package/scripts/ci/build-fixture-kb.mjs +67 -0
  80. package/scripts/ci/learning-replay-codex-adapter.mjs +62 -0
  81. package/scripts/ci/learning-replay-recorder.mjs +59 -0
  82. package/scripts/ci/mutate-hook-timeout.mjs +70 -0
  83. package/scripts/ci/stranger-fixture-stage.mjs +17 -0
  84. package/scripts/ci/stranger-scenario.mjs +228 -0
  85. package/scripts/ci/stranger-timeout.mjs +25 -0
  86. package/scripts/ci-verdict.mjs +29 -0
  87. package/scripts/claims-verify.mjs +710 -0
  88. package/scripts/clear-claude-tmp.sh +31 -0
  89. package/scripts/console-engine.mjs +434 -0
  90. package/scripts/console-engine.test.mjs +125 -0
  91. package/scripts/corpus-qa.mjs +250 -0
  92. package/scripts/correction-detect-embed.mjs +346 -0
  93. package/scripts/correction-detect-measure.mjs +270 -0
  94. package/scripts/correction-detect.mjs +686 -0
  95. package/scripts/count-chunks.mjs +54 -0
  96. package/scripts/described-questions.json +30 -0
  97. package/scripts/design-grade.mjs +58 -0
  98. package/scripts/dev-plugin-link.sh +105 -0
  99. package/scripts/distill-project.mjs +200 -0
  100. package/scripts/doc-currency.mjs +801 -0
  101. package/scripts/eval-brain.mjs +244 -0
  102. package/scripts/fix-metaharness-memretrieve.mjs +121 -0
  103. package/scripts/fix-workstream.mjs +291 -0
  104. package/scripts/full-hints.mjs +87 -0
  105. package/scripts/gate.sh +39 -0
  106. package/scripts/gates.mjs +146 -0
  107. package/scripts/gen-console-images.mjs +54 -0
  108. package/scripts/gen-images.mjs +47 -0
  109. package/scripts/git-clone-refresh.mjs +52 -0
  110. package/scripts/git-hooks/pre-push +126 -0
  111. package/scripts/goal-match.mjs +398 -0
  112. package/scripts/goldie-research.mjs +223 -0
  113. package/scripts/goldie-weekly.sh +67 -0
  114. package/scripts/health-repair.mjs +237 -0
  115. package/scripts/helix-scenario-questions.json +10 -0
  116. package/scripts/ingest-gists.mjs +230 -0
  117. package/scripts/ingest-meeting.mjs +115 -0
  118. package/scripts/ingest-repo.mjs +79 -0
  119. package/scripts/install-npx-witness.sh +49 -0
  120. package/scripts/issue-fix.mjs +558 -0
  121. package/scripts/issue-watch.mjs +276 -0
  122. package/scripts/issue4-close-note.md +31 -0
  123. package/scripts/key-canary.mjs +91 -0
  124. package/scripts/latency-to-surface.mjs +233 -0
  125. package/scripts/learning-enable.mjs +380 -0
  126. package/scripts/learning-replay.mjs +1570 -0
  127. package/scripts/learnings.mjs +62 -0
  128. package/scripts/lesson-gate.mjs +680 -0
  129. package/scripts/lesson-lifecycle.mjs +449 -0
  130. package/scripts/lesson-promote.mjs +262 -0
  131. package/scripts/lesson-ratify.mjs +98 -0
  132. package/scripts/lesson-seed.mjs +252 -0
  133. package/scripts/lesson-store.mjs +447 -0
  134. package/scripts/loop-checkpoint.mjs +86 -0
  135. package/scripts/memdb-health.sh +14 -0
  136. package/scripts/memory-doctor.mjs +326 -0
  137. package/scripts/model-catalog.mjs +79 -0
  138. package/scripts/nightly-controller.mjs +66 -0
  139. package/scripts/nightly-gists.sh +72 -0
  140. package/scripts/nightly-wrapper.sh +172 -0
  141. package/scripts/notify.sh +12 -0
  142. package/scripts/npx-witness.sh +56 -0
  143. package/scripts/onboarding-console.mjs +2922 -0
  144. package/scripts/private-fence.mjs +69 -0
  145. package/scripts/proactivity-metrics.mjs +118 -0
  146. package/scripts/proof-questions.json +56 -0
  147. package/scripts/protected-release-invocation.mjs +76 -0
  148. package/scripts/prove.mjs +95 -0
  149. package/scripts/proxy/claude-proxied.sh +57 -0
  150. package/scripts/proxy/proxy-revert.sh +59 -0
  151. package/scripts/proxy/proxy-up.sh +60 -0
  152. package/scripts/proxy/proxy-verify.mjs +142 -0
  153. package/scripts/publication-receipt.mjs +307 -0
  154. package/scripts/published-surface-probe.mjs +241 -0
  155. package/scripts/qe/card-lane-gate.mjs +162 -0
  156. package/scripts/qe/session-start-gate.mjs +229 -0
  157. package/scripts/qe/ux-suite.mjs +323 -0
  158. package/scripts/reconcile-project.mjs +0 -0
  159. package/scripts/record-lesson.mjs +113 -0
  160. package/scripts/refresh-model-catalog.mjs +99 -0
  161. package/scripts/release-authority.mjs +93 -0
  162. package/scripts/release-proof.mjs +9 -0
  163. package/scripts/release-vector.mjs +281 -0
  164. package/scripts/release.mjs +439 -0
  165. package/scripts/remedy-registry.mjs +247 -0
  166. package/scripts/rerank-cap-eval.mjs +265 -0
  167. package/scripts/rerank-cap-warm-ab.mjs +129 -0
  168. package/scripts/route-cheap.mjs +20 -15
  169. package/scripts/router-utilization.mjs +182 -0
  170. package/scripts/routing-flywheel.mjs +596 -0
  171. package/scripts/rvf-generation.mjs +104 -0
  172. package/scripts/rvf-index-audit.mjs +138 -0
  173. package/scripts/self-update.mjs +296 -0
  174. package/scripts/selfcheck.mjs +7 -1
  175. package/scripts/sign-bundle.mjs +69 -0
  176. package/scripts/signal-watch.mjs +171 -0
  177. package/scripts/stabilization-receipt.mjs +108 -0
  178. package/scripts/stack-sync.mjs +469 -0
  179. package/scripts/stamp-existing-rvf-generations.mjs +53 -0
  180. package/scripts/stamp-sweep.mjs +144 -0
  181. package/scripts/status-honesty.mjs +102 -0
  182. package/scripts/sync-version.mjs +217 -0
  183. package/scripts/token-report.mjs +102 -0
  184. package/scripts/top100-benchmark.mjs +479 -0
  185. package/scripts/top100-corpus.mjs +112 -0
  186. package/scripts/top100-semantic-assertions.mjs +449 -0
  187. package/scripts/update-apply.mjs +9 -0
  188. package/scripts/upgrade-notice.mjs +14 -0
  189. package/scripts/verify-bundle.mjs +51 -0
  190. package/scripts/verify-channels.mjs +184 -0
  191. package/scripts/verify-model-catalog.mjs +104 -0
  192. package/scripts/verify-nightly-close-issue4.sh +31 -0
  193. package/scripts/version.mjs +40 -0
  194. package/scripts/wired-check.mjs +867 -0
  195. package/plugin/scripts/finalize-token-meter.mjs +0 -25
@@ -0,0 +1,128 @@
1
+ /* RuvNet Brain — How to use it (page two).
2
+ Two behaviors, both progressive enhancement — with JS off the page reads exactly as before:
3
+ 1. The same theme toggle as the console (same 'rbc-theme' key, same data-theme mechanism).
4
+ 2. Collapsible sections (owner, 2026-07-24: the page "gets too overwhelming as a wall of
5
+ text"). Every .depth.card collapses behind its own header; only the inventory — the
6
+ section that IS the page — starts open. Open state persists per browser; a #hash
7
+ deep-link always opens its target. */
8
+ (function () {
9
+ 'use strict';
10
+
11
+ /* ── theme toggle (unchanged) ─────────────────────────────────────────────── */
12
+ var KEY = 'rbc-theme';
13
+ var btn = document.getElementById('theme-toggle');
14
+ function applyTheme(t) {
15
+ document.documentElement.dataset.theme = t;
16
+ try { localStorage.setItem(KEY, t); } catch (e) { /* private mode is fine */ }
17
+ }
18
+ if (btn) {
19
+ btn.addEventListener('click', function () {
20
+ applyTheme(document.documentElement.dataset.theme === 'light' ? 'dark' : 'light');
21
+ });
22
+ }
23
+
24
+ /* ── collapsible sections ─────────────────────────────────────────────────── */
25
+ var OPEN_KEY = 'rbc-tips-open';
26
+ var DEFAULT_OPEN = ['inventory']; // the lead section IS the page; everything else waits
27
+ var sections = Array.prototype.slice.call(document.querySelectorAll('section.depth.card'));
28
+ if (!sections.length) return;
29
+
30
+ function savedOpen() {
31
+ try {
32
+ var raw = localStorage.getItem(OPEN_KEY);
33
+ return raw ? JSON.parse(raw) : null;
34
+ } catch (e) { return null; }
35
+ }
36
+ function persist() {
37
+ try {
38
+ var open = sections.filter(function (s) { return !s.classList.contains('is-collapsed'); })
39
+ .map(function (s) { return s.id; });
40
+ localStorage.setItem(OPEN_KEY, JSON.stringify(open));
41
+ } catch (e) { /* private mode is fine */ }
42
+ }
43
+
44
+ function setOpen(sec, open) {
45
+ sec.classList.toggle('is-collapsed', !open);
46
+ var head = sec.querySelector(':scope > .depth-head');
47
+ if (head) head.setAttribute('aria-expanded', open ? 'true' : 'false');
48
+ }
49
+
50
+ var open = savedOpen() || DEFAULT_OPEN;
51
+ sections.forEach(function (sec) {
52
+ var head = sec.querySelector(':scope > .depth-head');
53
+ if (!head || !sec.id) return;
54
+
55
+ // Wrap EVERYTHING after the header — several sections carry an art <figure> as a sibling of
56
+ // .depth-body, and a collapsed section that still shows its full-bleed art has not collapsed.
57
+ // grid-template-rows animates the height without measuring it (no reflow jank).
58
+ var dc = document.createElement('div'); dc.className = 'dc';
59
+ var dci = document.createElement('div'); dci.className = 'dci';
60
+ var after = [];
61
+ var walk = head.nextElementSibling;
62
+ while (walk) { after.push(walk); walk = walk.nextElementSibling; }
63
+ if (!after.length) return;
64
+ sec.appendChild(dc); dc.appendChild(dci);
65
+ after.forEach(function (n) { dci.appendChild(n); });
66
+
67
+ // The header is the disclosure control: chevron, ARIA, keyboard.
68
+ var chev = document.createElement('span');
69
+ chev.className = 'dc-chev';
70
+ chev.setAttribute('aria-hidden', 'true');
71
+ var svgNS = 'http://www.w3.org/2000/svg';
72
+ var csvg = document.createElementNS(svgNS, 'svg'); csvg.setAttribute('viewBox', '0 0 24 24');
73
+ var cpath = document.createElementNS(svgNS, 'path'); cpath.setAttribute('d', 'M6 9l6 6 6-6');
74
+ csvg.appendChild(cpath); chev.appendChild(csvg);
75
+ head.appendChild(chev);
76
+ head.setAttribute('role', 'button');
77
+ head.setAttribute('tabindex', '0');
78
+ head.setAttribute('aria-controls', sec.id + '-body');
79
+ dc.id = sec.id + '-body';
80
+ sec.classList.add('dc-ready');
81
+
82
+ function toggle() { setOpen(sec, sec.classList.contains('is-collapsed')); persist(); }
83
+ head.addEventListener('click', function (e) {
84
+ if (e.target.closest && e.target.closest('a, button')) return; // links in headers stay links
85
+ toggle();
86
+ });
87
+ head.addEventListener('keydown', function (e) {
88
+ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); }
89
+ });
90
+
91
+ setOpen(sec, open.indexOf(sec.id) !== -1);
92
+ });
93
+
94
+ // One small master switch, right-aligned above the first section.
95
+ var all = document.createElement('p');
96
+ all.className = 'dc-all';
97
+ var allBtn = document.createElement('button');
98
+ allBtn.type = 'button';
99
+ function anyCollapsed() {
100
+ return sections.some(function (s) { return s.classList.contains('is-collapsed'); });
101
+ }
102
+ function labelAll() { allBtn.textContent = anyCollapsed() ? 'expand all' : 'collapse all'; }
103
+ allBtn.addEventListener('click', function () {
104
+ var opening = anyCollapsed();
105
+ sections.forEach(function (s) { setOpen(s, opening); });
106
+ persist(); labelAll();
107
+ });
108
+ all.appendChild(allBtn);
109
+ sections[0].parentNode.insertBefore(all, sections[0]);
110
+ labelAll();
111
+ sections.forEach(function (s) {
112
+ var h = s.querySelector(':scope > .depth-head');
113
+ if (!h) return;
114
+ h.addEventListener('click', function () { setTimeout(labelAll, 0); });
115
+ h.addEventListener('keydown', function () { setTimeout(labelAll, 0); });
116
+ });
117
+
118
+ // A #hash deep-link must always land on an OPEN section — from the console's cards, the
119
+ // metaharness cross-reference, or a shared URL.
120
+ function openHashTarget() {
121
+ var id = (location.hash || '').replace(/^#/, '');
122
+ if (!id) return;
123
+ var sec = document.getElementById(id);
124
+ if (sec && sec.classList.contains('depth')) { setOpen(sec, true); persist(); labelAll(); }
125
+ }
126
+ window.addEventListener('hashchange', openHashTarget);
127
+ openHashTarget();
128
+ }());
@@ -0,0 +1,88 @@
1
+ # RuvNet-Brain 4.0 line — what's new (the major-release highlights)
2
+
3
+ Updated: 2026-08-01
4
+
5
+ > **Source of truth** for the `/whats-new` command and the first-run upgrade message. Curated, honest,
6
+ > major-only — not the point-release churn. If a claim here isn't true of the shipping build, it does not
7
+ > belong here. The self-measurement claims are deliberately hedged: they are *new and filling*, not
8
+ > *proven*.
9
+ >
10
+ > **VERSION STATUS:** the public release line is now 4.x. Publication does not erase the remaining
11
+ > acceptance obligations: the exact public artifact must still pass the fail-closed release contract
12
+ > through fresh Claude Code and Codex hosts. Anything not proven through that boundary is listed as a
13
+ > limitation, never converted into a capability claim.
14
+
15
+ **One line:** the 4.0 line is where the brain got **honest, legible, fast, and self-measuring** — and
16
+ it's landing now.
17
+
18
+ ## The big things
19
+
20
+ ### Release proof is fail-closed
21
+ The 4.0 release path now separates a clean candidate seal from a post-publication seal. Dirty
22
+ lineage, zero/skipped/todo tests, open issues, red or pending exact-SHA workflows, a missing
23
+ `ruvnet-brain` self-RVF store, weak query-deadline margin, missing independent graders,
24
+ host/artifact mismatches, and public-byte drift are release failures rather than warnings.
25
+ `npm run release:proof -- --status --quick` shows the current live blockers.
26
+
27
+ ### 1. The Console is the front door
28
+ Type `/rvbc` and your whole RuvNet stack is on one live local page: what's installed, what the AI has
29
+ actually learned from *your* projects (real memories + distilled lessons, drill-down to the verbatim
30
+ cards), which subscription pays for what, and one-click **reversible** fixes for anything stale. New in
31
+ 4.0:
32
+ - a plain-English **explainer on every card** (no more guessing what "trust & provenance" means),
33
+ - every suggestion carries its **blast radius** — *just this project* vs *every project · this machine*,
34
+ - **safe on/off checkboxes** that appear *only* where the undo is proven,
35
+ - a **terminal-first install** — the granular "here's exactly what I'll do, uncheck any of it" flow runs
36
+ in your terminal, where an `npx` user expects it.
37
+
38
+ ### 2. It will not lie about your machine
39
+ Every number is measured live from your setup. **"We couldn't check" never renders as "off."** One
40
+ project's state can never leak into another project's view (a real bug 4.0 fixed in the console itself).
41
+ Empty-first, honest-always.
42
+
43
+ ### 3. Fast — and it tells you when it's ready
44
+ The console and tips page paint in **well under a second** (measured, with a QE suite that runs every
45
+ time). On a first scan it shows a **countdown** and then says *"it's live — take a look at your page,"*
46
+ so you're never staring at a blank screen wondering if it hung.
47
+
48
+ ### 4. It measures itself now
49
+ The brain records when it offered help and whether you acted on it — so over time it can **prove** it's
50
+ improving instead of asserting it. **Honest caveat:** this instrumentation is *new* and has only just
51
+ started collecting. 4.0 is not a claim of "proven better in the field" — it is the release that makes
52
+ that proof *possible*, and the evidence accrues as you use it.
53
+
54
+ ### 5. It learns across your projects
55
+ A lesson proven in one project can be **promoted to your global brain** and applied everywhere — and it
56
+ now **survives an update** (tested against the real updater, not argued).
57
+
58
+ ### 6. Runs on your account, cheapest capable model
59
+ The QE suite and model routing use **your Claude account, not an API key**, at the least-powerful model
60
+ that does the job. Nothing bills silently.
61
+
62
+ ### 7. Claude Code and Codex share one active runtime
63
+ Both hosts are wired to the same Stable Spine generation: the MCP search shell, lifecycle hooks,
64
+ skills and update behavior advance as one versioned runtime instead of being installed as unrelated
65
+ copies.
66
+
67
+ ### 8. Source grounding is an RVF-native product surface
68
+ The Brain searches per-repository RuVector RVF stores, joins hits to their source passages, and
69
+ returns cited repository paths. Model memory is not accepted as evidence for rUv-stack claims.
70
+
71
+ ### 9. Quality and harness workflows are explicit
72
+ Agentic-QE is the testing fleet. Harness scoring evaluates the orchestration layer, and cost-aware
73
+ routing can select cheaper capable models when the required provider access is configured. These are
74
+ named workflows a user can request, not silent substitutes.
75
+
76
+ ## What 4.0 deliberately does NOT claim
77
+ Stated up front because overclaiming is the one thing this product cannot do:
78
+ - **Not** "proven X% better" — the outcome ledger is still filling (see #4).
79
+ - **Not** "fully proactive / anticipatory" — the brain still mostly speaks when you open the console or
80
+ ask; the in-session, unprompted surface is the next frontier, not a shipped 4.0 guarantee.
81
+ - **Not** independently graded ≥95 on the exact public artifact. A score is not a release substitute.
82
+ - **Not** fully accepted while any critical exact-artifact, host, retrieval, version-convergence or
83
+ recovery invariant is FAIL, UNKNOWN, skipped or mocked-only.
84
+
85
+ ## For upgraders
86
+ On the first real major-version transition, the installer/session experience presents the concise
87
+ highlights once. Run `npx ruvnet-brain --whats-new` at any time to read this full list again, or
88
+ `npx ruvnet-brain --what-changed` to inspect the exact machine footprint and undo path for each piece.
@@ -19,19 +19,50 @@ export function modelCacheReady(modelCache, model, revision = null) {
19
19
  ].every((file) => fs.existsSync(file));
20
20
  }
21
21
 
22
+ function acquireMaterializeLock(destination, timeoutMs = 30_000) {
23
+ const lock = `${destination}.materialize-lock`;
24
+ const started = Date.now();
25
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
26
+ while (true) {
27
+ try {
28
+ fs.mkdirSync(lock);
29
+ return () => fs.rmSync(lock, { recursive: true, force: true });
30
+ } catch (error) {
31
+ if (error?.code !== 'EEXIST') throw error;
32
+ try {
33
+ const ageMs = Date.now() - fs.statSync(lock).mtimeMs;
34
+ if (ageMs > timeoutMs) {
35
+ fs.rmSync(lock, { recursive: true, force: true });
36
+ continue;
37
+ }
38
+ } catch { /* another process released it between checks */ }
39
+ if (Date.now() - started >= timeoutMs) {
40
+ throw new Error(`timed out waiting to materialize model cache: ${destination}`);
41
+ }
42
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
43
+ }
44
+ }
45
+ }
46
+
22
47
  // Revision-pinned downloads live below <model>/<revision>/, while strict offline reads resolve
23
48
  // <model>/ directly. Promote only the exact pinned files into that canonical offline location.
24
49
  export function materializeModelRevision(modelCache, model, revision) {
25
50
  if (!revision || !modelCacheReady(modelCache, model, revision)) return false;
26
51
  const source = path.join(modelPath(modelCache, model), revision);
27
52
  const destination = modelPath(modelCache, model);
28
- for (const entry of fs.readdirSync(source)) {
29
- fs.cpSync(path.join(source, entry), path.join(destination, entry), {
30
- recursive: true,
31
- force: true,
32
- });
53
+ const release = acquireMaterializeLock(destination);
54
+ try {
55
+ if (modelCacheReady(modelCache, model)) return true;
56
+ for (const entry of fs.readdirSync(source)) {
57
+ fs.cpSync(path.join(source, entry), path.join(destination, entry), {
58
+ recursive: true,
59
+ force: true,
60
+ });
61
+ }
62
+ return modelCacheReady(modelCache, model);
63
+ } finally {
64
+ release();
33
65
  }
34
- return modelCacheReady(modelCache, model);
35
66
  }
36
67
 
37
68
  // The RVF sidecar is the source of truth for the query embedder. Only sidecars with a matching
@@ -0,0 +1,3 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MCowBQYDK2VwAyEAgse9TAtehXUvUfTrJFY2CCHiCbmelR8yCgS//sen5/w=
3
+ -----END PUBLIC KEY-----
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruvnet-brain",
3
- "version": "4.0.1",
3
+ "version": "4.0.4",
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": {
@@ -8,6 +8,9 @@
8
8
  },
9
9
  "scripts": {
10
10
  "test": "node plugin/test/run-tests.mjs",
11
+ "release:proof": "node scripts/release-proof.mjs",
12
+ "benchmark:brain50": "node scripts/brain-latency-50.mjs",
13
+ "benchmark:novice50": "node scripts/brain-novice-50.mjs",
11
14
  "version:check": "node scripts/sync-version.mjs --check",
12
15
  "claims:verify": "node scripts/claims-verify.mjs",
13
16
  "claims:fix": "node scripts/claims-verify.mjs --fix",
@@ -61,33 +64,16 @@
61
64
  "!plugin/scripts/.ruvnet-brain/",
62
65
  "!plugin/test/",
63
66
  "README.md",
67
+ "docs/RELEASE-NOTES-4.0.md",
64
68
  "LICENSE",
69
+ "console/",
65
70
  "config/model-router/",
71
+ "scripts/",
66
72
  "kb/verify-citation.mjs",
67
73
  "kb/zip-extract.mjs",
68
74
  "kb/brain-profile.mjs",
69
75
  "kb/model-requirements.mjs",
70
- "scripts/model-router-engine.mjs",
71
- "scripts/model-router-setup.mjs",
72
- "scripts/model-router-status.mjs",
73
- "scripts/model-router-outcome.mjs",
74
- "scripts/subscription-hosts.mjs",
75
- "scripts/dual-host-deliberation.mjs",
76
- "scripts/dual-host-suggest.mjs",
77
- "scripts/route-cheap.mjs",
78
- "scripts/dispatch-receipt.mjs",
79
- "scripts/metaharness-receipts.mjs",
80
- "scripts/codex-routed.sh",
81
- "scripts/metaharness-router.mjs",
82
- "scripts/no-silent-substitution.mjs",
83
- "scripts/user-settings.mjs",
84
- "scripts/selfcheck.mjs",
85
- "scripts/hook-registry.mjs",
86
- "scripts/install-scope.mjs",
87
- "scripts/upgrade-notice.mjs",
88
- "scripts/falsify.mjs",
89
- "scripts/nightly-watchdog.mjs",
90
- "scripts/job-heartbeat.sh"
76
+ "keys/ruvnet-brain-signing.pub.pem"
91
77
  ],
92
78
  "engines": {
93
79
  "node": ">=18"
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "ruvnet-brain",
3
+ "description": "Source-grounded RuvNet Brain integrations for Claude Code and Codex.",
3
4
  "owner": {
4
5
  "name": "Stuart Kerr"
5
6
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ruvnet-brain",
3
3
  "description": "RuvNet brain transplant for Claude Code — grounds every RuvNet decision in real source across 69 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.0.1",
4
+ "version": "4.0.4",
5
5
  "author": {
6
6
  "name": "Stuart Kerr"
7
7
  },
@@ -18,6 +18,5 @@
18
18
  "brain",
19
19
  "mcp",
20
20
  "claude-code"
21
- ],
22
- "updated": "2026-07-30"
21
+ ]
23
22
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruvnet-brain",
3
- "version": "4.0.1",
3
+ "version": "4.0.4",
4
4
  "description": "Source-grounded RuvNet knowledge, lifecycle enforcement, and learning for Codex.",
5
5
  "author": {
6
6
  "name": "Stuart Kerr"
@@ -7,8 +7,8 @@ updated: 2026-07-20
7
7
  correct the user's spelling.
8
8
 
9
9
  1. Say: "Opening it now; it scans live while you watch."
10
- 2. Locate `scripts/onboarding-console.mjs` in the current repository, then
11
- `~/Code/ruvnet-brain/scripts/onboarding-console.mjs`. Do not invent another path.
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
12
  3. Run `node <resolved-script> --serve --open` in the background.
13
13
  4. Give the URL immediately. Never promise a duration; the page reports its own progress.
14
14
 
@@ -8,8 +8,9 @@ their actual machine and lets them configure and (with consent) fix it.
8
8
 
9
9
  Do this:
10
10
 
11
- 1. **Find the repo.** Prefer `~/Code/ruvnet-brain`. If `$CLAUDE_PLUGIN_ROOT` is set, the repo may be
12
- its parent directory. Use whichever path contains `scripts/onboarding-console.mjs`.
11
+ 1. **Find the installed runtime.** Use
12
+ `${RUVNET_BRAIN_KB:-$HOME/.cache/ruvnet-brain/kb}/.console-runtime/scripts/onboarding-console.mjs`.
13
+ A current-repository copy is allowed only for an explicit developer checkout.
13
14
 
14
15
  2. **Start the server in the BACKGROUND** (it is a long-running process) so this turn keeps going, and
15
16
  open the browser:
@@ -26,10 +26,11 @@ opening it now and it will scan itself live in their browser. Something in the s
26
26
  Say it like a person, not a status bar. **Do not** promise 20 seconds, a minute, or any duration: the
27
27
  page carries its own timing now, and a number invented here is a number the page will contradict.
28
28
 
29
- ## 2. Find the repo
29
+ ## 2. Find the installed runtime
30
30
 
31
- Prefer `~/Code/ruvnet-brain`. If `$CLAUDE_PLUGIN_ROOT` is set, the repo may be its parent
32
- directory. Use whichever path actually contains `scripts/onboarding-console.mjs`.
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.
33
34
 
34
35
  ## 3. Start it in the BACKGROUND and open the browser
35
36
 
@@ -7,8 +7,8 @@ updated: 2026-07-20
7
7
  correct the user's spelling.
8
8
 
9
9
  1. Say: "Opening it now; it scans live while you watch."
10
- 2. Locate `scripts/onboarding-console.mjs` in the current repository, then
11
- `~/Code/ruvnet-brain/scripts/onboarding-console.mjs`. Do not invent another path.
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
12
  3. Run `node <resolved-script> --serve --open` in the background.
13
13
  4. Give the URL immediately. Never promise a duration; the page reports its own progress.
14
14
 
@@ -9,14 +9,15 @@ The user wants the headline story of the **major** release they're on — the 4.
9
9
  **not** the "3.9.x → 3.9.y" point-release churn. Deliver it warmly and honestly, then offer the Console.
10
10
 
11
11
  **First, ground — never recite this from memory (it drifts every release):**
12
- 1. Read the running version from `${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json`. State it honestly.
12
+ 1. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/whats-new.mjs"`. This reads the running version and curated
13
+ notes from the same immutable installed payload. If it exits nonzero, report that exact failure;
14
+ do not substitute a checkout, download, or another installed version. State the version honestly.
13
15
  **Do NOT claim "you're on 4.0"** unless the version literally starts with `4.` — per ADR-042 the
14
16
  number stays `3.9.x-dev` until the 4.0 line is field-verified. The honest framing is: *"these are the
15
17
  4.0-line enhancements, and you already have them — the version stamps to 4.0 once they're proven in
16
18
  real use."*
17
- 2. Read `docs/RELEASE-NOTES-4.0.md` (the curated highlights + its VERSION STATUS banner). Its content is
18
- the source of truth for what follows — summarize it, don't invent beside it, and carry its honest
19
- version framing.
19
+ 2. Treat the executable's notes as the source of truth — summarize them, don't invent beside them,
20
+ and carry their honest version framing.
20
21
 
21
22
  **Then tell them what the 4.0 line is — the honest headline (adapt to the notes file; do NOT overclaim):**
22
23
 
@@ -49,8 +50,7 @@ word — or type `/rvbc`."* If they say yes, follow `rvbc.md` in this same direc
49
50
  warm heads-up about the ~20s scan).
50
51
 
51
52
  **Honesty rules for this command (same as the product):**
52
- - If `docs/RELEASE-NOTES-4.0.md` is missing, say the notes aren't written yet and summarize from what
53
- you can verify — never fabricate a highlight.
53
+ - If the installed executable fails, report its failure and do not fabricate a highlight.
54
54
  - Never claim a metric ("40% better", "95/100") the release has not independently earned. The self-
55
55
  measurement is new and still filling; say so plainly.
56
56
  - This is the MAJOR story only. If the user wants the point-release detail, point them at the repo's
@@ -0,0 +1,88 @@
1
+ # RuvNet-Brain 4.0 line — what's new (the major-release highlights)
2
+
3
+ Updated: 2026-08-01
4
+
5
+ > **Source of truth** for the `/whats-new` command and the first-run upgrade message. Curated, honest,
6
+ > major-only — not the point-release churn. If a claim here isn't true of the shipping build, it does not
7
+ > belong here. The self-measurement claims are deliberately hedged: they are *new and filling*, not
8
+ > *proven*.
9
+ >
10
+ > **VERSION STATUS:** the public release line is now 4.x. Publication does not erase the remaining
11
+ > acceptance obligations: the exact public artifact must still pass the fail-closed release contract
12
+ > through fresh Claude Code and Codex hosts. Anything not proven through that boundary is listed as a
13
+ > limitation, never converted into a capability claim.
14
+
15
+ **One line:** the 4.0 line is where the brain got **honest, legible, fast, and self-measuring** — and
16
+ it's landing now.
17
+
18
+ ## The big things
19
+
20
+ ### Release proof is fail-closed
21
+ The 4.0 release path now separates a clean candidate seal from a post-publication seal. Dirty
22
+ lineage, zero/skipped/todo tests, open issues, red or pending exact-SHA workflows, a missing
23
+ `ruvnet-brain` self-RVF store, weak query-deadline margin, missing independent graders,
24
+ host/artifact mismatches, and public-byte drift are release failures rather than warnings.
25
+ `npm run release:proof -- --status --quick` shows the current live blockers.
26
+
27
+ ### 1. The Console is the front door
28
+ Type `/rvbc` and your whole RuvNet stack is on one live local page: what's installed, what the AI has
29
+ actually learned from *your* projects (real memories + distilled lessons, drill-down to the verbatim
30
+ cards), which subscription pays for what, and one-click **reversible** fixes for anything stale. New in
31
+ 4.0:
32
+ - a plain-English **explainer on every card** (no more guessing what "trust & provenance" means),
33
+ - every suggestion carries its **blast radius** — *just this project* vs *every project · this machine*,
34
+ - **safe on/off checkboxes** that appear *only* where the undo is proven,
35
+ - a **terminal-first install** — the granular "here's exactly what I'll do, uncheck any of it" flow runs
36
+ in your terminal, where an `npx` user expects it.
37
+
38
+ ### 2. It will not lie about your machine
39
+ Every number is measured live from your setup. **"We couldn't check" never renders as "off."** One
40
+ project's state can never leak into another project's view (a real bug 4.0 fixed in the console itself).
41
+ Empty-first, honest-always.
42
+
43
+ ### 3. Fast — and it tells you when it's ready
44
+ The console and tips page paint in **well under a second** (measured, with a QE suite that runs every
45
+ time). On a first scan it shows a **countdown** and then says *"it's live — take a look at your page,"*
46
+ so you're never staring at a blank screen wondering if it hung.
47
+
48
+ ### 4. It measures itself now
49
+ The brain records when it offered help and whether you acted on it — so over time it can **prove** it's
50
+ improving instead of asserting it. **Honest caveat:** this instrumentation is *new* and has only just
51
+ started collecting. 4.0 is not a claim of "proven better in the field" — it is the release that makes
52
+ that proof *possible*, and the evidence accrues as you use it.
53
+
54
+ ### 5. It learns across your projects
55
+ A lesson proven in one project can be **promoted to your global brain** and applied everywhere — and it
56
+ now **survives an update** (tested against the real updater, not argued).
57
+
58
+ ### 6. Runs on your account, cheapest capable model
59
+ The QE suite and model routing use **your Claude account, not an API key**, at the least-powerful model
60
+ that does the job. Nothing bills silently.
61
+
62
+ ### 7. Claude Code and Codex share one active runtime
63
+ Both hosts are wired to the same Stable Spine generation: the MCP search shell, lifecycle hooks,
64
+ skills and update behavior advance as one versioned runtime instead of being installed as unrelated
65
+ copies.
66
+
67
+ ### 8. Source grounding is an RVF-native product surface
68
+ The Brain searches per-repository RuVector RVF stores, joins hits to their source passages, and
69
+ returns cited repository paths. Model memory is not accepted as evidence for rUv-stack claims.
70
+
71
+ ### 9. Quality and harness workflows are explicit
72
+ Agentic-QE is the testing fleet. Harness scoring evaluates the orchestration layer, and cost-aware
73
+ routing can select cheaper capable models when the required provider access is configured. These are
74
+ named workflows a user can request, not silent substitutes.
75
+
76
+ ## What 4.0 deliberately does NOT claim
77
+ Stated up front because overclaiming is the one thing this product cannot do:
78
+ - **Not** "proven X% better" — the outcome ledger is still filling (see #4).
79
+ - **Not** "fully proactive / anticipatory" — the brain still mostly speaks when you open the console or
80
+ ask; the in-session, unprompted surface is the next frontier, not a shipped 4.0 guarantee.
81
+ - **Not** independently graded ≥95 on the exact public artifact. A score is not a release substitute.
82
+ - **Not** fully accepted while any critical exact-artifact, host, retrieval, version-convergence or
83
+ recovery invariant is FAIL, UNKNOWN, skipped or mocked-only.
84
+
85
+ ## For upgraders
86
+ On the first real major-version transition, the installer/session experience presents the concise
87
+ highlights once. Run `npx ruvnet-brain --whats-new` at any time to read this full list again, or
88
+ `npx ruvnet-brain --what-changed` to inspect the exact machine footprint and undo path for each piece.
@@ -1,6 +1,5 @@
1
1
  {
2
- "_note": "STABLE SPINE (ADR-023): every hook routes through hook-shim.mjs, which resolves the ACTIVE generation from ~/.cache/ruvnet-brain/active.json per invocation. This file is boot-frozen, so matcher, command, and dispatch-mode changes require restart classification. Advisory hooks keep `|| true` and can never block a turn. FOUR blocking hooks remain unguarded because their exit codes are their contract: route-dispatch, design-wall, unprompted-speech, and protect-state. Issue #48 demoted verify-interface to advisory-only: raw shell reconstruction may suggest the structured ruvnet_cli_help/ruvnet_cli_run boundary but can never authorize or deny execution. protect-state remains a blocking offBehavior:'run' consent guard. continuation-gate remains advisory with offBehavior:'run'.",
3
- "_platform": "posix",
2
+ "description": "POSIX Stable Spine (ADR-023): every hook routes through hook-shim.mjs, which resolves the active generation per invocation. Advisory hooks fail open; blocking hooks preserve their exit-code contract.",
4
3
  "hooks": {
5
4
  "SessionStart": [
6
5
  {
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
2
2
  import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
+ import { loadRuntimePreferences, runtimeChildEnv } from '../scripts/runtime-preferences.mjs';
5
6
 
6
7
  export const MANAGED_EXECUTABLES = Object.freeze([
7
8
  'ruflo',
@@ -142,9 +143,21 @@ function writeStamps(executable, argv, env) {
142
143
  }
143
144
  }
144
145
 
146
+ export function resolveManagedExecutable(executable, env = process.env) {
147
+ if (executable !== 'ruflo') return executable;
148
+ const home = env.HOME || os.homedir();
149
+ const canonical = path.join(home, '.npm-global', 'bin', 'ruflo');
150
+ try {
151
+ fs.accessSync(canonical, fs.constants.X_OK);
152
+ return canonical;
153
+ } catch {
154
+ return executable;
155
+ }
156
+ }
157
+
145
158
  function execute(executable, argv, env) {
146
159
  return new Promise((resolve) => {
147
- const child = spawn(executable, argv, {
160
+ const child = spawn(resolveManagedExecutable(executable, env), argv, {
148
161
  env,
149
162
  shell: false,
150
163
  stdio: ['ignore', 'pipe', 'pipe'],
@@ -186,8 +199,9 @@ function execute(executable, argv, env) {
186
199
 
187
200
  function resultOf(executable, argv, result) {
188
201
  const output = [result.stdout, result.stderr].filter(Boolean).join(result.stdout && result.stderr ? '\n' : '');
189
- if (result.error || result.code !== 0) {
190
- const reason = result.error || `exit ${result.code}`;
202
+ const contradictoryFailure = /(?:^|\n)\s*(?:❌|\[ERROR\])|invalid pragma command|key not found/i.test(output);
203
+ if (result.error || result.code !== 0 || contradictoryFailure) {
204
+ const reason = result.error || (contradictoryFailure ? 'fatal output despite exit 0' : `exit ${result.code}`);
191
205
  return {
192
206
  content: [{ type: 'text', text: output || `${executable} ${argv.join(' ')} failed: ${reason}` }],
193
207
  isError: true,
@@ -220,7 +234,36 @@ export async function callManagedCli(toolName, args, env = process.env) {
220
234
  isError: true,
221
235
  };
222
236
  }
223
- return resultOf(executable, argv, await execute(executable, argv, env));
237
+ const policy = loadRuntimePreferences({ env, cwd: env.RUVNET_BRAIN_PROJECT_DIR || process.cwd() });
238
+ if (executable === 'agentic-flow' && policy.values.routing !== 'auto') {
239
+ return {
240
+ content: [{
241
+ type: 'text',
242
+ text: policy.values.routing === 'off'
243
+ ? 'Token-smart routing is off in RuvNet Brain Console; agentic-flow was not started.'
244
+ : 'Token-smart routing has not been enabled in RuvNet Brain Console; agentic-flow was not started.',
245
+ }],
246
+ isError: true,
247
+ };
248
+ }
249
+ const isFleetMutation = executable === 'agentic-qe'
250
+ && argv[0] === 'fleet'
251
+ && ['init', 'spawn', 'run'].includes(argv[1]);
252
+ if (isFleetMutation && policy.values.qeFleet !== true) {
253
+ return {
254
+ content: [{
255
+ type: 'text',
256
+ text: policy.values.qeFleet === false
257
+ ? 'The Agentic-QE fleet is off in RuvNet Brain Console; no QE agents were started.'
258
+ : 'The Agentic-QE fleet has not been enabled in RuvNet Brain Console; no QE agents were started.',
259
+ }],
260
+ isError: true,
261
+ };
262
+ }
263
+ const childEnv = (executable === 'agentic-flow' || executable === 'agentic-qe')
264
+ ? runtimeChildEnv({ env, cwd: env.RUVNET_BRAIN_PROJECT_DIR || process.cwd() })
265
+ : env;
266
+ return resultOf(executable, argv, await execute(executable, argv, childEnv));
224
267
  }
225
268
 
226
269
  return {