prism-mcp-server 9.0.6 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,6 +20,8 @@ npx -y prism-mcp-server
20
20
 
21
21
  Works with **Claude Desktop · Claude Code · Cursor · Windsurf · Cline · Gemini · Antigravity** — **any MCP client.**
22
22
 
23
+ https://github.com/dcostenco/prism-mcp/raw/main/docs/prism_mcp_demo.mp4
24
+
23
25
  ## 📖 Table of Contents
24
26
 
25
27
  - [Why Prism?](#why-prism)
@@ -437,13 +439,13 @@ A gorgeous glassmorphism UI at `localhost:3000` that lets you see exactly what y
437
439
 
438
440
 
439
441
  ### 🧬 10× Memory Compression
440
- Powered by a pure TypeScript port of Google's TurboQuant (inspired by Google's ICLR research), Prism compresses 768-dim embeddings from **3,072 bytes → ~400 bytes** — enabling decades of session history on a standard laptop. No native modules. No vector database required.
442
+ Powered by a pure TypeScript port of Google's TurboQuant (inspired by Google's ICLR research), Prism compresses 768-dim embeddings from **3,072 bytes → ~400 bytes** — enabling decades of session history on a standard laptop. No native modules. No vector database required. To mitigate quantization degradation (where repeated compress/decompress cycles could smear subtle corrections after 10k+ memories), Prism leverages autonomous **ledger compaction** and **Deep Storage cleanup** to guarantee high-fidelity memory integrity over time.
441
443
 
442
- ### 🐝 Multi-Agent Hivemind
443
- Multiple agents (dev, QA, PM) can work on the same project with **role-isolated memory**. Agents discover each other automatically, share context in real-time via Telepathy sync, and see a team roster during context loading. → [Multi-agent setup example](examples/multi-agent-hivemind/)
444
+ ### 🐝 Multi-Agent Hivemind & Enterprise Sync
445
+ While local SQLite is amazing for solo developers, enterprise teams cannot share a local SQLite file. Prism breaks the "local-only" ceiling via **Supabase Sync** and the **Multi-Agent Hivemind**—scaling effortlessly to teams of 50+ developers using agents. Multiple agents (dev, QA, PM) can work on the same project with **role-isolated memory**, discover each other automatically, and share context in real-time via Telepathy sync to a shared Postgres backend. → [Multi-agent setup example](examples/multi-agent-hivemind/)
444
446
 
445
447
  ### 🚦 Task Router
446
- Prism can score coding tasks and recommend whether to keep execution on the host model or delegate to a **local Claw agent** (a lightweight sub-agent powered by Ollama/vLLM for fast, local-safe edits). This enables faster handling of small edits while preserving host execution for complex work. In client startup/skill flows, use defensive delegation: route only coding tasks, call `session_task_route` only when available, delegate to `claw` only when executor tooling exists and task is non-destructive, and fallback to host when router/executor is unavailable. → [Task router real-life example](examples/router_real_life_test.ts)
448
+ Prism scores coding tasks across **6 weighted heuristic signals** (keyword analysis, file count, file-type complexity, scope, length, multi-step detection) and recommends whether to keep execution on the host cloud model or delegate to a **local Claw agent** (powered by deepseek-r1 / qwen2.5-coder via Ollama). File-type awareness routes config/docs edits locally while reserving systems-programming tasks for the host. The local agent features buffered streaming (handles split `<think>` tags), stateful multi-turn conversations, and automatic memory trimming. In client startup/skill flows, use defensive delegation: route only coding tasks, call `session_task_route` only when available, delegate to `claw` only when executor tooling exists and task is non-destructive, and fallback to host when router/executor is unavailable. → [Task router real-life example](examples/router_real_life_test.ts)
447
449
 
448
450
  ### 🖼️ Visual Memory
449
451
  Save UI screenshots, architecture diagrams, and bug states to a searchable vault. Images are auto-captioned by a VLM (Claude Vision / GPT-4V / Gemini) and become semantically searchable across sessions.
@@ -725,13 +727,13 @@ The Generator strips the `console.log`, resubmits, and the next `EVALUATE` retur
725
727
 
726
728
  ## 🆕 What's New
727
729
 
728
- > **Current release: v9.0.5JWKS Auth Security Hardening**
730
+ > **Current release: v9.1.0 — Task Router v2 & Local Agent Hardening**
729
731
 
730
- - 🔒 **v9.0.5JWKS Auth Security Hardening:** JWT audience/issuer claim validation (`PRISM_JWT_AUDIENCE`, `PRISM_JWT_ISSUER`), structured error logging for JWT failures, typed `PrismAuthenticatedRequest` interface, 11 new JWKS unit tests, Smithery server card fix. Vendor-neutral tested with Auth0, AgentLair, Keycloak, and custom JWKS endpoints.
732
+ - 🚦 **v9.1.0 — Task Router v2:** File-type complexity signal for intelligent code-vs-config routing, 6-signal weighted heuristic engine, multi-step false-positive fix, expanded file extension classification. Local agent hardened with buffered streaming, system prompts, memory trimming, and stateful `/api/chat` API.
733
+ - 🔒 **v9.0.5 — JWKS Auth Security Hardening:** JWT audience/issuer claim validation (`PRISM_JWT_AUDIENCE`, `PRISM_JWT_ISSUER`), structured error logging for JWT failures, typed `PrismAuthenticatedRequest` interface, 11 new JWKS unit tests, Smithery server card fix. Vendor-neutral — tested with Auth0, AgentLair ([llms.txt](https://agentlair.com/llms.txt)), Keycloak, and custom JWKS endpoints.
731
734
  - 🧠 **v9.0.0 — Autonomous Cognitive OS:** Token-Economic Reinforcement Learning (Surprisal Gate + Cognitive Budget), Affect-Tagged Memory (valence-scored retrieval), and Episodic→Semantic Consolidation. Your agents learn compression and develop intuition. → [Cognitive OS](#-autonomous-cognitive-os-v90)
732
735
  - 🧠 **v7.8.0 — Cognitive Architecture:** Episodic-to-Semantic memory consolidation (Hebbian learning), ACT-R Spreading Activation with multi-hop causal reasoning, Uncertainty-Aware Rejection Gate, and Dynamic Fast Weight Decay. → [Cognitive Architecture](#-cognitive-architecture-v78)
733
736
  - 🌐 **v7.7.0 — Cloud-Native SSE Transport:** Full Server-Sent Events MCP support for seamless network deployments.
734
- - ⚔️ **v7.4.0 — Adversarial Evaluation:** Split-brain anti-sycophancy pipeline with evidence-bound findings.
735
737
 
736
738
  👉 **[Full release history → CHANGELOG.md](CHANGELOG.md)** · **[ROADMAP →](ROADMAP.md)**
737
739
 
@@ -1100,12 +1102,37 @@ Prism has evolved from smart session logging into a **cognitive memory architect
1100
1102
 
1101
1103
  ---
1102
1104
 
1105
+ ## 💼 B2B Consulting & Enterprise Support
1106
+
1107
+ Prism MCP is open-source and free for individual developers. For teams and enterprises building autonomous AI workflows or integrating MCP-native memory at scale, we offer professional consulting and setup packages.
1108
+
1109
+ ### 🥉 Team Pilot Package
1110
+ *Perfect for engineering teams adopting MCP tools and collaborative agents.*
1111
+ * **What's included:** Full team rollout, managed Supabase configuration (for multi-device sync), Universal Import of legacy chat history, and dedicated setup support.
1112
+ * **Model:** Fixed-price engagement.
1113
+
1114
+ ### 🥈 Cognitive Architecture Tuning
1115
+ *For teams building advanced AI agents or autonomous pipelines.*
1116
+ * **What's included:** "Dark Factory" pipeline implementation tailored to your workflows, adversarial evaluator tuning, custom HDC cognitive route configuration, and local open-weight model integration (BYOM).
1117
+ * **Model:** Retainer or project-based.
1118
+
1119
+ ### 🥇 Enterprise Integration
1120
+ *Full-scale deployment for high-compliance environments.*
1121
+ * **What's included:** Active Directory / custom JWKS auth integration, Air-gapped on-premise deployment, custom OTel Grafana dashboards for cognitive observability, and custom skills/tools development.
1122
+ * **Model:** Custom enterprise quote.
1123
+
1124
+ **Interested in accelerating your team's autonomous workflows?**
1125
+ [📧 Contact us for a consultation](mailto:inquiries@prism-mcp.com) — let's build your organization's cognitive memory engine.
1126
+
1127
+ ---
1128
+
1103
1129
  ## 📦 Milestones & Roadmap
1104
1130
 
1105
- > **Current: v9.0.5** — JWKS Auth Security Hardening ([CHANGELOG](CHANGELOG.md))
1131
+ > **Current: v9.1.0** — Task Router v2 & Local Agent Hardening ([CHANGELOG](CHANGELOG.md))
1106
1132
 
1107
1133
  | Release | Headline |
1108
1134
  |---------|----------|
1135
+ | **v9.1.0** | 🚦 Task Router v2 — file-type routing signal, 6-signal heuristics, local agent streaming buffer |
1109
1136
  | **v9.0.5** | 🔒 JWKS Auth Security Hardening — audience/issuer validation, JWT failure logging, typed agent identity |
1110
1137
  | **v9.0** | 🧠 Autonomous Cognitive OS — Surprisal Gate, Cognitive Budget, Affect-Tagged Memory |
1111
1138
  | **v7.8** | 🧠 Cognitive Architecture — Hebbian consolidation, multi-hop reasoning, rejection gate, dynamic decay |
package/dist/cli.js CHANGED
File without changes
package/dist/config.js CHANGED
@@ -46,21 +46,21 @@ export const SERVER_CONFIG = {
46
46
  };
47
47
  // ─── Required: Brave Search API Key ───────────────────────────
48
48
  export const BRAVE_API_KEY = process.env.BRAVE_API_KEY;
49
- if (!BRAVE_API_KEY) {
49
+ if (!BRAVE_API_KEY && process.env.PRISM_DEBUG_LOGGING === "true") {
50
50
  console.error("Warning: BRAVE_API_KEY environment variable is missing. Search tools will return errors when called.");
51
51
  }
52
52
  // ─── Optional: Google Gemini API Key ──────────────────────────
53
53
  // Used by the gemini_research_paper_analysis tool.
54
54
  // Without this, the tool will still appear but will error when called.
55
55
  export const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY;
56
- if (!GOOGLE_API_KEY) {
56
+ if (!GOOGLE_API_KEY && process.env.PRISM_DEBUG_LOGGING === "true") {
57
57
  console.error("Warning: GOOGLE_API_KEY environment variable is missing. Gemini research features will be unavailable.");
58
58
  }
59
59
  // ─── Optional: Brave Answers API Key ──────────────────────────
60
60
  // Used by the brave_answers tool for AI-grounded answers.
61
61
  // This is a separate API key from the main Brave Search key.
62
62
  export const BRAVE_ANSWERS_API_KEY = process.env.BRAVE_ANSWERS_API_KEY;
63
- if (!BRAVE_ANSWERS_API_KEY) {
63
+ if (!BRAVE_ANSWERS_API_KEY && process.env.PRISM_DEBUG_LOGGING === "true") {
64
64
  console.error("Warning: BRAVE_ANSWERS_API_KEY environment variable is missing. Brave Answers tool will be unavailable.");
65
65
  }
66
66
  // ─── Optional: Voyage AI API Key ──────────────────────────────
package/dist/server.js CHANGED
File without changes
@@ -16,9 +16,31 @@ export async function getStorage() {
16
16
  // Use environment variable if explicitly set, otherwise fall back to db config
17
17
  const envStorage = process.env.PRISM_STORAGE;
18
18
  const requestedBackend = (envStorage || await getSetting("PRISM_STORAGE", ENV_PRISM_STORAGE));
19
- // Guardrail: if Supabase is requested but credentials are unresolved/invalid,
20
- // transparently fall back to local mode to keep dashboard + core tools usable.
21
- if (requestedBackend === "supabase" && !SUPABASE_CONFIGURED) {
19
+ // Guardrail: if Supabase is requested but env-var credentials are missing,
20
+ // check the dashboard config DB (prism-config.db) as a fallback before
21
+ // giving up. Dashboard settings take precedence over absent env vars.
22
+ let supabaseReady = SUPABASE_CONFIGURED;
23
+ if (!supabaseReady && requestedBackend === "supabase") {
24
+ const dashUrl = await getSetting("SUPABASE_URL");
25
+ const dashKey = await getSetting("SUPABASE_KEY");
26
+ if (dashUrl && dashKey) {
27
+ try {
28
+ const parsed = new URL(dashUrl);
29
+ if (parsed.protocol === "http:" || parsed.protocol === "https:") {
30
+ supabaseReady = true;
31
+ // Inject into process.env so downstream consumers (SupabaseStorage,
32
+ // SyncBus) pick them up without needing their own dashboard lookups.
33
+ process.env.SUPABASE_URL = dashUrl;
34
+ process.env.SUPABASE_KEY = dashKey;
35
+ debugLog("[Prism Storage] Using Supabase credentials from dashboard config");
36
+ }
37
+ }
38
+ catch {
39
+ // Invalid URL — fall through to local fallback
40
+ }
41
+ }
42
+ }
43
+ if (requestedBackend === "supabase" && !supabaseReady) {
22
44
  activeStorageBackend = "local";
23
45
  console.error("[Prism Storage] Supabase backend requested but SUPABASE_URL/SUPABASE_KEY are invalid or unresolved. Falling back to local storage.");
24
46
  }
@@ -1,13 +1,6 @@
1
- /**
2
- * SyncBus Factory — Routes to the correct sync implementation (v2.0 — Step 6)
3
- *
4
- * Returns SqliteSyncBus for local mode, SupabaseSyncBus for cloud mode.
5
- * Uses the same PRISM_STORAGE env var as the storage factory.
6
- *
7
- * Singleton pattern — only one bus per process (prevents duplicate watchers).
8
- */
9
1
  import { PRISM_STORAGE } from "../config.js";
10
2
  import { debugLog } from "../utils/logger.js";
3
+ import { getSetting } from "../storage/configStorage.js";
11
4
  let _bus = null;
12
5
  export async function getSyncBus() {
13
6
  if (_bus)
@@ -18,10 +11,11 @@ export async function getSyncBus() {
18
11
  }
19
12
  else {
20
13
  const { SupabaseSyncBus } = await import("./supabaseSync.js");
21
- const url = process.env.SUPABASE_URL;
22
- const key = process.env.SUPABASE_KEY || process.env.SUPABASE_ANON_KEY;
14
+ // Check env vars first, then fall back to dashboard config (prism-config.db)
15
+ const url = process.env.SUPABASE_URL || await getSetting("SUPABASE_URL");
16
+ const key = process.env.SUPABASE_KEY || process.env.SUPABASE_ANON_KEY || await getSetting("SUPABASE_KEY");
23
17
  if (!url || !key) {
24
- console.error("[SyncBus] Supabase credentials not found — falling back to local sync bus");
18
+ debugLog("[SyncBus] Supabase credentials not found in env or dashboard — falling back to local sync bus");
25
19
  const { SqliteSyncBus } = await import("./sqliteSync.js");
26
20
  _bus = new SqliteSyncBus();
27
21
  }
@@ -1,20 +1,20 @@
1
1
  /**
2
- * Task Router Handler (v7.1.0)
2
+ * Task Router Handler (v9.1.0)
3
3
  *
4
4
  * Pure, deterministic heuristic-based routing engine that analyzes a coding
5
5
  * task description and recommends whether it should be handled by the host
6
- * cloud model or delegated to the local claw-code-agent (Qwen3).
6
+ * cloud model or delegated to the local claw-code-agent (deepseek-r1 / qwen2.5-coder).
7
7
  *
8
- * No database queries. No API calls. Fully testable.
8
+ * No database queries in the pure route. No API calls. Fully testable.
9
+ * Experience-based ML bias (v7.2.0+) is applied post-hoc in the handler.
9
10
  *
10
- * Heuristic Signals (v7.1.0):
11
+ * Heuristic Signals:
11
12
  * 1. Keyword analysis (weight: 0.35)
12
- * 2. File count (weight: 0.20)
13
- * 3. estimated_scope enum (weight: 0.25)
14
- * 4. Task length proxy (weight: 0.10)
15
- * 5. Multi-step detection (weight: 0.10)
16
- *
17
- * v7.2.0 will add experience-based ML routing using SQLite feedback data.
13
+ * 2. File count (weight: 0.15)
14
+ * 3. File type / extension (weight: 0.10)
15
+ * 4. estimated_scope enum (weight: 0.20)
16
+ * 5. Task length proxy (weight: 0.10)
17
+ * 6. Multi-step detection (weight: 0.10)
18
18
  */
19
19
  import { isSessionTaskRouteArgs, } from "./sessionMemoryDefinitions.js";
20
20
  import { getStorage } from "../storage/index.js";
@@ -59,7 +59,8 @@ const MULTI_STEP_MARKERS = [
59
59
  "step 1", "step 2", "step 3",
60
60
  "then update", "then modify", "then create",
61
61
  "followed by", "subsequently",
62
- "1.", "2.", "3.",
62
+ // Note: removed bare "1.", "2.", "3." — too many false positives
63
+ // on version numbers (v1.2.3), decimals, and IP addresses.
63
64
  ];
64
65
  // ─── Heuristic Engine ────────────────────────────────────────
65
66
  /**
@@ -108,7 +109,32 @@ function fileCountSignal(files) {
108
109
  return -1.0;
109
110
  }
110
111
  /**
111
- * Compute a claw-affinity score from estimated_scope.
112
+ * Compute a claw-affinity score from file extentions.
113
+ * Simple configs/docs -> claw (+0.5)
114
+ * Complex low-level languages -> host (-0.5)
115
+ */
116
+ function fileTypeSignal(files) {
117
+ if (!files || files.length === 0)
118
+ return 0;
119
+ let simple = 0;
120
+ let complex = 0;
121
+ for (const f of files) {
122
+ if (f.match(/\.(md|json|yml|yaml|txt|csv|env|ini|toml|cfg)$/i))
123
+ simple++;
124
+ else if (f.match(/\.(cpp|cc|cxx|c|h|hpp|rs|go|java|swift|zig)$/i))
125
+ complex++;
126
+ // .ts, .js, .py, .rb, .sh, .css, .html — common scripting/web langs stay neutral (0)
127
+ }
128
+ if (simple > 0 && complex === 0)
129
+ return 0.5;
130
+ if (complex > 0 && simple === 0)
131
+ return -0.5;
132
+ if (complex > 0 && simple > 0)
133
+ return -0.2; // Complex outweighs simple
134
+ return 0;
135
+ }
136
+ /**
137
+ * Compute a claw-affinity score from scope.
112
138
  * minor_edit → strongly claw (+1.0)
113
139
  * bug_fix → moderate claw (+0.4) — some bugs are complex
114
140
  * new_feature → moderate host (-0.3)
@@ -125,17 +151,23 @@ function scopeSignal(scope) {
125
151
  }
126
152
  /**
127
153
  * Compute a claw-affinity score from task description length.
128
- * Short (< 200 chars) → claw-favoring (+0.5)
154
+ * Short (< 100 chars) → strongly claw (+1.0)
155
+ * Short-medium (< 200 chars) → claw (+0.5)
129
156
  * Medium (200-500 chars) → neutral (0.0)
130
- * Long (> 500 chars) → host-favoring (-0.5) — long = complex context
157
+ * Long (500-1500 chars) → host-favoring (-0.5)
158
+ * Very long (> 1500 chars) → strongly host (-1.0) due to context complexity
131
159
  */
132
160
  function lengthSignal(description) {
133
161
  const len = description.length;
162
+ if (len < 100)
163
+ return 1.0;
134
164
  if (len < 200)
135
165
  return 0.5;
136
166
  if (len <= 500)
137
167
  return 0.0;
138
- return -0.5;
168
+ if (len <= 1500)
169
+ return -0.5;
170
+ return -1.0;
139
171
  }
140
172
  /**
141
173
  * Detect multi-step task patterns.
@@ -153,8 +185,9 @@ function multiStepSignal(description) {
153
185
  // ─── Weights ─────────────────────────────────────────────────
154
186
  const WEIGHTS = {
155
187
  keyword: 0.35,
156
- fileCount: 0.20,
157
- scope: 0.25,
188
+ fileCount: 0.15,
189
+ fileType: 0.10,
190
+ scope: 0.20,
158
191
  length: 0.10,
159
192
  multiStep: 0.10,
160
193
  };
@@ -177,6 +210,7 @@ export function computeRoute(args) {
177
210
  // ── Compute individual signals ──
178
211
  const kw = keywordSignal(task_description);
179
212
  const fc = fileCountSignal(files_involved);
213
+ const ft = fileTypeSignal(files_involved);
180
214
  const sc = scopeSignal(estimated_scope);
181
215
  const ln = lengthSignal(task_description);
182
216
  const ms = multiStepSignal(task_description);
@@ -184,6 +218,7 @@ export function computeRoute(args) {
184
218
  // Positive = claw-favoring, Negative = host-favoring
185
219
  const composite = kw * WEIGHTS.keyword +
186
220
  fc * WEIGHTS.fileCount +
221
+ ft * WEIGHTS.fileType +
187
222
  sc * WEIGHTS.scope +
188
223
  ln * WEIGHTS.length +
189
224
  ms * WEIGHTS.multiStep;
@@ -206,6 +241,8 @@ export function computeRoute(args) {
206
241
  signals.push(`keyword analysis ${kw > 0 ? "favors claw" : "favors host"} (${kw.toFixed(2)})`);
207
242
  if (fc !== 0)
208
243
  signals.push(`file count signal: ${fc.toFixed(1)}`);
244
+ if (ft !== 0)
245
+ signals.push(`file type signal: ${ft.toFixed(1)}`);
209
246
  if (sc !== 0)
210
247
  signals.push(`scope "${estimated_scope}" signal: ${sc.toFixed(1)}`);
211
248
  if (ms !== 0)
@@ -1,26 +1,30 @@
1
- import { SUPABASE_URL, SUPABASE_KEY } from "../config.js";
1
+ // SUPABASE_URL / SUPABASE_KEY are read at call-time from process.env
2
+ // (not import-time) so dashboard-injected credentials are picked up.
2
3
  /**
3
4
  * Makes a single authenticated HTTP request to the Supabase REST API.
4
5
  * All public functions below delegate to this.
5
6
  */
6
7
  async function supabaseRequest(opts) {
7
- // Guard: ensure Supabase is configured before making any request
8
- if (!SUPABASE_URL || !SUPABASE_KEY) {
8
+ // Read credentials at call time (not import time) so that dashboard-injected
9
+ // values in process.env are picked up after storage/index.ts resolves them.
10
+ const url = process.env.SUPABASE_URL;
11
+ const key = process.env.SUPABASE_KEY;
12
+ if (!url || !key) {
9
13
  throw new Error("Supabase not configured (SUPABASE_URL / SUPABASE_KEY missing)");
10
14
  }
11
15
  // Build the full URL with any query parameters
12
- const url = new URL(`${SUPABASE_URL}${opts.path}`);
16
+ const reqUrl = new URL(`${url}${opts.path}`);
13
17
  if (opts.params) {
14
18
  for (const [k, v] of Object.entries(opts.params)) {
15
- url.searchParams.set(k, v);
19
+ reqUrl.searchParams.set(k, v);
16
20
  }
17
21
  }
18
22
  // Make the HTTP request with authentication headers
19
- const response = await fetch(url.toString(), {
23
+ const response = await fetch(reqUrl.toString(), {
20
24
  method: opts.method,
21
25
  headers: {
22
- "apikey": SUPABASE_KEY, // Supabase API key (required for all requests)
23
- "Authorization": `Bearer ${SUPABASE_KEY}`, // Also passed as Bearer token
26
+ "apikey": key, // Supabase API key (required for all requests)
27
+ "Authorization": `Bearer ${key}`, // Also passed as Bearer token
24
28
  "Content-Type": "application/json",
25
29
  // "Prefer" header controls response behavior:
26
30
  // - "return=representation" means return the inserted/updated row in the response
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prism-mcp-server",
3
- "version": "9.0.6",
3
+ "version": "9.1.1",
4
4
  "mcpName": "io.github.dcostenco/prism-mcp",
5
5
  "description": "The Mind Palace for AI Agents — a true Cognitive Architecture with Hebbian learning (episodic→semantic consolidation), ACT-R spreading activation (multi-hop causal reasoning), uncertainty-aware rejection gates (agents that know when they don't know), adversarial evaluation (anti-sycophancy), fail-closed Dark Factory pipelines, persistent memory (SQLite/Supabase), multi-agent Hivemind, time travel & visual dashboard. Zero-config local mode.",
6
6
  "module": "index.ts",