ruvnet-brain 4.0.1 → 4.0.2
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/.claude-plugin/marketplace.json +1 -0
- package/README.md +4 -4
- package/bin/install.mjs +100 -5
- package/console/CONTRACT.md +172 -0
- package/console/activity.js +753 -0
- package/console/app.js +4189 -0
- package/console/architecture.html +1221 -0
- package/console/assets/depth-1.webp +0 -0
- package/console/assets/depth-2.webp +0 -0
- package/console/assets/depth-3.webp +0 -0
- package/console/assets/harness-vs-plain.svg +259 -0
- package/console/assets/hero.webp +0 -0
- package/console/assets/memory.webp +0 -0
- package/console/assets/metaharness.svg +247 -0
- package/console/index.html +777 -0
- package/console/install-architecture.html +162 -0
- package/console/install-mockup.html +543 -0
- package/console/style.css +2144 -0
- package/console/tips.css +926 -0
- package/console/tips.html +858 -0
- package/console/tips.js +128 -0
- package/docs/RELEASE-NOTES-4.0.md +88 -0
- package/kb/model-requirements.mjs +37 -6
- package/keys/ruvnet-brain-signing.pub.pem +3 -0
- package/package.json +8 -22
- package/plugin/.claude-plugin/marketplace.json +1 -0
- package/plugin/.claude-plugin/plugin.json +2 -3
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/commands/brain-console.md +2 -2
- package/plugin/commands/configure.md +3 -2
- package/plugin/commands/rvbc.md +4 -3
- package/plugin/commands/rvcb.md +2 -2
- package/plugin/hooks/hooks.json +1 -2
- package/plugin/mcp/managed-cli-interface.mjs +47 -4
- package/plugin/mcp/server.mjs +21 -0
- package/plugin/scripts/detach.mjs +14 -0
- package/plugin/scripts/first-session-worker.mjs +38 -0
- package/plugin/scripts/ground-ruvnet.sh +16 -6
- package/plugin/scripts/hook-shim.mjs +7 -7
- package/plugin/scripts/learn-capture.sh +22 -3
- package/plugin/scripts/learn-flush.mjs +21 -4
- package/plugin/scripts/runtime-preferences.mjs +269 -0
- package/plugin/scripts/session-start-core.mjs +477 -0
- package/plugin/scripts/session-start.sh +3 -858
- package/plugin/skills/brain-console/SKILL.md +4 -2
- package/plugin/skills/release-proof/SKILL.md +81 -0
- package/plugin/skills/release-proof/agents/openai.yaml +4 -0
- package/plugin/skills/release-proof/references/receipt-contract.md +38 -0
- package/plugin/skills/release-proof/scripts/release-proof.mjs +210 -0
- package/plugin/skills/ruvnet-brain/PLAYBOOK.md +5 -1
- package/plugin/skills/rvbc/SKILL.md +9 -6
- package/scripts/adr-backfill.mjs +107 -0
- package/scripts/advocacy-outcomes.mjs +808 -0
- package/scripts/agentdb-context.mjs +216 -0
- package/scripts/agentdb-fleet-doctor.mjs +101 -0
- package/scripts/ascii-drift.mjs +236 -0
- package/scripts/behavioral-l1-l4.mjs +210 -0
- package/scripts/brain-capability-check.mjs +72 -0
- package/scripts/brain-grade-groundtruth.mjs +100 -0
- package/scripts/brain-latency-50.mjs +227 -0
- package/scripts/brain-novice-50.mjs +189 -0
- package/scripts/brain-stamp.mjs +94 -0
- package/scripts/brain-state.mjs +212 -0
- package/scripts/build-bundle.mjs +522 -0
- package/scripts/build-concepts.mjs +132 -0
- package/scripts/build-l2.mjs +71 -0
- package/scripts/build-primer.mjs +73 -0
- package/scripts/build-symbols.mjs +68 -0
- package/scripts/calibrate-router.mjs +97 -0
- package/scripts/capability-audit.mjs +321 -0
- package/scripts/capability-registry.mjs +876 -0
- package/scripts/check-indexation.mjs +108 -0
- package/scripts/check-legibility.mjs +189 -0
- package/scripts/ci/build-fixture-kb.mjs +67 -0
- package/scripts/ci/learning-replay-codex-adapter.mjs +62 -0
- package/scripts/ci/learning-replay-recorder.mjs +59 -0
- package/scripts/ci/mutate-hook-timeout.mjs +70 -0
- package/scripts/ci/stranger-fixture-stage.mjs +17 -0
- package/scripts/ci/stranger-scenario.mjs +228 -0
- package/scripts/ci/stranger-timeout.mjs +25 -0
- package/scripts/ci-verdict.mjs +29 -0
- package/scripts/claims-verify.mjs +710 -0
- package/scripts/clear-claude-tmp.sh +31 -0
- package/scripts/console-engine.mjs +434 -0
- package/scripts/console-engine.test.mjs +125 -0
- package/scripts/corpus-qa.mjs +250 -0
- package/scripts/correction-detect-embed.mjs +346 -0
- package/scripts/correction-detect-measure.mjs +270 -0
- package/scripts/correction-detect.mjs +686 -0
- package/scripts/count-chunks.mjs +54 -0
- package/scripts/described-questions.json +30 -0
- package/scripts/design-grade.mjs +58 -0
- package/scripts/dev-plugin-link.sh +105 -0
- package/scripts/distill-project.mjs +200 -0
- package/scripts/doc-currency.mjs +801 -0
- package/scripts/eval-brain.mjs +244 -0
- package/scripts/fix-metaharness-memretrieve.mjs +121 -0
- package/scripts/full-hints.mjs +87 -0
- package/scripts/gate.sh +39 -0
- package/scripts/gates.mjs +146 -0
- package/scripts/gen-console-images.mjs +54 -0
- package/scripts/gen-images.mjs +47 -0
- package/scripts/git-clone-refresh.mjs +52 -0
- package/scripts/git-hooks/pre-push +126 -0
- package/scripts/goal-match.mjs +398 -0
- package/scripts/goldie-research.mjs +223 -0
- package/scripts/goldie-weekly.sh +67 -0
- package/scripts/health-repair.mjs +250 -0
- package/scripts/helix-scenario-questions.json +10 -0
- package/scripts/ingest-gists.mjs +230 -0
- package/scripts/ingest-meeting.mjs +115 -0
- package/scripts/ingest-repo.mjs +79 -0
- package/scripts/install-npx-witness.sh +49 -0
- package/scripts/issue-fix.mjs +639 -0
- package/scripts/issue-watch.mjs +276 -0
- package/scripts/issue4-close-note.md +31 -0
- package/scripts/key-canary.mjs +91 -0
- package/scripts/latency-to-surface.mjs +233 -0
- package/scripts/learning-enable.mjs +380 -0
- package/scripts/learning-replay.mjs +1570 -0
- package/scripts/learnings.mjs +62 -0
- package/scripts/lesson-gate.mjs +680 -0
- package/scripts/lesson-lifecycle.mjs +449 -0
- package/scripts/lesson-promote.mjs +262 -0
- package/scripts/lesson-ratify.mjs +98 -0
- package/scripts/lesson-seed.mjs +252 -0
- package/scripts/lesson-store.mjs +447 -0
- package/scripts/loop-checkpoint.mjs +86 -0
- package/scripts/memdb-health.sh +14 -0
- package/scripts/memory-doctor.mjs +271 -0
- package/scripts/model-catalog.mjs +79 -0
- package/scripts/nightly-controller.mjs +66 -0
- package/scripts/nightly-gists.sh +72 -0
- package/scripts/nightly-wrapper.sh +180 -0
- package/scripts/notify.sh +12 -0
- package/scripts/npx-witness.sh +56 -0
- package/scripts/onboarding-console.mjs +2749 -0
- package/scripts/private-fence.mjs +69 -0
- package/scripts/proactivity-metrics.mjs +118 -0
- package/scripts/proof-questions.json +56 -0
- package/scripts/prove.mjs +95 -0
- package/scripts/proxy/claude-proxied.sh +57 -0
- package/scripts/proxy/proxy-revert.sh +59 -0
- package/scripts/proxy/proxy-up.sh +60 -0
- package/scripts/proxy/proxy-verify.mjs +142 -0
- package/scripts/published-surface-probe.mjs +241 -0
- package/scripts/qe/card-lane-gate.mjs +162 -0
- package/scripts/qe/session-start-gate.mjs +229 -0
- package/scripts/qe/ux-suite.mjs +323 -0
- package/scripts/reconcile-project.mjs +0 -0
- package/scripts/record-lesson.mjs +113 -0
- package/scripts/refresh-model-catalog.mjs +99 -0
- package/scripts/release-proof.mjs +9 -0
- package/scripts/release-vector.mjs +281 -0
- package/scripts/release.mjs +395 -0
- package/scripts/remedy-registry.mjs +247 -0
- package/scripts/rerank-cap-eval.mjs +265 -0
- package/scripts/rerank-cap-warm-ab.mjs +129 -0
- package/scripts/route-cheap.mjs +20 -15
- package/scripts/router-utilization.mjs +182 -0
- package/scripts/routing-flywheel.mjs +596 -0
- package/scripts/rvf-generation.mjs +104 -0
- package/scripts/rvf-index-audit.mjs +138 -0
- package/scripts/self-update.mjs +508 -0
- package/scripts/selfcheck.mjs +7 -1
- package/scripts/sign-bundle.mjs +69 -0
- package/scripts/signal-watch.mjs +171 -0
- package/scripts/stack-sync.mjs +469 -0
- package/scripts/stamp-existing-rvf-generations.mjs +53 -0
- package/scripts/stamp-sweep.mjs +144 -0
- package/scripts/status-honesty.mjs +102 -0
- package/scripts/sync-version.mjs +217 -0
- package/scripts/token-report.mjs +102 -0
- package/scripts/top100-benchmark.mjs +479 -0
- package/scripts/top100-corpus.mjs +112 -0
- package/scripts/top100-semantic-assertions.mjs +449 -0
- package/scripts/update-apply.mjs +9 -0
- package/scripts/upgrade-notice.mjs +14 -0
- package/scripts/verify-bundle.mjs +51 -0
- package/scripts/verify-channels.mjs +184 -0
- package/scripts/verify-model-catalog.mjs +104 -0
- package/scripts/verify-nightly-close-issue4.sh +31 -0
- package/scripts/version.mjs +40 -0
- package/scripts/wired-check.mjs +864 -0
- package/plugin/scripts/finalize-token-meter.mjs +0 -25
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# 🧠 RuvNet Brain
|
|
6
6
|
|
|
7
|
-
### 🧠 RuvNet Brain — [](https://github.com/stuinfla/ruvnet-brain/blob/main/plugin/.claude-plugin/plugin.json)
|
|
8
8
|
|
|
9
9
|
**A portable, source-grounded brain over Reuven Cohen's (rUv's) RuvNet stack — delivered as a Claude Code plugin that makes Claude _use_ the stack instead of fighting it.**
|
|
10
10
|
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
[](https://isovision.ai/ruvnet-brain/)
|
|
31
31
|
[](LICENSE)
|
|
32
32
|
[](#testing--proof)
|
|
33
|
-
[](#testing--proof)
|
|
34
34
|
|
|
35
35
|
> **One Brain generation everywhere.** npm, the GitHub tag/release, bundle manifests, source metadata, and checksum-bound RVF generations must share the same product version. Headline claims are regenerated and checked by the claims ledger (`scripts/claims-verify.mjs`); other numbers below are hand-stamped and dated:
|
|
36
36
|
> - **`plugin`** (badge above) — the Claude Code plugin itself: SKILL.md, the grounding hooks, the MCP server. Read live from [`plugin/.claude-plugin/plugin.json`](plugin/.claude-plugin/plugin.json). Updates often — this is where behavior fixes land.
|
|
@@ -485,7 +485,7 @@ node plugin/test/run-tests.mjs # full plugin QA over real JSO
|
|
|
485
485
|
| **L4 "orchestrate"** | **downgraded — measures speech, not obedience** | L4 asserts the hook's own injected prose contains required words (`must: ['take the wheel','SPARC','swarm',…]`). That proves **the brain spoke**. It cannot fail when the advice is read and ignored — which is the failure this product exists to prevent. Counterfactual replay against a brain-off control (ADR-058 §D4) is what will earn this row back |
|
|
486
486
|
| **Plugin QA** | **60 / 60** | manifests, hook firing, MCP `initialize`/`tools/list`, capability battery |
|
|
487
487
|
| **Clean-room install** | **3 / 3** | download the published bundle fresh → unzip → query → grounded, cited answers |
|
|
488
|
-
| **Unit tests** | **2,327 passing, 169 todo** ·
|
|
488
|
+
| **Unit tests** | **2,327 passing, 169 todo** · 34% of ALL source covered | `npm run test:cov` regenerates both — the coverage floor fails CI if it slips (`claims:verify` re-derives the %, it is not a hand-typed badge). 34% is the honest number over every shipped file; the previous "75%" measured a hand-picked 8-file subset |
|
|
489
489
|
| **Grounding proof** | `npx ruvnet-brain --doctor` | asks a real question, then checks the cited path really exists in the on-disk store; a citation that doesn't resolve is reported as **NOT grounded** |
|
|
490
490
|
| **Held-out eval** | **grounded 100/100** · routed 63/80 | `npm run eval` — 120 frozen, hash-pinned questions across 5 strata, never used for tuning, graded on ground truth, never by a model |
|
|
491
491
|
|
|
@@ -522,7 +522,7 @@ node forge-ask-all.mjs --dir . --q "How does RuVector implement HNSW vector sear
|
|
|
522
522
|
|
|
523
523
|
This project versions in the open (see the live badge up top for the exact plugin version; the downloadable knowledge bundle is a separate track) — we don't claim “done,” “complete,” or “zero hallucinations.” Where it stands:
|
|
524
524
|
|
|
525
|
-
- ✅ **The grounding brain is real and proven** —
|
|
525
|
+
- ✅ **The grounding brain is real and proven** — 63 public stores · 153,369 public source chunks (70 built stores incl. private), dual embeddings, cross-encoder rerank, plugin (MCP tool + enforcement hook + skill), all re-runnable.
|
|
526
526
|
- ✅ **Code-level depth** — the code-rich repos are indexed to full function bodies; “how is it implemented?” returns the implementation. Verified in the shipped bundle (clean-room 3/3).
|
|
527
527
|
- ✅ **Routing holds** — named 47/48, described 26/28, scenario 7/8; behavioral L1–L3 all pass (**L4 downgraded — it measures that the brain spoke, not that anything listened**); private stores fenced out of the public bundle (zero-leak verified).
|
|
528
528
|
- ⚠️ **Two routing residuals** (above) — surfaced, not hidden.
|
package/bin/install.mjs
CHANGED
|
@@ -95,6 +95,7 @@ const FLAG_ENABLE_SPEND_GUARD = argv.includes('--enable-spend-guard');
|
|
|
95
95
|
const FLAG_DISABLE_SPEND_GUARD = argv.includes('--disable-spend-guard'); // the missing undo
|
|
96
96
|
const FLAG_UNINSTALL = argv.includes('--uninstall'); // reverse everything, in one command
|
|
97
97
|
const FLAG_WHAT_CHANGED = argv.includes('--what-changed'); // show our footprint on this machine
|
|
98
|
+
const FLAG_WHATS_NEW = argv.includes('--whats-new'); // show curated major-release highlights
|
|
98
99
|
// ── onboarding-experience flags (all optional; every offer is safe to decline) ──
|
|
99
100
|
const FLAG_YES = argv.includes('--yes') || argv.includes('-y'); // accept every optional offer non-interactively
|
|
100
101
|
const FLAG_PLAN = argv.includes('--plan') || argv.includes('--dry-run'); // show the interactive checklist, then exit — install NOTHING
|
|
@@ -598,6 +599,50 @@ function installReader(cacheDir) {
|
|
|
598
599
|
ok('reader installed');
|
|
599
600
|
}
|
|
600
601
|
|
|
602
|
+
// The Console must survive the temporary npm/npx extraction directory. Before 4.0.2 its skills
|
|
603
|
+
// searched a developer checkout, so `/rvbc` worked for maintainers and failed for clean users even
|
|
604
|
+
// though installation was green. Persist the exact runtime shipped by the installer underneath the
|
|
605
|
+
// installed KB: Node then resolves optional reader dependencies from `<cacheDir>/node_modules`, and
|
|
606
|
+
// both Claude Code and Codex get one stable path with no source clone or second package install.
|
|
607
|
+
export function installConsoleRuntime(cacheDir, sourceRoot = REPO_ROOT) {
|
|
608
|
+
const runtime = path.join(cacheDir, '.console-runtime');
|
|
609
|
+
const staged = `${runtime}.tmp-${process.pid}`;
|
|
610
|
+
const prior = `${runtime}.prior-${process.pid}`;
|
|
611
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
612
|
+
fs.rmSync(prior, { recursive: true, force: true });
|
|
613
|
+
fs.mkdirSync(staged, { recursive: true, mode: 0o700 });
|
|
614
|
+
|
|
615
|
+
const required = [
|
|
616
|
+
['console', 'console'],
|
|
617
|
+
['scripts', 'scripts'],
|
|
618
|
+
['plugin/scripts', 'plugin/scripts'],
|
|
619
|
+
['kb/brain-profile.mjs', 'kb/brain-profile.mjs'],
|
|
620
|
+
['bin/install.mjs', 'bin/install.mjs'],
|
|
621
|
+
['package.json', 'package.json'],
|
|
622
|
+
];
|
|
623
|
+
for (const [from, to] of required) {
|
|
624
|
+
const source = path.join(sourceRoot, from);
|
|
625
|
+
if (!fs.existsSync(source)) {
|
|
626
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
627
|
+
throw new Error(`console runtime is incomplete: missing ${from}`);
|
|
628
|
+
}
|
|
629
|
+
const target = path.join(staged, to);
|
|
630
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
631
|
+
fs.cpSync(source, target, { recursive: true, force: true, preserveTimestamps: true });
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (fs.existsSync(runtime)) fs.renameSync(runtime, prior);
|
|
635
|
+
try {
|
|
636
|
+
fs.renameSync(staged, runtime);
|
|
637
|
+
fs.rmSync(prior, { recursive: true, force: true });
|
|
638
|
+
} catch (error) {
|
|
639
|
+
if (fs.existsSync(prior) && !fs.existsSync(runtime)) fs.renameSync(prior, runtime);
|
|
640
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
641
|
+
throw error;
|
|
642
|
+
}
|
|
643
|
+
return path.join(runtime, 'scripts', 'onboarding-console.mjs');
|
|
644
|
+
}
|
|
645
|
+
|
|
601
646
|
// ── plugin presence: the ONLY reliable proof the slash commands will exist ───────────────────────
|
|
602
647
|
// Reported by a user on 3.4.21-dev whose install was otherwise healthy: `/rvbc` returned
|
|
603
648
|
// "Unknown command: /rvbc. Did you mean /rvf?". search_ruvnet worked, the KB was current — the
|
|
@@ -856,6 +901,7 @@ export function wireCodexHost({
|
|
|
856
901
|
serverDir = codexServerDir(),
|
|
857
902
|
source = path.join(__dirname, '..', 'plugin', 'mcp', 'server.mjs'),
|
|
858
903
|
hookWrapperSource = path.join(__dirname, '..', 'plugin', 'scripts', 'codex-hook-wrapper.mjs'),
|
|
904
|
+
runtimePreferencesSource = path.join(__dirname, '..', 'plugin', 'scripts', 'runtime-preferences.mjs'),
|
|
859
905
|
hookWrapperPath = codexHookWrapperPath(codexDir),
|
|
860
906
|
announce = true,
|
|
861
907
|
} = {}) {
|
|
@@ -876,14 +922,21 @@ export function wireCodexHost({
|
|
|
876
922
|
if (announce) warn('MCP structured-interface module missing from this bundle — Codex left untouched (non-fatal)');
|
|
877
923
|
return { host: true, action: 'no-source' };
|
|
878
924
|
}
|
|
925
|
+
if (!fs.existsSync(runtimePreferencesSource)) {
|
|
926
|
+
if (announce) warn('MCP runtime-preferences module missing from this bundle — Codex left untouched (non-fatal)');
|
|
927
|
+
return { host: true, action: 'no-source' };
|
|
928
|
+
}
|
|
879
929
|
const serverPath = path.join(serverDir, 'server.mjs');
|
|
880
930
|
const managedCliPath = path.join(serverDir, 'managed-cli-interface.mjs');
|
|
931
|
+
const runtimePreferencesPath = path.join(path.dirname(serverDir), 'scripts', 'runtime-preferences.mjs');
|
|
881
932
|
fs.mkdirSync(serverDir, { recursive: true });
|
|
882
933
|
// Write-beside-then-rename, both here and for the config below (issue #43): an interrupted plain
|
|
883
934
|
// copy leaves a TORN server.mjs at the exact path a prior install's config already points at, so
|
|
884
935
|
// Codex spawns half a file. rename() over the target is atomic; a failure leaves the old bytes.
|
|
885
936
|
// Copy the dependency first. If the later server swap fails, the previously registered server
|
|
886
937
|
// remains byte-intact and continues to import a backward-compatible module at the same path.
|
|
938
|
+
fs.mkdirSync(path.dirname(runtimePreferencesPath), { recursive: true });
|
|
939
|
+
atomicReplace(runtimePreferencesPath, (tmp) => fs.copyFileSync(runtimePreferencesSource, tmp));
|
|
887
940
|
atomicReplace(managedCliPath, (tmp) => fs.copyFileSync(managedCliSource, tmp));
|
|
888
941
|
atomicReplace(serverPath, (tmp) => fs.copyFileSync(source, tmp));
|
|
889
942
|
if (fs.existsSync(hookWrapperSource)) {
|
|
@@ -899,7 +952,7 @@ export function wireCodexHost({
|
|
|
899
952
|
ok('Codex already declares ruvnet-brain in your own config — left exactly as you wrote it');
|
|
900
953
|
info(` to hand it to us instead, delete that ${c.bold('[mcp_servers.ruvnet-brain]')} block and re-run this installer`);
|
|
901
954
|
}
|
|
902
|
-
return { host: true, action, serverPath, managedCliPath, hookWrapperPath };
|
|
955
|
+
return { host: true, action, serverPath, managedCliPath, runtimePreferencesPath, hookWrapperPath };
|
|
903
956
|
}
|
|
904
957
|
if (text !== before) {
|
|
905
958
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
@@ -910,7 +963,7 @@ export function wireCodexHost({
|
|
|
910
963
|
info(` server: ${serverPath} ${c.dim('(persistent copy — the npx dir vanishes)')}`);
|
|
911
964
|
info(` ${c.dim('only our marked block is written; every other section is byte-preserved')}`);
|
|
912
965
|
}
|
|
913
|
-
return { host: true, action, serverPath, managedCliPath, hookWrapperPath, changed: text !== before };
|
|
966
|
+
return { host: true, action, serverPath, managedCliPath, runtimePreferencesPath, hookWrapperPath, changed: text !== before };
|
|
914
967
|
}
|
|
915
968
|
|
|
916
969
|
const CODEX_PLUGIN_ID = 'ruvnet-brain@ruvnet-brain';
|
|
@@ -1553,7 +1606,9 @@ async function doctor() {
|
|
|
1553
1606
|
if (env.ruflo) {
|
|
1554
1607
|
rufloOperational = probeRufloOperationalHealth();
|
|
1555
1608
|
if (rufloOperational.healthy) {
|
|
1556
|
-
ok(
|
|
1609
|
+
ok(rufloOperational.directMode
|
|
1610
|
+
? 'Ruflo direct mode ready — daemon/swarm is stopped by design; AgentDB remains CLI-backed'
|
|
1611
|
+
: 'Ruflo operational — runtime, memory, and learning signals agree');
|
|
1557
1612
|
} else {
|
|
1558
1613
|
warn('Ruflo CLI is present, but operational learning is DEGRADED — availability is not enforcement.');
|
|
1559
1614
|
if (rufloOperational.stopped) warn(' live status reports STOPPED / swarm not running');
|
|
@@ -2421,6 +2476,18 @@ function printFootprint({ heading = 'What this put on your machine' } = {}) {
|
|
|
2421
2476
|
return items;
|
|
2422
2477
|
}
|
|
2423
2478
|
|
|
2479
|
+
function showWhatsNew() {
|
|
2480
|
+
const notes = path.join(REPO_ROOT, 'docs', 'RELEASE-NOTES-4.0.md');
|
|
2481
|
+
if (!fs.existsSync(notes)) {
|
|
2482
|
+
console.error('RuvNet Brain release notes are missing from this artifact.');
|
|
2483
|
+
process.exitCode = 1;
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
const text = fs.readFileSync(notes, 'utf8');
|
|
2487
|
+
process.stdout.write(text);
|
|
2488
|
+
if (!text.endsWith('\n')) process.stdout.write('\n');
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2424
2491
|
/**
|
|
2425
2492
|
* Surgically remove ONLY our block from CLAUDE.md, leaving every other line exactly as it was.
|
|
2426
2493
|
* Backed up and written atomically, same as when it was added — taking something away is at least
|
|
@@ -3070,8 +3137,15 @@ export function classifyRufloOperationalHealth({ status = '', memory = '', metri
|
|
|
3070
3137
|
&& /Total Routes\s*[|:]?\s*0\b/i.test(metrics)
|
|
3071
3138
|
&& /Total Executed\s*[|:]?\s*0\b/i.test(metrics);
|
|
3072
3139
|
const memoryContradiction = statusSaysNoMemory && memoryEntries > 0;
|
|
3140
|
+
// Brain 4 is explicitly zero-daemon: `ruflo memory store/search` open the per-project
|
|
3141
|
+
// AgentDB directly. A stopped orchestration daemon therefore makes daemon-owned status
|
|
3142
|
+
// and metrics non-authoritative; treating that intentional state as degraded made Doctor
|
|
3143
|
+
// exit 1 immediately after proving source-grounded retrieval worked. Keep the strict
|
|
3144
|
+
// contradiction/learning checks when a daemon is actually running.
|
|
3145
|
+
const directMode = stopped;
|
|
3073
3146
|
return {
|
|
3074
|
-
healthy:
|
|
3147
|
+
healthy: directMode || (!memoryContradiction && !zeroLearning),
|
|
3148
|
+
directMode,
|
|
3075
3149
|
stopped,
|
|
3076
3150
|
zeroLearning,
|
|
3077
3151
|
memoryContradiction,
|
|
@@ -3653,6 +3727,7 @@ Usage:
|
|
|
3653
3727
|
npx ruvnet-brain --disable-nightly Remove the nightly schedule (safe to run any time)
|
|
3654
3728
|
npx ruvnet-brain --what-changed Show exactly what RuvNet Brain has put on this machine,
|
|
3655
3729
|
with the undo command for each piece
|
|
3730
|
+
npx ruvnet-brain --whats-new Show the curated v3 → v4 capabilities and honest limits
|
|
3656
3731
|
npx ruvnet-brain --uninstall Remove all of it (bundle, LaunchAgents, and our CLAUDE.md
|
|
3657
3732
|
block only — your own CLAUDE.md content is preserved and backed up)
|
|
3658
3733
|
npx ruvnet-brain --enable-spend-guard Install the hourly runaway-agent spend alarm (alert-only)
|
|
@@ -3692,7 +3767,17 @@ It is safe to re-run at any time. After installing, restart Claude Code so the g
|
|
|
3692
3767
|
|
|
3693
3768
|
// ── main ─────────────────────────────────────────────────────────────────────────────────────────
|
|
3694
3769
|
(async () => {
|
|
3695
|
-
|
|
3770
|
+
// Importing an executable module for its exported policy helpers must never install software.
|
|
3771
|
+
// The old contract required every caller to remember RUVNET_BRAIN_IMPORT_ONLY=1; one missed flag
|
|
3772
|
+
// in a unit test ran a real install against the maintainer's HOME. Direct argv identity is the
|
|
3773
|
+
// authority boundary. The old IMPORT_ONLY flag may still be present in a long-lived test worker;
|
|
3774
|
+
// it must never suppress a genuinely direct CLI execution.
|
|
3775
|
+
const canonical = (value) => {
|
|
3776
|
+
try { return fs.realpathSync(value); } catch { return path.resolve(value); }
|
|
3777
|
+
};
|
|
3778
|
+
const invokedDirectly = Boolean(process.argv[1])
|
|
3779
|
+
&& canonical(process.argv[1]) === canonical(fileURLToPath(import.meta.url));
|
|
3780
|
+
if (!invokedDirectly) return;
|
|
3696
3781
|
if (FLAG_HELP) return showHelp();
|
|
3697
3782
|
// `process.exitCode`, not `return` — doctor()'s verdict is the whole point of running it in a
|
|
3698
3783
|
// script. A bare `return await doctor()` discarded the number, which is how "! Needs attention"
|
|
@@ -3711,6 +3796,7 @@ It is safe to re-run at any time. After installing, restart Claude Code so the g
|
|
|
3711
3796
|
if (FLAG_DISABLE_SPEND_GUARD) { disableSpendGuard(); return; }
|
|
3712
3797
|
if (FLAG_UNINSTALL) { uninstallAll(); return; }
|
|
3713
3798
|
if (FLAG_WHAT_CHANGED) { printBanner('what RuvNet Brain put on this machine'); printFootprint(); return; }
|
|
3799
|
+
if (FLAG_WHATS_NEW) { showWhatsNew(); return; }
|
|
3714
3800
|
|
|
3715
3801
|
printBanner('installer');
|
|
3716
3802
|
console.log(c.dim("I'll set up the brain for Claude Code and Codex, explaining each step as I go.\n"));
|
|
@@ -3856,6 +3942,15 @@ It is safe to re-run at any time. After installing, restart Claude Code so the g
|
|
|
3856
3942
|
}
|
|
3857
3943
|
|
|
3858
3944
|
installReader(cacheDir);
|
|
3945
|
+
try {
|
|
3946
|
+
const consoleEntry = installConsoleRuntime(cacheDir);
|
|
3947
|
+
ok(`Brain Console installed at ${consoleEntry}`);
|
|
3948
|
+
} catch (error) {
|
|
3949
|
+
die(
|
|
3950
|
+
`the Brain Console runtime could not be installed (${error.message})`,
|
|
3951
|
+
`The knowledge base is present, but /rvbc would be broken. Re-run the installer from a complete package.`,
|
|
3952
|
+
);
|
|
3953
|
+
}
|
|
3859
3954
|
const plugin = wirePlugin();
|
|
3860
3955
|
// Codex hosts got nothing before this (issue #42): shipped, never registered. Non-fatal like every
|
|
3861
3956
|
// other wiring step — a second host we cannot reach must never break the one we can.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Onboarding Console — API + data contract (v1)
|
|
2
|
+
|
|
3
|
+
Updated: 2026-07-17
|
|
4
|
+
Created: 2026-07-15
|
|
5
|
+
|
|
6
|
+
The single source of truth both the backend (`scripts/onboarding-console.mjs`) and the
|
|
7
|
+
frontend (`console/index.html` + `app.js` + `style.css`) build against. Implements ADR-0013
|
|
8
|
+
and DDD-0002. **The ordering is the design: Mirror → Explain → Recommend → (consent) Apply → Undo.**
|
|
9
|
+
|
|
10
|
+
The server binds `127.0.0.1` only and mints a random `token` per launch. Every mutating request
|
|
11
|
+
must echo the token. The page receives the token inlined at render time (`window.__CONSOLE_TOKEN__`).
|
|
12
|
+
A GET with a wrong/absent token still serves read-only state; a POST with a wrong token is `403`.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## GET `/api/state` — fast sections (no network)
|
|
17
|
+
|
|
18
|
+
Returns in well under a second. `memory.fleet` is **`null` here by design** — scanning every memory
|
|
19
|
+
store on the machine costs ~90ms each and a real machine has 100+, which is far too slow to sit in
|
|
20
|
+
front of the page's first paint. The fleet arrives separately from `GET /api/memory`.
|
|
21
|
+
|
|
22
|
+
`GET /api/state?fast=1` replays the last good gather from disk (~3ms) so a repeat load paints
|
|
23
|
+
instantly, then the live call replaces it. The cached copy never contains `token` — that is minted
|
|
24
|
+
per server run and spliced in on read.
|
|
25
|
+
|
|
26
|
+
```jsonc
|
|
27
|
+
{
|
|
28
|
+
"token": "…",
|
|
29
|
+
"generatedAt": "2026-07-14T…Z",
|
|
30
|
+
"host": { "user": "stuartkerr", "platform": "darwin", "node": "v22…", "npmPrefix": "~/.npm-global" },
|
|
31
|
+
"sections": {
|
|
32
|
+
"wiring": {
|
|
33
|
+
"summary": { "npx": 190, "global": 12, "mcp": 6, "plugin": 5, "projectsWithNpx": 16 },
|
|
34
|
+
"sites": [
|
|
35
|
+
{ "scope": "project", "project": "ruvnet-brain", "file": ".claude/settings.json",
|
|
36
|
+
"event": "PreToolUse", "matcher": "Bash", "spec": "npx @claude-flow/cli@latest hooks …",
|
|
37
|
+
"mechanism": "NPX" }
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"memory": {
|
|
41
|
+
"fleet": [
|
|
42
|
+
{ "name": "ruvnet-brain", "total": 1023, "embedded": 1021, "coverPct": 99.8,
|
|
43
|
+
"patterns": 456, "learns": true, "findings": [] }
|
|
44
|
+
],
|
|
45
|
+
"health": {
|
|
46
|
+
"project": "ruvnet-brain", "score": 92, "summary": "learns; recall-quality not probed",
|
|
47
|
+
"dimensions": [
|
|
48
|
+
{ "key": "liveness", "label": "Liveness", "status": "ok",
|
|
49
|
+
"detail": "store→search round-trip works on the live path", "deduction": 0 },
|
|
50
|
+
{ "key": "coverage", "label": "Coverage", "status": "ok", "detail": "checkpoint present, <1d old", "deduction": 0 },
|
|
51
|
+
{ "key": "recallQuality", "label": "Recall quality", "status": "notTested",
|
|
52
|
+
"detail": "no embedding round-trip run this session", "deduction": 0 },
|
|
53
|
+
{ "key": "compactionSurvival", "label": "Compaction survival", "status": "ok",
|
|
54
|
+
"detail": "PreCompact snapshot present", "deduction": 0 },
|
|
55
|
+
{ "key": "sessionSurfacing", "label": "Session surfacing", "status": "ok",
|
|
56
|
+
"detail": "SessionStart hook surfaces state", "deduction": 0 }
|
|
57
|
+
],
|
|
58
|
+
"notTested": ["recallQuality"]
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"savings": {
|
|
62
|
+
"totals": { "count": 3, "usdSaved": 0.42, "msSaved": 18400 }, // null ⇒ render "nothing measured yet"
|
|
63
|
+
"note": "receipts only — no modelled or projected savings",
|
|
64
|
+
"receipts": [
|
|
65
|
+
{ "at": "2026-07-13T…Z", "capability": "model-routing", "task": "…",
|
|
66
|
+
"chosenTier": "haiku", "baselineTier": "opus", "measuredMs": 4200, "measuredUsd": 0.14 }
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"config": {
|
|
70
|
+
"path": "~/.claude/ruvnet-brain/config.json",
|
|
71
|
+
"exists": true,
|
|
72
|
+
"values": { "openrouterKey": true, "nightly": true, "routing": "auto", "qeFleet": false },
|
|
73
|
+
"schema": [
|
|
74
|
+
{ "key": "openrouterKey", "label": "OpenRouter API key", "type": "secret",
|
|
75
|
+
"help": "Unlocks cheap-model routing + the self-improvement loop", "secret": true },
|
|
76
|
+
{ "key": "nightly", "label": "Nightly brain refresh", "type": "bool",
|
|
77
|
+
"help": "Rebuild the KB from pinned SHAs overnight" },
|
|
78
|
+
{ "key": "routing", "label": "Token-smart routing", "type": "enum",
|
|
79
|
+
"options": ["auto", "off"], "help": "Route cheap tasks to smaller models" },
|
|
80
|
+
{ "key": "qeFleet", "label": "On-demand QE fleet", "type": "bool",
|
|
81
|
+
"help": "Agentic-QE test fleet, spun up on request" }
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
"recommendations": [ /* Recommendation[] — non-stack, e.g. de-npx a project */ ]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## GET `/api/memory` — the across-your-projects fleet scan (slow, ~7–10s)
|
|
90
|
+
|
|
91
|
+
```jsonc
|
|
92
|
+
{ "fleet": [ { "name": "ruvnet-brain", "total": 1023, "embedded": 1021, "coverPct": 99.8, … } ] }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Split out of `/api/state` so it cannot block first paint. The page renders memory health immediately
|
|
96
|
+
and merges this list into the same card once it lands.
|
|
97
|
+
|
|
98
|
+
## GET `/api/stack` — the network audit (slow, ~5–20s; page loads a skeleton first)
|
|
99
|
+
|
|
100
|
+
```jsonc
|
|
101
|
+
{
|
|
102
|
+
"packages": [
|
|
103
|
+
{ "name": "ruflo", "installed": "3.30.2", "target": "3.30.2", "tag": "alpha", "state": "CURRENT" }
|
|
104
|
+
// state ∈ CURRENT | BEHIND | AHEAD | BROKEN | UNRESOLVED
|
|
105
|
+
],
|
|
106
|
+
"shadows": [
|
|
107
|
+
{ "name": "@ruvector/rvf", "version": "0.1.9", "global": "0.2.3", "dir": "~/.npm/_npx/…", "stale": true }
|
|
108
|
+
],
|
|
109
|
+
"summary": { "total": 40, "behind": 0, "broken": 1, "ahead": 0, "current": 38, "shadows": 15, "stale": 15 },
|
|
110
|
+
"recommendations": [ /* Recommendation[] — sync BEHIND, purge stale shadows */ ]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Recommendation — the aggregate the whole page is built around
|
|
115
|
+
|
|
116
|
+
**A Recommendation CANNOT exist without non-empty `evidence`, a `cost`, and an `undo`.** The
|
|
117
|
+
backend factory throws otherwise (DDD invariant, schema-enforced). The UI must render all four.
|
|
118
|
+
|
|
119
|
+
```jsonc
|
|
120
|
+
{
|
|
121
|
+
"id": "sync-stack",
|
|
122
|
+
"title": "Sync 1 stale shadow of @ruvector/rvf",
|
|
123
|
+
"rationale": "A second copy in the npx cache preempts your global binary and quietly serves 0.1.9.",
|
|
124
|
+
"severity": "IMPORTANT", // INFO | SUGGESTED | IMPORTANT
|
|
125
|
+
"touchesMachine": true, // ⇐ if true, the UI MUST show plainImpact + require an explicit confirm
|
|
126
|
+
"plainImpact": "This removes an extra, out-of-date copy of a tool sitting in a temporary folder on your computer. Your main copy is newer and stays untouched. Nothing you use will stop working — the temporary copy rebuilds itself automatically the next time it's needed. Fully reversible.",
|
|
127
|
+
"evidence": [ { "observed": "@ruvector/rvf@0.1.9 in ~/.npm/_npx while global is 0.2.3", "source": "stack-sync findShadows" } ],
|
|
128
|
+
"cost": { "time": "~0s", "latency": "none", "usd": 0, "risk": "low" },
|
|
129
|
+
"change": { "kind": "run-script", "human": "purge the stale npx shadow", "cmd": "node scripts/stack-sync.mjs --sync" },
|
|
130
|
+
"undo": { "kind": "restore-dir", "human": "npx re-resolves on next use; backup kept at <dir>.bak-<ts>" }
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**`touchesMachine` and `plainImpact` are load-bearing.** `touchesMachine: false` means the action
|
|
135
|
+
only writes RuvNet-Brain's own settings file in your user folder and changes nothing about how your
|
|
136
|
+
computer runs other software (e.g. Save Settings). `touchesMachine: true` means it installs, removes,
|
|
137
|
+
or rewires something the rest of your system uses — those **must** render `plainImpact` (jargon-free,
|
|
138
|
+
says what happens + why it's safe + that it's reversible) and a distinct "this changes your computer"
|
|
139
|
+
confirm step before Apply is allowed. Write `plainImpact` for a smart person who has never heard of npx.
|
|
140
|
+
|
|
141
|
+
## POST `/api/apply` — the ONLY writer (consent-gated)
|
|
142
|
+
|
|
143
|
+
Request: `{ "token", "ids": ["sync-stack", …], "preStateHash": "…" }`
|
|
144
|
+
Behavior (DDD Change Plan invariants): **re-read the world**, abort with `worldMoved` if `preStateHash`
|
|
145
|
+
no longer matches, **record the inverse first**, back up every mutated file to `<file>.bak-<ts>`, then run.
|
|
146
|
+
Response: `{ "results": [ { "id", "ok", "undoToken", "log" } ] }`
|
|
147
|
+
|
|
148
|
+
## POST `/api/save-config` — save Settings at user level
|
|
149
|
+
|
|
150
|
+
Request: `{ "token", "values": { … } }` → writes `~/.claude/ruvnet-brain/config.json`
|
|
151
|
+
(backup first, undo recorded). Response: `{ "ok", "backup", "undoToken" }`
|
|
152
|
+
|
|
153
|
+
## POST `/api/undo` — reverse a prior apply/save
|
|
154
|
+
|
|
155
|
+
Request: `{ "token", "undoToken" }` → Response: `{ "ok" }`
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Section order on the page (progressive disclosure — each collapsible, each independently useful)
|
|
160
|
+
|
|
161
|
+
1. **Your stack** — installed / current / duplicated / broken (from `/api/stack`)
|
|
162
|
+
2. **How it's wired** — npx vs global, where (from wiring)
|
|
163
|
+
3. **What we'd suggest** — the Recommendation cards (evidence · cost · undo · Apply/Skip)
|
|
164
|
+
4. **Is your memory actually working?** — the 0–100 health score with named deductions
|
|
165
|
+
5. **MetaHarness / Agentic-QE savings** — receipts only, or an honest "nothing measured yet"
|
|
166
|
+
6. **Settings** — the editable form, one **Save** button, writes at user level
|
|
167
|
+
|
|
168
|
+
## Design law (from ADR-0013)
|
|
169
|
+
- Read-only by default. Opening the page changes nothing.
|
|
170
|
+
- Existing choices are data, not errors. `AHEAD` is legal. `NPX` is shown with its tradeoff, never labelled "wrong".
|
|
171
|
+
- Every number traces to a receipt or an observation. No "up to 90%". No estimates.
|
|
172
|
+
- Nothing above `SUGGESTED` severity for anything not measured on THIS machine.
|