Architecture
Carabase is a decentralized, privacy-first personal AI assistant. Instead of running your knowledge through a multi-tenant cloud, it splits into two halves connected over a private network: a lightweight native client (macOS, plus an iOS companion) and a self-hosted AI engine — the host. Your persona, your knowledge graph, your vectors, and every third-party credential live only on your own hardware.
The things in the box
Section titled “The things in the box”┌──────────────────────┐ Tailscale ┌────────────────────────────────────────────────┐│ macOS client (Tauri)│◄─── WireGuard tunnel ───►│ Host (the brain) ││ iOS client (SwiftUI)│ MagicDNS / :3000 │ ││ Admin SPA (Preact) │ │ Fastify API (TypeScript) ││ /admin/ │ │ ├── POST /api/v1/agent/message (single chat) ││ │ │ ├── /folios /entities /daily-notes /imports ││ │ │ └── OAuth · sync-rules · model-routing · … ││ │ │ ││ │ │ ChatEngine seam → 4 engines: ││ │ │ openclaw · host_native · codex_cli · claude_code││ │ │ ││ │ │ MCP server — 14 retrieval tools ││ │ │ served at /mcp (Streamable HTTP) + /mcp/sse ││ │ │ ││ │ │ PostgreSQL 16 + pgvector · pg-boss · node-cron ││ │ │ Knowledge graph (entities + typed edges) ││ │ │ OpenClaw Gateway (:18789, local, optional) │└──────────────────────┘ └────────────────────────────────────────────────┘Core principles
Section titled “Core principles”| Principle | What it means |
|---|---|
| Zero-trust security | The host exposes zero public ports. All traffic rides a WireGuard-backed Tailscale mesh. |
| Data sovereignty | Persona, PostgreSQL, the knowledge graph, vectors, and all tool credentials (AES-256-GCM encrypted) live only on your hardware. |
| Single-tenant | One workspace per host, no central gateway. Isolation is enforced by PostgreSQL Row-Level Security plus explicit workspace_id filtering. |
| Always-on compute | Heavy LLM work, embedding, and the background cron/queue jobs run on the host, sparing the client’s battery. |
The host process
Section titled “The host process”A single Node.js process. On boot it:
- Loads
.env.<env>(dev / staging / production). - Refuses to start if
HOST_MASTER_KEY(the credential-encryption key) isn’t set. - Checks for pending database migrations and exits with a clear
SCHEMA_DRIFTmessage rather than 500-looping on a missing column. - Registers the API routes under
/api/v1/. - Mounts the embedded Admin SPA at
/admin/. - Starts the pg-boss job queues (harvest, summary, curation, import-commit, agent-task, …) and the in-process
node-cronschedule. - If an OpenClaw gateway is configured, starts and health-monitors it, and registers the host’s own MCP server with it.
The bare /health and /api/v1/health endpoints skip workspace-context middleware so the client’s reachability poller never gets a false “host unreachable” reading.
Chat: one contract, four engines
Section titled “Chat: one contract, four engines”Every conversational turn from every client — macOS, iOS Siri/Summon, the CLI — enters through a single route, POST /api/v1/agent/message. The route assembles a bounded system prompt, then resolves a chat engine from the workspace’s chat_runtime setting and dispatches to it. There are four:
openclaw— the premium default. Wraps the OpenClaw gateway, which holds the agent runtime: tool execution, memory injection, and upstream model selection.host_native— the open-source chat floor. An AI-SDK reasoning loop runs directly on the host against the workspace’s configured model, with no gateway required. It is grounded: it answers personal/workspace questions only from data it retrieves, abstaining rather than guessing, and it carries a wall-clock deadline and rolling history compaction so long sessions stay bounded.codex_cli/claude_code— read-only vendor-CLI bridges. Each drives the operator’s own locally-installedcodexorclaudeCLI (authenticated by their own login) and reaches the mesh through the host’s MCP server. They run read-only by default — write tools are denied at the access gate.
When chat_runtime is auto, the host picks OpenClaw if a gateway is configured, otherwise host-native — so a self-host with no gateway chats out of the box. The vendor-CLI bridges are never auto-selected; they’re explicit opt-ins. See OpenClaw runtime and other runtimes for setup detail.
A chat turn streams back as server-sent events. A 200 response head does not by itself mean success — a failed turn surfaces a typed error frame in the stream, and only clean turns are persisted to history.
The MCP server
Section titled “The MCP server”Carabase exposes its retrieval layer as a Model Context Protocol server, so any agent — the host’s own engines, or an external client like Claude Desktop, Cursor, or Codex over your tailnet — can query the mesh. It is served at /mcp (Streamable HTTP) and /mcp/sse.
There are 14 canonical retrieval tools, including:
carabase_search_semantic— pgvector semantic search over document bodies.carabase_search_graph— knowledge-graph traversal with provenance and confidence (bounded depth and connection count).carabase_search_lexical—pg_trgmtext grep for rare proper nouns (“grep my notes for X”).carabase_search_visual/carabase_search_multimodal— image and fused text+image search.carabase_query_metadata— structured filters (entity by name, folio by id, date ranges).carabase_route_and_execute— a cross-strategy router that fans a query across legs and fuses the results.carabase_verify_hypothesis— corroborate or contradict a claim via an LLM entailment judge.carabase_read_folio— read a synthesized folio narrative plus its citations.
The full surface (including query_timeseries, traverse_memory_network, scan_mesh, find_entity_candidates, and resolve_mesh_uri) is in the MCP tools reference.
The inbound /mcp surface sits behind an optional bearer-token gate: with nothing configured it trusts the tailnet, and minting any access token turns the gate on. Tokens can be scoped read-only, in which case write tools are refused.
The knowledge engine
Section titled “The knowledge engine”The substrate the agents read and write:
- Folios — the unified narrative substrate. One concept covers plain collections (manual groupings) and engine-maintained textures (
taste/domain/projectnarratives synthesized from your data). Membership is either pinned (manual, never evicted) or auto (gathered by the engine and refreshed nightly). - Knowledge graph — entities and typed edges, each carrying its source kind, a confidence score, and provenance. Edges support bi-temporal validity (a fact can be invalidated and superseded rather than deleted).
- Memory and the daily-note timeline — the persistent-fact and chronological layers.
- Artifacts — the chunked, embedded body substrate that powers semantic retrieval.
Every LLM call that maintains this — synthesis, curation, classification, summarization — runs through a typed, traced skill harness so each step is validated, retried, and recorded.
Postgres + pgvector
Section titled “Postgres + pgvector”One database per environment (carabase_dev, carabase_staging, carabase_prod), with Row-Level Security on every workspace-scoped table — so even if a query forgets its WHERE workspace_id = ? clause, the database enforces isolation.
pgvector powers semantic and visual search; pg-boss reuses the same Postgres for the job queues, so there’s no separate Redis or message broker.
Background workers
Section titled “Background workers”Cron- and queue-driven, all in-process. They keep the mesh fresh without a client open: connector syncs (GitHub, Gmail, Calendar, and the rest), memory distillation, folio/texture synthesis, the dream cycle, corpus curation, retention purges, and trace cleanup. Connectors that push from an edge device (Apple Notes/Files/Photos, iMessage) feed the same harvest queue.
There is no external orchestrator — pg-boss plus node-cron in a single process, no Kubernetes and no separate scheduler.
The Admin SPA
Section titled “The Admin SPA”A lightweight Preact + Vite single-page app served from the host at /admin/. It is the full browser-based configuration surface — Setup wizard, Connections, OAuth Apps, Sync Rules, AI Engine, Skills, Folios, Curation, Traces, and more. Headless deployments with no native client use this as the entire control panel.
The network layer
Section titled “The network layer”No public IPs, no port forwarding, no TLS-certificate management. Clients reach the host over its Tailscale MagicDNS name or tailnet IP on port 3000. The OpenClaw gateway port (18789) is never exposed externally — only the Fastify API accepts connections.
What’s intentionally NOT in the box
Section titled “What’s intentionally NOT in the box”- No SaaS dashboard — there is no central site to log into.
- No multi-user accounts — single-tenant, one workspace per host.
- No public-internet listener — the Tailscale-only network model is what makes the host safe to run.
- No external orchestrator — queues and crons run in-process.