> ## Documentation Index
> Fetch the complete documentation index at: https://chatcli.edilsonfreitas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Live Dashboard

> Watch what every chatcli process on your machine is doing, in real time, as a graph that lights up while things happen: agents, LLM requests, tools, skills, MCP servers, the seven harness patterns, background work and outbound connections.

`/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**.

<Frame caption="Live: edges pulse and the feed tails as things happen; `/` searches the graph (here for the shell tool), `e` narrows the feed to errors. (Synthetic data.)">
  <img src="https://mintcdn.com/encom/4V8E1JPPjwsxz-ga/images/live-dashboard.gif?s=01f522a70bd5ecfe4ab823d9879979fa" alt="Animated ChatCLI live dashboard: two processes reporting, particles flowing along edges, a search for the shell tool and the feed switched to errors only" width="1200" height="800" data-path="images/live-dashboard.gif" />
</Frame>

***

## Opening it

| Command | What it does |
| - | - |
| `/dash` | Start the dashboard and open it in the browser |
| `/dash url` | Start it and only print the address |
| `/dash status` | Show whether this process is recording, and which processes report |
| `/dash off` | Stop it |
| `chatcli dash` | Serve the dashboard from a terminal of its own, until `Ctrl+C` |

`/dash` works **while a turn is running** (type it mid-run) and **over ACP**, where the address comes back to the IDE chat.

<Info>The browser only opens from an interactive terminal. From a daemon, a pipe or an IDE, the address is printed instead.</Info>

***

## 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:

```bash theme={"system"}
export CHATCLI_DASH=1
```

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.

| Node kind | What is reported |
| - | - |
| **session** | The process: surface (`repl`, `acp`, `gateway`, `mcp`, `daemon`, `tool`, …), pid, the **pair that serves the next request** and what decided it (`route`: `session`, `override` after [`@model use`](/agents/model-routing), or `skill` from a skill's model hint; `via`: `@model use`, `/switch`, `/provider`, `run start`, `gateway`, …), the session's running **cost**, tokens and requests, and **how full the context window is** (`ctx 37%`, the same projection the turn footer prints; past 100% means the next turn compacts). Every change of pair is a line of its own in the feed (`model → PROVIDER:model · override · @model use`) and the card keeps the last changes |
| **agent** | Every orchestrator, [squad worker](/agents/agent-squad), subagent, [MoA](/agents/mixture-of-agents) member and [task graph](/agents/task-graph) run: turn `3/30`, tool calls, current action, outcome |
| **llm** | One hub per `PROVIDER:model`. Each request hangs from **the agent that made it**, with payload size, history length and tool count. Every usage report adds what the call consumed (input, output, cache read and write tokens), the lane it ran in (main, worker, background) and the model's running tokens, requests and **cost**: the numbers [`/cost`](/providers/cost-tracking) shows, as they change |
| **tool** | Every tool execution: the orchestrator loop, squad workers, and the RPC / `chatcli tool` path. A call refused by the [security policy](/coder/coder-security) shows as `blocked` |
| **skill** | A [skill](/tools/builtin-skills) counts as activated when it is actually delivered to the model (after trigger match, dedup and cooldown): at run start, mid-loop or on a chat turn. Aging out of the window shows as `collapsed` |
| **mcp** | One node per [MCP server](/extensions/mcp-integration) with its state (`starting`, `connected`, `failed`, `disconnected`, `stopped`, `auth required`) and tool count; every `tools/call` is a timed span carrying the tool name |
| **pattern** | The [seven harness patterns](/agents/harness/overview), each with **what it concluded** (see below) |
| **background** | [Scheduler](/tools/scheduler) jobs, `@proc` processes, the memory worker, **skill self-evolution** (`skill-evolution`: candidates, then `1 authored · 2 evolved`, `3 suggested`, `no change`; each skill written is a point on its own node, `created` or `evolved`), history compaction, language servers, the `@browser` session, auto-update staging |
| **conn** | Outbound HTTP by **hostname**: method, status, latency, bytes. A token stream shows as one live connection with its real duration |
| **rpc** | chatcli acting as a server ([MCP server](/server/mcp-server), [ACP](/server/acp)): every inbound method, and what the server asks of the client |
| **turn** | Chat turns on every surface — the REPL, the [web UI](/usage/web-ui), MCP, ACP and the gateway — and one-shot turns. The `chatcli web` child that `/web` starts is a process of its own and gets its own window, labeled `web` |

### The seven patterns, with outcomes

[Self-Refine, CoVe and Reflexion](/agents/harness/overview) 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.

| Pattern | Outcome shown |
| - | - |
| [ReAct](/agents/harness/react) | every loop, with the turns it took (a park is a deliberate outcome, not a failure) |
| [Plan-and-Solve](/agents/harness/plan-and-solve) | `routed to @taskgraph`, `dry run preview`, `executed N steps` |
| [Reflexion](/agents/harness/reflexion) | the trigger and `lesson queued`, then from the background worker: `lesson saved`, `no lesson`, `retrying`, `dead letter` |
| [RAG + HyDE](/agents/harness/rag-hyde) | `augmented retrieval`, `fell back to plain hints` |
| [Self-Refine](/agents/harness/self-refine) | `rewrote draft`, `kept draft`, `rolled back`, `failed`, with the pass count |
| [CoVe](/agents/harness/cove) | `verified clean`, `found discrepancy`, `corrected draft` |
| [Reasoning backbone](/agents/harness/reasoning-backbone) | the effort tier it attached, and to which agent |

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

**Every process is a window of its own.** Drag it by its titlebar to put it anywhere: it stays where you drop it, so three processes you want to follow together can sit side by side, and the windows you did not touch stack under each other by their real size and flow around the ones you placed. Windows may overlap; the one touched last is on top and owns the clicks. Double-click a titlebar to hand the window back to the stack. **Drag any node to place it** where you want: it stays there, the edges follow, the rest of its column closes up and the window of its process stretches to keep hugging it, pushing the next window down instead of covering it. To move a **whole kind at once** (all the skills, all the tools), drag its header, the `⠿ SKILL` label above the first card, or Shift-drag any of its cards; cards that show up later join the group where you put it. Cards never overlap: what you moved last holds its ground and whatever is in its way slides down. Double-click a placed card or a moved header to hand it back to the automatic layout, or **Reset layout** to do that for everything. Drag the background to pan, scroll to zoom, `0` or **Fit** to fit, `Space` or **Pause** to freeze, click a node for details. Mouse, touch and pen all work. The chips at the top show and hide processes; the legend at the bottom shows and hides node kinds.

**The look is one deliberate choice**: a dark terminal, the palette of the ChatCLI deck (amber, cyan, violet and green on a near-black ground, monospace throughout). The header is a macOS terminal titlebar with a thin activity line; each process is a terminal window of its own; the feed is a `$ tail -f` of the log. A **light** terminal [theme](/usage/ui-theme) is the one thing that re-dresses the chrome, since a light terminal needs a light page; a dark theme keeps the deck's palette. The language follows your terminal.

**At a glance.** Six tiles sum what the shown processes report: session cost, requests, active nodes, the fullest context window, errors (with the last minute beside them) and events per second with a sparkline. Each window's titlebar carries its own cost, requests, context fill and error count.

**Finding things.** `/` focuses the search: every node that does not match dims, matches glow (an agent matches by name or by its current action). `e`, the errors tile or **Errors only** narrows the feed to errors; the kind selector narrows it to one kind. Hidden kinds and feed filters are remembered per browser. Every model hub shows the **prompt-cache hit** of its last request (`cache 84%`), on the card and in the popover. The phase labels an agent leaves with [`@dash mark`](#driving-it-from-the-agent) show as `◆` rows. **Export** downloads the events of the shown processes as NDJSON, what a bug report needs.

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.

***

## Driving it from the agent

The agent has the same handle on the dashboard as `/dash`, plus a way to read what it sees, through the **`@dash`** tool, registered in agent and coder mode like [`@model`](/agents/model-routing) and [`@agents`](/agents/agent-squad):

| `cmd` | What it does |
| - | - |
| `status` | Whether this process records, the dashboard address if one is served, which chatcli processes report |
| `open` / `url` | Start the dashboard (once per session), take the lease and return the address for the user; `open` also opens the browser, only on an interactive terminal, never unattended |
| `off` | Stop it; processes go quiet as the lease runs out |
| `summary` (`all: true` for every live process) | The reduced graph, as text: session pair, route and cost, agents with turn and tools, LLM requests per model with tokens and cost, tools, skills, MCP servers, patterns, background work, connections and the recent errors, the same figures the page shows |
| `events` (`limit`, `kind`, `status`, `all`) | The newest raw events, metadata only, narrowed to one kind and one status |
| `mark` (`note`) | A short phase label (one line, 80 characters) on this process's timeline, a `◆` row in the feed |

```
<tool_call name="@dash" args='{"cmd":"summary"}' />
<tool_call name="@dash" args='{"cmd":"events","args":{"kind":"tool","status":"error","limit":20}}' />
<tool_call name="@dash" args='{"cmd":"mark","args":{"note":"phase: running the test suite"}}' />
```

`summary` and `events` read the same spool the page polls, so they say when nothing is recording and how to turn it on. Everything they return is metadata, as the telemetry itself is. `status`, `url`, `summary` and `events` are read-only for the [security policy](/coder/coder-security); `open`, `off` and `mark` run serially. The tool works from every surface, `chatcli tool @dash status` included; `CHATCLI_AGENT_DASH_TOOL=false` unregisters it.

***

## 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. The automatic sweep at boot removes the spools of processes dead for more than **24 hours**. On demand, `/storage prune pulse` removes the spool of **every process that is no longer running**, right away:

```bash theme={"system"}
/storage prune pulse          # simulate
/storage prune pulse --apply  # remove
```

A process that is still recording is never a candidate, and neither is the lease file. A process that exited without closing its spool reads as alive for up to 20 seconds (the heartbeat window), so a prune in that window skips it and the next one takes it. See `/storage` in the [command reference](/reference/command-reference).

***

## Configuration

| Variable | Default | Description |
| - | - | - |
| `CHATCLI_DASH` | unset | `1` / `true` / `on` / `yes` records from boot without waiting for a dashboard lease. Reloadable |
| `CHATCLI_AGENT_DASH_TOOL` | `true` | Registers the `@dash` tool in agent/coder mode. `false` / `0` / `off` unregisters it |

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

***

## Relationship to other observability

| You want | Use |
| - | - |
| To **watch the runtime live**, as a graph, across processes | **`/dash`** (this page) |
| To watch one [task graph](/agents/task-graph) run in depth: gates, verdicts, critical path, cost per task | `/taskgraph dash` |
| Tokens, cost and cache behavior of the session | [`/cost`](/providers/cost-tracking) |
| Metrics in your own backend (Grafana, Datadog, …) | the [OpenTelemetry exporter](/server/server-mode#opentelemetry-export-otlp) (`OTEL_EXPORTER_OTLP_ENDPOINT`) |
| A tamper-evident record of every LLM request | the [audit trail](/security/overview) (`CHATCLI_AUDIT_LOG_PATH`), which also records **which agent run** made each request (`caller`) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.