Skip to main content
/dash opens a live graph of the runtime in your browser. Every agent, every LLM request, every tool call, every skill that activates, every MCP server, every harness pattern that fires, every background job and every outbound connection is a node; an edge pulses each time something happens on it. It is end-to-end telemetry with no setup: no collector, no agent, no account. It is off by default and costs nothing while off.
ChatCLI live dashboard: a graph of agents, LLM, tools, skills, MCP servers, harness patterns, background work and connections

One band per process. Agents form a tree by their real parent; everything they use is a hub with counters, latency and state. (Synthetic data.)


Opening it

/dash works while a turn is running (type it mid-run) and over ACP, where the address comes back to the IDE chat.
The browser only opens from an interactive terminal. From a daemon, a pipe or an IDE, the address is printed instead.

It sees every process, not just this one

Opening the dashboard makes every chatcli process on the machine start reporting: the REPL you typed /dash in, a second terminal, the gateway daemon, the ACP agent inside your IDE, the MCP server another client is driving, the scheduler daemon. Each one is a band on the page. This is what chatcli dash is for: the ACP agent, the MCP server and the daemons have no prompt to type /dash into, and their stdout is a protocol stream. A dashboard in another terminal is the only window into them.

How recording turns on and off

  1. Whoever serves a dashboard keeps a small lease file renewed under ~/.chatcli/pulse/.
  2. Every chatcli process checks that lease every two seconds. While it is unexpired, the process records to its own spool.
  3. The lease is renewed only while a browser is actually polling. Close the tab, and about 30 seconds later every process goes quiet again on its own. Nothing stays on by accident.
To record from boot without waiting for a dashboard (useful for the surfaces with no prompt), set:
It is read live: changing it in .env takes effect on /reload.

What you see

Sessions and agents are one node each, linked by their real parent, so a multi-agent dispatch reads as a tree. Everything else is a hub aggregated by name (the @coder tool, the github MCP server, the self-refine pattern) showing calls, how many are active right now, errors and average latency. The graph stays stable and fires, instead of exploding into one node per call.

The seven patterns, with outcomes

Self-Refine, CoVe and Reflexion run silently: they rewrite a worker’s output, flag a discrepancy or queue a lesson without printing a line. The dashboard shows not only that a pattern fired but what it concluded. A pattern that is disabled, or whose guards reject the result, did nothing and stays dark.

Things that are easy to miss without it

  • A compaction looks like a hang. History compaction summarizes the conversation with an LLM call of its own and holds the turn for as long as that takes. On the dashboard it is a compaction span that ends with applied or skipped.
  • A permission dialog nobody answered. Over ACP/MCP it shows as a client:session/request_permission call that never ends.
  • The dev server you started an hour ago. @proc processes are replayed when the dashboard opens, so they show up even if they started long before.
  • Which worker spent the requests. Each LLM request hangs from the agent that made it.

Using the page

Drag to pan, scroll to zoom, 0 or Fit to fit, Space or Pause to freeze, click a node for details. The chips at the top show and hide processes; the legend at the bottom shows and hides node kinds. The page follows your terminal theme and language. A dashboard opened in the middle of a run starts from what is live right now (running agents, connected MCP servers, background processes), not from empty.

Privacy and safety

Events carry metadata only: names, sizes, durations, statuses, token counts. The following never leave the process, and tests enforce each one:
  • prompt text, the task given to an agent, model output, error text
  • tool arguments and tool output, MCP call arguments and results
  • file paths touched by a tool
  • URL paths and query strings (where API keys and bot tokens travel): only the hostname is shown
  • a process command line: only the program name, and only when the first word is a plain program rather than a VAR=value assignment
  • a browser URL or anything on a page; a scheduled job’s payload, message or output
The server is local but not open. It binds to 127.0.0.1 on an ephemeral port, and on top of that:
  • every API call needs a random token minted at start. It reaches the page through the address once, moves to memory and leaves the address bar;
  • every request must carry the exact Host it was bound to, which closes DNS rebinding from a web page;
  • GET only, a strict Content-Security-Policy, no CDN, no network calls.
The dashboard is a read-only observer: it reads the spool from disk and holds no state. Closing it, reloading it or opening a second tab never affects a running session.

Cost

With the dashboard off, each instrumented point costs one atomic load, and a process does one stat every two seconds to check the lease. No spans are built, no bodies are wrapped. While recording, emitting never blocks: a full queue drops the event and counts the drop, and a slow consumer loses events instead of slowing the others. /dash status and /config dash show published and dropped counts.

Storage

Each process writes to ~/.chatcli/pulse/<instance>/ in size-rotated segments capped at roughly 16 MB per process, with a heartbeat that tells live processes from dead ones. Spools of dead processes are removed after 24 hours, at boot and on demand:
A process that is still recording is never a candidate. See /storage in the command reference.

Configuration

/config dash shows the variable, whether this process is recording, the spool directory and the event counters.

Relationship to other observability