Architecture
Every service, resident, and topic in Caura — the core tier that ships in OSS, the platform tier that ships managed, how a write flows through the event bus, and what differs between self-host and managed deployments.
Four core services, one event bus, scheduled residents, Postgres + pgvector underneath. Synchronous on the response path, async on the heavy work. Two tiers: the core tier (core-* services) is the OSS product; the platform tier (the gateway and platform-* services) is the managed and enterprise control plane — structurally separate, not just commercially.
How work flows through Caura
Four core services, one event bus, scheduled residents. Synchronous on the response path, async on the heavy work. Dashed = managed only.
Memories enter through one of exactly three ingest paths — realtime (an agent chose to write), reflective (the Interviewer), and bulk (imports and documents). The memory pipeline page follows one write through the stages; this page maps the machinery.
Core tier
core-api
FastAPI service and the hot node. Handles HTTP and MCP requests — the MCP server is mounted at /mcp on the same app, so a single deployment serves both surfaces. It applies auth, trust, quotas, and keystones; writes raw memories; serves recall reads (vector + full-text + entity-graph, blended); and hosts the Interviewer submit endpoint, the Skills Inbox routes, and the admin lifecycle-fanout endpoints the residents fire into.
After a successful write, what happens next depends on the deployment (see the variance table): on self-host (deployment_mode=inline, the OSS default) core-api embeds and enriches inline on the write path; on managed (deferred) it publishes embed-requested / enrich-requested to the event bus for core-worker. Contradiction detection runs post-commit, fire-and-forget via an async track_task (see services/contradiction_detector.py's detect_contradictions_async) — the write itself does not block on it.
core-api is also a consumer: it subscribes to memclaw.memory.embedded / .enriched (the return edge on the diagram — how contradiction detection fires on the deferred path), to the crystallize / entity-link / insights lifecycle topics (their pipeline machinery lives here), and to memclaw.org.settings-changed as a broadcast so every process drops its settings cache when governance controls change.
core-worker
Async worker, managed deployments only — the OSS compose stack does not include it, and doesn't need it: OSS runs inline. On managed it subscribes to embed-requested and enrich-requested, calls the configured embedding + entity-extraction providers, writes structured rows back through core-storage-api, and also carries the archive/purge lifecycle consumers (per-tenant concurrency, retry + DLQ).
core-storage-api
Thin Postgres gateway used by every other service for memory CRUD and pgvector ops. Runs two uvicorn workers by default (its Dockerfile CMD); raising that means overriding the container command — measure against your own workload before backfills rather than assuming a throughput number.
core-operations
The scheduler service — a fourth core service that fires nine registered cron ticks (see core-operations/src/core_operations/app.py). Each tick calls a core-api admin endpoint, which fans out one event per active tenant; tenants that haven't opted in to a feature never appear in its fanout and pay zero cost.
| Tick | Cadence | Drives |
|---|---|---|
lifecycle-archive-expired | daily | archive memories past their expiry |
lifecycle-archive-stale | daily | archive long-untouched memories |
lifecycle-purge-soft-deleted | daily | hard-delete soft-deleted rows past retention |
lifecycle-crystallize | daily | Crystallizer consolidation |
lifecycle-entity-link | daily | entity-link discovery |
lifecycle-insights | daily | insights discovery |
agent-digest | daily | per-agent activity digests (opt-in) |
agent-digest-weekly | weekly | weekly digest window |
interviewer-schedule | hourly | queues due interview_request fleet commands |
One deliberate exception: Forge distillation is not a core-operations tick. Its cadence comes from an external scheduler hitting POST /admin/lifecycle/fanout/forge-distill — on self-host you provide that cron; on managed the platform fires it. This is the only feature whose schedule is operator-supplied.
Redis
In both compose files and required: backs the cache and per-tenant rate limits, and is health-probed by /api/v1/health. Without it, caching and rate limiting fail — it is not an optional accelerator.
TEI local embedder (optional)
A supported local-embedding deployment (--profile embed-local in compose): Text Embeddings Inference serving BAAI/bge-m3 (1024-dim), for self-hosters who want no external embedding API. Without it, embedding uses the configured remote provider.
Residents
A resident is a scheduled server-side job that operates on stored data rather than serving a request: the six lifecycle jobs, Agent Digests, the Interviewer scheduler, and Forge. core-operations provides the clock; the work itself runs where each consumer is registered:
- embed / enrich and archive / purge — core-worker on managed; core-api on OSS (no worker process).
- crystallize / entity-link / insights — always core-api, in both deployments (the pipeline machinery lives there).
- Forge distill — consumed via the Skill Factory service code in core-api; cadence operator-supplied on self-host (above).
Every lifecycle tick writes one lifecycle_audit row per tenant, so a silent failure is visible in data, not just logs.
Event bus
OSS default is an in-process bus; the managed deployment uses Google Pub/Sub. The /api/v1/health route's event_bus field reports the current backend's status. Five topic families (common/events/topics.py):
| Family | Topics |
|---|---|
memclaw.memory.* | created · embed-requested · embedded · enrich-requested · enriched |
memclaw.lifecycle.* | archive-expired-requested · archive-stale-requested · purge-soft-deleted-requested · crystallize-requested · entity-link-requested · insights-requested · forge-distill-requested |
memclaw.pipeline.* | entity-extract-requested · entity-extracted |
memclaw.org.* | settings-changed (broadcast — every process drops its settings cache) · suppression-changed (tenant suppress / restore mirroring) |
memclaw.audit.* | event-recorded |
The write flow is a loop, not a line: embedded / enriched flow back to core-api (green arrow on the diagram), which is how contradiction detection fires on the deferred path — the worker announces completion, core-api reacts.
Platform tier (managed / enterprise)
Self-hosters can skip this section — none of it runs in the OSS stack. On managed deployments an nginx gateway fronts everything, and six platform-* services form the control plane: platform-auth-api (identity — API keys, Broker installs), platform-audit-api (the tamper-evident audit log), platform-admin-api (tenant administration), platform-storage-api, platform-operations (platform-side scheduled jobs), and an internal devops bot.
The Broker's place in the system
The Caura Broker is the local daemon (memclawd) on a developer machine that connects coding agents to Caura and enforces policy, redaction, and audit before anything leaves the machine. Architecturally it is a producer (lane 0) with its own identity plane:
- Frozen wire contract. The install endpoints (
installs/register,claim,heartbeat,policy/stream) plusaudit-logare a frozen v1 contract, enforced by oasdiff breaking-change gates in CI in both repos (platform-auth-api/openapi.broker.json,platform-audit-api/openapi.broker.json; the OSS core-api baseline landed with its own gate). A breaking change to what deployed Brokers depend on fails the PR. - Verified identity. The gateway plumbs
X-Caura-Credential-Kind: install_credentialandX-Install-UUIDinto core-api, which namespaces Broker-owned agents asbroker:<install>— cross-install attribution can't be forged, and bulk writes carry per-item attribution. - Two modes. Personal mode (an unjoined install) works self-contained; Fleet mode joins the install to a Broker Fleet for heartbeats, policy streaming, and dashboard governance.
How install credentials differ from user API keys, and what broker:<install> ownership means for reads, is covered under trust levels.
Deployment variance
Say it once: what actually differs between the stacks.
| Concern | Self-host (OSS) | Managed / enterprise |
|---|---|---|
| Embed + enrich | Inline in core-api (deployment_mode=inline) | Deferred to core-worker |
| core-worker process | Not in compose | Separate service |
| Event bus | InProcessEventBus | Google Pub/Sub |
| Archive / purge consumers | Registered in core-api | Subscribed by core-worker |
| Crystallize / entity-link / insights | core-api | core-api (same) |
| Forge cadence | Operator-provided external cron | Fired by managed infra |
| Broker governance | Personal mode | Fleet mode: heartbeat, policy stream, audit |
| Embeddings | OpenAI-compatible provider or TEI local | Platform-tier provider (Vertex) |
| Platform tier + gateway | Absent | Present |
OpenClaw plugin (optional)
Lives inside an OpenClaw gateway and claims the memory slot, replacing memory-core and exposing the memclaw_* tools to every agent that runs through the gateway. It is also the push-delivery path for Skill Factory active skills and hosts the plugin-buffer Interviewer collector. See OpenClaw integration.