Documentation Last reviewed 2026-08-08

Architecture

What the system is made of, where each thing lives, and what happens to one message.

How a message moves through a node

Everything inside the dashed boundary runs on one machine you control · last reviewed 2026-08-08

The spine runs across the centre: a message lands on the bus, the Dispatcher works out who it is for, an agent takes a turn, and the AI Gateway is the single door to a model. Everything else sits next to what it connects to. The Database is the foundation underneath. Pick a view below to follow one route at a time, because there is more than one and pretending otherwise would be the easiest way to mislead you.

VIEW
Open at full size YOUR MACHINE NOTHING DIALS IN web chat (sync) records inbound new external mail directed model messages, events logs always if heavy picked up as a task start runs model (gateway) reply (mail/tg) fast path Web Chat live Email live Telegram live WhatsApp planned SMS planned Voice live Web Server routing + TLS Security login & access Office UI chats, tasks, docs Admin UI configure (Panel) Communication channel adapters in/out Outbound Sender sends replies (20s) Core the kernel THE BUS Messages dialogue Events system journal Events: every component writes here Dispatcher Intake notices new work, resolves who it is for Task watch delegated work, a safety net Runner launches free agents claims one at a time, fails closed FRONT OFFICE woken by a message Front desk BACK OFFICE woken by a task Coordinator Specialists AI Gateway one door to models Providers Anthropic Google OpenRouter OpenAI etc. via OpenRouter Memory remembers Planner tracks bigger jobs Documents docs & knowledge Tools what agents do Rules who-talks-to-whom Orchestrator the workflow engine Workflows started by the owner Flow agents the steps a workflow runs Database one Postgres cluster · registry, messages, append-only event log Monitoring services + metrics the model call is the only thing that leaves
Following an email. Choose the Email route view to light this path:
  1. The Email adapter polls the mailbox. Nothing is pushed to the machine; it dials out.
  2. Communication records the message in Core, which writes a row on the bus. Arrival and handling are separate steps.
  3. Intake notices the new row and resolves who it is for. It does not launch anything.
  4. The Runner claims that agent, fail closed, and wakes it. Two wakes for the same agent cannot run at once.
  5. The agent takes its turn with the tools it was granted, and reaches a model through the one AI Gateway.
  6. The reply is written back as a row. The Outbound Sender is the only thing that transmits, so every outgoing message exists as a record first.
Solid lines always happen. Dashed lines happen when needed: Rules apply on every turn, while Memory, Documents and Tools are pulled only when the work calls for them, and heavy jobs become a Planner task for the back office.
Not one path, four. Conversational channels take the fast path straight to the Dispatcher and answer synchronously, in seconds rather than the wake loop's tens of seconds. Mail and internal traffic take the wake loop above. Web chat is synchronous through the web server. Workflows are driven by the Orchestrator as a sequence of steps rather than a single agent turn. They differ in how an agent is invoked, not in where anything is stored: every one of them lands on the same bus and the same event log.
What is drawn in dashes is not built. Boxes marked planned have no adapter behind them today. They are on the map because leaving them off would be the more flattering choice and the less useful one. What is and is not connected is listed in full on the integrations page, and what the system does not do at all is on limits.
Pick a view to follow one route. Click the map for a readable copy.
10+ services
8+ containers
1 postgres cluster
4 schemas
160 install checks
Services
core-api:8030
The registry and its API. Everything that changes, changes here.
dispatcher:8101
Resolves the recipient of an inbound message and wakes one agent.
gateway:8000
One route out to whichever model provider is configured.
runner
Claims an agent and launches its turn. Fails closed.
communication
The channel adapters: mail, telegram, slack.
office:8050
The panel the owner watches and approves from.

Alongside them, as containers on the same machine: documents Version-controlled document store; memory Semantic search over what agents wrote down; planner Tasks and objectives, node-local; auth Sign-in for the panel; proxy TLS termination and routing; voice The voice channel.

This list has not changed since the codebase was written. Forty-one releases have shipped and none of them added or removed a service. What changes is what runs on top.

A Smart Node is one machine. On it run a set of named services, one Postgres cluster, and a registry that says what exists. Everything else, including every agent, is a row in that registry. None of it is set up by hand.

That sentence is the whole design, and the rest of this page is what it means in practice.

The entities

The system knows a fixed number of kinds of thing. Each kind has exactly one home. Not "usually lives here" but "exists only here". Adding an agent means adding a row, and the directory, the memory space, the group membership and the permissions all follow from that row. None of them is a separate act of setup.

EntityDeclared inAlso materialised as
Agentsn_config.agentsA directory under /srv/agents/, a memory space, a Unix group
Channelsn_config.channels, agent_channelsA binding between an address and an agent
Toolsn_config.tools, granted via agent_toolsAn executable body plus its usage text in the prompt
Policysn_config.policiesText composed into the prompts of agents in that category
Personsn_config.users, user_channelsThe identity a message is resolved against
Messagesn_core.messagesAn append-only bus row plus its delivery state
Eventsn_core.eventsAn append-only audit record
Documentthe node's document storeA file under version control
Taskthe node's planner

This is the difference between a system and a wrapper around a model call. A wrapper has no entities. It has a prompt and a key.

The perimeter

Everything above sits on the customer's machine, inside the dashed boundary in the diagram. Mail is polled over IMAP, Telegram is long-polled, Slack runs over an outbound socket: every channel dials out, so none of them needs a port opened toward the node. What you publish beyond that is a firewall decision on your own machine. Details on install.

What leaves: the model call, and whatever the channels you enabled must reach in order to send.

What happens to one message

There is not one path. There are four, and which one runs is decided by the channel the message arrived on. The commonest is the wake loop, which handles mail, Slack and internal traffic. The numbers below are the numbered badges in the diagram.

  1. An adapter polls the channel and writes the message into sn_core.messages. Arrival and handling are separate steps.
  2. The recipient is resolved by matching recipient against the channel bindings in agent_channels. Internal traffic matches an agent's slug directly. No routing table, no routing column: the answer is a query.
  3. The dispatcher claims that agent and wakes it. The claim fails closed, so two wakes cannot run at once.
  4. The prompt is composed from the registry: the agent's own definition, the usage text of each tool it holds, the rules for its categories. Not read from a file a person maintains.
  5. The model call goes out through the gateway.
  6. The reply is written back as an outbound row and a timer sends it. Every outgoing message exists as a record before it exists as an email.

The other three paths: a fast path for chat channels where latency matters, a synchronous path for web and panel chat, and a flow path where the runner drives a sequence of steps. They differ in how the agent is invoked, not in where anything is stored.

Where things are stored

One Postgres cluster. The three schemas below carry everything this page has described; a fourth holds extensions. The document store and the planner are separate databases on the same cluster.

SchemaHolds
sn_configThe registry: agents, channels, tools, policies, people, integrations
sn_coreThe domain: messages, delivery state, events, model sessions
publicLogin

sn_core.messages and sn_core.events are append-only, enforced by a database trigger rather than by convention. Grants, policy changes and permission changes are written into the same event log as everything else, so the record of what an agent was allowed to do sits next to the record of what it did.

Reviewed 2026-08-08. Older than 90 days counts as broken. Something here wrong? Tell me