Skip to main content
The Observability API gives you programmatic access to Clawboo’s orchestration event log. You can query raw events, reconstruct a full mission trace with metrics, pull the error-taxonomy feed, read the fleet-health triage, fold the delegation graph from the event stream, live-tail events over Server-Sent Events, and mirror client-observed runtime events back into the log. All routes are always on — there is no feature gate. Every payload-bearing response redacts the event’s JSON data field before it is sent: credential-shaped keys and values are masked with ••••. Numeric telemetry (token counts, cost) survives the mask.

Routes

MethodPathSummary
GET/api/obs/eventsQuery the orchestration event feed
GET/api/obs/traces/:traceIdOne reconstructed trace and aggregate metrics
GET/api/obs/errorsThe error-taxonomy feed
GET/api/obs/healthFleet-health triage (working/idle/stalled/zombie)
GET/api/obs/graphEvent-sourced delegation/status/cost graph projection
GET/api/obs/streamSSE live-tail (Server-Sent Events)
POST/api/obs/ingestMirror client-observed runtime events into the log
POST/api/eval/smokeRun the deterministic eval smoke suite

GET /api/obs/events

Queries rows from the event log filtered by your parameters, ordered by the monotonic seq cursor. Default order is asc (causal/chronological).
teamId
string
Match events for one team.
taskId
string
Match events for one board task.
agentId
string
Match events for one agent.
traceId
string
Match events sharing a trace id.
kinds
string
Comma-separated list of event kinds to include (e.g. "cost,error").
since
number
ts >= (wall-clock ms) — a recent-window read.
afterSeq
number
seq > cursor — strictly monotonic, collision-free. Use for polling.
limit
number
Row cap. Defaults to 500.
order
string
"desc" for recent-first. Anything else is asc.

Response 200 OK

events
array
Matched events with the inner data field redacted.
Event kinds: task_created, task_claimed, status_changed, comment_added, dep_linked, execution_started, execution_completed, tool_call, tool_result, cost, approval_requested, approval_resolved, error, span_start, span_end, session_rotated, routine_fired, routine_dispatched, routine_completed, routine_error, team_chat_post, speaker_selected, turn_bound_hit.
# Last 100 cost and error events for a team, recent first
curl "http://localhost:18790/api/obs/events?teamId=<team-uuid>&kinds=cost,error&order=desc&limit=100"

GET /api/obs/traces/:traceId

Reconstructs one trace — every event sharing the traceId, ordered causally (seq ASC). Aggregate metrics are computed from the un-redacted events first, then each event’s data is masked for display, so numeric telemetry in metrics is accurate. The trace read is capped at 5,000 events. An unknown traceId returns 200 with an empty events array and zeroed metrics.

Response 200 OK

traceId
string
The requested trace id.
events
array
All events in this trace, data field redacted.
metrics
object
Aggregate metrics across the trace.
curl http://localhost:18790/api/obs/traces/<trace-id>

GET /api/obs/errors

The error-taxonomy feed — every error event, recent-first, projected to a compact shape. Pass harnessBug=true to filter to errors whose class is Unknown (a harness bug indicator).
harnessBug
string
Pass "true" to filter to harness-bug errors only.
since
number
ts >= (wall-clock ms) lower bound.

Response 200 OK

errors
array
Error rows, recent-first (capped at 500).
harnessBugCount
number
Count of harness-bug errors in the full window, regardless of the harnessBug filter. Use this to badge an alert count.
# Harness-bug alerts in the last hour
curl "http://localhost:18790/api/obs/errors?harnessBug=true&since=$(($(date +%s%3N) - 3600000))"

GET /api/obs/health

Fleet-health triage — a per-agent state folded from the event log, time-sensitive against Date.now(). Capped at 5,000 events.
StateCondition
workingOpen execution with a recent event (within 5 minutes)
idleNo open execution
stalledOpen execution, quiet for more than 5 minutes
zombieOpen execution, quiet for more than 30 minutes — process almost certainly dead
teamId
string
Scope to one team.

Response 200 OK

agents
array
One entry per agent that appears in the event window.
curl "http://localhost:18790/api/obs/health?teamId=<team-uuid>"

GET /api/obs/graph

Folds the ordered event stream into a delegation/status/cost graph projection. This is a pure projection — replaying the same log always reproduces the same graph. Capped at 5,000 events.
teamId
string
Scope the projection to one team.

Response 200 OK

tasks
array
Task nodes with status, assignee, and cost.
taskEdges
array
Edges between tasks: kind is 'delegation' or 'dependency'.
agents
array
Agent nodes with accumulated cost and task ids.
agentEdges
array
Agent-to-agent delegation edges.
curl "http://localhost:18790/api/obs/graph?teamId=<team-uuid>"

GET /api/obs/stream (SSE)

Live-tail of the event log over Server-Sent Events. The handler polls the log every 750 ms on the monotonic seq cursor and pushes new rows as they arrive. Resume from a known position via the standard EventSource Last-Event-ID header or the ?since=<seq> query param.
This is an SSE route. Use curl -N or an EventSource client. Each frame carries id: <seq> so the browser can resume automatically on reconnect without replaying from the beginning.
teamId
string
Scope the tail to one team.
taskId
string
Scope the tail to one board task.
agentId
string
Scope the tail to one agent.
since
number
Resume cursor (seq). Defaults to 0.

SSE frame catalog

FrameWhenDescription
: connectedOn openSSE comment; ignored by EventSource
data: <json>Per new log row (poll every 750 ms)Full event row with data field redacted; id: value is the row’s seq
: keepaliveEvery 20 sSSE comment to keep the connection warm
# Stream events for a specific task
curl -N "http://localhost:18790/api/obs/stream?taskId=<task-uuid>"

# Resume from a known seq position
curl -N "http://localhost:18790/api/obs/stream?taskId=<task-uuid>&since=4187"

POST /api/obs/ingest

Mirrors client-observed runtime events into the durable log. The OpenClaw runtime is observed in the browser, so the SPA forwards those events here to keep the activity terminal uniform across runtimes. Accepted kinds are whitelisted to tool_call, tool_result, and error — board lifecycle events are never accepted here. Each event is best-effort: a malformed row is skipped, never failing the batch. Maximum 200 events per call.

Request body

events
array
Events to ingest. Non-whitelisted kinds are silently dropped.

Response 200 OK

{ "ok": true, "count": 3 }
curl -X POST http://localhost:18790/api/obs/ingest \
  -H 'Content-Type: application/json' \
  -d '{"events":[{"kind":"tool_call","taskId":"<task-uuid>","agentId":"<agent-id>","data":{"toolName":"web_search"}}]}'

POST /api/eval/smoke

Runs the deterministic eval smoke suite — the same subset CI runs. Uses no live model, no provider keys, and no network. Each trial gets its own temporary SQLite board disjoint from the real clawboo.db.

Request body

trials
number
Number of trials per task. Clamped to 1–3. Defaults to 1.
k
number
The k in pass@k. Clamped to 1–3. Defaults to trials.

Response 200 OK

{
  tasks: Array<{
    taskId: string
    suite: 'capability' | 'regression'
    kind: 'coding' | 'research' | 'coordination'
    passAt1: number    // empirical pass@1
    passPowK: number   // probability all k trials pass
    meanScore: number  // mean partial-credit score
  }>
  passAt1: number    // macro-averaged across tasks
  passPowK: number
  k: number
}
curl -X POST http://localhost:18790/api/eval/smoke \
  -H 'Content-Type: application/json' \
  -d '{"trials":3,"k":2}'

See also