Skip to content

Run Monitor

The Run Monitor is the “what is happening right now” surface: a read-only, chat-like view of everything in flight — streaming agent text, tool calls resolving in place, shell commands and their output, plan updates, and gate pauses — in near-realtime.

It is non-interactive by design. It observes exactly the same event stream the canvas animates from, so it can never disagree with the canvas about what happened.

The Run Monitor following a live run

One feed for every run in flight, filterable to one.

Click the running indicator in the status bar — it reads idle, ⟳ running <workflow> or ⟳ 3 running, and it is a button. Or ⌘⇧PMonitor: Live Run Feed. It opens as a tab like anything else, so you can leave it open beside the code an agent is editing.

Feed items are typed — status changes, streaming model text, tool calls, shell commands, and plans — each rendered with its own affordance rather than flattened into log lines. A tool call appears when it is issued and fills in when its result arrives, so a long-running call is visibly pending rather than absent.

Every item carries its run’s workflow id, the node that produced it, and a timestamp:

Item Looks like Comes from
Status ▶ build-pipeline started (cron 0 2 * * *), ✓ … completed, ✕ … failed: <error> run.started / run.completed / run.failed
Text 🤖 A bubble that grows token by token, marked streaming… until it closes node.delta, closed by node.completed
Tool read_file {"path":"src/index.ts"}, marked running…, then → ✓ <preview> tool.call patched by tool.result
Shell $ $ npm test then → exit 0 and the head of the output shell.exec
Plan ☑ scaffold ▸ implement ☐ tests plan.update, from the set_plan tool

Publishes and pauses punctuate the feed as statuses too: ▦ morning-brief: 6 widget(s) published, 🗺 latchai-map: 3 view(s) published, ⏸ review waiting for review, ☑ review approved.

A node that fails closes its bubble with ✕ <error> rather than leaving it spinning, so a run that died has a visible last word.

Two caps keep a long night from eating the tab: 600 items across all runs, and 8,000 characters per streaming bubble (it keeps the tail, prefixed with ). The full text is always in the run log on disk.

Newest runs come first in the filter, labelled with their workflow id and the tail of the run id when one is known. Selecting a run narrows the feed to it; “all” shows everything the daemon is doing at once — which, with triggers armed, is often more than one thing.

The feed auto-follows the stream only while you are pinned to the bottom. Scroll up to read something and it stops fighting you; scroll back down and following resumes.

Because dashboard and atlas builds drive the same tool loop as workflow runs and emit the same events, they appear in the Run Monitor too — a briefing being assembled at 7am looks like any other run, under the workflow id dashboard:<id> or atlas:<id>. Subworkflows appear as runs of their own, which is what makes a pipeline of pipelines legible.

Two things are deliberately absent. Chat turns are excluded — the chat panel already renders them, in more detail. And a trigger.skipped event, which has no run to belong to, goes to the events panel instead.

Open the app while a cron run is halfway through and the feed is not empty. On connect, LatchAI asks the engine what is running, reads those runs’ persisted logs, and replays them through the same reducer the live socket feeds — so the monitor, the canvas and the status bar all catch up to the present. It isn’t a replay mode: this is the current run, with no “(replay)” label, and the live stream takes over from there.

Surface What it holds
Run Monitor Live, chat-shaped, this browser session. Clearing it empties only this view
Events panel (⌘J) The raw event lines — kind, node, path, arguments — with clickable file paths. Last 200 events, streaming text excluded
The canvas The same events as node status, per node, on the workflow you’re looking at
<home>/runs/<runId>.jsonl The append-only truth. Every event, in order, forever
Reporting () Run history, transcripts and token usage across runs

Clearing the feed is a view-level action, not a delete: history stays in Reporting and on disk.