Skip to main content
Events stream execution notifications such as starts, content deltas, pauses, and completion. They do not themselves persist conversation memory. Applications can consume or record them, and the HTTP job store and background-task APIs retain bounded event logs. Traces capture span input, output, errors, timing, and usage through the configured tracing provider.

Traces

A Trace is the core data structure that captures execution information for every runnable execution, providing a complete audit trail of what happened. This tracing system enables complete observability into your application’s behavior and performance. For the previous LLM example, a single span inside the run’s trace would look like this:
Spans are stored in a Trace — a dict keyed by call_id. Access them during or after a run via get_run_context()._trace or helper methods like step_span(). That’s a single span, but spans don’t usually come in isolation — they’re organized into larger execution units: Runs.

Runs

A Run represents the complete execution of your application - from the moment you invoke a runnable until it finishes. Think of it as the lifecycle of a single request or operation, whether that’s a simple function call or a complex multi-step agent workflow. Every Run is composed of a collection of spans:
  • Simple execution: Running a single tool generates one span — the tool’s input, output, timing, and metadata
  • Complex execution: Running an agent generates multiple spans as it decides which tools to use, calls LLMs for reasoning, executes tools, and processes results
All spans within a run share the same run_id (via RunContext.id), creating a complete execution history that you can analyze, debug, or replay.

The Run Context

Traces are stored in the RunContext - a central hub that manages all run data. You can access traces during execution, control storage behavior, and use this system to share data between different parts of your run. More on this in the Context section.

When a save fails

The trace is saved as each span completes. If the provider fails to store a snapshot, for example the platform rejecting a run whose parent it has no record of, or an outage that outlasts the retries, the run still completes and returns its output. The failure is logged as an error and counted as tracing:save_failed in the run’s usage. Cancellation is not caught.

Platform trace cache

PlatformTracingProvider caches traces this process successfully saves, so a following agent or workflow run can load its parent’s trace without another platform request. This also applies to voice turns. The cache holds up to 256 distinct runs and 64 MiB of serialized traces across the process by default; saving the same run again replaces its snapshot and refreshes its expiry. A failed save drops that run’s cached snapshot, so the next read goes to the platform. When saves of the same run overlap, the most recently taken snapshot decides what is cached, whichever request finishes last, even if its cached copy has since been evicted. Configure the cache with environment variables:
  • TIMBAL_TRACE_CACHE_MAX_ENTRIES: maximum number of cached runs, a non-negative integer. Default: 256.
  • TIMBAL_TRACE_CACHE_TTL_SECS: seconds since the last successful save, a non-negative finite number. Default: 300. Reading a trace does not extend its lifetime.
Setting either value to 0 disables caching and clears existing entries on the next cache access. Invalid values produce one warning per distinct value and fall back to the corresponding default. Settings are read on each cache access. Cache reads and writes remove expired entries, including entries for other runs. Cleanup is lazy: an idle process retains entries until the next cache access. When either limit is exceeded, the least recently saved runs are evicted; a single trace larger than the byte limit is not cached. Eviction only removes the local copy; traces remain stored on the platform, and cache misses fetch them there. Traces fetched from the platform are not added to this cache. A read of a run this process is still saving waits up to 2 seconds for the saves already in flight, with or without the cache: until a PATCH lands, the platform may answer 404 or an older snapshot. This covers a voice turn whose save is still on the wire when the next turn starts. Entries are scoped by host, organization, app, token, and run ID, and each read returns an independent copy. Updates made by another process can remain invisible until the cached entry expires or is evicted; lower the TTL or disable caching when those updates must be visible immediately.