Skip to main content
SmithersEvent is the discriminated union of lifecycle events the runtime and observability layer understand. Most variants are emitted by the runtime; reserved variants are called out in Event Types. The full type definition, and source of truth for field shapes, lives in Types.

Subscribe via onProgress

Read from the NDJSON log

Events append to .smithers/executions/<runId>/logs/stream.ndjson (configure with logDir / --log-dir; disable with --no-log).
Or with the CLI:

Common fields

Every event has type, runId, timestampMs; node-scoped adds nodeId/iteration; attempt-scoped adds attempt.

Token usage semantics

TokenUsageReported is a final cumulative total for one agent attempt, not an incremental sample. Current runtimes emit one record when the attempt settles, including a failed attempt when its provider error carries usage:
The token total is inputTokens + outputTokens. Cache and reasoning fields explain that total; they are not extra tokens. costUsd is absent when the resolved model is not in the built-in price table. When a provider omits the exact non-cached breakdown, freshInputTokens falls back to its reported inputTokens counter for compatibility with CLI adapters and historical logs. Smithers versions around 0.20 could write the growing cumulative total more than once during an attempt. When reading those historical logs, group by nodeId + iteration + attempt and keep the last record; summing every record over-counts the run. Current persistence does this automatically: _smithers_run_usage upserts by that attempt identity, while retries use new attempt numbers and remain separate. Use bunx smthrs inspect RUN_ID or bunx smthrs usage --run RUN_ID for the authoritative aggregate.

Event categories

Used by bunx smthrs events --type <category> and the metrics layer. RunStateChanged is categorized as run because the type is part of the public event union, but the current runtime does not emit it; use RunStatusChanged from the stream plus getRun / computeRunState for derived run state. RunFinished persists optional failedChildren and failedChildKeys. A nonzero count keeps lifecycle status finished but makes computeRunState return succeeded-with-failures. OpenApiToolCalled is categorized as openapi for forward compatibility, but the current OpenAPI tool factory records Effect metrics and log spans rather than emitting that event onto the run event bus.

Effect reverts

EffectRevertStarted identifies the tool or Task effect, its original effectStatus, and the time-travel operation. EffectRevertFinished records successful compensation. EffectRevertFailed includes the handler error and leaves the effect blocking. SideEffectBoundaryCrossed records a forced crossing or a warning-only plain fork. Its report contains blocking, revertible, and warnings arrays. Forced crossings remain visible after the command returns. A late tool completion sets lateCompletion: true and identifies the operation that archived the journal row with archivedByOp when applicable. If the row is still live after compensation, its revert status becomes revert-stale.

Built-in metrics

trackSmithersEvent from smthrs/observability exposes this mapping for custom integrations. See Observability for the full OTLP/Prometheus setup.