Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.meetcuria.com/llms.txt

Use this file to discover all available pages before exploring further.

Curia is built around a central message bus that connects five layers. Four domain layers — Channel, Dispatch, Agent, and Execution — have hard security boundaries enforced at registration time. A fifth System layer provides trusted cross-cutting infrastructure (audit logger, memory engine, scheduler). All communication between layers flows through typed events on the bus, backed by Postgres for persistence.

The five layers

LayerResponsibilityExample components
ChannelTranslates platform messages (Signal, Email, CLI, HTTP) into normalized bus eventsSignal adapter, Email adapter, CLI adapter
DispatchRoutes messages to agents, enforces policy (rate limits, trust scoring, injection detection), translates responses back to channelsDispatcher, PII redactor
AgentLLM-powered agents with isolated memory scopes — receives tasks, reasons, invokes skills, produces responsesCoordinator, Email Triage, Research Analyst
ExecutionRuns skills (local TypeScript handlers or MCP tools), validates permissions, sanitizes outputsSkill executor, MCP client
SystemTrusted infrastructure with full pub/sub access to all event typesAudit logger, Memory engine, Scheduler, Dream engine

Bus security enforcement

The bus validates publisher authorization at registration time. A module registered as layer: "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:
1

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.
2

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.
3

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.
4

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.
5

Agent incorporates results

The agent receives the skill result, may invoke additional skills, and eventually publishes an agent.response event.
6

Dispatch routes the response

The Dispatch layer translates the agent.response into an outbound.message, applying PII redaction based on channel policy.
7

Channel delivers

The originating channel adapter (subscribed to outbound.message) sends the response via the platform API — an email reply, a Signal message, a CLI output, or an HTTP response.

Inter-agent communication

Agents can communicate with each other through the Bullpen — a structured, threaded discussion space. An agent publishes an agent.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.

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 — UUID
  • timestamp — when the event was created
  • type — the discriminant (e.g. inbound.message, skill.invoke)
  • source_layer — which layer published it
  • source_id — which component published it
  • parent_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

  1. Hard security boundaries — layers are physically prevented from unauthorized actions, not just organizationally separated
  2. Everything is auditable — every event, decision, and inter-agent exchange is logged and traceable
  3. Memory-first — sophisticated knowledge graph with temporal awareness, not just conversation logs
  4. Extensible by design — new channels, skills, and agents added without touching core code
  5. Restart-safe — all state lives in Postgres; no in-process state that dies with the process
  6. Single-tenant simplicity — no multi-tenant complexity; deploy multiple instances for multiple users

Tech stack

ComponentTechnology
RuntimeNode.js 22+ with TypeScript (ESM)
DatabasePostgreSQL 16+ with pgvector
LLM SDKs@anthropic-ai/sdk, openai, ollama
MCP@modelcontextprotocol/sdk (client)
HTTPFastify
ConfigYAML with env var interpolation
Loggingpino (structured JSON)
Migrationsnode-pg-migrate (plain SQL)
EmbeddingsOpenAI 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.