Expand description
The agentd runtime: the supervisor’s event loop over durable state, the turn workers it spawns, and the lifecycle policy.
Startup is strictly ordered, because each step depends on the last:
parse+validate config → connect MCP servers (a failed server is contained,
not fatal) → connect the store or refuse to start → restore → build the
registry, validating overrides against the servers that actually answered →
discover skills → resolve the instruction → load workflows → arm start
nodes (once fires unless a live run was restored, so a restart does not
re-fire it) → re-spawn pending subagents → announce proc.ready → enter
the loop. Nothing accepts outside work before proc.ready.
Re-exports§
pub use reactor::Runtime;
Modules§
- activity
- Live activity: what each working unit is doing right now, for the display clients’ working row.
- artifacts
- Artifacts: named pieces of content produced by turns and steps,
store-backed, delivered on A2A tasks and referenced by large step outputs
as
{"$artifact": id}so a big payload travels by reference rather than being copied into every message that mentions it. Content is stored inline (JSON or text) up toMAX_INLINE_BYTES; the record carries{name, mime, size, sha256, content, created_by, sensitive}. - audit
- The audit stream: an append-only
record of who did what — every A2A call, every principal-driven tool/command,
config reloads, restores, store conflicts, and kills. Each event is
{ts, principal, role, action, target, outcome, request_id, trace, instance}, emitted to the configured sinks:log(a closed-vocabularyauditlog line) and/orstore(a durable, append-onlyKind::Auditrecord, ULID-keyed — never CAS’d, never listed, so it cannot be rewritten). Audit is security telemetry: it answers “why did the agent do that, and on whose authority?”. - breaker
- The circuit breaker for remote-effect steps —
retry’s cross-run sibling. - children
- The runtime’s flat child tree: every turn worker and subagent is a
direct child of the supervisor — the tree is one level deep, so there is
exactly one process that can orphan work and exactly one place that reaps.
Children are spawned through
supervisor::spawn(the reaper + PDEATHSIG + process groups), tracked here with their purpose, liveness and cancellation, and torn down by the kill ladder on drain. - env
- The environment data a system-prompt template renders, and the built-in default template that renders it.
- events
- The runtime’s event vocabulary: everything the loop reacts to arrives here — child frames, reaped children, executor results, timers, signals, and the durable inbox events (A2A messages, start-node firings, signals).
- goal
- The self-correcting goal watchdog. A supervisor-level periodic
check — it never blocks the agent loop — of whether the configured
goalis achieved, or the agent is stuck (no progress acrossstuck_afterchecks): - http_
node - The
httpworkflow node: make an outbound REST call from a workflow —GET/POST/PUT/PATCH/DELETEwithheaders,query, and ajson/bodypayload — and observe{status, ok, headers, body, json}. This is also how a workflow emits a webhook (aPOSTto a URL). It runs on an executor thread over the one SSRF-guarded HTTP client, so every outbound dial in the daemon passes the same guard; the URL and body are already template-rendered (render_spec) against the run’s data. - human
- Human-in-the-loop: the
ask_humaninternal tool and the workflowhumannode, wired to the interface. - nested
- Nested bodies:
foreach/batch(dynamic fan-out over an array, batches with bounded parallelism and rate pacing, per-batch durable progress, positional collection,on_error: continueslots),iterate(a bounded structured loop withwhile/until/max_iterations),parallel(static branches, fan-in object),race(first branch to finish wins, the rest are cancelled) andsubgraph(an inline sub-DAG). Body steps are ordinary steps executed under a scope: their run-record ids are<parent>[<index>].<step>(elements / iterations),<parent>{<branch>}.<step>(branches) or<parent>.<step>(subgraph); templates inside a body seeitem,index,batch,iteration,branchandsteps.<sibling>resolved within the scope. The parent step’swaitrecord carries the durable progress. - pressure
- Resource pressure, and what a healthy daemon does about it: shed new work, drain what is in flight.
- reactor
- The runtime state + event loop: one single-threaded reactor over child frames, reaped children, executor results, timers, the durable inbox and signals.
- reload
- Hot reload of the configuration: SIGHUP or
lifecycle.watch_configre-merges the files and re-validates. The reload is all-or-nothing — if any restart-only path changed the whole reload is refused asrestart_requiredand the running configuration stays, so the daemon never ends up half on one configuration and half on another. - starts
- Start nodes are a workflow’s triggers: beyond
onceandmanual, the long-lived start kinds fire runs while the instance lives —loop(re-run on completion,interval/until/max_iterations/backoff),schedule(cron /every,catch_up),subscribe(an MCP resource update, notify-then-read,debounce/coalesce/filter/window),signal(a named signal),event(an internal lifecycle event), anda2a(a principal’s message routed here). Asubscribestart has noclaimorshard: agentd holds no lease and partitions no work — exactly-one-owner across a fleet belongs to whatever the work comes FROM, because only that can hand an item to somebody else when a holder dies (seedocs/scaling.md). Start-node state (last fired, iteration, missed, next deadline, debounce) is durable in the manifest, so a restart resumes the schedule rather than restarting it. - steps
- Runs and steps: arming start nodes,
turning start events into durable runs, scheduling ready steps every tick,
executing the step kinds (data steps in-loop, MCP calls on executor
threads,
agent/thinkin turn workers,sleepon durable timers,finishclosing the run), retries +on_errorrouting, and theworkflow.*tools. - subagents
- The subagent registry behind the
subagent.*tools: flat children spawned from the one chokepoint (caps: depth/breadth/total/rate), recorded durably assubagent/<handle>(payload, mode, status, result), withsync(the caller waits),async(a handle;subagent.await),detached(fire and forget) andwarm(stays alive;subagent.send). - timers
- The durable timer wheel: absolute
deadlines owned by a step, a tool request, a start node or the lifecycle;
armed through the store, fired by the loop’s tick (
fire), re-armed from the restored records at startup (past deadlines fire immediately). - tools
- Internal tool execution: the runtime is the single place
internal tools run — for a turn worker’s
ToolRequest(answered withToolResult), for a workflow step (tool/memory.*/ … kinds) and for A2A commands. Keeping them here means every state change is made by the state owner. Arguments are validated against the contract’s input schema before dispatch and results against the output schema after (schema failure ⇒ a tool error, never a panic). Some tools are deferred (sleep,subagent.run sync,subagent.await,await,think,context.compact,workflow.run wait,workflow.wait): the request is parked inpendingand answered when its wait resolves. Mapped tools (overrides) run on an executor thread against the runtime’s own MCP connection. - turns
- Turn dispatch: building a turn worker’s input (system
prompt, context slice, tool definitions by grant, skills, memory hints),
budget admission at dispatch, spawning the worker, and folding
TurnDoneback into the durable state (context delta, replies,finish, compaction). - waits
- Orchestration steps — the integration, intelligence and control kinds:
wait(on a resource update, a CEL condition, a signal, a run, a subagent, a conversation message, or a deadline),join(fan-in of runs/subagents),workflow(a child run:sync | async | detached,cascade),workflow.signal/workflow.wait/workflow.cancel,subagent,human(through theask_humancontract),mcp.resource(read | list | prompt | complete),a2a.delegate(the outbound A2A client), thethinkpresets (classify | extract | summarize | judge | route), and stepcache(memoized outputs by input hash). Waits suspend the step durably (StepState.wait) and are resolved by the loop’s tick. - worker
- The turn worker: a child process (
Role::Turn) that runs ONE turn over the context slice the supervisor handed it — a root / conversation turn, a boundedagentstep, or a structuredthink— and reports the transcript delta, the usage and the outcome (TurnDone).
Functions§
- capabilities
- A static capability document for
--capabilities: describes the configured surface with no side effects — it does not connect to MCP servers, read secrets, or start the loop, so it is safe to run against a production configuration. It reflects the configuration (what the agent is set up to do), not live state. - run
- Start the runtime for a loaded configuration and block until it stops. Returns the process exit code: startup failures report before the loop is entered, so a non-zero return here is always a refusal to run rather than a partially started daemon.