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).
Common fields
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:
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 bybunx 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.