ArchitectureThe components, the request path, and what happens end to end when you send a message.

Seed Agents is a local-first, account-scoped agent system. The desktop app configures an agent server, stores provider secrets, creates agents, works in durable sessions, streams model responses, delegates work to children, and inspects everything that executed.

Design principles

Stated in agents/docs/system-overview.md:7-24, and worth reading as constraints rather than aspirations:

    Signed control plane — every HTTP action is a signed DAG-CBOR envelope (Protocol).

    Account isolation — persisted state belongs to one Seed account; queries must prove ownership.

    Durable sessions — append-only event logs, replayed by sequence number.

    Live clients — desktop subscribes over a signed WebSocket.

    Secret redaction — API keys are encrypted at rest and never returned.

    Visible tools — tool calls and results are durable events rendered in the UI.

    Shared hypermedia behaviorread uses the same SDK code the CLI uses, never a shell-out.

    Inspectable operation — a built-in /agents inspector and diagnostic logs.

    Five verbs, one address space — new capability is a new address or callable, not a new provider tool.

    Configuration is content — tools and memory are documents in the agent's Space.

    The log is symmetric — the user holds the same verbs; every event names its actor.

    Everything that executes is a run — turns, children, and scripts are rows in one tree that is also the queue.

Components

Desktop app ├─ Local agents server subprocess (same artifact as the Docker image) ├─ Agents routes: list, detail, session ├─ Assistant sidebar (a session view like any other, just narrower) ├─ daemon-backed signing for the selected account ├─ signed CBOR HTTP client + signed WebSocket subscription └─ shared chat renderer Agents service (Bun) ├─ /api/message signed action API ├─ /agents/ws signed subscription API ├─ /agents status + inspector UI ├─ SQLite persistence (state, and the runs table that is also the queue) ├─ AES-GCM secret storage ├─ Pi SDK-backed model execution loop ├─ the five verbs (read / write / call / delegate / plan) ├─ tool documents in ~/tools + the <space> index in every prompt ├─ run queue: leases, boot sweep, park/resume, wake sources └─ QuickJS script engine with a content-keyed journal Shared Seed libraries ├─ @shm/shared/blobs — Ed25519 signatures and principals ├─ @shm/shared/cbor — canonical DAG-CBOR ├─ @seed-hypermedia/client — URL resolution and markdown conversion └─ desktop daemon — signing for the selected account

What happens when you send a message

The end-to-end path (agents/docs/system-overview.md:62-93), which touches nearly every concept in these docs:

    The desktop sends a signed MessageSession action.

    The server appends a durable user message and creates a run row for the turn, claimed inline on the interactive queue. Session status now derives as streaming.

    It builds an in-memory Pi session from the provider record, the decrypted key, the agent's system prompt plus the shared runtime prompt and its <space> index, and the tool set: the five verbs plus whichever callables this thread has already expanded.

    Pi runs the provider loop and emits streaming, tool, and final events.

    Text deltas become session-partial service events → appendPartial over the WebSocket → rendered live.

    Tool calls and results are appended as durable events stamped actor: 'agent'. A call for an unexpanded tool returns that tool's contract instead of an error, and the contract's presence in the transcript promotes the tool for the rest of the thread (touch-expand).

    If the turn used delegate, each child gets its own run row; the parent parks on them without holding resources and resumes when they resolve.

    The final assistant message is appended; the run finalizes — rolling child usage up, settling plan steps whose children all succeeded, recording any obligation it ended without meeting, and possibly firing a run-completed trigger.

    Session status re-derives to idle, or error when the latest run failed.

Where things live

Concern

Code

Service, verbs, runtime

agents/src/api-service.ts (very large — use rg -a, it contains NUL bytes)

Run queue

agents/src/runs.ts

Script engine

agents/src/workflow-host.ts

Tool documents

agents/src/tool-documents.ts

Memory

agents/src/agent-memory.ts

Sandboxed execution

agents/src/code-exec.ts

Triggers

agents/src/activity-triggers.ts, schedule-triggers.ts, activity-monitor.ts

Protocol types + tool contracts

agents/protocol/src/index.ts, tool-registry.ts

Schema + migrations

agents/src/sqlite-schema.sql, agents/src/sqlite.ts

Desktop UI

frontend/apps/desktop/src/pages/agents/, models/agents.ts

Related

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime