Records complete agent execution traces to JSONL files for accurate token usage measurement and session analysis.
The primary use case is measuring token usage that the agent consumes. Each LLM interaction is recorded with detailed token breakdowns:
- Input/output tokens
- Reasoning tokens
- Cache read/write tokens
- Computed totals
packages/opencode/src/trajectory/
├── index.ts # Public exports
├── types.ts # Event type definitions
├── recorder.ts # Core recording logic
└── config.ts # Configuration defaults
| Event | Description |
|---|---|
session_start |
Agent session initialization with model info |
llm_interaction |
LLM call with full token usage breakdown |
stream_event |
Granular streaming events (reasoning, response, tool calls) |
tool_execution |
Tool invocations with timing and results |
agent_step |
Agent loop state transitions |
compaction |
Context compaction events |
The llm_interaction event captures:
usage: {
inputTokens: number
outputTokens: number
reasoningTokens?: number
cacheReadTokens?: number
cacheWriteTokens?: number
totalInputTokens?: number // input + cache read
totalOutputTokens?: number // output + cache write
totalCacheTokens?: number // cache read + write
}Trajectories are written to .opencode/trajectories/ as JSONL files:
trajectory_{sessionID}_{timestamp}.jsonl
Each line is a self-contained JSON event with timestamp and session ID.
The recorder hooks into:
- prompt.ts — Session start/stop, agent steps, tool executions, title generation
- processor.ts — Stream events during LLM streaming
- compaction.ts — Context compaction events
- summary.ts — Summary generation LLM calls
import { TrajectoryRecorder } from "./trajectory"
// Start recording (typically at session creation)
TrajectoryRecorder.start(sessionID, { agent, model })
// Record events
await TrajectoryRecorder.record(sessionID, event)
// High-level capture for LLM interactions
await TrajectoryRecorder.captureInteraction(sessionID, { ... })
// Stop and flush
await TrajectoryRecorder.stop(sessionID)Static defaults (no runtime configuration):
- enabled:
true - outputPath:
.opencode/trajectories - bufferSize:
1000events - flushStrategy:
end_of_stream - captureStreamEvents:
true
- Silent failures — Recording errors don't interrupt agent execution
- Buffered writes — Events buffered until stream end for efficiency
- JSONL format — Append-friendly, streamable, easy to parse
- No data truncation — Full event data preserved for accurate analysis