⚠️ v0.10 alpha. Production-ready for single-operator / small-team use. Breaking changes are likely until v1.0 lands multi-tenancy + SSO + signed release artifacts. Schema migrations are forward-only — back up your Postgres before upgrading minor versions. See the Roadmap for what's gated on v1.0.
The nervous system for multi-agent LLM workflows. One Go binary on one Postgres database, doing three things every multi-agent stack reinvents badly:
1. Cross-session coordination · 2. Shared semantic memory · 3. Capability-typed orchestration (v0.6)
Stop running three services (agentmemory + a broker + your own task queue) when one Postgres schema does the lot. Plays directly into Kronaxis Router for the cheapest-competent-model decision.
BSL 1.1 · Website · API · Why use it · vs agentmemory / mem0 / Letta
┌─ POST /v1/coord ──▶ broadcast to other sessions (pg_notify)
Tab A (orchestrator) ──┤
├─ POST /v1/memo ──▶ bank a finding (semantic + tsvector + recency)
└─ POST /v1/task ──▶ create work item, required_capabilities=[...]
│
│ (Fabric routes by capability)
▼
┌──── POST /v1/task/claim ──── Tab B (capabilities=["go-build"])
Kronaxis Fabric ─────────────► ├──── POST /v1/task/claim ──── Tab C (capabilities=["python","gpu-3090"])
(one Go binary, └──── POST /v1/task/claim ──── CI runner (capabilities=["docker","aws"])
one Postgres schema)
│
├──── GET /v1/coord/recent ─── any session polls broadcasts
├──── POST /v1/memo/search ─── 90ms hybrid search over 1000s of memos
└──── POST /v1/router/obs ──── learning loop for Kronaxis Router
Tab D (your agent) ──POST /v1/chat/completions──▶ Kronaxis Router ──▶ cheapest competent model
(uses fabric memo search to keep context tiny)
Three jobs, one substrate. Coord channel for "what is everyone else doing right now". Memory for "what did I learn last week". Task graph + capability dispatch for "who in this fleet is best placed to do X". All on the same Postgres, same Bearer token, same single Go binary.
Pairs with Kronaxis Router: Router decides WHICH model. Fabric decides WHAT context. Together you stop paying frontier prices for context you didn't need to send to a model that didn't need to be that big.
Reason 1 — Multi-agent stacks reinvent coordination badly. Five Claude Code tabs on the same project. An overnight cron. A CI runner. Each one needs to (a) see what the others are doing, (b) avoid duplicating work, (c) hand off findings, (d) recover when a tab crashes. The default answer today is some combination of Slack channel humans monitor, ad-hoc REST endpoints, and "remember to message me when you're done". Fabric ships a coord channel + task graph + capability dispatch on one Postgres schema. The orchestrator pattern we used to build Fabric itself (one MAIN tab coordinating four worker tabs across two hosts) was hand-coordinated via Fabric's coord broadcasts. v0.6 formalises it with typed sessions + presence + automatic dispatch.
Reason 2 — Stop preloading 100 KB of project notes into every session. Every Claude Code / Codex / Aider session starts by loading CLAUDE.md + MEMORY.md + curated notes. That's 60–90 K tokens per turn, every turn, in every session. Fabric replaces it with on-demand hybrid search: only the 3 memos relevant to this turn get loaded, ranked semantically + lexically + by recency.
Real measurement on a real project (this one): 715 → 172 line CLAUDE.md + 1050 → 51 line MEMORY.md after the fabric cutover. ~92 K tokens saved per session preload. At Anthropic Opus rates that's ~£0.45 per session, ~£14/day for a 30-session day. Compounds fast.
Better than grepping your own notes:
- Semantic search — query "database connection pool exhaustion fix" finds memos that say "postgres max_connections raised after 503 burst" without sharing a single word
- Hybrid rank — cosine (50%) + tsvector (30%) + recency (20%) so a fresh half-baked memo doesn't outrank a verified 3-week-old reference
- Score-comparable across queries — 0–1 cosine-based, not a per-query magic number
Drops into your existing stack without rewiring:
- MCP stdio shim →
~/.claude.jsonconfig = nativemcp__fabric__searchtool in Claude Code - Plain HTTP + Bearer = curl from anything else (shell scripts, CI, other agents)
- Postgres-backed = your DBA already knows how to back it up
- Embeddings via local Ollama = zero per-query cost, zero data leaving your box
Memos solve "what did I learn last week". The other half of multi-agent workflows is "what is the agent in the other tab doing right now". Fabric ships a coord channel on the same Postgres: POST /v1/coord writes a row to public.coord_messages and fires pg_notify('coord', ...); GET /v1/coord/recent lets any session poll the last N events filtered by sender / recipient / since.
# Tab A broadcasts a finding
curl -X POST -H "Authorization: Bearer $FABRIC_KEY" -H "Content-Type: application/json" \
-d '{"sender":"A","recipient":"all","subject":"db migration done","body":"schema v17 applied"}' \
http://fabric:8201/v1/coord
# Tab B (or a CI runner, or your laptop) reads the recent broadcasts
curl -H "Authorization: Bearer $FABRIC_KEY" \
"http://fabric:8201/v1/coord/recent?limit=10&recipient=all"We used this in tonight's session to coordinate five concurrent agent tabs (orchestrator + workers) on the same project. It is the unsung infrastructure piece — agentmemory / mem0 / Letta don't have a cross-session event bus, only memory. Multi-agent workflows on a single project need both, and Fabric ships both behind the same Bearer token on the same Postgres.
# 1. Schema (one-time, in your existing Postgres)
psql -h db.example.com -U postgres -d kronaxis \
-c "CREATE SCHEMA IF NOT EXISTS fabric; CREATE EXTENSION IF NOT EXISTS vector;"
# 2. Pull the embedding model (one-time)
ollama pull nomic-embed-text
# 3. Build + run
go build -o /tmp/fabric ./cmd/fabric
FABRIC_KEY=secret-bearer-token \
FABRIC_PG_DSN="postgres://user:pass@db:5432/kronaxis" \
FABRIC_LISTEN=:8201 \
/tmp/fabric &
# 4. Bank a memo
curl -X POST -H "Authorization: Bearer secret-bearer-token" -H "Content-Type: application/json" \
-d '{"title":"production-postgres password","content":"in 1Password under Infra-Prod","type":"reference"}' \
http://localhost:8201/v1/memo
# 5. Find it later
curl -X POST -H "Authorization: Bearer secret-bearer-token" -H "Content-Type: application/json" \
-d '{"query":"where is the prod db password","top_k":1}' \
http://localhost:8201/v1/memo/search
# → returns your memo with score 0.92That's it. systemd unit + MCP shim in deploy/.
Fair warning before reading the table: most of the alternatives are memory-only systems. Fabric is three things in one binary (coord channel + memory store + orchestrator-coming). Compare on a feature they don't have and the comparison is by definition unfair to them. We've split the table by job-area so you can see what Fabric uniquely covers vs where alternatives match.
| Dimension | Fabric | agentmemory | mem0 | Letta/MemGPT |
|---|---|---|---|---|
| Search | Hybrid (cosine + tsvector + recency) | BM25 + vector + graph (RRF) | Vector + graph | Vector only |
| Embeddings | Local Ollama, free at query time | Local Xenova, free | Cloud-provider call per query | Cloud-provider call per query |
| Lines of code | ~700 (single file) | thousands across hooks/UI | thousands | tens of thousands (full agent runtime) |
| Storage | Postgres + pgvector | SQLite + iii-engine | Qdrant or pgvector | Postgres + vector DB |
| MCP wire-up | ~/.claude.json 5-line stanza |
Same | Manual | Manual |
| Auto-capture hooks | No (explicit remember calls) |
Yes (12 lifecycle hooks) | No | No (agent self-edits) |
| Real-time viewer | No (psql is your viewer) |
Yes (port 3113) | Cloud dash | Cloud dash |
| Dimension | Fabric | Redis Streams | NATS JetStream | RabbitMQ | Raw pg_notify |
|---|---|---|---|---|---|
| Adds a new service to run | No (reuses your Postgres) | Yes (Redis) | Yes (NATS cluster) | Yes (RabbitMQ) | No |
| Persistent event log | Yes (coord_messages table) |
Yes (XADD stream) | Yes (JetStream) | Yes (with disk queue) | No (fires once, not stored) |
| Audit via SQL | Yes (SELECT * FROM coord_messages WHERE …) |
No (custom CLI) | No (nats stream) |
No (mgmt UI) | N/A |
| Push notifications (sub-second) | Yes (pg_notify trigger) | Yes (XREAD BLOCK) | Yes | Yes (consumer push) | Yes |
| Filter by recipient / since | Yes (?recipient=X&since=…) |
Consumer groups | Subjects | Routing keys | DIY |
| Bearer-auth same as memory | Yes (one token, one service) | Separate auth | Separate auth | Separate auth | Postgres role |
| Best for | Multi-agent project coord on existing Postgres | High-throughput cache+stream | Microservice fleets | Enterprise messaging | Quick hacks |
For genuine high-throughput broker workloads (millions of msg/s) use NATS or Redis. For multi-agent coord on a project (events per second, not per millisecond), Fabric gives you a sufficient subset on the Postgres you already run.
| Dimension | Fabric v0.6 | Temporal | CrewAI | LangGraph | AutoGen | Celery / Prefect |
|---|---|---|---|---|---|---|
| Adds a new service | No (Postgres) | Yes (Temporal cluster + Cassandra/ES) | No (Python library) | No (Python library) | No (Python library) | Yes (broker + workers) |
| Cross-language agents | Yes (HTTP from anything) | Yes (SDKs) | Python only | Python only | Python only | Python only |
| Task graph storage | Postgres (fabric.tasks) |
Internal events DB | In-memory | In-memory | In-memory | Result backend |
| Capability-typed dispatch | Yes (required_capabilities matched to session.capabilities) |
Workflow workers | Role-based | State-based | Agent types | Routing keys |
| Presence + heartbeat | Yes (90 s auto-offline) | Yes (workers) | No | No | No | Yes (workers) |
| Built-in pub/sub | Yes (same coord channel) | Signals | No | No | No | No |
| Built-in semantic memory | Yes (same memo store) | No | No (DIY RAG) | Some (state) | No (DIY) | No |
| Sweet spot | Multi-agent coding sessions on one project | Production workflows at scale | LLM agent crews | LLM agent state machines | LLM agent conversations | Background jobs |
If you're orchestrating a 1000-worker production payment pipeline, take Temporal. If you're orchestrating five Claude Code tabs + a CI runner on one project, the Temporal cluster is overkill and you don't already have it running. Fabric is the small-team multi-agent-coding subset of Temporal's job, on the database you already have.
| Dimension | Fabric v0.5 | Sourcegraph | codegraph (MCP) | ast-grep | ripgrep + ctags |
|---|---|---|---|---|---|
| Self-host friction | One binary | Docker compose / SaaS | One binary | One binary | Native |
| MCP-native | Yes (same mcp__fabric__search namespace) |
No (HTTP/GQL) | Yes | No | No |
| Symbol embeddings | Yes (cosine on signature + docstring) | Yes (Cody) | No | No | No |
| Cross-symbol edges (calls / imports) | Yes (symbol_edges) |
Yes | Yes | No | Limited (ctags) |
| Same auth as memory + coord | Yes (one Bearer) | Separate | Yes (different MCP) | N/A | N/A |
| Languages day-one | Go + Python | 50+ | Many | Many | All (lexical only) |
| Inotify re-index | v0.5+1 | Yes | Yes | One-shot | One-shot |
| Storage | Postgres (same DB as memos + coord) | Custom Zoekt + Postgres | SQLite | None | tags file |
If you need cross-50-language enterprise code search, Sourcegraph wins. If you want symbol search + relationships in the same Bearer-authed MCP namespace your agents already use for memory and coord, Fabric is the integrated choice.
| Dimension | Fabric | agentmemory | mem0 | Letta |
|---|---|---|---|---|
| External deps | Postgres + Ollama (both standard) | None (SQLite) | Qdrant/pgvector | Postgres + vector DB |
| Backup story | pg_dump (you already know it) |
Custom SQLite + iii state | Multi-service | Multi-service |
| Ops surface | Standard Postgres | Custom SQLite + iii engine | Multi-service | Multi-service |
| Self-host friction | One binary + systemd --user |
One binary + node runtime | Docker compose | Docker compose |
| Cost / scale story | pgvector scales to millions; Postgres ops you already do | SQLite hits write-lock at scale | Qdrant means another service | Vector DB means another service |
When Fabric wins:
- You already run Postgres, you want one more schema not one more service.
- You want the simplest possible audit trail (
SELECT * FROM fabric.memos WHERE deleted_at IS NULL). - You want to pair it with a router (cost-conscious shop, that's the point).
- You want the operator to learn one thing (Postgres) not three (SQLite + iii-engine + custom viewer).
When agentmemory / mem0 / Letta might fit better:
- You don't want to run Postgres (agentmemory wins — pure SQLite, zero external).
- You want auto-capture hooks across many agent platforms with no integration work (agentmemory's 12 lifecycle hooks).
- You want a full agent runtime not just memory (Letta).
Fabric is for the operator who already runs production Postgres and wants to stop paying frontier prices for preloaded context. Everything else is a side-quest.
If you run Kronaxis Router you already decided: cheap models for the 80%, frontier for the 20%, agentic CLIs as OpenAI endpoints. Fabric closes the loop on the OTHER half of LLM cost — the context window.
Without fabric: With fabric:
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
agent reads MEMORY.md (300 KB) agent calls mcp__fabric__search
agent reads CLAUDE.md (100 KB) → 3 memos, 2 KB, 90 ms
agent reads 5 project docs (50 KB)
total preload: ~120 K tokens total preload: ~500 tokens
sends to Router → frontier sends to Router → sovereign 7B (50× cheaper)
~$0.60 per turn @ Opus ~$0.001 per turn @ Qwen 7B
Same answer quality on the typical "how does X work" query, because the model receives the specific 3 relevant memos instead of being asked to grep a 120 K-token preload. Per-session bill drops 100–600× when both run together.
| Method | Path | Auth | Notes |
|---|---|---|---|
| GET | /v1/health |
— | DB + embedding model status |
| POST | /v1/memo |
Bearer | Create memo. sha256 dedup. Returns {id, sha256, deduped, embedded} |
| GET | /v1/memo/:id |
Bearer | Read |
| PUT | /v1/memo/:id |
Bearer | Partial update. Re-embeds on change |
| DELETE | /v1/memo/:id |
Bearer | Soft delete (sets deleted_at) |
| POST | /v1/memo/search |
Bearer | {query, top_k?, type?, mode?} → ranked hits |
| POST | /v1/memo/backfill |
Bearer | Embed any memos with NULL embedding |
| POST | /v1/coord |
Bearer | {sender, recipient, subject, body} → coord_messages + pg_notify |
| GET | /v1/coord/recent |
Bearer | ?limit=&since=&recipient= |
| POST | /v1/symbol |
Bearer | v0.5 — upsert code symbol (indexer-side) |
| POST | /v1/symbol/edge |
Bearer | v0.5 — upsert symbol→symbol edge (calls/imports/references) |
| POST | /v1/symbol/search |
Bearer | v0.5 — hybrid search over symbols (same shape as memo search) |
| GET | /v1/symbol/:id/callers |
Bearer | v0.5 — incoming edges |
| GET | /v1/symbol/:id/callees |
Bearer | v0.5 — outgoing edges |
| POST | /v1/symbol/reindex |
Bearer | v0.5 — one-shot reindex hook (calls scripts/kx-fabric-indexer.py) |
| POST | /v1/session |
Bearer | v0.6 — register/refresh {id, host, capabilities}, idempotent |
| POST | /v1/session/:id/heartbeat |
Bearer | v0.6 — 30 s heartbeat; 90 s offline reaper |
| GET | /v1/sessions |
Bearer | v0.6 — ?status=&capability= filters |
| POST | /v1/task |
Bearer | v0.6 — create {title, brief, required_capabilities, created_by} |
| POST | /v1/task/claim |
Bearer | v0.6 — body {session_id}, atomic capability-matched claim |
| POST | /v1/task/:id/complete |
Bearer | v0.6 — body {result, status?} |
| GET | /v1/tasks |
Bearer | v0.6 — ?status=&assigned=&since= |
| GET | /v1/federation/coord/since/:id |
Bearer | v0.7 — pull coord_messages above high-water |
| POST | /v1/federation/coord/import |
Bearer | v0.7 — bulk import from peer |
| POST | /v1/federation/peer |
Bearer | v0.7 — register {id, url, bearer_token} peer |
| GET | /v1/federation/peers |
Bearer | v0.7 — list peers + last-pull state |
| POST | /v1/router/observation |
Bearer | v0.8 — record {request_hash, task_category, model_id, cost_usd, latency_ms, outcome} |
| GET | /v1/router/recommend |
Bearer | v0.8 — ?category=X → ranked model list over 30-day window |
Search mode: hybrid (default), semantic, tsvector.
| Env | Required | Default | Notes |
|---|---|---|---|
FABRIC_KEY |
Yes | — | Single shared Bearer token |
FABRIC_PG_DSN |
Yes | — | postgres://user:pass@host:5432/db |
FABRIC_LISTEN |
No | :8201 |
Bind address |
OLLAMA_URL |
No | http://localhost:11434 |
Embedding service |
Schema migration runs on boot (CREATE TABLE IF NOT EXISTS, ALTER TABLE ADD COLUMN IF NOT EXISTS). pgvector + tsvector extensions required (CREATE EXTENSION IF NOT EXISTS vector).
Add to ~/.claude.json:
"mcpServers": {
"fabric": {
"type": "stdio",
"command": "python3",
"args": ["/path/to/scripts/kx-fabric-mcp.py"],
"env": {
"FABRIC_URL": "http://your-server:8201",
"FABRIC_KEY": "secret-bearer-token"
}
}
}New sessions get mcp__fabric__search, mcp__fabric__remember, mcp__fabric__health as native tools.
Built + deployed on a single project (this one) on 2026-05-25:
- 600 memos imported from a 567-file curated
memory/*.mdtree in 13 seconds. - All 600 embedded via Ollama (
nomic-embed-text768d, local, free). mcp__fabric__searchreturned the right memo as top hit on 6/6 test queries.- Latency 89-181 ms p50 LAN. Cold-start embed ~3 s once, then warm.
- A/B vs agentmemory on identical queries: tied on quality, 2-3× faster on latency.
- Drove a 76% reduction in
CLAUDE.mdsize (715 → 172 lines) by extracting pitfall sections to fabric memos. Sessions still find the content via search. - v0.5 → v0.8 shipped same day: schema + endpoints + smoke tests for code graph, orchestrator, federation, router learning. End-to-end smoked: session-register → task-create → capability-matched claim → router-observation → router-recommend all green.
v0.8.0. Memos + coord + code graph + orchestrator + federation primitives + router learning loop — all in one binary, one Postgres database, one Bearer token. Single shared key, no multi-tenancy, no RBAC. Production-ready for single-operator / small-team use; v1.0 items below gate broader deployment.
Memory substrate (v0.2)
- Memo CRUD with sha256 dedup via
ON CONFLICT - Hybrid search — cosine 50% + tsvector 30% + recency 20% (configurable mode)
- Embeddings via Ollama
nomic-embed-text, 768d, pgvector ivfflat index - Backfill endpoint for memos with NULL embedding
- Soft delete (
deleted_atfiltered from all reads)
Coord channel (v0.2)
public.coord_messages+ pg_notify pub/sub for cross-session events- Filter recent events by sender / recipient / since
origin_hostcarried through since v0.7
Code graph (v0.5)
fabric.symbols+fabric.symbol_edgesschema (functions / methods / types +calls/imports/referencesedges)- Hybrid name + semantic search over symbols (same shape as memo search)
- Callers / callees lookups (
GET /v1/symbol/:id/callers) - Indexer at
scripts/kx-fabric-indexer.py(tree-sitter, Go + Python tier 1, one-shot mode)
Orchestrator (v0.6)
fabric.sessions+fabric.tasksschema with capability arrays- Atomic capability-matched task claim (
UPDATE … RETURNING …) - 30 s heartbeat / 90 s offline reaper / 5 min stale-task auto-revert
- Formalises the MAIN-orchestrator + worker-sessions pattern that today is hand-coordinated
Federation primitives (v0.7)
origin_hoston coord + tasks,fabric.federation_peersregistry- Pull-based replication endpoint (peer A polls peer B's
/v1/federation/coord/since/:high_water) - 5 s background poll loop per registered peer
- Logical replication slots remain operator-side ops; fabric provides the data plane
Router learning loop (v0.8)
fabric.router_observationsschema captures{request_hash, task_category, model_id, cost_usd, latency_ms, outcome, outcome_score?}GET /v1/router/recommend?category=Xreturns ranked model list over 30-day window, sorted bysuccess_rate / cost_usd_avg- The cheapest-competent-model decision now gets data-driven over time
Shared infrastructure
- Bearer-token auth (single shared
FABRIC_KEY) on every endpoint except/v1/health - Schema migrations idempotent on boot (
CREATE/ALTER … IF NOT EXISTS) - 3 smoke-test bash scripts per version in
scripts/test/v0.X-smokes.sh
v0.5 → v0.8 shipped 2026-05-25 in one binary. Remaining:
- v0.3 (parked) — Per-tenant Bearer keys, RBAC scopes, audit log table
- v0.4 (parked) — Native MCP stdio (no Python shim), WebSocket subscriptions on coord
- v0.9 — inotify-driven incremental code reindex (
cmd/fabric-watcher/,feature/v0.9-inotify-watcher); quality grader integration that auto-fillsrouter_observations.outcome_score - v0.10 — logical-replication-slot federation (today's polling becomes the v0.9 fallback path)
- v1.0 — Multi-tenancy, SSO, signed release artifacts, formal MCP surface
The end state: one Postgres-backed nervous system that replaces ad-hoc memory, ad-hoc inter-session coord, ad-hoc orchestrator-worker dispatch, ad-hoc code-graph snapshots, and ad-hoc router heuristics with one auditable store. v0.8.0 lands all five substrate pieces; v0.9+ tightens them.
BSL-1.1. Source-available; internal + non-commercial use granted. Production / commercial use requires a separate licence — contact contact@kronaxis.co.uk.
Same licence model as Kronaxis Router.