Skip to content

Observability

Z-M-Huang edited this page Apr 29, 2026 · 3 revisions

Observability

The primitives that make a session visible — correlation IDs, spans, audit events — and how extensions (especially Loggers) hook into them. Observability is a core surface; Loggers are the extension category that plugs sinks into it.


Three primitives

flowchart LR
    Turn[turn starts] --> Cor[correlationId<br/>assigned]
    Cor --> Span[spans opened<br/>per stage / tool / request]
    Span --> Events[events published<br/>to bus]
    Events --> Audit[audit records<br/>persisted]
    Events --> Logger[loggers subscribe<br/>and fan out]
Loading
Primitive Purpose
Correlation ID Threads one logical operation (a turn, a tool call, an approval exchange) across many events.
Span Bounded interval with start / end / result used by tracers to reconstruct timing.
Event Typed record published on the Event Bus.
Audit record Typed record persisted durably. See Audit Trail.

Correlation IDs and spans are core-emitted. Extensions consume them.


Correlation IDs

Every logical operation has a correlation ID. Common ancestors:

Operation Correlation root
Turn One turnId per turn; every event in the turn carries it.
Tool call A new correlation ID for the call; child of the turn.
Approval exchange Child of the tool call.
Provider request Child of the turn.
Reload Session-scoped correlation ID for the reload event family.
Session resume Session-scoped.

Correlation IDs nest. A subscriber can thread a tool call and every related event (approval request, hook fires, post-tool transform, result) into one view by filtering on correlationId.

The session's Audit Trail uses the same correlation IDs. An operator who sees ToolCallApproved in audit can pull every related event from the bus (or durable audit log) by correlation.


Spans

Spans wrap bounded operations with start and end timestamps:

  • Per-stage spans (StagePreFiredStagePostFired).
  • Per-tool-call spans.
  • Per-provider-request spans.
  • Per-hook spans (observer and transform hooks).

Spans are visible via their corresponding …Started / …Completed / …Failed events on the bus. There is no separate SpanRecord shape in v1; the bus events carry the timing information needed to reconstruct spans externally.

Tracers that want OTLP / OpenTelemetry shape implement that mapping in a Logger extension. Core does not ship an OTLP exporter.


The event bus as telemetry source

The primary observability surface is the Event Bus. Loggers, UIs, and debuggers subscribe to it. Filters let a subscriber take only what it needs:

Subscriber intent Filter
"Show me everything about turn X" correlationId = turnId
"Warn on deprecations" kinds = [DeprecationWarning]
"Alert on security events" kinds = [ProjectTrusted, MCPServerTrusted, ToolCallDenied, ...]
"Measure tool durations" kinds = [ToolInvocationStarted, ToolInvocationSucceeded, ToolInvocationFailed]

Filters are declared in the logger's contract. See Loggers.


The bus vs the audit trail

Concern Event Bus Audit Trail
Reliability Lossy (overflow drops). Durable.
Shape Broad (many event kinds). Narrow (security / change / lifecycle).
Consumers UIs, loggers, debuggers. Operators, reviewers.
Retention Session only. Per session store policy.

Events describe. Audit records. Many events produce an audit record; not all. See Audit Trail.


Instrumentation that core owns

The set of things core instruments is fixed in v1. Extensions do not add new spans to the kernel; they may emit their own observational events through the Host API:

Core-instrumented Not extensible?
Session lifecycle Yes — extensions cannot replace session stages.
Turn + stage spans Yes — the stage set is core.
Tool calls Yes — core wraps every dispatch.
Provider requests Yes — core wraps every provider call.
Hook invocations Yes — core fires hooks and records.
Interaction Protocol exchanges Yes — core routes requests / responses.

Extension-emitted events

An extension may emit a typed observational event through the Host API:

  • ObserverEvent{kind, payload} published to the bus.
  • Subject to filter rules on subscribing loggers.
  • Not audited by default — extensions that want durability promote via a Logger, or the core audit emitter with audit class.

Extension events must not imply control. The bus is projection only. See Event Bus.


Redaction

Resolved secrets — env values, keyring values, decrypted credentials — are never carried by events or audit records. They appear only as references (envName, secretRef). This is invariant across LLM Context Isolation, Secrets Hygiene, and the Session Manifest.

Transcript content (user input, provider request and response bodies, tool args and results) is recorded verbatim by the bundled file logger because stud-cli is a local-only tool — see Audit Trail § Content vs references. Loggers with redactSecrets: true apply best-effort token-shape redaction as a second line of defense, in case an API key leaks into a model response or a tool result.

A logger that wants unredacted output (debug logger on disk, never shipped) opts in explicitly. That choice is recorded in the session manifest for the logger's origin entry.


Determinism implications

Correlation IDs and spans are generated at emission time; they are non-deterministic (time-based / random). Workflows relying on deterministic replays should treat observability output as non-essential — the determinism tests cover behavior, not trace content.

See Determinism and Ordering.


Extension health as an observability surface

Extensions report health via Health and Diagnostics — a concrete event shape the loader and runtime emit for startup and runtime issues. Every reload, capability mismatch, validation diagnostic, dependency resolution failure, and trust decision is observable through the bus.


Related pages

Introduction

Reading

Core runtime

Contracts

Category contracts

Context

Security

Runtime behavior

Operations

Providers (bundled)

Integrations

Reference extensions

Tools

UI

Session Stores

Loggers

Providers

Hooks

Context Providers

Commands

Case studies

Flows

Maintainers

Clone this wiki locally