@claude-flow/cli 3.53.0 → 3.54.0
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/helpers/helpers.manifest.json +4 -4
- package/.claude/helpers/hook-handler.cjs +23 -3
- package/.claude/helpers/intelligence.cjs +104 -2
- package/README.md +141 -44
- package/catalog-manifest.json +2 -2
- package/dist/src/commands/memory.js +9 -1
- package/dist/src/memory/embedding-q8.d.ts +19 -0
- package/dist/src/memory/embedding-q8.js +38 -0
- package/dist/src/memory/memory-bridge.d.ts +7 -0
- package/dist/src/memory/memory-bridge.js +7 -1
- package/dist/src/memory/memory-initializer.d.ts +5 -0
- package/dist/src/memory/memory-initializer.js +7 -1
- package/dist/src/missions/schemas.d.ts +125 -125
- package/dist/src/mods/command-registry/schema.d.ts +199 -199
- package/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.54.0",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "c8d218526a3c34034c2a69de23f507f0eb0f70d59c16426a8edc849e6ac22529",
|
|
6
|
-
"hook-handler.cjs": "
|
|
7
|
-
"intelligence.cjs": "
|
|
6
|
+
"hook-handler.cjs": "c3f9e7d2f5b33fd396d43de24fc77cb2b33eaf962114dcb9ee92a8075746b0fe",
|
|
7
|
+
"intelligence.cjs": "ac5033a77bcea9796856629d5d319bde9ab6b7edf0dcd0d4af187ce30af90836",
|
|
8
8
|
"statusline.cjs": "4a48353b4f1566fa4379b00fd0321b6676a22b6cc91fbbd8380ac5183d619468",
|
|
9
9
|
"router.cjs": "16648b3c0d73b6681ac2d8d13def6a68286c57f5a11004de5b19a0fa088c833d"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
-
"signature": "
|
|
12
|
+
"signature": "670XlbndW0uatGNpiwtcNsZqZBQdr5vao9SQbLOBW7bXpMc198/7Qr59o2/AlT3vs/nQkQe+vUcngqY2IQZwBQ==",
|
|
13
13
|
"algorithm": "ed25519"
|
|
14
14
|
}
|
|
@@ -379,14 +379,33 @@ async function main() {
|
|
|
379
379
|
const handlers = {
|
|
380
380
|
'route': () => {
|
|
381
381
|
// Inject ranked intelligence context before routing
|
|
382
|
-
|
|
382
|
+
// ADR-472: keep the detailed recall so ONE bounded log record (ids, scores, router pick; never the prompt) is appended after routing.
|
|
383
|
+
let recall = null;
|
|
384
|
+
if (intelligence && (intelligence.getContextDetailed || intelligence.getContext)) {
|
|
383
385
|
try {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
+
if (intelligence.getContextDetailed) {
|
|
387
|
+
recall = intelligence.getContextDetailed(prompt);
|
|
388
|
+
if (recall && recall.text) console.log(recall.text);
|
|
389
|
+
} else {
|
|
390
|
+
const ctx = intelligence.getContext(prompt);
|
|
391
|
+
if (ctx) console.log(ctx);
|
|
392
|
+
}
|
|
386
393
|
} catch (e) { /* non-fatal */ }
|
|
387
394
|
}
|
|
395
|
+
const logRecall = (result) => {
|
|
396
|
+
try {
|
|
397
|
+
if (recall && intelligence.appendRecall) {
|
|
398
|
+
intelligence.appendRecall(recall, {
|
|
399
|
+
sessionId: hookInput.session_id || hookInput.sessionId || null,
|
|
400
|
+
agent: result && result.agent,
|
|
401
|
+
confidence: result && result.confidence,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
} catch (e) { /* non-fatal: the log never blocks a prompt */ }
|
|
405
|
+
};
|
|
388
406
|
if (router && router.routeTask) {
|
|
389
407
|
const result = router.routeTask(prompt);
|
|
408
|
+
logRecall(result);
|
|
390
409
|
// Format output for Claude Code hook consumption — real data only
|
|
391
410
|
const row = (text) => `| ${text.substring(0, 60).padEnd(60)} |`;
|
|
392
411
|
const output = [
|
|
@@ -400,6 +419,7 @@ const handlers = {
|
|
|
400
419
|
];
|
|
401
420
|
console.log(output.join('\n'));
|
|
402
421
|
} else {
|
|
422
|
+
logRecall(null);
|
|
403
423
|
console.log('[INFO] Router not available, using default routing');
|
|
404
424
|
}
|
|
405
425
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
const fs = require('fs');
|
|
18
18
|
const path = require('path');
|
|
19
|
+
const crypto = require('crypto');
|
|
19
20
|
|
|
20
21
|
function resolveProjectRoot(startDir) {
|
|
21
22
|
if (process.env.CLAUDE_PROJECT_DIR) {
|
|
@@ -39,6 +40,10 @@ const STORE_PATH = path.join(DATA_DIR, 'auto-memory-store.json');
|
|
|
39
40
|
const GRAPH_PATH = path.join(DATA_DIR, 'graph-state.json');
|
|
40
41
|
const RANKED_PATH = path.join(DATA_DIR, 'ranked-context.json');
|
|
41
42
|
const PENDING_PATH = path.join(DATA_DIR, 'pending-insights.jsonl');
|
|
43
|
+
// ADR-472: bounded local log of WHICH ranked entries each recall surfaced (ids + scores; never the prompt text).
|
|
44
|
+
const RECALL_LOG_PATH = path.join(DATA_DIR, 'recall-log.jsonl');
|
|
45
|
+
const RECALL_LOG_MAX_BYTES = 1024 * 1024; // under the console's 2 MB read cap, so the log is readable when fullest
|
|
46
|
+
const RECALL_LOG_MAX_RECORDS = 1000;
|
|
42
47
|
const LEGACY_PENDING_PATH = path.join(process.cwd(), '.claude-flow', 'data', 'pending-insights.jsonl');
|
|
43
48
|
const SESSION_DIR = path.join(PROJECT_ROOT, '.claude-flow', 'sessions');
|
|
44
49
|
const SESSION_FILE = path.join(SESSION_DIR, 'current.json');
|
|
@@ -595,11 +600,94 @@ function init() {
|
|
|
595
600
|
};
|
|
596
601
|
}
|
|
597
602
|
|
|
603
|
+
// ── Recall log (ADR-472) ─────────────────────────────────────────────────────
|
|
604
|
+
// One compact record per surfaced recall: when, which session, a one-way digest of the prompt, and the ids / scores /
|
|
605
|
+
// ranks the hook surfaced (plus the router's pick). Never the prompt text, never values. Local, bounded, fail-open.
|
|
606
|
+
|
|
607
|
+
/** First 16 hex characters of sha256(trimmed prompt): a join key, not a copy of the prompt. */
|
|
608
|
+
function promptDigest(prompt) {
|
|
609
|
+
return crypto.createHash('sha256').update(String(prompt).trim()).digest('hex').slice(0, 16);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** Ids and categories come from the user's own memory files; mask anything shaped like a credential before it is written. */
|
|
613
|
+
function maskToken(value, max) {
|
|
614
|
+
return String(value == null ? '' : value)
|
|
615
|
+
.replace(/[\u0000-\u001f\u007f]/g, ' ')
|
|
616
|
+
.replace(/(?:sk-|ghp_|gho_|xox[abp]-|AKIA|eyJ)[A-Za-z0-9_\-]{8,}|[A-Za-z0-9+\/=_-]{40,}/g, '[masked]')
|
|
617
|
+
.slice(0, max);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const OFF_RE = /^(0|false|off|no)$/i;
|
|
621
|
+
|
|
622
|
+
/** Default ON (local file, ids and scores only; routing-outcomes.json already keeps task text). Off by RUFLO_RECALL_LOG=0 or claude-flow.config.json {"recallLog":{"enabled":false}}. */
|
|
623
|
+
function recallLogEnabled() {
|
|
624
|
+
const env = process.env.RUFLO_RECALL_LOG;
|
|
625
|
+
if (env !== undefined && String(env).trim() !== '') return !OFF_RE.test(String(env).trim());
|
|
626
|
+
try {
|
|
627
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(PROJECT_ROOT, 'claude-flow.config.json'), 'utf-8'));
|
|
628
|
+
if (cfg && cfg.recallLog && cfg.recallLog.enabled === false) return false;
|
|
629
|
+
} catch { /* absent or malformed config = enabled */ }
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** A record is at least ~140 bytes, so a file under this size cannot hold more than RECALL_LOG_MAX_RECORDS: no need to count lines. */
|
|
634
|
+
const RECALL_LOG_COUNT_FLOOR = 100 * 1024;
|
|
635
|
+
|
|
636
|
+
/** Keep the newest half when the log passes its byte or record cap. Rewrite through a temp file so a reader never sees half a file. */
|
|
637
|
+
function rotateRecallLog() {
|
|
638
|
+
try {
|
|
639
|
+
const stat = fs.statSync(RECALL_LOG_PATH);
|
|
640
|
+
if (stat.size < RECALL_LOG_COUNT_FLOOR) return;
|
|
641
|
+
const lines = fs.readFileSync(RECALL_LOG_PATH, 'utf-8').split('\n').filter(Boolean);
|
|
642
|
+
if (stat.size <= RECALL_LOG_MAX_BYTES && lines.length <= RECALL_LOG_MAX_RECORDS) return;
|
|
643
|
+
// Newest first until half of either cap is reached.
|
|
644
|
+
const keep = [];
|
|
645
|
+
let bytes = 0;
|
|
646
|
+
for (let i = lines.length - 1; i >= 0 && keep.length < RECALL_LOG_MAX_RECORDS / 2; i--) {
|
|
647
|
+
bytes += lines[i].length + 1;
|
|
648
|
+
if (bytes > RECALL_LOG_MAX_BYTES / 2) break;
|
|
649
|
+
keep.unshift(lines[i]);
|
|
650
|
+
}
|
|
651
|
+
const tmp = RECALL_LOG_PATH + '.' + process.pid + '.tmp';
|
|
652
|
+
fs.writeFileSync(tmp, keep.join('\n') + '\n', { encoding: 'utf-8', mode: 0o600 });
|
|
653
|
+
fs.renameSync(tmp, RECALL_LOG_PATH);
|
|
654
|
+
} catch { /* best effort */ }
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* appendRecall(detailed, meta) — one JSONL record for a recall getContextDetailed returned. meta: { sessionId, agent, confidence }.
|
|
659
|
+
* Returns true when a record was written. Never throws and never blocks the hook.
|
|
660
|
+
*/
|
|
661
|
+
function appendRecall(detailed, meta) {
|
|
662
|
+
try {
|
|
663
|
+
if (!detailed || !Array.isArray(detailed.surfaced) || detailed.surfaced.length === 0) return false;
|
|
664
|
+
if (!recallLogEnabled()) return false;
|
|
665
|
+
const m = meta || {};
|
|
666
|
+
const record = {
|
|
667
|
+
v: 1,
|
|
668
|
+
at: Date.now(),
|
|
669
|
+
sid: m.sessionId ? maskToken(m.sessionId, 64) : null,
|
|
670
|
+
digest: detailed.digest,
|
|
671
|
+
surfaced: detailed.surfaced.slice(0, 10).map((e) => ({
|
|
672
|
+
id: maskToken(e.id, 80),
|
|
673
|
+
score: Math.round((e.score || 0) * 10000) / 10000,
|
|
674
|
+
rank: e.rank,
|
|
675
|
+
cat: maskToken(e.category, 40),
|
|
676
|
+
})),
|
|
677
|
+
};
|
|
678
|
+
if (m.agent) record.router = { agent: maskToken(m.agent, 30), confidence: typeof m.confidence === 'number' ? Math.round(m.confidence * 1000) / 1000 : null };
|
|
679
|
+
ensureDataDir();
|
|
680
|
+
rotateRecallLog();
|
|
681
|
+
fs.appendFileSync(RECALL_LOG_PATH, JSON.stringify(record) + '\n', { encoding: 'utf-8', mode: 0o600 });
|
|
682
|
+
return true;
|
|
683
|
+
} catch { return false; }
|
|
684
|
+
}
|
|
685
|
+
|
|
598
686
|
/**
|
|
599
687
|
* getContext(prompt) — Called from route. Budget: <15ms.
|
|
600
688
|
* Matches prompt to ranked entries, returns top-5 formatted context.
|
|
601
689
|
*/
|
|
602
|
-
function
|
|
690
|
+
function getContextDetailed(prompt) {
|
|
603
691
|
if (!prompt) return null;
|
|
604
692
|
|
|
605
693
|
const ranked = readJSON(RANKED_PATH);
|
|
@@ -653,7 +741,17 @@ function getContext(prompt) {
|
|
|
653
741
|
lines.push(` * (${e.score.toFixed(2)}) ${display} [rank #${i + 1}, ${accessed}x accessed]`);
|
|
654
742
|
}
|
|
655
743
|
|
|
656
|
-
return
|
|
744
|
+
return {
|
|
745
|
+
text: lines.join('\n'),
|
|
746
|
+
digest: promptDigest(prompt),
|
|
747
|
+
surfaced: topEntries.map((e, i) => ({ id: e.id, score: e.score, rank: i + 1, category: e.category || '' })),
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/** The context text the hook prints, or null. Thin wrapper over getContextDetailed (callers that only print keep working). */
|
|
752
|
+
function getContext(prompt) {
|
|
753
|
+
const detailed = getContextDetailed(prompt);
|
|
754
|
+
return detailed ? detailed.text : null;
|
|
657
755
|
}
|
|
658
756
|
|
|
659
757
|
/**
|
|
@@ -1137,6 +1235,10 @@ function stats(outputJson) {
|
|
|
1137
1235
|
module.exports = {
|
|
1138
1236
|
init,
|
|
1139
1237
|
getContext,
|
|
1238
|
+
getContextDetailed,
|
|
1239
|
+
appendRecall,
|
|
1240
|
+
recallLogEnabled,
|
|
1241
|
+
promptDigest,
|
|
1140
1242
|
recordEdit,
|
|
1141
1243
|
feedback,
|
|
1142
1244
|
consolidate,
|
package/README.md
CHANGED
|
@@ -1,24 +1,85 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<a href="https://cognitum.one/agentic-engineering"><img src="ruflo/assets/ruflo-neon-flicker.gif" alt="Ruflo animated neon sign" width="100%"></a>
|
|
4
|
+
|
|
5
|
+
**An agent meta-harness for Claude Code and Codex.**
|
|
4
6
|
|
|
5
7
|
<!-- Try Ruflo — the 3 badges first-time visitors actually act on -->
|
|
6
8
|
[](https://www.npmjs.com/package/ruflo)
|
|
7
9
|
[](https://opensource.org/licenses/MIT)
|
|
8
10
|
[](https://github.com/ruvnet/claude-flow)
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="data/npm-downloads.latest.json"><img src="docs/assets/readme/badges/downloads.svg?v=mobile-readable-3" width="300" alt="Ecosystem npm downloads: 12.52M over 12 months through October 4, 2026"></a>
|
|
14
|
+
<br>
|
|
15
|
+
<a href="https://github.com/ruvnet/claude-flow"><img src="docs/assets/readme/badges/claude.svg?v=mobile-readable-3" width="300" alt="Claude Code"></a>
|
|
16
|
+
<a href="https://www.npmjs.com/package/@claude-flow/codex"><img src="docs/assets/readme/badges/codex.svg?v=mobile-readable-3" width="300" alt="Codex Plugin"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<a id="start-here"></a>
|
|
22
|
+
|
|
23
|
+
## <img src="docs/assets/readme/icons/terminal.svg" width="32" height="32" alt=""> Get started with Ruflo
|
|
24
|
+
|
|
25
|
+
<img src="docs/assets/readme/icons/plugins.svg" width="28" height="28" alt=""> **Start in Claude Code** with core tools, the visual console and runtime mods. Requires Claude Code **2.1.287 or later**. Run inside Claude Code:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
/plugin marketplace add ruvnet/ruflo
|
|
29
|
+
/plugin install ruflo-core@ruflo
|
|
30
|
+
/plugin install ruflo-console@ruflo
|
|
31
|
+
/plugin install ruflo-mods@ruflo
|
|
32
|
+
/reload-plugins
|
|
33
|
+
/ruflo
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Core** provides foundation tools. **Console** opens the agent cockpit. **Mods** add routing and policy enforcement inside Claude Code. Mods run with your account's permissions; review their code before installing.
|
|
37
|
+
|
|
38
|
+
<img src="docs/assets/readme/icons/terminal.svg" width="28" height="28" alt=""> **Using Codex or another MCP enabled tool?** Use NPX for Ruflo project setup and connect your client to the Ruflo MCP server. Run the setup wizard in your project terminal:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx ruflo@latest init wizard
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For clients that support local stdio MCP servers, configure **command** `npx` and **arguments** `["-y", "ruflo@latest", "mcp", "start"]`. The equivalent server command is:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx -y ruflo@latest mcp start
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
MCP exposes Ruflo tools to your client. The console and mods above are Claude Code integrations; hook support depends on the client.
|
|
51
|
+
|
|
52
|
+
[Compare install paths](#quick-start) · [Open the console](#console-walkthrough) · [User guide](docs/USERGUIDE.md)
|
|
53
|
+
|
|
54
|
+
<div align="center">
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Optional: ruOS Desktop
|
|
58
|
+
|
|
59
|
+
<a href="https://ruos.cognitum.one"><img src="ruflo/assets/ruos-animated.svg" alt="ruOS — A desktop that runs itself" width="100%"></a>
|
|
60
|
+
|
|
61
|
+
**Connect ruOS to ChatGPT or Claude via MCP:**
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
https://ruos.cognitum.one/mcp
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
<!-- RuVector promo -->
|
|
70
|
+
<a href="https://github.com/ruvnet/ruvector"><img src="docs/assets/readme/ruvector-promo-depth.svg" width="100%" alt="RuVector: Give your agents memory. Local vector search, persistent context, graph relationships and feedback learning. Explore RuVector."></a>
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npx ruvector
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
16
78
|
|
|
17
79
|
# Ruflo
|
|
18
80
|
|
|
19
81
|
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
20
82
|
|
|
21
|
-
**An agent meta-harness for Claude Code and Codex.**
|
|
22
83
|
|
|
23
84
|
[](docs/ruflo-explained.md)
|
|
24
85
|
|
|
@@ -31,13 +92,16 @@ A 14-chapter guide: from the basic idea to a first useful task, then memory, age
|
|
|
31
92
|
|
|
32
93
|
One `npx ruflo init` gives Claude Code a nervous system: agents self-organize into swarms, learn from every task, remember across sessions, and — with federation — securely talk to agents on other machines without leaking data. You keep writing code. Ruflo handles the coordination.
|
|
33
94
|
|
|
34
|
-
|
|
35
|
-
Self-Learning / Self-Optimizing Agent Architecture
|
|
95
|
+
<p align="center"><img src="docs/assets/readme/learning-cinematic-compact.svg" width="100%" alt="Ruflo trajectory learning: branching memory paths, outcome feedback, contrastive AI and local learning. No LLM required for local vector retrieval and contrastive updates; agent execution may still use an LLM."></p>
|
|
36
96
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
97
|
+
<sub>Conceptual learning loop. Local vector retrieval and contrastive updates can run without an LLM; embeddings and configured learning modules are still required. See the <a href="v3/@claude-flow/cli/src/services/ruvector-training.ts">RuVector training integration</a> and <a href="v3/@claude-flow/neural/src/modes/balanced.ts">trajectory contrastive learning</a>.</sub>
|
|
98
|
+
|
|
99
|
+
<details>
|
|
100
|
+
<summary>Architecture in text</summary>
|
|
101
|
+
|
|
102
|
+
User → Ruflo (CLI/MCP) → Router → Swarm → Agents → Memory → LLM providers. Memory feeds useful experience back into routing. This is a conceptual flow, not a live execution trace.
|
|
103
|
+
|
|
104
|
+
</details>
|
|
41
105
|
|
|
42
106
|
> **New to Ruflo?** You don't need to learn 314 MCP tools or 26 CLI commands. After `init`, just use Claude Code normally — the hooks system automatically routes tasks, learns from successful patterns, and coordinates agents in the background.
|
|
43
107
|
|
|
@@ -50,15 +114,34 @@ User --> Ruflo (CLI/MCP) --> Router --> Swarm --> Agents --> Memory --> LLM Prov
|
|
|
50
114
|
|
|
51
115
|
---
|
|
52
116
|
|
|
53
|
-
<p align="center"><img src="docs/assets/
|
|
117
|
+
<p align="center"><img src="docs/assets/readme/console.svg" alt="Mission control: inspect agent work" width="100%"></p>
|
|
118
|
+
|
|
119
|
+
<p align="center"><img src="docs/assets/ruflo-console-workflows.svg" width="952" height="964" alt="An animated recording of the ruflo console inside Claude Code: the boot (the neon sign and every area checked), then the Workflows page on a sample run: phases and agents with model, tokens and time; drilling from a run into one agent's activity, log and result; search; failure triage; cost; replay and compare; the control tab with a confirm card; and the mission autopilot panel"></p>
|
|
120
|
+
|
|
121
|
+
<img src="docs/assets/readme/console-icon-workflows.svg" width="28" height="28" alt=""> **Your agent cockpit.** Track workflows, agents, models, tokens and cost beside Claude Code. The animation shows startup checks and a **sample workflow**, not a live session.
|
|
122
|
+
|
|
123
|
+
<img src="docs/assets/readme/console-icon-inspect.svg" width="28" height="28" alt=""> **Inspect any run.** Open agent logs and results, search, triage failures, replay and compare. Start with `npx ruflo init`, restart Claude Code, then `/ruflo`. [Full console tour](docs/assets/ruflo-console-walkthrough-wide.gif).
|
|
54
124
|
|
|
55
|
-
<
|
|
125
|
+
<img src="docs/assets/readme/console-icon-control.svg" width="28" height="28" alt=""> **Let Claude drive. You set the limits.** Enable **Settings → Claude control** to navigate and run console actions. Choose `read`, `write`, `manage` or `full`, with `ask` or `auto` approval. The current default is **read + ask**; raising the level is your choice. Actions above your permission level are refused, and network, spending and destructive actions require confirmation even in `auto`. Review the live action log or press **Take back control** to stop Claude control. [Details](v3/docs/adr/ADR-444-claude-controls-the-console.md).
|
|
56
126
|
|
|
57
|
-
|
|
127
|
+
<a id="console-walkthrough"></a>
|
|
128
|
+
|
|
129
|
+
### One task: create a mission with Claude
|
|
130
|
+
|
|
131
|
+
<img src="docs/assets/readme/console-icon-workflows.svg" width="28" height="28" alt=""> **Watch the recorded console session below.** Claude creates a mission, opens the Learning and Security pages, and reports its actions in Overview.
|
|
132
|
+
|
|
133
|
+
1. **Set the boundary.** Install the console using the commands below, open `/ruflo`, then choose **Settings → Claude control → write + ask**.
|
|
134
|
+
2. **Give a concrete request.** Try: “Create a mission to add a dark mode toggle. Show me the mission and its status.”
|
|
135
|
+
3. **Approve creation.** Claude opens Missions and sets the goal. Confirm the pending create action in the console.
|
|
136
|
+
4. **Verify the result.** Check that Missions contains the goal and Overview records the action. Creating a mission does not mean the feature has been implemented.
|
|
137
|
+
5. **Keep control.** **Take back control** pauses Claude's console tools. A later call should be refused until you restore control.
|
|
138
|
+
|
|
139
|
+
**What the recording demonstrates:** a real Claude Haiku session with `write + auto`, mission creation, page navigation, a refused swarm stop, and control being taken back. The steps above use `ask` so you approve creation yourself. The separate workflow animation uses sample data; neither is evidence of completed swarm work or memory recall.
|
|
140
|
+
|
|
141
|
+
[Implementation and recorded test findings](v3/docs/adr/ADR-444-claude-controls-the-console.md) · [Reproduction script](plugins/ruflo-console/scripts/e2e-control.sh)
|
|
58
142
|
|
|
59
143
|
<p align="center"><img src="docs/assets/ruflo-console-claude-control.gif" alt="Claude Code with the ruflo console beside it: Claude sets a mission goal, creates the mission and opens the Learning, Security and Overview pages through the console tools; the Claude control dashboard logs each action; swarm-stop is refused because it needs the full level; the person clicks Take back control and the next request is refused"></p>
|
|
60
144
|
|
|
61
|
-
<sub>A real recording (Claude Haiku, a few cents): control set to <code>write</code> with auto-confirm. Setting a goal and creating the mission is within that level; stopping a swarm needs <code>full</code>, so it is refused; after <b>Take back control</b> every call is refused.</sub>
|
|
62
145
|
|
|
63
146
|
**Install the mods from the ruflo marketplace** (Claude Code 2.1.287 or later; mods run with your account's permissions and are not sandboxed, so read the code first):
|
|
64
147
|
|
|
@@ -73,6 +156,8 @@ User --> Ruflo (CLI/MCP) --> Router --> Swarm --> Agents --> Memory --> LLM Prov
|
|
|
73
156
|
|
|
74
157
|
## Quick Start
|
|
75
158
|
|
|
159
|
+
<p align="center"><img src="docs/assets/readme/quick-start.svg" alt="Start building with Ruflo" width="100%"></p>
|
|
160
|
+
|
|
76
161
|
There are **two different install paths** with very different surface areas. Pick based on what you need (#1744):
|
|
77
162
|
|
|
78
163
|
| | **Claude Code Plugin** | **CLI install (`npx ruflo init`)** |
|
|
@@ -183,7 +268,7 @@ This adds slash commands and agent definitions. `ruflo-core` (installed above) d
|
|
|
183
268
|
|
|
184
269
|
</details>
|
|
185
270
|
|
|
186
|
-
### CLI Install
|
|
271
|
+
### <img src="docs/assets/readme/icons/terminal.svg" width="28" height="28" alt=""> CLI Install
|
|
187
272
|
|
|
188
273
|
**macOS / Linux / WSL / Git-Bash:**
|
|
189
274
|
|
|
@@ -207,7 +292,7 @@ npm install -g ruflo@latest
|
|
|
207
292
|
|
|
208
293
|
> 💡 **Windows users:** the `curl ... | bash` form needs a POSIX shell (Git-Bash, WSL, MSYS). The `npx ruflo@latest init wizard` line works natively in PowerShell and cmd. If you hit an `'bash' is not recognized` error, use the `npx` line instead — both end up running the same init flow.
|
|
209
294
|
|
|
210
|
-
### MCP Server
|
|
295
|
+
### <img src="docs/assets/readme/icons/network.svg" width="28" height="28" alt=""> MCP Server
|
|
211
296
|
|
|
212
297
|
```bash
|
|
213
298
|
# Add Ruflo as an MCP server in Claude Code
|
|
@@ -218,35 +303,39 @@ claude mcp add claude-flow -- npx ruflo@latest mcp start
|
|
|
218
303
|
|
|
219
304
|
## What You Get
|
|
220
305
|
|
|
306
|
+
<p align="center"><img src="docs/assets/readme/capabilities.svg" alt="Your agent toolkit" width="100%"></p>
|
|
307
|
+
|
|
308
|
+
<table>
|
|
309
|
+
<tr><td width="50%"><a href="plugins/ruflo-swarm/README.md"><img src="docs/assets/readme/card-swarm.svg" width="100%" alt="Agent teams"></a></td><td width="50%"><a href="plugins/ruflo-rag-memory/README.md"><img src="docs/assets/readme/card-memory.svg" width="100%" alt="Persistent memory"></a></td></tr>
|
|
310
|
+
<tr><td width="50%"><a href="plugins/ruflo-intelligence/README.md"><img src="docs/assets/readme/card-learning.svg" width="100%" alt="Learning loops"></a></td><td width="50%"><a href="plugins/ruflo-security-audit/README.md"><img src="docs/assets/readme/card-security.svg" width="100%" alt="Security controls"></a></td></tr>
|
|
311
|
+
<tr><td width="50%"><a href="https://ruvnet.github.io/ruflo"><img src="docs/assets/readme/card-plugins.svg" width="100%" alt="Plugin marketplace"></a></td><td width="50%"><a href="plugins/ruflo-ruvllm/README.md"><img src="docs/assets/readme/card-routing.svg" width="100%" alt="Models and routing"></a></td></tr>
|
|
312
|
+
</table>
|
|
313
|
+
|
|
221
314
|
| Capability | Description |
|
|
222
315
|
|------------|-------------|
|
|
223
|
-
|
|
|
224
|
-
|
|
|
225
|
-
|
|
|
226
|
-
|
|
|
227
|
-
|
|
|
228
|
-
|
|
|
229
|
-
|
|
|
230
|
-
|
|
|
231
|
-
|
|
|
232
|
-
|
|
|
233
|
-
|
|
|
316
|
+
| <img src="docs/assets/readme/icons/agents.svg" width="28" height="28" alt=""> **100+ Agents** | Specialized agents for coding, testing, security, docs, architecture |
|
|
317
|
+
| <img src="docs/assets/readme/icons/network.svg" width="28" height="28" alt=""> **Comms Layer** | Zero-trust federation — agents across machines/orgs discover, authenticate, and exchange work securely |
|
|
318
|
+
| <img src="docs/assets/readme/icons/swarm.svg" width="28" height="28" alt=""> **Swarm Coordination** | Hierarchical, mesh, and adaptive topologies with consensus |
|
|
319
|
+
| <img src="docs/assets/readme/icons/learning.svg" width="28" height="28" alt=""> **Self-Learning** | SONA neural patterns, ReasoningBank, trajectory learning |
|
|
320
|
+
| <img src="docs/assets/readme/icons/memory.svg" width="28" height="28" alt=""> **Vector Memory** | HNSW-indexed AgentDB — measured ~1.9x faster at N=20k, ~3.2x–4.7x at N=5k vs brute force (recall@10 ~0.99); ANN wins above the crossover, ties/loses at small N. See [audit](docs/reviews/intelligence-system-audit-2026-05-29.md) + [`scripts/benchmark-intelligence.mjs`](scripts/benchmark-intelligence.mjs) |
|
|
321
|
+
| <img src="docs/assets/readme/icons/workers.svg" width="28" height="28" alt=""> **Background Workers** | 12 auto-triggered workers (audit, optimize, testgaps, etc.) |
|
|
322
|
+
| <img src="docs/assets/readme/icons/plugins.svg" width="28" height="28" alt=""> **Plugin Marketplace** | 33 native Claude Code plugins + 21 npm plugins |
|
|
323
|
+
| <img src="docs/assets/readme/icons/routing.svg" width="28" height="28" alt=""> **Multi-Provider** | Claude, GPT, Gemini, Cohere, Ollama with smart routing |
|
|
324
|
+
| <img src="docs/assets/readme/icons/security.svg" width="28" height="28" alt=""> **Security** | AIDefence, input validation, CVE remediation, path traversal prevention |
|
|
325
|
+
| <img src="docs/assets/readme/icons/federation.svg" width="28" height="28" alt=""> **Agent Federation** | Cross-installation agent collaboration with zero-trust security |
|
|
326
|
+
| <img src="docs/assets/readme/icons/audit.svg" width="28" height="28" alt=""> **[MetaHarness](docs/metaharness-user-guide.md)** | Audit your AI agent setup before you ship. Grade readiness (1-100), scan tool configs for security issues, snapshot the whole project to catch regressions over time, and find templates that match your repo. `ruflo eject` turns a ruflo project into a standalone agent toolkit with its own name. [Full guide](docs/metaharness-user-guide.md). |
|
|
327
|
+
|
|
328
|
+
### <img src="docs/assets/readme/icons/learning.svg" width="28" height="28" alt=""> Learning from experience
|
|
329
|
+
|
|
330
|
+
<p align="center"><img src="docs/assets/readme/learning-flow.svg" width="100%" alt="Recall, execute, evaluate, store, adapt and reuse: an illustrative agent learning cycle."></p>
|
|
331
|
+
|
|
332
|
+
Useful trajectories and task feedback can inform future work. Results depend on the configured memory, learning components and quality of feedback. [Learning plugin](plugins/ruflo-intelligence/README.md).
|
|
234
333
|
|
|
235
334
|
### Agent Federation — Slack for Agents
|
|
236
335
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
keys stripped from you in transit
|
|
241
|
-
|
|
|
242
|
-
v
|
|
243
|
-
Their Agent <-- [ Block attacks ] <-- [ Check identity ] <------+
|
|
244
|
-
Stops prompt Rejects forgeries
|
|
245
|
-
injection
|
|
246
|
-
|
|
247
|
-
Audit trail on both sides.
|
|
248
|
-
Trust builds over time. Bad behavior = instant downgrade.
|
|
249
|
-
```
|
|
336
|
+
<p align="center"><img src="docs/assets/readme/federation.svg" alt="Connected intelligence across machines" width="100%"></p>
|
|
337
|
+
|
|
338
|
+
<p align="center"><img src="docs/assets/readme/federation-flow.svg" width="100%" alt="Outbound agent, data filtering, signing and encryption, identity verification, input checks and receiving agent."></p>
|
|
250
339
|
|
|
251
340
|
Slack gave teams channels. Federation gives agents the same thing — **shared workspaces across trust boundaries**, where agents on different machines, orgs, or cloud regions can discover each other, prove who they are, and collaborate on tasks.
|
|
252
341
|
|
|
@@ -348,6 +437,8 @@ User --> Claude Code / CLI
|
|
|
348
437
|
|
|
349
438
|
## Documentation
|
|
350
439
|
|
|
440
|
+
<p align="center"><img src="docs/assets/readme/documentation.svg" alt="Guides, architecture and verification" width="100%"></p>
|
|
441
|
+
|
|
351
442
|
Four docs for four audiences:
|
|
352
443
|
|
|
353
444
|
| Doc | When to read it |
|
|
@@ -378,6 +469,8 @@ User Guide section index:
|
|
|
378
469
|
|
|
379
470
|
## Support
|
|
380
471
|
|
|
472
|
+
<p align="center"><img src="docs/assets/readme/support.svg" alt="Build with the Ruflo community" width="100%"></p>
|
|
473
|
+
|
|
381
474
|
| Resource | Link |
|
|
382
475
|
|----------|------|
|
|
383
476
|
| Documentation | [User Guide](docs/USERGUIDE.md) |
|
|
@@ -386,6 +479,10 @@ User Guide section index:
|
|
|
386
479
|
| Community | [Agentics Foundation Discord](https://discord.com/invite/dfxmpwkG2D) |
|
|
387
480
|
| Powered by | [Cognitum.one](https://cognitum.one) |
|
|
388
481
|
|
|
482
|
+
<p align="center"><img src="docs/assets/readme/signal-divider.svg" alt="Ruflo" width="100%"></p>
|
|
483
|
+
|
|
389
484
|
## License
|
|
390
485
|
|
|
391
486
|
MIT - [RuvNet](https://github.com/ruvnet)
|
|
487
|
+
|
|
488
|
+
<a href="https://cognitum.one"><img src="docs/assets/readme/cognitum-banner-v2.svg" width="100%" alt="Cognitum One: Ambient Intelligence at the edge of the Physical World. Explore cognitum.one."></a>
|
package/catalog-manifest.json
CHANGED
|
@@ -9,6 +9,7 @@ import { distillCommand } from './memory-distill.js';
|
|
|
9
9
|
import { backupCommand } from './memory-backup.js';
|
|
10
10
|
import { countSiblingStoreRows } from '../memory/sibling-store.js';
|
|
11
11
|
import { resolveDbPath } from '../memory/memory-initializer.js';
|
|
12
|
+
import { MAX_LIST_EMBEDDINGS } from '../memory/embedding-q8.js';
|
|
12
13
|
import { existsSync } from 'node:fs';
|
|
13
14
|
import { siblingAgentDbPath } from '../memory/memory-bridge.js';
|
|
14
15
|
import { validateIdentifier } from '../mcp-tools/validate-input.js';
|
|
@@ -778,16 +779,23 @@ const listCommand = {
|
|
|
778
779
|
type: 'number',
|
|
779
780
|
default: 20
|
|
780
781
|
},
|
|
782
|
+
{
|
|
783
|
+
name: 'embeddings',
|
|
784
|
+
description: `ADR-472: with --format json, add each entry's stored embedding as int8+scale (embeddingQ8: {dims, scale, b64}); read-only, at most ${MAX_LIST_EMBEDDINGS} entries per call`,
|
|
785
|
+
type: 'boolean',
|
|
786
|
+
default: false
|
|
787
|
+
},
|
|
781
788
|
DB_PATH_OPTION
|
|
782
789
|
],
|
|
783
790
|
action: async (ctx) => {
|
|
784
791
|
const namespace = ctx.flags.namespace;
|
|
785
792
|
const limit = ctx.flags.limit;
|
|
793
|
+
const includeEmbedding = ctx.flags.embeddings === true && ctx.flags.format === 'json';
|
|
786
794
|
// Use sql.js directly for consistent data access
|
|
787
795
|
try {
|
|
788
796
|
const { listEntries, resolveDbPath: _rdbList } = await import('../memory/memory-initializer.js');
|
|
789
797
|
const dbPathList = _rdbList(ctx.flags.path);
|
|
790
|
-
const listResult = await listEntries({ namespace, limit, offset: 0, dbPath: dbPathList });
|
|
798
|
+
const listResult = await listEntries({ namespace, limit, offset: 0, dbPath: dbPathList, ...(includeEmbedding && { includeEmbedding: true }) });
|
|
791
799
|
if (!listResult.success) {
|
|
792
800
|
output.printError(`Failed to list: ${listResult.error}`);
|
|
793
801
|
return { success: false, exitCode: 1 };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-472: a stored embedding as int8 + scale, for `memory list --embeddings`. Pure; no store access.
|
|
3
|
+
*/
|
|
4
|
+
/** Most embeddings `memory list --embeddings` will emit per call, and the longest vector it will encode. */
|
|
5
|
+
export declare const MAX_LIST_EMBEDDINGS = 500;
|
|
6
|
+
export declare const MAX_EMBEDDING_DIMS = 4096;
|
|
7
|
+
/** A stored embedding as int8 with one scale, base64: ~1/4 the bytes of rounded JSON floats, enough for a 2D projection or a cosine screen. */
|
|
8
|
+
export type EmbeddingQ8 = {
|
|
9
|
+
dims: number;
|
|
10
|
+
scale: number;
|
|
11
|
+
b64: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Read-only view of a stored embedding (a JSON array in the `embedding` column) as int8 + scale. Returns undefined for a missing,
|
|
15
|
+
* malformed, non-finite, constant-zero or over-long vector, so a caller never gets a guessed one. Each value is within scale/2 of the
|
|
16
|
+
* original (scale = max|v| / 127); cosine against the original stays above 0.9999 for unit-scale text embeddings.
|
|
17
|
+
*/
|
|
18
|
+
export declare function encodeEmbeddingQ8(stored: unknown): EmbeddingQ8 | undefined;
|
|
19
|
+
//# sourceMappingURL=embedding-q8.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-472: a stored embedding as int8 + scale, for `memory list --embeddings`. Pure; no store access.
|
|
3
|
+
*/
|
|
4
|
+
/** Most embeddings `memory list --embeddings` will emit per call, and the longest vector it will encode. */
|
|
5
|
+
export const MAX_LIST_EMBEDDINGS = 500;
|
|
6
|
+
export const MAX_EMBEDDING_DIMS = 4096;
|
|
7
|
+
/**
|
|
8
|
+
* Read-only view of a stored embedding (a JSON array in the `embedding` column) as int8 + scale. Returns undefined for a missing,
|
|
9
|
+
* malformed, non-finite, constant-zero or over-long vector, so a caller never gets a guessed one. Each value is within scale/2 of the
|
|
10
|
+
* original (scale = max|v| / 127); cosine against the original stays above 0.9999 for unit-scale text embeddings.
|
|
11
|
+
*/
|
|
12
|
+
export function encodeEmbeddingQ8(stored) {
|
|
13
|
+
if (stored === null || stored === undefined)
|
|
14
|
+
return undefined;
|
|
15
|
+
let values;
|
|
16
|
+
try {
|
|
17
|
+
values = typeof stored === 'string' ? JSON.parse(stored) : stored;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
if (!Array.isArray(values) || values.length < 2 || values.length > MAX_EMBEDDING_DIMS)
|
|
23
|
+
return undefined;
|
|
24
|
+
let max = 0;
|
|
25
|
+
for (const v of values) {
|
|
26
|
+
if (typeof v !== 'number' || !Number.isFinite(v))
|
|
27
|
+
return undefined;
|
|
28
|
+
max = Math.max(max, Math.abs(v));
|
|
29
|
+
}
|
|
30
|
+
if (max === 0)
|
|
31
|
+
return undefined;
|
|
32
|
+
const scale = max / 127;
|
|
33
|
+
const bytes = new Int8Array(values.length);
|
|
34
|
+
for (let i = 0; i < values.length; i++)
|
|
35
|
+
bytes[i] = Math.max(-127, Math.min(127, Math.round(values[i] / scale)));
|
|
36
|
+
return { dims: values.length, scale: Number(scale.toPrecision(6)), b64: Buffer.from(bytes.buffer).toString('base64') };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=embedding-q8.js.map
|
|
@@ -136,6 +136,8 @@ export declare function bridgeListEntries(options: {
|
|
|
136
136
|
includeContent?: boolean;
|
|
137
137
|
/** ADR-323: restrict rows to these provenance types. */
|
|
138
138
|
provenanceFilter?: string[];
|
|
139
|
+
/** ADR-472: include each entry's embedding as int8+scale (`embeddingQ8`); at most MAX_LIST_EMBEDDINGS rows. */
|
|
140
|
+
includeEmbedding?: boolean;
|
|
139
141
|
}): Promise<{
|
|
140
142
|
success: boolean;
|
|
141
143
|
entries: {
|
|
@@ -150,6 +152,11 @@ export declare function bridgeListEntries(options: {
|
|
|
150
152
|
/** #2073: Present when `includeContent: true` was requested. */
|
|
151
153
|
content?: string;
|
|
152
154
|
provenanceType?: string;
|
|
155
|
+
embeddingQ8?: {
|
|
156
|
+
dims: number;
|
|
157
|
+
scale: number;
|
|
158
|
+
b64: string;
|
|
159
|
+
};
|
|
153
160
|
}[];
|
|
154
161
|
total: number;
|
|
155
162
|
error?: string;
|