| 1 | # Darwin Cortex - Gateway Contract (binding) |
| 2 | |
| 3 | The keystone. One service, one verb: **`ask`**. Fans out to every memory engine in parallel, |
| 4 | reconciles by the source-of-truth hierarchy, synthesizes one answer with clickable receipts, and |
| 5 | is itself exposed as the single MCP every agent calls. |
| 6 | |
| 7 | **Runtime:** Python 3.11 · FastAPI · `httpx` (async) · `mcp` SSE client · `pydantic` v2. |
| 8 | **Lives on:** Darwin CT (REDACTED-IP). During dev may run on CT215. |
| 9 | **Ports:** HTTP API `:9890` · MCP SSE shim `:9891`. |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## 1. Engines (fan-out targets) - all already live on REDACTED-IP |
| 14 | |
| 15 | | key | transport | primary calls | answers | |
| 16 | |---|---|---|---| |
| 17 | | `rag` | SSE `:9876` | `homelab_search`, `homelab_context` | content / what / where / why | |
| 18 | | `cbm` | SSE `:9877` | `search_graph`, `get_architecture` | code structure, blast radius | |
| 19 | | `serena` | SSE `:9878` | `find_symbol`, `find_referencing_symbols` | live symbol truth | |
| 20 | | `memgraph` | SSE `:9879` | `query_entities`, `query_relations` | decisions, ownership, handoffs | |
| 21 | | `inbox` | HTTP (Memos API) | list/search memos | Zion's raw captures | |
| 22 | |
| 23 | Each engine is wrapped in an **adapter** with: a hard timeout (default 4000ms), a normalizer that |
| 24 | maps its native result into the common `Hit` shape, and **graceful degradation** - a dead engine |
| 25 | returns `{engine, status:"down", hits:[]}`, never throws. The set of up/down engines is returned to |
| 26 | the UI verbatim (it drives the organism's health-as-anatomy). |
| 27 | |
| 28 | --- |
| 29 | |
| 30 | ## 2. API |
| 31 | |
| 32 | ### `POST /ask` |
| 33 | ```jsonc |
| 34 | // request |
| 35 | { |
| 36 | "query": "string", |
| 37 | "mode": "both", // "chat" | "search" | "both" (default "both") |
| 38 | "scope": ["rag","cbm"], // optional engine subset; default all |
| 39 | "k": 12, // max hits per engine |
| 40 | "synthesize": true // run LLM synthesis for the chat answer |
| 41 | } |
| 42 | ``` |
| 43 | ```jsonc |
| 44 | // response |
| 45 | { |
| 46 | "answer": "string|null", // prose synthesis (null if mode=search or synth unavailable) |
| 47 | "receipts": [ // every claim in `answer` cites one of these |
| 48 | {"id":"r1","source":"rag","path":"...","last_seen":"2026-06-24T00:04:00Z","confidence":0.92,"snippet":"..."} |
| 49 | ], |
| 50 | "hits": [ // raw ranked results (the "search" half of the surface) |
| 51 | {"engine":"rag","title":"...","path":"...","snippet":"...","score":0.81, |
| 52 | "last_seen":"...","confidence":0.92} |
| 53 | ], |
| 54 | "conflicts": [ // where engines disagreed + who won and why |
| 55 | {"claim":"Hermes status","winner":"live-infra","losers":["agent-memory"],"reason":"memory stale 40d"} |
| 56 | ], |
| 57 | "engines": [ {"engine":"rag","status":"up","ms":312}, {"engine":"cbm","status":"down"} ], |
| 58 | "took_ms": 480 |
| 59 | } |
| 60 | ``` |
| 61 | |
| 62 | ### `GET /health` |
| 63 | Per-engine liveness + freshness (drives organism anatomy): |
| 64 | ```jsonc |
| 65 | {"engines":[{"engine":"rag","status":"up","last_ingest":"2026-06-24T00:04:00Z","staleness_h":0.4}], "ok":true} |
| 66 | ``` |
| 67 | |
| 68 | --- |
| 69 | |
| 70 | ## 3. Ranking & reconciliation (Zion's ruling, recency-gated) |
| 71 | |
| 72 | Authority when sources conflict: |
| 73 | ``` |
| 74 | live infra state > recent files > agent memory > older notes |
| 75 | ``` |
| 76 | Implement as a **per-hit score**: |
| 77 | ``` |
| 78 | score = w_authority(source) * recency_decay(last_seen) * confidence * relevance |
| 79 | ``` |
| 80 | - `w_authority`: live-infra 1.0, recent-file 0.8, agent-memory 0.6, older-note 0.4 |
| 81 | - `recency_decay`: `exp(-age_days / HALF_LIFE)`, HALF_LIFE default 30d. **This is the Darwin valve** - |
| 82 | it pushes stale agent-memory *below* fresher notes automatically (the exact fix for the Hermes lie). |
| 83 | - A "recent file" is `mtime < 30d`; older → demoted to the notes tier. |
| 84 | - When two hits assert the same fact and disagree, the higher `score` wins; the loss is recorded in |
| 85 | `conflicts[]` with a human reason. Never silently drop the loser. |
| 86 | |
| 87 | --- |
| 88 | |
| 89 | ## 4. Synthesis routing (cost-aware; 3060 currently DOWN) |
| 90 | |
| 91 | | question complexity | synthesizer | note | |
| 92 | |---|---|---| |
| 93 | | cheap / factual | qwen3:8b on 3060 (`http://REDACTED-IP:11434/api/chat`, `think:false`) | **fallback while 3060 down → deterministic ranked-merge (no LLM)** | |
| 94 | | hard / multi-source | Opus (Claude API) | gated behind a flag; no paid calls until enabled | |
| 95 | |
| 96 | v1 ships with **deterministic ranked-merge always working** (top hits → templated answer + receipts), |
| 97 | LLM synthesis pluggable behind `synthesize` + an available-backend check. Never hard-depend on a |
| 98 | backend that may be asleep. |
| 99 | |
| 100 | --- |
| 101 | |
| 102 | ## 5. MCP exposure - the unified verb |
| 103 | |
| 104 | Expose one tool, `darwin_ask(query, mode?, scope?)`, over **stdio + SSE `:9891`**, so Zion's agents |
| 105 | (Codex CT241, GLM/OpenCode CT247, Cockpit, this Claude) replace four memory tools with one. Register |
| 106 | in each agent's MCP config as `darwin`. The four underlying engines stay available for power use, but |
| 107 | `darwin_ask` is the front door. |
| 108 | |
| 109 | --- |
| 110 | |
| 111 | ## 6. Non-negotiables |
| 112 | - No claim in `answer` without a matching `receipts[]` entry. Provenance or it doesn't ship. |
| 113 | - Every engine failure degrades gracefully and is surfaced, never hidden. |
| 114 | - State/cache on **local ext4** (`/var/lib/darwin` or `/var/tmp/darwin`), NEVER on the CIFS share |
| 115 | (CIFS → `database is locked`). |
| 116 | - Read-only against the engines. The Cortex never writes to RAG/cbm/Serena/memgraph. |
| 117 | - Self-test: `tests/test_reconcile.py` must prove a 40-day-stale agent-memory "Hermes active" loses |
| 118 | to live infra "Hermes stopped". That test is the regression guard for the bug that started Darwin. |