The five layers
| Layer | Responsibility | Example components |
|---|---|---|
| Channel | Translates platform messages (Signal, Email, CLI, HTTP) into normalized bus events | Signal adapter, Email adapter, CLI adapter |
| Dispatch | Routes messages to agents, enforces policy (rate limits, trust scoring, injection detection), translates responses back to channels | Dispatcher, PII redactor |
| Agent | LLM-powered agents with isolated memory scopes — receives tasks, reasons, invokes skills, produces responses | Coordinator, Research Analyst |
| Execution | Runs skills (local TypeScript handlers or MCP tools), validates permissions, sanitizes outputs | Skill executor, MCP client |
| System | Trusted infrastructure with full pub/sub access to all event types | Audit logger, Memory engine, Scheduler, Dream engine |
Bus security enforcement
The bus validates publisher authorization at registration time. A module registered aslayer: "channel" can only publish event types in the channel allowlist (inbound.message, inbound.event). Attempting to publish skill.invoke throws an error. This is a hard security boundary — it’s architectural, not policy.
A compromised channel adapter cannot invoke skills, write to memory, or modify agent state. It can only publish inbound messages, which are then subject to the full dispatch policy pipeline before reaching any agent.
The System layer is the exception — it has full publish and subscribe access to all event types. This is reserved for trusted infrastructure components that need cross-cutting access to operate.
Message flow
A complete round-trip for an inbound message:Channel receives a message
A channel adapter (Signal, Email, CLI, or HTTP) receives a platform message and publishes an
inbound.message event on the bus.Dispatch evaluates policy
The Dispatch layer (subscribed to
inbound.message) resolves the sender’s contact record, computes a trust score, checks rate limits, scans for prompt injection, and — if the message passes all gates — publishes an agent.task event.Agent reasons and acts
The Coordinator agent (subscribed to
agent.task) receives the task, loads context (entity memory, working memory, autonomy score), and calls the LLM. If the agent needs to take action, it publishes skill.invoke events.Execution runs the skill
The Execution layer (subscribed to
skill.invoke) validates permissions against the skill manifest, runs the skill handler, sanitizes the output, and publishes a skill.result event.Agent incorporates results
The agent receives the skill result, may invoke additional skills, and eventually publishes an
agent.response event.Dispatch routes the response
The Dispatch layer translates the
agent.response into an outbound.message, applying PII redaction based on channel policy.Inter-agent communication
Agents can communicate with each other through the Bullpen — a structured, threaded discussion space. An agent publishes anagent.discuss event addressed to another agent, which responds in the same thread. All Bullpen messages flow through the bus with the same security model and are written to the audit log with full causal tracing.
You can observe, intervene in, or start Bullpen threads from any channel.
Outbound context bridge
When Curia sends a message it often expects a reply that needs to come back to a specific agent with specific context. The outbound context bridge is a small registry that records every outbound message — channel, originating agent, content preview, expected-reply hint, delegation hint, TTL — so that when an inbound reply arrives, the dispatcher can prepend a[ACTIVE OUTBOUND CONTEXT] block to the coordinator’s task. The coordinator reads that block and decides whether to delegate the reply back to the originating specialist.
The bridge is what lets the meeting-debrief agent claim threads for replies to its own outbound prompts, the research-analyst hold a multi-turn conversation with the CEO, and the coordinator route a Signal reply about an urgent email back to the CEO Inbox agent — all without coupling the routing logic to message bodies. Every send skill auto-registers an entry on success; callers can attach delegation metadata via an optional context_bridge input. Entries expire on a TTL (6 hours for auto-registered, 24 hours for explicit) and are released either by the coordinator (when it detects the conversation has ended) or by a periodic cleanup job.
Event type registry
All event types are defined as a TypeScript discriminated union — no untyped payloads or string-typed event names. Each event carries:id— UUIDtimestamp— when the event was createdtype— the discriminant (e.g.inbound.message,skill.invoke)source_layer— which layer published itsource_id— which component published itparent_event_id— causal chain linking (optional)payload— typed per event type
Write-ahead audit logging
The audit logger writes events to Postgres before delivering them to other subscribers. If the process crashes after the audit write but before subscriber delivery, the event is logged but unprocessed. This gives at-least-once delivery for all events and exactly-once audit recording.Design principles
- Hard security boundaries — layers are physically prevented from unauthorized actions, not just organizationally separated
- Everything is auditable — every event, decision, and inter-agent exchange is logged and traceable
- Memory-first — sophisticated knowledge graph with temporal awareness, not just conversation logs
- Extensible by design — new channels, skills, and agents added without touching core code
- Restart-safe — all state lives in Postgres; no in-process state that dies with the process
- Single-tenant simplicity — no multi-tenant complexity; deploy multiple instances for multiple users
Tech stack
| Component | Technology |
|---|---|
| Runtime | Node.js 24+ with TypeScript (ESM) |
| Database | PostgreSQL 16+ with pgvector |
| LLM SDKs | @anthropic-ai/sdk, openai, ollama |
| MCP | @modelcontextprotocol/sdk (client) |
| HTTP | Fastify |
| Config | YAML with env var interpolation |
| Logging | pino (structured JSON) |
| Migrations | node-pg-migrate (plain SQL) |
| Embeddings | OpenAI text-embedding-3-small (1536 dimensions) |
The layers model
How governance layers compose — from channel trust to skill-level action risk.
Security overview
The security architecture and audit framework that underpins every layer.