Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Inspecting Runs

Every pipeline run leaves a paper trail across three surfaces: the triggers table (the entry point), the run's trace (envelope + per-phase tasks), and the agent's logs (raw stdout / parsed turns). This page walks through how to navigate them when you need to know what happened.

1. Find a trigger

Triggers are the source of truth — every webhook, every cron tick, every MCP call enters the system through one. The DB is the most direct way to list them:

PGPASSWORD=bento psql -h localhost -U bento -d bento \
  -c "select id, kind, source, event_type, pipeline, status, run_id, arrived_at
      from triggers
      order by arrived_at desc
      limit 10;"
      id      |  kind   | source  | event_type          | pipeline  | status | run_id     | arrived_at
--------------+---------+---------+---------------------+-----------+--------+------------+--------------------
 d990d0a0-5f1 | webhook | github  | pull_request.opened | pr-review | done   | XbSjXLrysC | 2026-05-26 11:35:21
 e10552e5-7d1 | schedule| -       | -                   | heartbeat | done   | mecOey_7rx | 2026-05-26 11:40:00

Filter by kind, pipeline, status, or source to narrow down. The shortened id (first 12 chars) is enough for the trace command — bento trace accepts any unique prefix.

2. Trace a trigger

bento trace <id> follows one trigger through every layer it touched:

bento trace d990d0a0-5f1
══════════════════════════════════════════════════════════════════════
  TRACE: d990d0a0-5f1
══════════════════════════════════════════════════════════════════════
 
┌─ Trigger
│  id:         d990d0a0-5f1
│  kind:       webhook
│  source:     github/pull_request.opened
│  pipeline:   pr-review
│  status:     done
│  arrived:    Tue May 26 2026 12:35:21
│  completed:  Tue May 26 2026 12:42:38
│  run_id:     XbSjXLrysC

 
┌─ Workload
│  id:       043cbc31-31ac-4726-862c-07511d286547
│  status:   active
│  ttl:      3600s

 
┌─ Invocations (1)
└── [a020a45e] reviewer
      runtime=claude model=claude-sonnet-4-6 status=completed duration=436.7s
      ✓ workspace-setup (setup) 1457ms [ok]
      ✓ task:reviewer (spawn) 220750ms [ok]
      ✓ task:reviewer (spawn) 232402ms [ok]
      ✓ spawn (spawn) 435163ms [ok]
 
      ┌─ Orchestrator Output
      │ <agent's final synthesised reply>

The four sections, top to bottom:

  • Trigger — what came in (HTTP webhook, cron, MCP), when, which pipeline matched, terminal status.
  • Workload — the longer-lived container an invocation belongs to. One webhook can submit several invocations under one workload.
  • Invocations — one per agent run. Each lists its phases (workspace-setup, spawn, hooks) with duration + outcome. An orchestrated run shows task:<agent> sub-spawns for each tool call the orchestrator made.
  • Orchestrator Output — what the agent finally returned, after notes / citations / post-back processing.

Useful flags

FlagWhen
--jsonPipe to jq for scripted inspection
--no-messagesSkip agent message parsing — faster when the run is long

3. Read the agent's stdout

The trace shows what the agent said at the end. To see how it got there — turn-by-turn, tool calls, intermediate thoughts — go to the agent log:

# Raw stream-json (the format the runtime CLI emitted)
bento daemon logs XbSjXLrysC --agent
 
# Same data, collapsed to readable per-turn text
bento daemon logs XbSjXLrysC --agent --render flat

--render flat is usually what you want during debugging; raw is for piping into a parser.

4. Watch a daemon in flight

For live tracing — what the daemon is doing right now — tail its log:

bento daemon logs        # last 50 lines
bento daemon logs -f     # follow mode (tail -f)
bento daemon logs -n 200 # widen the window

The daemon's name: field in .bento/daemon.yaml (default bento) determines where things live and what they're called:

ThingPath / label
Log file~/.bento/<name>/daemon.log
PID file~/.bento/<name>/daemon.pid
launchd labeldev.bento.<name>
systemd unit<name>.service
Process title<name>-daemon

So with name: myproject, journalctl reads:

journalctl --user -u myproject.service -f

Run-id-stamped lines correlate with bento trace:

[INFO] [workload-manager] invocation a020a45e running
[INFO] [workload-manager] invocation a020a45e workspace ready  duration=1457ms
[INFO] [workload-manager] pipeline [pr-review] executing  run=XbSjXLrysC ...

5. Common questions

"Why did the agent fail?"bento trace <id> first. If the failure is in a hook, the failing step shows outcome=errored with the captured stderr. If the failure is in the agent itself, drop to bento daemon logs <runId> --agent --render flat.

"What did the agent actually see?" — the run dir on disk: ~/.bento/workspaces/<workspace>/runs/<runId>/. It holds the assembled prompt (meta.json), the agent's stdout/stderr files, and per-step artifacts under steps/.

"Why didn't my webhook match a pipeline?" — list discarded triggers:

PGPASSWORD=bento psql -h localhost -U bento -d bento \
  -c "select id, source, event_type, note from triggers
      where status = 'discarded'
      order by arrived_at desc limit 10;"

The note column carries the matcher's verdict (e.g. no pipeline matched, filter rejected: <expr>).

"What did setup actually do?" — the workspace-setup task is the first phase in every invocation; its duration tells you whether a clone happened (seconds) or it was a no-op mkdir (milliseconds). The shell script that ran is deterministic from WorkspaceSource — see packages/sandboxes/src/setup-script.ts:buildSetupScript.