An htop-style monitor for AI coding agent sessions written in Rust.
Reads session transcripts from your local agent data directories, extracts token usage, and estimates cost using built-in pricing tables.
| Client | Data source | Status |
|---|---|---|
| Claude Code | ~/.claude/projects/<slug>/<uuid>.jsonl |
Stable |
| Codex | ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl |
Stable |
| Gemini CLI | `~/.gemini/tmp/<project_hash>/chats/*.(json | jsonl)` |
| OpenCode | ~/.local/share/opencode/storage/{session,message}/… |
Best-effort |
Adding a new client is a single impl Client in agtop-core::clients.
See docs/gemini-cli.md for Gemini CLI integration
details, data sources, and implementation notes.
When an agent CLI is running, agtop correlates its OS process to the
session transcript it's writing. The session table's PID column shows
the live PID; the Process tab in the bottom panel shows liveness
state (live / stopped), match confidence, and live resource metrics
(CPU usage, resident memory, virtual memory, cumulative disk I/O, and disk I/O throughput).
Correlation uses the session id literal in argv (--resume <uuid>,
-s <ses_…>) as the most-confident signal, the transcript file held
open by the CLI as the next-best signal, and falls back to scoring on
cwd, binary name, and start-time overlap.
See docs/session-pid-tracking-status.md
for per-client coverage and the matching algorithm details.
| Platform | Process enum | Fd enum (definitive) | Score fallback |
|---|---|---|---|
| Linux | ✅ | ✅ (/proc) | ✅ |
| macOS | ✅ | ✅ (libproc) | ✅ |
| Windows | ✅ | ❌ | ✅ |
On Windows the score-only fallback still works but may be ambiguous when multiple agents run in the same cwd.
v0.4 adds live process metrics. Each matched session now surfaces CPU
usage, resident/virtual memory, cumulative disk I/O, and disk read/write
throughput sampled from the OS on every refresh. The dashboard ACTIVITY
sparkline reflects the stronger of CPU load or normalized disk throughput.
TUI columns CPU, MEM, R/s, and W/s are visible by default (plus VSZ,
DISK R, DISK W in the Config tab); a dedicated Process bottom-panel
tab shows all metrics with room to read them. The --list table gains PID,
CPU, MEM, R/s, and W/s columns; --json includes the expanded
process_metrics field.
v0.3 adds session ↔ OS-process correlation. When a CLI is running
agtop binds the right PID to the right session row across all
supported clients, including realistic Linux+VSCode setups (opencode serve, codex app-server), nvm-managed Node hosts (Gemini under Node
v24/v25), and --resume workflows. See "Process tracking" above.
v0.2 added an interactive TUI (ratatui + crossterm) on top of the v0.1 analysis engine. Three output modes:
- (no flag) — interactive htop-style dashboard (default).
--list— human-readable one-shot table.--json— full analysis as JSON (per-bucket tokens + cost).
The TUI refreshes in the background every --delay seconds (default 2)
via a dedicated tokio worker thread; the core analysis layer remains
TUI-free.
cargo build --release
# binary at target/release/agtopRust toolchain: 1.75+ (works with 1.93 as of this commit).
# Interactive TUI (default)
agtop
# Interactive TUI refreshing every 5 seconds instead of the default 2
agtop --delay 5
# Start directly in the btop-style dashboard view
agtop --dashboard
# One-shot table (good for scripts / CI)
agtop --list
# Only Claude Code sessions under the "Max" plan (Claude sessions marked included)
agtop --list --plan max --agentic-client claude
# Dump everything as JSON (good for piping to jq)
agtop --json
# Multiple agentic client filters
agtop --list --agentic-client claude --agentic-client codex
# Non-interactive refresh loop (for headless monitoring). Not valid with --json.
agtop --list --watch --delay 5
# Write debug logs to a file while running the TUI (the TUI is unaffected)
agtop --log-file /tmp/agtop.logWhen the host terminal supports a real graphics protocol (Kitty,
iTerm2, Sixel), agtop renders small SVG logos from
models.dev next to the subscription name in the
session table, dashboard provider list, and info pane. Logos are
cached to ~/.cache/agtop/logos/ for 7 days.
Terminals without a graphics protocol (alacritty, VSCode terminal, gnome-terminal, …) fall back to the standard text-only layout — the logo column is omitted entirely so the table looks identical to pre-logo builds. No configuration knob is needed.
| Keys | Action |
|---|---|
j / k or ↓ / ↑ |
Move selection |
g / G (or Home/End) |
Jump to first / last row |
| PgUp / PgDn | Move ±10 rows |
/ |
Enter filter mode (Esc clears, Enter confirms) |
F6 or > |
Cycle sort column |
i |
Flip sort direction |
d |
Toggle classic/dashboard layout |
| Tab / Shift-Tab | Cycle bottom-panel tabs (Info, Process, Cost, …) |
F5 or r |
Manual refresh |
q / F10 / Ctrl-C |
Quit |
retail— standard API pricing for all clients (default).max— treats Claude sessions as included (Claude Max / Pro), retail elsewhere.included— every session marked as included (enterprise / bundled).
rust-agtop/
├── crates/
│ ├── agtop-core/ # Client trait + parsing + pricing (library)
│ │ └── src/clients/ # claude.rs, codex.rs, opencode.rs, util.rs
│ └── agtop-cli/ # `agtop` binary (clap + table/json output)
└── Cargo.toml # workspace root
Core types:
Clienttrait:list_sessions()+analyze(summary, plan).SessionSummary: metadata discovered without re-reading the full transcript.SessionAnalysis: summary +TokenTotals+CostBreakdown+ProcessMetrics.PlanUsage: best-effort plan/limit snapshots for dashboard panes.ProcessCorrelator: matches sessions to live OS processes and samples resource metrics each refresh.
The client layer is Send + Sync; the TUI drives it from a background
refresh thread. ProcessCorrelator is stateful (retains prior snapshot
to emit a transient Stopped frame when a process exits) and must be
held across refresh iterations rather than re-created each cycle.
cargo test # unit tests (pricing lookup + LiteLLM cache + parsing)
cargo clippy -- -D warningsagtop uses two sources, consulted in order:
- LiteLLM cache — on first run (or when the cache is stale) agtop
downloads
model_prices_and_context_window.jsonto~/.cache/agtop/litellm-pricing.jsonwith a 24 h TTL. Covers almost every model you're likely to see. - Built-in fallback tables in
agtop-core/src/pricing.rs. Used for any model LiteLLM doesn't know about, and whenever agtop can't reach the network.
Control flags:
agtop --list --refresh-pricing # force an immediate fetch
agtop --list --no-pricing-refresh # stay fully offline (built-in tables only)- Cost figures are estimates based on public API prices. Many subscription
plans (Claude Max/Pro, ChatGPT Plus/Pro, etc.) charge flat rates or bundle
tokens differently. Treat
$as a resource-consumption proxy, not a bill. - OpenCode's on-disk format is undocumented and may change. The client is conservative and degrades gracefully when fields are missing.
- Claude Code subagent sidechain transcripts (
<uuid>/subagents/*.jsonl) are folded into the parent session's totals. The table marks such sessions as<id>+Nwhere N is the number of sidechain files merged. The JSON output surfaces the same count assubagent_file_count.
After cloning, install the git hooks with prek to catch CI failures locally before pushing:
cargo install prek # or: cargo binstall prek
prek installThe hooks run cargo fmt --check, cargo clippy (warnings as errors), and cargo doc (warnings as errors) — matching the CI pipeline exactly.
GPL-2.0-only, matching the upstream project.