Skip to content

collectiveai-team/rust-agtop

Repository files navigation

rust-agtop

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.

Supported agents

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.

Process tracking

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 matrix

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.

Status

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.

Build

cargo build --release
# binary at target/release/agtop

Rust toolchain: 1.75+ (works with 1.93 as of this commit).

Usage

# 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.log

Provider logos

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

TUI keys

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

Plans

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

Architecture

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:

  • Client trait: 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.

Testing

cargo test           # unit tests (pricing lookup + LiteLLM cache + parsing)
cargo clippy -- -D warnings

Pricing data

agtop uses two sources, consulted in order:

  1. LiteLLM cache — on first run (or when the cache is stale) agtop downloads model_prices_and_context_window.json to ~/.cache/agtop/litellm-pricing.json with a 24 h TTL. Covers almost every model you're likely to see.
  2. 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)

Caveats

  • 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>+N where N is the number of sidechain files merged. The JSON output surfaces the same count as subagent_file_count.

Development

After cloning, install the git hooks with prek to catch CI failures locally before pushing:

cargo install prek   # or: cargo binstall prek
prek install

The hooks run cargo fmt --check, cargo clippy (warnings as errors), and cargo doc (warnings as errors) — matching the CI pipeline exactly.

License

GPL-2.0-only, matching the upstream project.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages