Control API
The daemon's localhost HTTP API — every endpoint.
The daemon serves a control API on http://127.0.0.1:4319 (configurable via
control.host / control.port). The CLI is one client; the browser UI is
another. It binds to 127.0.0.1 and is unauthenticated locally; exposing it
on a non-local host requires control.token, sent as
Authorization: Bearer <token>.
Endpoints
Section titled “Endpoints”GET /health
Section titled “GET /health”{ "ok": true } — used by the CLI to detect a running daemon.
GET /status
Section titled “GET /status”The daemon’s startup snapshot: pid, uptime, mode (global | project),
registered projects and whether each contributed workflows, and the loaded
workflow count.
GET /workflows
Section titled “GET /workflows”All loaded workflows: name, triggerKind, scopeId, tags.
GET /runs
Section titled “GET /runs”Run history, newest first. Query parameters:
| Param | Meaning |
|---|---|
limit | max rows (default 50) |
offset | pagination offset |
workflow | only this workflow’s runs |
status | running | ok | error |
GET /runs/count
Section titled “GET /runs/count”{ "total": n } for the same workflow / status filters — pagination
totals.
GET /runs/:id
Section titled “GET /runs/:id”One run’s detail: { run, steps }, where each step carries status, timing,
JSON output, error, and captured logs.
GET /runs/:id/artifacts
Section titled “GET /runs/:id/artifacts”Files the run wrote: [{ path, size, mtime }], paths relative to the run’s
artifact directory.
GET /runs/:id/artifacts/<path>
Section titled “GET /runs/:id/artifacts/<path>”Download one artifact. Paths that escape the run’s directory are refused.
POST /run/:name
Section titled “POST /run/:name”Fire a workflow once. The JSON body arrives as ctx.event.input. Optional
?project=<root> resolves duplicate workflow names to the intended scope.
Returns { runId, status, error? } when the run settles.
POST /replay/:runId
Section titled “POST /replay/:runId”Re-run a workflow against the stored event of a previous run. Bypasses dedup deliberately.
POST /runs/:id/cancel
Section titled “POST /runs/:id/cancel”Abort an executing run via its AbortSignal (the same path as a timeout).
200 { "cancelled": true }, or 409 if the run isn’t currently executing.
GET /approvals
Section titled “GET /approvals”All approvals across the daemon’s scopes, pending
first, newest first: [{ scopeId, approval }], where approval carries
id, status, the request text, payload, rounds, replies, and
timestamps.
POST /approvals/:id/respond
Section titled “POST /approvals/:id/respond”Record a human reply on a pending approval. Body: { "text": "...", "user"?, "scopeId"? } (scopeId disambiguates duplicate ids across scopes). The
approvals.responded() trigger turns the reply into an event on its next
poll. 404 for an unknown id, 409 when the approval is already resolved
or expired.
GET /stream
Section titled “GET /stream”Server-sent events. Pushes an update event whenever the (filtered) runs
list changes; accepts the same limit / offset / workflow / status
parameters as GET /runs, plus run=<id> to include that run’s live detail:
event: updatedata: { "runs": [...], "detail": { "run": {...}, "steps": [...] } }The browser UI uses this for live run watching; curl -N works too.
POST /webhooks/<connector>
Section titled “POST /webhooks/<connector>”Webhook intake for connector triggers. The one route open without a token —
protected by each connector’s HMAC signature verification instead; connectors
fail closed when no webhookSecret is configured.
The browser UI
Section titled “The browser UI”GET / serves the UI — the prebuilt app shipped in the package when present,
with a dependency-free fallback page otherwise. Disable with
control.ui: false.