Skip to content

Repository files navigation

agmon

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.

agmon dashboard

Features

  • 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.

Requirements

  • 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.

Quick start

npm install
npm run dev

Open 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:4600

How it works

agmon 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_Process query per poll.
  • Linux: reads /proc directly (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).

Log capture wrappers (optional)

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.sh

Then, 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 integration (optional)

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 again

The 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. A kill -9 leaves the file behind, which is why the pid is checked too.
  • They are async command 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-lived node process 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.

Configuration

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.

Keyboard shortcuts

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

HTTP API

Method Path Description
GET /api/export/<logId> Download a zip with the session's log and metadata.

Troubleshooting

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

Then restart the affected Claude Code sessions. npm run hooks:uninstall removes them entirely if you would rather not have hooks at all.

Notes

  • 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.

Contributing

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.

Security

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.

License

MIT, see LICENSE.

About

See your agents working :)

Topics

Resources

Contributing

Security policy

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages