A local, real-time dashboard for watching AI coding agents (Claude Code, Codex, OpenCode, Kimi CLI) run on your machine. It shows who launched who as a process graph, streams their logs, and keeps a history of every session.
- Invocation graph: every running agent shows up as a node, linked to the nearest agent ancestor. Intermediate shells (bash, zsh, pwsh, cmd) are collapsed, so "Claude launched OpenCode" appears as a direct edge.
- Live log streaming through opt-in wrappers, with search and auto-scroll in a side panel.
- CPU and RAM sparklines per process, sampled on every poll.
- Activity states (active, idle, idle for too long) and anomaly alerts for things like sustained RAM growth or an agent that stopped using CPU and might be stuck waiting for input.
- Side-by-side log compare: pin one process and read its output next to another.
- Timeline with start and end bars, switchable between 15 minute, 1 hour and 24 hour windows.
- Persistent history of finished sessions, with zip export of the log and metadata.
- Project filters based on working directory, keyboard shortcuts, dark and light themes.
- Node.js 20 or newer
- Windows 10/11, Linux, or macOS
Windows is by far the most tested platform, since agmon started there. Linux and macOS support is newer, so issues and reports from those systems are very welcome.
npm install
npm run devOpen http://localhost:5173. The backend listens on port 4600 (WebSocket at /ws) and Vite proxies to it.
For production, build the frontend and serve everything from one port:
npm run build
npm start # http://localhost:4600agmon polls the process table every 2 seconds, computes CPU% from the delta of accumulated CPU time, and rebuilds the tree.
- Windows: one PowerShell
Get-CimInstance Win32_Processquery per poll. - Linux: reads
/procdirectly (stat, cmdline, statm). No child processes are spawned per poll. - macOS: one
ps -axo pid=,ppid=,rss=,time=,lstart=,command=per poll.
A process counts as an agent when its executable name or full command line matches one of the regexes in config/harnesses.json. Shells never count as agents, they only invoke. Each agent node gets attached to its nearest agent ancestor, which is what collapses the shells in between.
One known limitation of the command line heuristic: an agent's command line usually contains its own prompt, so an unrelated process that merely mentions a harness name in its command line (a grep for "claude", say) can show up as a node. Narrow the patterns or use ignorePatterns if that gets noisy.
Processes agmon cannot read (permission denied, or the process died mid-poll) are skipped without breaking the poll. Finished processes stay on the graph, dimmed, for 5 minutes (retainEndedMs).
The wrappers are not required for monitoring. Any agent started normally shows up with its tree, CPU/RAM and timeline. The wrappers only add log capture: no OS lets you attach to the stdout of a process that is already running, so capture has to be opted into at launch time.
Install the shell functions (safe to run more than once):
# Windows, PowerShell
.\wrappers\install-wrappers.ps1# Linux / macOS, bash or zsh
bash wrappers/install-wrappers.shThen, in a new terminal:
claude-mon -p "explain this repo"
codex-mon ...
opencode-mon run "fix tests"
kimi-mon ...
# or the generic form:
agmon <command> <args...>On Windows cmd.exe, use the wrappers\agmon.cmd shim by full path, or add the wrappers folder to your PATH:
C:\path\to\agmon\wrappers\agmon.cmd claude -p "..."The wrapper writes the combined output to logs/<harness>-<timestamp>-<pid>.log (still echoing to your console) plus a .meta.json recording the wrapper PID. The backend tails the file and attaches the log to whichever graph node descends from that PID.
Agents started without a wrapper still appear on the dashboard, with a grey log indicator and a note in the side panel.
One limitation: with stdout on a pipe, most agents detect they are not on a TTY and fall back to plain output. That is ideal for one-shot runs like claude -p "...". Full interactive TUIs may render degraded in the console.
Claude Code can report what it is doing through hooks. agmon ships a set of hooks that post a small JSON payload to the backend whenever a session starts, a prompt is submitted, a tool runs, a subagent spawns or a turn ends. They cost zero tokens, since nothing is added to the model context.
Install them into your Claude Code settings:
npm run hooks:install
npm run hooks:install -- --dry-run # print the resulting settings without writing
npm run hooks:uninstall # remove them againThe installer only touches the agmon hook entries, so any hooks you already configured stay in place. Restart Claude Code afterwards so it reloads its settings.
They go into ~/.claude/settings.json, which means every Claude Code session on the machine runs them, in every repo, whether or not you are watching that one. Two properties follow from that, and both are deliberate:
- Nothing runs while the dashboard is closed. The backend publishes
data/server.json(pid, port, timestamp) while it is listening, and the hooks read it before doing anything else. No file, a timestamp older than 45 seconds, or a pid that is gone, and they exit without opening a connection. Akill -9leaves the file behind, which is why the pid is checked too. - They are
asynccommand hooks, and every path out of them exits 0. Claude Code never waits on them and never reports one as failed, so a session in an unrelated repo cannot be disturbed by agmon being closed, misconfigured or broken. The cost is one short-livednodeprocess per event.
Once a session is reporting, the graph node for that agent shows the model it is running, the tool it is executing right now, and a pulsing counter when subagents are active. The side panel adds a session block with the full model name, the number of tools executed so far, and a live feed of the last events with timestamps. Agents without the hooks installed keep working exactly as before, just without this extra detail.
Everything lives in config/harnesses.json:
| Field | Type | Description |
|---|---|---|
pollIntervalMs |
number | Process polling interval, in milliseconds. |
retainEndedMs |
number | How long finished processes stay visible (dimmed) on the graph. |
logsDir |
string | Directory the wrappers write logs to, relative to the repo root. |
serverPort |
number | Backend HTTP/WebSocket port. |
ignorePatterns |
string[] | Regexes matched against the command line. A hit excludes the process entirely. |
activity.idleMinutes |
number | Minutes without meaningful CPU before a process is flagged as idle for too long. |
activity.ramGrowthSamples |
number | Consecutive samples of rising RAM required to raise a growth anomaly. |
harnesses[] |
object[] | The agents to detect (see below). |
Adding a new agent:
{
"id": "aider",
"label": "Aider",
"color": "#2ECC71",
"patterns": ["\\baider\\b"]
}Patterns are case-insensitive regexes, applied first to the executable name and then to the full command line. Be careful with broad ignorePatterns: an agent's command line contains its prompt, so a prompt that mentions the pattern would make that process disappear from the graph.
Restart npm run dev after editing the config. For log capture, add a matching wrapper function (aider-mon) to your shell profile. The installer scripts show the format.
| Key | Action |
|---|---|
/ |
Focus the search box |
Esc |
Blur search, or close the side panel |
Up / Down |
Select the previous or next process |
t |
Toggle dark / light theme |
| Method | Path | Description |
|---|---|---|
GET |
/api/export/<logId> |
Download a zip with the session's log and metadata. |
Claude Code repeats PreToolUse:Read hook error / connect ECONNREFUSED 127.0.0.1:4600 on every tool call.
Hooks installed before this change were http hooks pointing straight at the backend. Claude Code cannot run those in the background, and it prints a notice in the transcript each time one fails to connect, so closing the dashboard turned every session on the machine into a wall of errors. They are non-blocking and nothing is actually broken, but the noise is real.
Re-run the installer to replace them:
npm run hooks:installThen restart the affected Claude Code sessions. npm run hooks:uninstall removes them entirely if you would rather not have hooks at all.
- Session history is persisted to
data/history.jsonl. - The UI ships in English and Brazilian Portuguese. Adding a language is one file in
web/src/i18n, contributions welcome.
Issues and pull requests are welcome, bug reports from Linux and macOS especially. See CONTRIBUTING.md for how to get set up and what to check before opening a pull request.
The backend binds to 127.0.0.1 and has no authentication by design, but requests from other origins are still rejected. See SECURITY.md for the threat model and how to report a vulnerability privately.
MIT, see LICENSE.
