Crumb format
JSONL schema and crumb types
Each crumb is a JSON object. When stored, they are written as JSONL (one JSON object per line).
Schema
{
"ts": "2026-03-07T10:00:00.123Z",
"ns": "auth-service",
"msg": "user logged in",
"data": { "userId": "123", "method": "oauth" },
"dt": 2.5,
"pid": 12345,
"type": "crumb",
"ctx": { "requestId": "abc-123" },
"traceId": "a1b2c3",
"depth": 0,
"tags": ["auth", "login"],
"sid": "f7g8h9"
}Fields
| Field | Type | Required | Description |
|---|---|---|---|
ts | string | Yes | ISO 8601 timestamp |
ns | string | Yes | Namespace |
msg | string | Yes | Message |
data | unknown | No | Structured data |
dt | number | Yes | Delta time in ms since last crumb from this trail |
pid | number | Yes | Process ID |
type | string | Yes | Crumb type (see below) |
ctx | object | No | Merged context from child() and AsyncLocalStorage |
traceId | string | No | Trace ID from scope() |
depth | number | No | Nesting depth from scope() |
tags | string[] | No | Tags for filtering (omitted when empty) |
sid | string | No | Session ID (omitted when not in a session) |
Crumb types
| Type | Emitted by |
|---|---|
crumb | crumb() |
scope:enter | crumb.scope() start |
scope:exit | crumb.scope() end |
scope:error | crumb.scope() error |
snapshot | crumb.snapshot() |
assert | crumb.assert() |
time | crumb.timeEnd() |
session:start | crumb.session() |
session:end | session.end() |
Storage
Crumbs are stored in ~/.agentcrumbs/crumbs.jsonl by default. One JSON object per line, no trailing comma, no wrapping array.