Architecture¶
The bird's-eye view of what runs in a CAESAR install. Every section links to the ADR that locked in the design — that's where the why lives.
Shape¶
┌──────────────────────────────────────┐
│ HTTP clients (phone, browser, n8n) │
└───────────────────┬──────────────────┘
│
┌───────────────────────▼────────────────────┐
│ Praetor │
│ FastAPI + LangGraph brain (ADR-0006) │
│ /v1/chat /v1/devices /v1/hook/* │
│ /dashboard /metrics /healthz │
└──┬──────┬──────┬──────────────┬────────────┘
│ │ │ │
┌───────┘ │ └─────┐ └──────────┐
▼ ▼ ▼ ▼
HA Bridge LLM Gateway SQLite + optional NATS bus
(REST + WS, (Anthropic / vector store (optional;
ADR-0007) OpenAI / audit_log, memory, ADR-0009)
Ollama, facts, episodes, │
ADR-0011/26) sessions │
▼
┌──────────────────┐
│ Legion pool │
│ in-tree workers │
│ + plugins via │
│ caesar.plugins │
│ entry points │
│ (ADR-0035) │
└──────────────────┘
proactive triggers (ADR-0030/31/32)
─────────────────────────────────
Scheduler · HAEventDriver · Webhook
all fire the same brain graph as /v1/chat
Subsystems below are loaded conditionally based on
CaesarSettings.
The minimum running install is Praetor + SQLite + an LLM provider;
everything else opts in.
Praetor — the central brain¶
- Python service. FastAPI for HTTP/WS, LangGraph for the brain-graph state machine. See ADR-0006.
- One process. The brain graph runs
call_llm → dispatch_toolsin a loop until the model either finishes or hitsmax_iterations. - Owns: conversation turn handling, system-prompt composition (facts + episodes + operator override), policy gating, audit-log writes, dispatch to Legion workers, the dashboard, and metrics.
- Emits an audit row for every decision (chat completion, tool call, trigger fire, plugin load). See ADR-0012. Decisions are replayable.
LLM Gateway¶
- Provider-agnostic abstraction over Anthropic, OpenAI, and Ollama. See ADR-0011 for the original shape and ADR-0026 for the multi-provider rewrite.
- Per-task routing: an operator can send
/v1/chatto Claude while routingmemory_extractandmemory_summariseto a cheap local Ollama, no code changes.
Legion — worker agent pool¶
- Workers register with the bus on startup and advertise capabilities
(
light.turn_on,web_search,mqtt.publish, …). The brain finds workers by capability via the registry and dispatches over NATS request/reply. See ADR-0009. - In-tree workers ship inside the
caesarpackage:memory_recall,semantic_recall,calculator,web_search,calendar_read,notify. Enabled viaCAESAR_LEGION__INPROCESS_WORKERS. - Plugin workers are third-party PyPI packages discovered through
the
caesar.pluginsentry-point group. Praetor scans them at startup, validates each manifest, and the result joins the in-process pool. See ADR-0035 + BUILD-A-PLUGIN.md. - Workers on other hosts authenticate to the bus with per-identity NKEYs. See ADR-0027 + RUN-A-WORKER.md.
HA Bridge¶
- Single module owning the REST + WebSocket connection to Home Assistant. See ADR-0007.
- Exposes
call_serviceto the brain as a tool; reads HA state via the dashboard's device list at/v1/devices. - All real-world service calls flow through the Policy Engine first.
- The same WS subscription powers the HAEventDriver (proactive ADR-0031).
Memory¶
Two layers, both opt-in beyond the always-on audit log:
- Episodic.
audit_logtable in SQLite — every brain decision + the inputs that produced it. The retention sweeper deletes rows older thanCAESAR_MEMORY__RETENTION_DAYS. See ADR-0019 + ADR-0020. - Semantic. A vector store fed by a background indexer that
embeds recent audit rows; queried by the
semantic_recallworker. See ADR-0010. - Personal facts (v1.8).
personal_factstable; a background extractor reads recent chats and stores{key, value, confidence}rows that are auto-injected into future chat system prompts. See ADR-0033. - Episodes (v1.9).
episode_summariestable; per-chat 1-2 sentence summaries embedded for similarity-ranked auto-recall. See ADR-0034.
Policy Engine¶
- Gatekeeper between Praetor/Legion and the real world. See ADR-0013 (HA service-call gate) + ADR-0028 (generalisation to non-HA tools, plugin tools ride this same path).
- YAML allow-list with optional per-call constraints (e.g. limit
light.turn_onto specificentity_ids; restrictweb_searchdomains). - Deny-all by default —
CAESAR_POLICY__RULES_PATHunset means no tool runs.
Message Bus¶
- NATS, per ADR-0009.
- Subject namespacing:
caesar.dispatch.<worker_id>,caesar.registry.*,caesar.reply.<inbox>. - Disabled by default. Enabling it brings up the Legion pool and the
plugin loader; without it, Praetor runs single-process and the brain
only has
call_service(when HA is wired). - Multi-host operation gated by per-identity NKEYs (ADR-0027).
Proactive triggers¶
The same brain graph that serves /v1/chat also runs unattended when
something else fires:
- Scheduler — cron expressions in
triggers.yaml(ADR-0030). - HAEventDriver — HA WS subscription dispatching matching events to the brain (ADR-0031).
- WebhookDispatcher —
POST /v1/hook/{trigger_id}with per-trigger bearer tokens (ADR-0032).
All three feed ProactiveRunner.fire(...), which invokes the brain
with proactive=true in the safety preamble — biases toward
summarise + notify over act-on-the-house. See
PROACTIVE-CAESAR.md.
Dashboard¶
- Server-side HTMX, embedded in Praetor. See ADR-0021.
- Live audit log via SSE (the
AuditEventBusfans new rows to subscribers in the same process). - Surfaces facts, episodes, sessions, and an operator-editable system-prompt override.
- Opt-in:
/dashboard/*returns 404 untilCAESAR_DASHBOARD__TOKENis set.
Observability¶
- Prometheus
/metrics— request counts, chat duration, policy decisions, audit-event counters. - OpenTelemetry tracing — optional install (
caesar[otel]); spans cover the brain graph + every tool dispatch. See ADR-0023. - Structured JSON logging —
caesar.logconfigures a structlog pipeline. See ADR-0018.
Distribution¶
- Published as
caesaron PyPI (Sigstore provenance via Trusted Publishers; SR-011 follow-up) andghcr.io/sinidious/caesaras a multi-arch Docker image with attestations. See ADR-0029. caesar initgenerates a working.env+policy.yaml+triggers.yaml+ Praetor NKEY in one shot.
Voice in¶
CAESAR doesn't ship a voice satellite. Voice input is "any HTTP
client that posts to /v1/chat": phone OS dictation (Gboard / iOS
keyboard / Whisper-based system services), browser dictation, or a
custom transcription pipeline you run yourself. ADR-0008 rewrote
away from the original Wyoming-satellite plan.
Trust boundaries¶
See SECURITY-MODEL.md. Short version:
- HTTP clients (phone, browser, webhook senders) are untrusted user
surfaces.
/v1/chatand/v1/devicesare bearer-token gated when exposed beyond loopback (SR-001);/v1/hook/*has per-trigger bearer auth. - Praetor is the only component that holds long-lived credentials (LLM API keys, HA token, dashboard token, NKEY seed).
- Workers run with the privileges of the process they live in;
plugins are a code-trust act (
pip install= trust). The Policy Engine is the last line that mediates real-world side effects, and it cannot distinguish plugin tools from in-tree tools.