Skip to content

Event Log

Every Bivvy session can record what happened as a structured event log: one JSON object per line, one file per run. The log is meant for after-the-fact debugging, audits, and tooling that wants to inspect a run without scraping terminal output.

It is enabled by default. Reading the log requires nothing more than cat, tail, or jq.

Where logs live

Logs are written to ~/.bivvy/logs/ (the user’s home directory). One file is created per session. Filenames have the form:

2026-04-25T10-00-00_<session-suffix>.jsonl

The leading timestamp is the session start time in UTC (with : replaced by - so the name is filesystem-safe). The trailing suffix uniquely identifies the session.

Each file is plain JSONL — every line is an independent JSON object. Files remain after the session ends and are cleaned up later according to the retention policy.

Enabling and disabling

Event logging is on by default. Toggle it in .bivvy/config.yml:

settings:
logging: true # default — write JSONL logs to ~/.bivvy/logs/

To turn it off entirely:

settings:
logging: false # no log files are written

When logging: false, no log files are created and the retention sweep does not run. You can still see real-time output in the terminal; only the on-disk record is suppressed.

Retention

Bivvy expires old logs automatically. Cleanup runs at the start of each session, before the new log file is created.

settings:
logging: true
log_retention_days: 30 # default — delete files older than this
log_retention_mb: 500 # default — total cap; oldest deleted first
FieldDefaultBehavior
log_retention_days30Files older than this many days are deleted.
log_retention_mb500If the total size of the log directory exceeds this many megabytes, the oldest files are deleted until the total is back under the limit.

Both limits apply on every run: age first, then size. Non-.jsonl files in ~/.bivvy/logs/ are never touched.

What a log line looks like

Every line has the same outer shape:

{
"ts": "2026-04-25T10:00:00.123Z",
"session": "sess_1745575200_abcdef01",
"type": "step_completed",
"...": "type-specific fields"
}
FieldDescription
tsISO 8601 UTC timestamp with milliseconds, when Bivvy emitted the event.
sessionUnique session ID. The same session ID appears on every line of one file.
typeThe event variant — see event categories below.
Other fieldsVary by type. Each event carries enough context to be read on its own.

Two real lines from a small run:

{"ts":"2026-04-25T10:00:00.012Z","session":"sess_1745575200_abcdef01","type":"session_started","command":"run","args":["--verbose"],"version":"1.10.0","working_directory":"/Users/me/code/myapp"}
{"ts":"2026-04-25T10:00:01.456Z","session":"sess_1745575200_abcdef01","type":"step_completed","name":"bundle_install","success":true,"exit_code":0,"duration_ms":1444}

Event categories

Bivvy emits events for every meaningful moment of a run. The exact set is defined in src/logging/events.rs; the broad shape is:

CategoryExample type valuesWhen emitted
Sessionsession_started, session_ended, config_loadedOnce per run, plus when config is parsed.
Workflowworkflow_started, workflow_completedOnly when a workflow is executing (not for lint, status, etc.).
Step lifecyclestep_planned, step_filtered_out, step_decided, step_starting, step_output, step_completed, step_skippedThe full life of every step in the plan.
Decision signalscheck_evaluated, precondition_evaluated, satisfaction_evaluated, rerun_detected, dependency_blocked, requirement_gapThe signals the decision engine used to decide what to do with each step.
User interactionuser_prompted, user_respondedAny interactive prompt and its answer.
Snapshotsbaseline_established, baseline_updated, snapshot_capturedChange-check baselines and explicit bivvy snapshot calls.
Recoveryrecovery_started, recovery_action_takenFailure analysis and the option the user picked from the recovery menu.

You don’t need to memorize the list. Reading a log file end-to-end will walk you through exactly what the decision engine saw, what it decided, and what ran — in order.

Sensitive steps

Steps marked sensitive: true have their command output and any error messages replaced with "[REDACTED]" or "[SENSITIVE]" in the log. The event is still emitted (so timing and success are preserved), but the content does not land on disk.

Inspecting logs

Find the most recent log:

Terminal window
ls -t ~/.bivvy/logs/ | head -1

Tail it as it grows:

Terminal window
tail -f ~/.bivvy/logs/2026-04-25T10-00-00_abcdef01.jsonl

Pretty-print every event with jq:

Terminal window
jq . ~/.bivvy/logs/2026-04-25T10-00-00_abcdef01.jsonl

Show just the step results:

Terminal window
jq 'select(.type == "step_completed") | {name, success, exit_code, duration_ms}' \
~/.bivvy/logs/2026-04-25T10-00-00_abcdef01.jsonl

Find every failed step across every recent log:

Terminal window
jq -c 'select(.type == "step_completed" and .success == false)' \
~/.bivvy/logs/*.jsonl

Because each line is independent JSON, any tool that can read JSONL — jq, grep, log shippers, your own scripts — works without setup.

Logs and project scoping

bivvy last and bivvy history read this same log directory. They scope their output to the current project by matching the working_directory field on each file’s session_started event. If you delete or move a project’s log files, bivvy last and bivvy history simply see a shorter history; nothing else breaks.

bivvy history --clear removes only the log files belonging to the current project — logs from other projects are left alone.