Daemon API
The local HTTP API of the ADF daemon, which loads agents from .adf files, runs them and streams their events. 192 operations in 22 groups, generated from the OpenAPI document.
On this page
1Endpoints
| Group | Description | Operations |
|---|---|---|
| Health | Liveness. The only route that needs no bearer token. | 1 |
| Daemon | The daemon process itself: this OpenAPI document and graceful shutdown. | 2 |
| Events | Live umbilical event stream (Server-Sent Events) and per-agent replay windows. | 2 |
| Agents | Load, start, stop and inspect agents: status, config, tools, metadata, local tables, logs and usage. | 28 |
| Loops | Cognition loops: main plus an agent's inner loops, their persisted history, context usage and compaction. | 8 |
| Chat | Chat turns, event triggers and the agent's message inbox / outbox. | 7 |
| Files | The agent's virtual file system, including its primary document and mind. | 12 |
| Identity (agent) | An agent's own identity store: DID, keys, password and stored values (metadata only, never values). | 16 |
| Owner identity | The owner identity on this machine (seed phrase, keychain or passphrase file). State-changing routes are loopback only. | 6 |
| Credentials | Per-agent provider, MCP and channel credentials. Writes take a value; reads return metadata only. | 6 |
| Channels | Channel adapters (Telegram, email, …) attached to an agent and their live state. | 5 |
| MCP | MCP servers attached to an agent, their live state, and the daemon-wide registrations. | 6 |
| Providers & sign-in | App-level LLM providers, model lists, agent provider configs and subscription sign-in (ChatGPT, Grok). | 14 |
| Tasks & approvals | Human-in-the-loop: tool approvals, ask requests and suspend prompts. | 8 |
| Timers | An agent's scheduled wake-ups. | 4 |
| Templates | Agent templates new agents are created from. Every route needs a ready owner identity (409 identity_not_ready). | 12 |
| Tracked folders | Folders whose agents the daemon autostarts (settings.trackedDirectories). | 5 |
| Runtime | Runtime diagnostics, token usage and token counting, daemon-wide and per agent. | 11 |
| Network | Mesh registration, the mesh HTTP server and WebSocket diagnostics. | 12 |
| Compute | The Podman compute environment and its containers. | 11 |
| Admin | Package installs for MCP servers, channel adapters and the code sandbox. | 12 |
| Settings | The daemon settings file. Secret and identity keys are never read or written here. | 4 |
| Total | 22 groups | 192 |
2Base URL
The daemon listens on http://127.0.0.1:7385 by default and speaks plain HTTP. Set the address withADF_DAEMON_HOST and ADF_DAEMON_PORT. Requests and responses are JSON. SendContent-Type: application/json only with a body.
Agents are addressed by id, handle or name ({id}). Loop-aware routes take loop; absent means main.
export TOKEN=$(adf daemon token)
curl http://127.0.0.1:7385/health
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:7385/agents3Authentication
Every route except GET /health needs a bearer token:
Authorization: Bearer <token>Per-install token from <settings dir>/daemon-token (printed by adf daemon token), or ADF_DAEMON_TOKEN. Local adf clients send it automatically.
ADF_DAEMON_TOKEN overrides the file, on the daemon and in clients. A missing or wrong token gets401 with code unauthorized.
4Request guard
Three header checks run on every route, before authentication. The daemon sends no CORS headers, so web pages cannot call it.
| Check | Refused with |
|---|---|
Host must name this daemon: 127.0.0.1, localhost or [::1] on any port, or the bind address. Extra names go in ADF_DAEMON_ALLOWED_HOSTS. | 403 host_not_allowed |
An Origin header that is not one of those hosts | 403 cross_origin |
Sec-Fetch-Site: cross-site or same-site | 403 cross_origin |
These routes answer local callers only (403 loopback_only): a loopback connection with no proxy header (Forwarded, X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Proto,X-Real-IP, Via).
- POST
/daemon/shutdown - POST
/identity/create - POST
/identity/restore - POST
/identity/unlock - POST
/identity/lock - POST
/identity/confirm-backup
Behind a reverse proxy on the same host, start the daemon with ADF_DAEMON_BEHIND_PROXY=1. These routes then also need X-ADF-Local-Proof, a secret the daemon writes at every start to<settings dir>/daemon-local-proof. The adf CLI and terminal app on that host send it; a caller through the proxy cannot.
5Turns and events
POST /agents/{id}/chat and POST /agents/{id}/trigger answer 202 with aturnId. Every event of that turn carries it as turn_id, ending with turn.completedor agent.error. Messages sent while the loop is busy queue in arrival order and are not dropped; the first interrupts the running turn.
GET /events is a server-sent event stream. Each frame has a daemon-wide cursor, also the SSEid. Resume with ?since=<cursor> or Last-Event-ID, plus?epoch=. Every connection opens with a stream.hello frame that names the daemon run (epoch). A stream.gap frame reports that frames were lost or the daemon restarted; re-read agent state when you get one. Replay comes from an in-memory buffer of the last 1000 frames.
6Errors
Errors are JSON with a human-readable error and a stable machine code. Every error has acode: a specific one where the route defines it, otherwise the status default (bad_request,forbidden, not_found, not_supported, conflict,internal_error, upstream_error, unavailable). Show error; branch oncode.
{ "error": "Unknown agent \"agent-1\"", "code": "not_found" }| Field | Type | Description |
|---|---|---|
errorrequired | string | Human-readable message |
code | string | Stable machine-readable code. Every error body has one: route-specific where listed, else the status default (400 bad_request, 403 forbidden, 404 not_found, 405 not_supported, 409 conflict, 500 internal_error, 502 upstream_error, 503 unavailable) |
A body the HTTP framework cannot parse (malformed JSON, or an empty body sent withContent-Type: application/json) is refused with 400 in Fastify's shape:{ statusCode, code, error, message }. Send no Content-Type on bodiless POSTs.
| Status | Meaning | Codes |
|---|---|---|
| 400 | Invalid request: missing or malformed field, query parameter or body. A body Fastify cannot parse gets Fastify's own shape (statusCode, code, error, message). | bad_request FST_ERR_CTP_EMPTY_JSON_BODY |
| 401 | Missing or wrong bearer token (unauthorized) | |
| 403 | The request guard refused it: Host header not allowed (host_not_allowed, DNS-rebinding protection) or a browser cross-site request (cross_origin) | host_not_allowed cross_origin loopback_only |
| 404 | Unknown agent (or the named resource: loop, task, file, …) | ask_not_found not_found |
| 405 | Not available on this daemon (the subsystem is read-only or lacks this operation) | |
| 409 | The resource is in a state that does not allow this now | identity_not_ready name_taken |
| 422 | The template was refused (template_missing, template_unreviewed, template_invalid) or the new file could not load (load_failed) | |
| 500 | Unexpected runtime failure | |
| 502 | An upstream call failed (e.g. the summarization request of a compaction); nothing was changed | |
| 503 | The subsystem is not configured on this daemon |
7Versioning
The API is not versioned by URL. This reference documents API version 0.2.0. A running daemon serves its own contract at GET /openapi.json, and GET /runtime returns its package version as daemon.version.
- Ignore fields you do not know. New fields are added without notice.
- Treat a
404on a route you need as an older daemon: fall back, or ask the user to update. - There are no ETags. The last write wins; re-read before you replace a whole config.
8Mesh server
Agent websites, agent cards and ALF message delivery are served by a separate HTTP server on the mesh port (default7295), not by this API. It does not use the daemon token. It is on by default and starts once a reachable agent loads; /network/server/* and meshServerEnabled control it.
| Method | Path | Description |
|---|---|---|
| GET | /health | Mesh server health check |
| GET | /ping | Runtime identity probe |
| GET | /agents | Agent directory, filtered by visibility |
| GET | /agents/:handle/card | One agent's card |
| GET | /agents/:handle/health | One agent's health |
| POST | /agents/:handle/inbox | ALF message delivery |
POST /agents/:handle/inbox is the only way to deliver a real inbound message: it takes a full, signedALF message. POST /agents/{id}/trigger on the Daemon API does not substitute for it. Everything else under /agents/:handle/* is served by the agent itself: see HTTP serving.
9Specification file
This reference is generated from docs/daemon/openapi.json in the ADF repository, atv0.7.4 (commit 56f129b). Download it to generate a client or load it into an OpenAPI tool.
Download openapi.json · OpenAPI 3.1.0 · 192 operations
For concepts and flows (chat turns, the event stream, approvals, identity), read the API guide. To install and run the daemon, see ADF daemon.