Skip to main content
The orchestration event log is the append-only stream every observability surface reads. It is simultaneously the always-on local trace store (a trace is all events sharing a traceId, ordered by seq), the graph-projection source (delegation / status / cost), and the metric + error-taxonomy source. This page is the reference for the two typed contracts that define it: the event kinds (the discriminated union in @clawboo/obs) and the runtime error classes (the Cursor-model classifier). Both contracts live in @clawboo/obs, pure, browser-safe, zero runtime dependency on the OTel SDK. Events are persisted insert-only with secrets scrubbed; one trace per board task, spans per run / tool.

At a glance

The kinds are an append-only enum; kinds are added (e.g. session_rotated, the routine_* family, the team_chat_post family), never renamed or removed, so old traces keep parsing. Each addition lands in @clawboo/obs before any emit site.

The correlation envelope

Every event, regardless of kind, validates against orchestrationEventSchema. The runtime schema validates the envelope strictly but treats data as an open object (z.record), so an emit site can never drop an event on a minor data-shape drift. Observability captures best-effort; the kind → data shapes below are TypeScript interfaces (a discriminated union) that keep producers and projection reducers typed without risking event loss at the wire.
parseOrchestrationEvent(value) validates and defaults data before persistence.

Event kinds

The 23 members of ORCHESTRATION_EVENT_KINDS, grouped by concern. Each data shape is the TypeScript interface from KindToData. Fields without ? are always present at the producer; ? fields are optional. data is open at the wire, so any consumer must tolerate missing fields.

Board lifecycle

task_created

A board task was created.

task_claimed

A task was atomically claimed by an assignee.

status_changed

A task transitioned state. to is always present; from may be null (first transition).

comment_added

A comment / system note landed on a task.

dep_linked

A dependency edge (blocks / blocked-by) was added.

Execution

execution_started

An execution process opened for a task run.

execution_completed

An execution closed with its outcome. The costUsd / token fields carry the run’s final total (authoritative for the run, see cost reconciliation).

tool_call

A runtime invoked a tool. toolCallId correlates with the matching tool_result.

tool_result

A tool returned. isError drives the tool-error-rate metric.

cost

An incremental cost/token tick during a run. These accumulate per run; see cost reconciliation.

Approvals

approval_requested

A tool / delegation approval was requested.

approval_resolved

An approval was resolved (allow / deny / expire).

Errors

error

A runtime / tool failure. The errorClass and harnessBug fields are filled at the emit site by running the failure through classifyError and isHarnessBug. A harnessBug: true event additionally fires a structured harness-bug alert.
errorClass is typed string (not the RuntimeErrorClass union) because the executor runner also emits PolicyDenied for a brokered-tool denial, a non-fatal denial path that is not a runtime failure. Every other value is one of the eight error classes.

Spans

span_start

Opens a span in the trace tree.

span_end

Closes a span.

Session rotation

session_rotated

A run rotated to a fresh successor session (context exhaustion / max-turns). Continuity rides a short handoff note, not the transcript.

Routines (scheduler)

routine_fired

A scheduled_runs ledger row fired.

routine_dispatched

A fire materialized (or bound to) a board task and dispatched it. dispatchPath records the wake-bridge branch.

routine_completed

A fire’s dispatch reached a terminal outcome. nextRunAt is null when disarmed (a spent once@ or an errored recurring routine).

routine_error

A fire failed (the routine is parked / disarmed until a human resumes).

Peer chat

team_chat_post

A post landed in a team room. authorAgentId is resolved from the MCP connection binding, never from tool args (anti-spoof).

speaker_selected

The speaker-selection policy nominated the next agent to talk in a bounded exchange.

turn_bound_hit

A bounded peer-chat exchange ended (the chatter-forever guard).

Cost reconciliation

cost events are incremental and execution_completed carries the run’s final total. A runtime that reports cost only at completion (no mid-run cost events) would otherwise read $0 / 0 tokens in the metrics while the graph showed the real total. Both the metrics fold (summarizeMetrics) and the graph projection (projectGraph) reconcile per run (keyed by taskId): they take max(sum of cost events, execution_completed total), so the two code paths converge regardless of how a runtime reports cost, no double counting, and the completion total supplies the value when there were no cost events at all.

Error taxonomy

Every runtime / tool failure is classified: a failure is mapped to a baseline of expected classes; anything that doesn’t match is Unknown, and an Unknown is treated as a harness bug, surfaced as an alert (a flagged error event plus an error-level structured log) rather than silently swallowed. Expected classes get baselined per runtime so anomalies in their rate can be alerted on later; an Unknown alerts immediately.

Classes

RUNTIME_ERROR_CLASSES, the eight members of RuntimeErrorClass:

classifyError(code, message)

Joins code and message into one haystack (`${code ?? ''} ${message ?? ''}`, trimmed). An empty haystack returns Unknown. Otherwise the rules are tried in order, first match wins (the order is RateLimitedUserAbortedTimeoutUnexpectedEnvContextOverflowInvalidArgsProviderError), so the more specific / overloaded signals (rate-limit, abort) are checked before the broader provider / env buckets. ContextOverflow sits deliberately before InvalidArgs: an oversized-input 400 is a context overflow, not a generic bad request. No match returns Unknown.

isHarnessBug(cls)

Returns true only for Unknown. An unknown class is, by definition, a defect in the harness itself, so it alerts immediately rather than being absorbed as expected noise.

Per-runtime baselines

BASELINE_EXPECTED_CLASSES maps a runtime id to the classes whose mere occurrence is not an alert (only a spike in their rate would be). The baseline for openclaw, claude-code, codex, and hermes is identical, six classes (InvalidArgs, Timeout, ProviderError, RateLimited, UserAborted, UnexpectedEnv). Any runtime not in the map (including clawboo-native) falls back to GENERIC_BASELINE, which is those six plus ContextOverflow (seven). Unknown is never in any baseline; it always alerts.
true when cls is unexpected for the runtime: always true for Unknown, otherwise true when cls is not in that runtime’s baseline.
Unknown is not the only class outside a baseline. ContextOverflow is absent from all four named-runtime baselines but present in GENERIC_BASELINE, so isUnexpectedFor('openclaw', 'ContextOverflow') is true today while isUnexpectedFor('clawboo-native', 'ContextOverflow') is false. The other six non-Unknown classes are in every baseline, so they are never unexpected. The per-runtime map has already diverged once; it exists so further divergence (a runtime that genuinely never rate-limits, say) can flag a class as anomalous without code changes.

How the taxonomy feeds the surfaces

  • The executor runner classifies each failure as it drains a run’s events, fills errorClass + harnessBug into the emitted error event, and fires a harness-bug alert when the class is Unknown (a brokered-tool denial is emitted with errorClass: 'PolicyDenied' and harnessBug: false, never alerting).
  • The observability error-taxonomy view breaks error events down by class and surfaces the Unknown/harness-bug count.
  • The fleet-health view (projectFleetHealth) folds the same log into the fleet-health triage taxonomy AgentHealthStatus: working / idle / stalled / zombie, by how long an agent has been quiet while an execution is open (idle = no open execution; working/stalled/zombie by quiet-time thresholds).
  • The graph projection (projectGraph) folds the log into the task-delegation and agent graphs, applying the same per-run cost reconciliation as the metrics.
See the observability dashboard for how these render in the UI, and the observability REST API for the /api/obs/* endpoints that serve the event log, traces, errors, graph, and fleet health.

See also

Last modified on August 8, 2026