Architecture

Core owns coordination. Containers run turns.

Suzumio separates orchestration from execution. The core process owns project truth and scheduling; the Docker runner performs one isolated turn and exits.

Layer Map

CLI / HTTP / WebUI
        |
        v
Suzumio Core
  Config loader
  SQLite store
  Message router
  Artifact registry
  ToolHost
  Non-preemptive scheduler
        |
        v
Docker backend
  Creates turn input JSON
  Starts one container per turn
  Monitors container exit
        |
        v
Container runner
  Reads /turn/input.json
  Runs mock or AI mode
  Calls Suzumio /tool for project tools
  Writes /turn/output.json

Core Process

The core process is the authority for project-level records. If data should be visible in CLI, HTTP, WebUI, or audit logs, it belongs in SQLite through the core store.

ModuleResponsibility
config.tsLoads YAML, resolves imports, applies extends, validates config, and renders final YAML.
store.tsCreates and queries SQLite tables for projects, agents, messages, reads, turns, events, tool calls, and artifacts.
scheduler.tsImplements the nonpreemptive-mailbox scheduling rule.
tools.tsDefines core tools and executes ToolHost calls with token and allowlist checks.
server.tsHTTP API, SSE stream, ToolHost route, and embedded WebUI.
backend.tsDocker container creation, bind mounts, runner input/output, and turn completion.
runner.tsContainer entrypoint for mock or model-backed turns.

Runner Contract

The runner receives all context through one input file and reports back through one output file. This keeps execution replaceable without changing project-state semantics.

type RunnerTurnInput = {
  project: string
  agent: { id: string; role: string; prompt: string; model?: string }
  turn: { id: string; prompt: string }
  workspace: string
  controllerUrl: string
  token: string
  runner: RunnerConfig
  tools: ToolDefinition[]
}
type RunnerTurnOutput = {
  text: string
  usage?: Record<string, unknown>
}

Docker Isolation

Each turn container receives a small, explicit environment:

Completed containers are currently kept for early debugging. Cleanup policy should become configurable as the Docker backend hardens.

Tool Flow

Model asks for tool
  runner converts model tool call
  runner POSTs /tool to Suzumio
  ToolHost verifies token and tool allowlist
  ToolHost records tool_calls row
  core tool runs against SQLite/artifact store
  ToolHost records success or failure
  runner returns tool output to model

The model does not receive arbitrary host tools by default. Tools are configured per agent and executed by the core ToolHost.

Message Delivery

Agents do not poll for messages. Suzumio renders unread inbound messages into the next turn prompt and records which turn consumed which message. This avoids polling loops and makes scheduling decisions auditable.

SQLite as Project Truth

Each project has one SQLite file. The container runner does not maintain the project database. Durable state must flow through output files or ToolHost calls.

TablePurpose
projectsProject status, task, resolved config JSON, submitted report path.
agentsAgent roster, prompts, tool allowlists, token, active turn.
messagesDirect and channel messages.
message_readsWhich turn consumed which inbound message.
turnsTurn execution records and output text.
eventsAppend-style event timeline.
tool_callsAudited tool execution records.
artifactsPublished file artifacts with hashes and metadata.

Why the Boundary Matters

Keeping project truth in the core runtime makes agent execution disposable. A runner can fail, be replaced, or be upgraded while the project database, message history, artifacts, and user-control surface remain stable.