Execution logs
Per-node testing, the server dry-run Test button, and the Runs tab — full per-run history with per-node event timelines.
Automations are easier to debug than agent conversations because each step is explicit and inspectable. Two surfaces give you visibility:
- The editor's Logs panel — streams status while you test.
- The editor's Runs tab — persisted per-run history, populated
from
automation_runs/automation_run_events.
Per-node testing
Every node has a Play icon (test) that appears on hover, left of the ⋮ menu. Clicking it runs just that node with its current inputs and shows the result in the left Logs panel.
For executable nodes:
- REST API Request — runs a real
fetch()(with optional CORS proxy), shows the built request (method, URL, headers, body) and the response. - Code — evaluates the JavaScript and shows the return value or error.
- Tool Call — invokes the tool with the current arguments.
- Condition — shows which branch would be taken.
- Prompt — calls the LLM with the resolved prompt.
For config nodes (Model, Identity, Sandbox, Tools, Sub-agents), the test validates the config but doesn't run anything.
Test = server dry run
The editor's top-bar Test button (▶) runs the whole graph as a
server dry run — the real automation-executor walks the flow,
same code path as a live run, but sends (SMS, email) and row writes
are stubbed. Per-node results stream back into the Logs panel with
the same status semantics as production:
✓— the node succeeded✗— the node failed (error message included)↷— the node was skipped (a pruned condition branch)
This replaced the older client-side simulator that walked the graph in JS. There is now one execution truth — a graph that passes Test will run the same way when a trigger fires.
The Logs panel
The left panel has three tabs (four when the editor is bound to a persisted automation):
- Logs — chronological list of test results
- Runs — persisted per-run history (only shown for saved automations — see below)
- Variables — current values of workflow variables
The Logs tab has a compact toolbar:
- Search filter
- Status filter dropdown (All / Success / Error / Info)
- Copy button — click any log to copy it; click Copy All to copy the entire history
- Clear button — flush the log history
Each log entry is collapsible. For HTTP and tool calls, the body renders as an expandable JSON tree (strings, numbers, booleans color-coded; arrays and objects collapsible with chevron toggles).
Drag the right edge of the panel to resize it (200 – 480 px). The drag handle highlights on hover.
The Runs tab
Once the editor is bound to a persisted automation, a Runs tab
appears in the left panel. It reads from automation_runs +
automation_run_events via useAutomations().listRuns /
listRunEvents and shows:
- Recent runs (most recent first) — overall status, duration, start time
- Trigger source — webhook / schedule / event / manual
- Per-node event timeline — one row per node execution with status, duration, output snippet, and any error message
- A refresh button (the tab auto-refreshes after a Test or Run finishes)
A nightly retention cron (migration 157) trims old runs so the tab stays scannable over time.
Real Run stats
Every executed run — Test dry run or live — writes back into
automations.last_run_at and last_run_status. The Automations
list panel uses those to render the row's status dot and the
"last run" timestamp beside each name, so the surface reflects the
runtime state without a manual refresh.
Tips for debugging
- Test bottom-up. Start with the leaf nodes (Tool Call, REST API) so you know their results before testing parents.
- Use Notes. Drop Note nodes near tricky parts of the graph to remind future-you what's expected.
- Bind to test outputs. Once you've tested an upstream node, its output appears in the ƒ modal under Actions → [node] → output. Use it to wire downstream bindings.
- Inspect variable state. The Variables tab updates live during test runs — handy when a Change Variable node isn't doing what you expect.
- Prefer server Test over per-node Play for flow-level questions ("does my condition route right?", "what happens after the wait?") — the server dry run walks the whole graph and prunes false branches exactly the way a live run does, so a green Test = green Run.