boxer

Events

The JSON event stream boxer writes when telemetry is on, its schema, and how to read it.

With telemetry on, boxer writes one JSON event per line for each thing it decides or does.

[telemetry]
enabled         = true
sink            = "file"     # none | file | stderr | otel
path            = ""         # default $XDG_STATE_HOME/boxer/events.jsonl
record_commands = false
endpoint        = ""         # otel only

The stream is off by default. With no [telemetry] table and no BOXER_TRACE, boxer writes nothing. The keys are in the configuration reference.

BOXER_TRACE=<path> turns on the file sink at that path, whatever the configuration says. enabled = true with no sink uses the file sink. The OpenTelemetry sink exists only in a binary built with -tags otel.

Shape

{
  "time": "2026-09-20T14:31:09.236Z",
  "event": "provision",
  "scope": "sb-7e1852e4a3c3",
  "harness": "claude-code",
  "duration_ms": 623.4,
  "outcome": "ok",
  "payload": { "created": true, "image": "node:24-bookworm-slim", "image_reason": "detected package-lock.json" }
}
Field
timeRFC 3339 with nanoseconds, UTC
eventOne of the names below
scopeThe sandbox key. Absent for hook, rewrite, deny, mcp and gc
harnessThe harness, when one was named
duration_msHow long it took, when measured
outcomeok, error, denied or skipped
payloadEvent-specific fields

scope, harness, duration_ms, outcome and payload are omitted when empty. Treat a missing field as absent, and ignore event names and payload keys you do not recognise. Names and fields are added, never repurposed.

eventWhenpayload
resolveA scope was resolvedisolation, degraded, warnings (a count)
provisionA sandbox was created or started, prep ran, or a fork was prepared or branchedcreated, image and image_reason, or kind (prep, fork-prepare, fork) and count
packA pack was written, skipped for disk space, or failedkind (env, harness, image, named), image or name, path, free_bytes when skipped
runA command ran in the guestexit, command
rewriteA hook replaced a command with its sandboxed formtool, command
denyA hook refused a commandtool, reason
hookA hook was invokedevent (the harness's hook name), purpose
mcpAn MCP tool was calledtool, command
gcA sweep ranmachines, packs, dry_run
errorA refusalcause, reason

Redaction

Unless record_commands = true, the payload keys command, argv, env and setup are replaced by their length, as command_len and so on. Values of env_passthrough and secrets never enter an event. The separate last-run record is covered in the security model.

Reading it back

boxer logs -n 50          # the last 50 events
boxer logs --json         # the raw events, as an array
boxer logs --scope NAME   # one sandbox
boxer watch --json        # new events, interleaved with state changes

The file sink also holds plain-text hook trace lines. boxer logs skips anything that is not an event.

On this page