Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

476 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

abtop

Like btop, but for your AI coding agents.

See Claude Code, Codex CLI, OpenCode, Grok, and Kimi Code sessions at a glance — token usage, context window %, rate limits, child processes, open ports, and more. Sessions are discovered from local process and file state across macOS, Linux, and Windows.

demo

Why

  • Running 3+ agents across projects? See them all in one screen.
  • Hitting rate limits? Watch your quota in real-time.
  • Agent spawned a server and forgot to kill it? Orphan port detection.
  • Context window filling up? Per-session % bars with warnings.

Contents

Collection reads local state and needs no API keys or provider authentication. The normal TUI and --once can invoke the installed Claude CLI to generate session titles; see Privacy for the exact data boundary. Optional Codex hook integration records only bounded, content-free lifecycle metadata. It never participates in the interactive Codex launch path: plain codex ... remains native. Setup invokes bounded native compatibility-preflight and plugin-administration commands. Legacy zsh inspection can also run bounded login and non-login probes so an unexported ZDOTDIR is not missed. The native plugin integration and normal launch path never wrap, replace, alias, or proxy Codex, and abtop never inspects provider credentials. A narrowly scoped 0.6 compatibility trampoline for an already-loaded retired wrapper is documented below.

Install

macOS / Linux

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/graykode/abtop/releases/latest/download/abtop-installer.sh | sh

Cargo

Building or installing from source requires Rust 1.88 or newer.

cargo install abtop

Windows

Native support — no WSL required. Uses sysinfo for process info and host CPU/MEM metrics, and netstat -ano for listening ports. Windows has no load average, so LOAD is reported as 0. OpenCode session discovery additionally requires the sqlite3 CLI (winget install SQLite.SQLite); without it abtop prints a one-time warning to stderr.

powershell -c "irm https://github.com/graykode/abtop/releases/latest/download/abtop-installer.ps1 | iex"

Or run cargo install abtop from a terminal with the Rust toolchain available. Claude Code config is resolved automatically from %USERPROFILE%\.claude.

Other

Pre-built binaries for all platforms are available on the GitHub Releases page.

Optional dependencies

The base monitor starts without provider credentials or account setup. Extra local programs enable the following features:

Feature Requirement
OpenCode sessions A sqlite3 CLI on PATH with -readonly and -json support
Claude account quota bash and python3 in Claude Code's hook environment
Generated session titles An installed claude CLI; the normal TUI and --once may invoke claude --print
Codex lifecycle audit and exit correlation (macOS/Linux) Native codex-cli 0.146.0 with the stable, enabled hooks and plugins features and the exact supported 11-event generated hook schema
Project dirty-file counts git on PATH
Full Unix process, open-file, port, and MCP discovery ps and lsof
abtop --update curl and sh

Missing optional dependencies degrade only their corresponding feature. For example, abtop can still monitor non-OpenCode sessions without sqlite3.

Quick Start

Launch the monitor immediately after installation:

abtop

No setup is required for ordinary local session discovery. Two optional setup commands enable data that providers do not otherwise expose reliably.

Claude account quota

abtop --setup

This installs a Claude Code StatusLine hook in the active config root: CLAUDE_CONFIG_DIR when it is valid UTF-8 and names an existing directory, otherwise ~/.claude. It writes abtop-statusline.sh and registers it in settings.json; the hook later produces abtop-rate-limits.json when a Claude response supplies rate_limits. If statusLine.command is already a different nonempty string, setup exits instead of replacing that setting. Restart any running Claude Code sessions after setup. Quota appears after the next response that includes quota data and remains unavailable when the provider does not supply it.

abtop --setup is Claude-only. It does not inspect or change Codex configuration.

Codex lifecycle audit and exit correlation

The integration records content-free lifecycle boundaries for auditing and exact process-exit correlation. Codex 0.146.0 cannot attest the effective hook engine of a live thread, so setup does not make live Codex Thinking, Executing, Waiting, or Idle rows available; those rows remain non-actionable Unknown / Unavailable.

Native hook integration is currently supported on macOS and Linux. Windows still gets Codex process, rollout, token, context, and quota metadata, but its live lifecycle status remains Unknown; secure hook setup fails before changing Codex configuration there.

Install abtop's isolated local Codex plugin for the current abtop executable:

abtop --setup-codex

Setup uses the native codex plugin commands to register and enable abtop@abtop-local in the current ${CODEX_HOME:-~/.codex}. It does not edit PATH, define a shell function or alias, replace the Codex executable, or change command-line arguments. Existing global hooks, notify, plugins, and OpenTelemetry configuration remain untouched. Normal Codex commands keep their native behavior:

codex
codex resume
codex fork
codex --yolo

Setup supports exactly codex-cli 0.146.0. It also requires the native feature list to contain the exact hooks stable true and plugins stable true rows, and verifies that the uppercase ManagedHooksRequirements.properties in generated v2/ConfigRequirementsReadResponse.json are exactly the declared 11-event set. Older, newer, or structurally different releases fail closed until that contract is audited; if plugin installation cannot complete, setup attempts a lost-update-safe rollback of legacy profile edits and preserves any concurrent editor save rather than overwriting it.

Restart Codex after setup. If Codex asks for a trust review, approve only the 11 hooks attributed to abtop@abtop-local; setup never writes trusted hook hashes itself. A successful setup can therefore exit 0 while review is still required, whereas abtop --codex-integration-status remains exit 1 / not ready until the base config trusts and enables all 11 exact hooks. Run abtop --codex-integration-status to audit the installation. See Codex Hook Integration for its status and privacy limits. After replacing or updating the abtop binary, run abtop --setup-codex again: the exact helper digest is part of the hook identity, so old integration state deliberately becomes Unknown until the new plugin copy is installed, reviewed, and loaded by a fresh Codex session.

Command Reference

Command Behavior
abtop Launch the interactive monitor.
abtop --once Print one human-readable snapshot. It may wait up to 30 seconds for missing titles generated by claude --print.
abtop --json Print one machine-readable JSON snapshot without spawning summary jobs.
abtop --theme <name> Override the theme for this launch. Use the TUI to persist a choice.
abtop --mouse Enable mouse click and wheel handling; mouse capture is otherwise off.
abtop --demo Show deterministic demo data with default panels and theme (unless --theme is supplied); persisted discovery/visibility settings are ignored, as are keyboard r, x, X, and Enter actions.
abtop --exit-on-jump Exit abtop after a successful Enter terminal jump.
abtop --setup Install the Claude quota hook. It does not change Codex configuration.
abtop --setup-codex On macOS/Linux, remove exact legacy abtop Codex wrapper blocks, then install or repair the isolated abtop@abtop-local Codex plugin.
abtop --uninstall-codex Remove abtop's local Codex plugin integration and exact retired wrapper blocks, preserve its content-free audit data, and leave unrelated configuration unchanged.
abtop --codex-integration-status Audit native compatibility, the local plugin source and installed cache, declaration, helper, base trust/enablement, and retired-wrapper cleanup. It reports not ready on unsupported platforms.
abtop --version, abtop -V Print the installed abtop version.
abtop --update Download and run the latest release shell installer using curl and sh.

--once can wait for title generation before printing, while --json performs a single summary-free collection pass and is the safer interface for scripts and local tools.

The three Codex administration commands are exact singleton invocations. They return exit code 0 on success, exit code 1 when setup/uninstall fails or integration status is not ready, and exit code 2 for invalid command-line usage.

Integration status audits the exact bundle and trust/enablement recorded in base $CODEX_HOME/config.toml; it is not an attestation of a live thread's in-memory hook engine. Profiles, command-line or per-thread overrides, project/config-lock layers, managed/cloud policy, and live reload can differ. Codex 0.146.0 exposes no thread/PID/generation-bound proof of the effective hook engine, so a healthy setup or status result is installation readiness only: every live Codex Think, Exec, and Idle candidate remains non-actionable Unknown. Only the independently validated process-exit transition described below can promote to heuristic Done.

Codex Hook Integration

On macOS and Linux, abtop --setup-codex creates a private local marketplace and plugin below the active ${CODEX_HOME:-~/.codex}:

$CODEX_HOME/abtop/marketplace/
├── .agents/plugins/marketplace.json
└── plugins/abtop/
    ├── .codex-plugin/plugin.json
    ├── hooks/hooks.json
    └── scripts/abtop-codex-hook.{sh,cmd}

Before committing the integration, setup requires exactly codex-cli 0.146.0, exact hooks stable true and plugins stable true feature rows, and an exact match for the supported 11-event contract in v2/ConfigRequirementsReadResponse.json's uppercase ManagedHooksRequirements.properties. It then registers the marketplace and plugin by invoking the exact lexical codex entry selected from PATH whose execution proved that version and contract. This preserves argv-sensitive shims such as mise rather than silently substituting their canonical target. Setup verifies that the plugin is installed and enabled. Runtime state is stored in $CODEX_HOME/plugins/data/abtop-abtop-local. Re-running setup repairs or updates the bundle. A changed abtop executable path or byte content changes the helper digest; even a byte-identical replacement must be followed by setup, so run setup again after every abtop update or replacement and restart Codex. The plugin version and hook command include the schema revision and helper identity digest, causing Codex to request a new trust review instead of silently reusing an old approval. Hook evidence is accepted only when the private source bundle, Codex's installed cached copy, install attestation, and base trust/enablement state match the current declaration exactly. Those checks establish installation integrity, not complete effective per-thread hook coverage.

Setup and uninstall serialize owned plugin mutations with the stable $CODEX_HOME/.abtop-codex-plugin.lock. On Unix it is a same-owner regular file with mode 0600, is revalidated while held, and is retained after uninstall so concurrent administrative processes cannot lock different replacement inodes. A source-local $CODEX_HOME/abtop/.setup.lock belongs only to older installations and is removed as legacy source-bundle debris; it is not the current lock.

Compatibility preflight briefly invokes codex app-server generate-json-schema to inspect that local release's schema. This subprocess is not a relay, supervisor, monitoring transport, or persistent daemon, and abtop never attaches to a Codex daemon. Every native Codex administrative command receives null stdin, has a 15-second overall timeout, and captures at most 1 MiB from each of stdout and stderr. On Unix it runs in its own process group with nonblocking pipe drains; abtop terminates that group on timeout or when descendants retain an output pipe for 100 ms after the leader exits, then reaps only for a bounded interval. On Windows the portable path uses bounded reader channels and a kill-on-close Job Object when assignment succeeds, with direct child termination as a fallback. Mutating plugin commands are bracketed by checks of the exact selected Codex executable identity and fail if it changes.

The plugin subscribes, without matchers, to the exact 11-event set validated for Codex 0.146.0:

Session and turn Tools and interaction Subagents and compaction
SessionStart, SessionEnd, UserPromptSubmit, Stop PreToolUse, PermissionRequest, PostToolUse SubagentStart, SubagentStop, PreCompact, PostCompact

Each hook is synchronous, silent, and limited to one second, so it can delay the corresponding Codex edge by at most that configured timeout. The helper parses at most 4 MiB as a stream, materializes only bounded lifecycle fields, discards every other JSON value, and attempts to drain malformed input. The launcher and helper absorb all errors and produce no stdout or stderr. Monitoring therefore fails open for Codex itself: an unavailable or outdated abtop reduces monitoring confidence but cannot deny or alter the agent action after the bounded hook returns.

Setup does not add PostToolUseFailure, because Codex 0.146.0 does not advertise that event for plugins. It also leaves existing user hooks, notify, OpenTelemetry, and other plugins unchanged. Do not bypass hook trust globally. After setup, restart plain native Codex and review only the 11 hooks shown for abtop@abtop-local.

No shell integration is installed. Setup removes only the exact legacy blocks delimited by # >>> abtop managed codex >>> and # <<< abtop managed codex <<<; missing blocks are already clean, while malformed or duplicate markers fail closed without editing the file. Replacements are locked, revalidated, atomic, and rolled back safely if migration cannot complete on macOS/Linux. Unrelated aliases, functions, and profile contents are preserved. Zsh, bash, and fish are migrated automatically when applicable. To discover an unexported custom ZDOTDIR, setup, uninstall, and integration-status inspection can run strictly framed, output-bounded login and non-login zsh probes; zsh evaluates its normal startup files, but abtop persists none of their content. Windows setup is unsupported before migration; Windows uninstall can instead return exact manual PowerShell cleanup guidance. If an old wrapper function is still loaded in the current shell, start a fresh shell after setup. On macOS/Linux, migration and integration-status inspection share the stable private mode-0600 lock ~/.abtop-codex-migration.lock. The file is created on the first inspection and intentionally retained so concurrent processes never lock different replacement inodes; it contains no provider or shell-profile content. The non-Unix lock implementation is a no-op.

Uninstall applies the same exact-marker migration and preserves the bounded content-free state in $CODEX_HOME/plugins/data/abtop-abtop-local for audit. As a recovery rule it always asks native Codex to remove the reserved abtop@abtop-local plugin ID first, including when the marketplace record is missing, malformed, or conflicting; do not use that reserved ID for an unrelated plugin. It removes the marketplace registration and source bundle only after proving they point to abtop's exact local source, otherwise it preserves them and exits with manual-recovery guidance. Other profile content and Codex configuration remain unchanged. Unlike setup and healthy-status validation, uninstall accepts any exact stable X.Y.Z Codex semver so a downgrade or upgrade cannot strand the integration without a recovery path.

Release 0.6 retains abtop codex -- ... only as a hidden compatibility trampoline for an already-loaded legacy wrapper. It requires that wrapper's exact captured Codex path and directly delegates arguments, standard streams, and exit status to the native executable; on Unix, process replacement also preserves native signal behavior. It is not a monitoring launcher, has no argument allowlist, and is scheduled for removal in 0.7. New scripts and documentation must always invoke codex ... directly.

Interface

The numbered panels can be toggled with 17; their visibility is persisted. For orientation, press ? for help, / to filter sessions, c for configuration, Enter to jump to an actionable terminal, and x twice to confirm a session kill. See Key Bindings for the complete controls.

Panel Contents
1 Context Token-rate history and per-session context-window gauges when reliable window data exists.
2 Quota Account-level Claude and Codex quota windows and reset times. Other providers do not expose a reliable local quota source.
3 Tokens Input, output, cache, turn, and selected-session token history.
4 Projects Project branch and dirty-file counts collected through git.
5 Ports Agent child listeners, conflicts, and ports orphaned after their parent session exits.
6 Sessions Session list, current status/task, selected-session evidence, children, subagents, timeline, and file audit.
7 MCP Detected Codex mcp-server processes, profiles, rollout counts, and recent activity. A rollout updated within 30 minutes counts as active.

MCP-owned rollouts are suppressed from Sessions by default to prevent duplicate or ghost rows. M changes that behavior for the current run only.

The supported minimum terminal size is 60x18; smaller terminals show a size warning when the pane is tall enough to render it. Widths from 60 through 99 use a tabbed Work / Usage / System layout, while widths of 100 or more use the desktop layout. In desktop mode, Sessions receive priority when height is constrained and the Context panel is omitted first; narrow-mode sections split the available height equally unless one is maximized. 120x40 or larger remains recommended.

Mouse capture is off by default so drag selection and copy continue to work. Launch with --mouse to enable panel, tab, session, zoom, and orphan-port click targets plus wheel navigation.

Terminal Jump

Press Enter to focus the terminal running an actionable selected agent. abtop supports Herdr 0.7.0 or newer, cmux, tmux, and iTerm2 on macOS. When abtop runs inside Herdr, it can jump to agents in any pane, tab, or workspace in the same Herdr session; no additional setup is required. Unsupported environments do nothing. iTerm2 can request macOS Automation permission on first use. Before jumping, abtop freshly revalidates the provider process and its exact process incarnation; Unknown, Done, and otherwise non-actionable rows cannot be targeted.

tmux new -s work
# pane 0: abtop
# pane 1: claude (project A)
# pane 2: claude (project B)
# → Enter on a session in abtop jumps to its pane

The same flow works inside Herdr: run abtop in one pane, run agents elsewhere in the same session, then press Enter on the selected abtop row.

Supported Agents

✅ means available, ⚠ means conditional or deliberately limited, and ❌ means unavailable. Provider-specific caveats and evidence authorities are explained in Status and Evidence.

Feature Claude Code Codex CLI OpenCode Grok Kimi Code
Session discovery
Token tracking
Context window % ⚠ estimated ⚠ local data ⚠ local config
Status detection ⚠ mixed evidence ⚠ exact exit only ⚠ limited ⚠ mixed evidence
Current task ❌ live unavailable ⚠ generic
Account quota
Git status
Children / ports
Subagents
Memory status

Status and Evidence

Status answers what the agent is doing; evidence answers how confidently abtop can prove it. UI labels and their JSON enum values are:

UI JSON Meaning
◉ Think Thinking A model turn is open and no tool is currently running.
● Exec Executing A tool, task, subagent, background terminal, or verified active child is working.
◌ Wait Waiting An explicit unresolved approval or question requires user action. It wins over concurrent background work.
○ Idle Idle The live session has no active model, tool, task, or interaction work.
? Unknown Unknown Ownership or lifecycle proof is missing, stale, malformed, disconnected, contradictory, or otherwise insufficient.
⏳ Rate RateLimited The provider reports a current rate-limit block. A quota percentage alone never sets this lifecycle status.
✗ Error Error The provider reports a current fatal session or turn failure. Raw provider error content is not used as the task label.
✓ Done Done A verified process exit has been observed.

After ownership and lifecycle validation, precedence is Waiting > RateLimited > Error > Executing > Thinking > Idle. abtop never turns elapsed time, low CPU, or an old transcript timestamp into Wait. Unknown is the fail-closed result when that precedence cannot be applied safely; Done is terminal exit evidence.

Each row also carries one of these evidence authorities:

Authority Meaning
Provider Exact provider lifecycle data. Codex hook evidence is never promoted to this authority.
Heuristic A local-file or process inference that is useful but not provider-authoritative.
Unavailable No sufficiently reliable current source exists.

The evidence record includes a machine-readable reason, observation and status-since timestamps, connection generation, consecutive matching count, and bounded sample history. observed_at_ms is the time of the newest evidence sample; its displayed freshness is the age of that observation. status_since_ms is when the current status began. connection_generation identifies a protocol connection generation; zero is used for hook and other non-protocol evidence and is displayed as . Consecutive matching counts samples with the same status, authority, and connection generation. --once prints the current evidence plus the latest five status samples. The selected-session detail shows the same line when terminal width permits; --json always includes the complete current fields and latest five content-free samples. Fields ending in _ms use Unix epoch milliseconds.

Process actions fail closed too. Unknown and Done rows, Unavailable evidence, a missing exact process identity, or a failed fresh PID/provider revalidation disables both kill and terminal jump. Kimi is stricter: even a non-Unknown heuristic row is non-actionable; its process actions require Provider authority. The first x records an exact-session confirmation and a matching second press within two seconds performs the kill. A Grok confirmation reports how many logical sessions share the target PID.

Codex Done is transition-bound. This collector instance must first observe an exact live PID/start ↔ supported-version rollout-tree binding, then observe that same process incarnation become gone. It anchors the 30-second window at that transition and retains a bounded, content-free, non-actionable in-memory tombstone through the exact boundary, even if the source state later disappears. A temporarily unavailable hook-state scan may preserve an existing tombstone but cannot create one; a fresh collector that first sees an already-gone process, or sees only a reused numeric PID, cannot fabricate Done. Other providers can disappear immediately after verified exit. Historical Codex rollouts never create PID-zero Done rows.

Claude Code

Claude discovery maps live processes to local config roots and transcripts. Recognized native registry states and durable transcript, tool, and subagent lifecycle can provide Provider evidence; activity inferred only from descendant processes is Heuristic. An unorderable native/transcript disagreement, or incomplete subagent lifecycle that would otherwise look idle, fails closed to Unknown. Account quota requires the Claude setup hook.

Quota values older than ten minutes remain visible but are dimmed and omit their reset countdown. The panel has one Claude column: if several Claude roots contain quota files, the first discovered value is used, with ~/.claude checked before the environment and additional roots.

Codex CLI

Codex combines the content-free events from Codex Hook Integration with local rollout data. Hooks establish lifecycle edges; rollouts supply session identity, project/model metadata, tokens, context, quota, summaries, and subagent relationships. Rollout ordering, mtime, token activity, CPU use, child activity, and incomplete tool records never establish live status by themselves.

Codex 0.146.0 exposes no thread/PID/generation-bound attestation of the effective hook engine after profile, project/config-lock, managed/cloud, command-line, per-thread, and live-reload layers are applied. Base trust, enablement, bundle integrity, individual hook events, and rollout correlation therefore cannot prove complete live coverage. abtop retains the bounded lifecycle candidates for audit and exit correlation, but production live Codex rows are always non-actionable Unknown / Unavailable; they never promote to Thinking, Executing, or Idle.

The independent exit proof still requires exact process-incarnation, session, configuration, and event correlation. The matched process-owned root rollout must report exact cli_version = "0.146.0", and every discovered descendant rollout must report that same version. Missing, different, child-only, or descendant-mismatched version metadata cannot seed exit proof. abtop applies this deliberately strict matrix:

Evidence Codex status
A previously observed exact live PID/start ↔ supported-version rollout-tree binding, followed by that same process incarnation changing from live to gone Done / Heuristic for 30 seconds
Any otherwise complete lifecycle shape that would suggest root model work, child model work, or turn completion Unknown / Unavailable; effective live hook coverage is unattested
A root PreToolUse/open rollout tool, any child with an open tool, PermissionRequest, or a request_user_input candidate Unknown / Unavailable; Codex may be executing or waiting for approval
Any SessionStart, including startup, resume, clear, and compact Generation evidence only; never sufficient for Idle
Rollout stream_error/error, failed task_complete, an unparseable open descriptor, or a nonterminal extra root tree Unknown / Unavailable; invalid rollout lifecycle cannot seed new exit proof
A child PreToolUse/open tool or any direct-child active/terminal/provisional mismatch Unknown / Unavailable; incomplete child lifecycle never proves live work or rest
Missing/different root or descendant cli_version; delayed, aborted, stale, duplicate, mismatched, or unsupported active/non-direct child lifecycle; missing/out-of-order hooks; uncovered or hosted tools; a relevant process descendant when root inactivity is required; malformed/stale state; configuration drift; or ambiguous ownership Unknown / Unavailable

Codex queues startup, resume, and clear SessionStart hooks into the next turn, immediately before UserPromptSubmit; those sources reset to a clean generation. A compact SessionStart follows PostCompact inside the current turn and preserves active work. Every source proves a lifecycle boundary, not the absence of work, and none can become Idle on its own. A newly opened empty composer may emit no hook evidence and remains Unknown.

Stop and SubagentStop are provisional candidates: another hook may block a stop, and the same root or child can continue in the same turn. Later matching activity reopens that actor. A provisional child stop closes only when the exact child rollout later reaches task_complete; continued child model work remains an internal lifecycle candidate only. The public live row stays Unknown in every case. Neither SessionStart nor Stop alone proves Idle.

Codex 0.146.0 does not expose enough prompt-display and resolution lifecycle to distinguish approval/question waits safely. Therefore those states are intentionally Unknown, never guessed as Wait, Exec, or Idle: observing a PermissionRequest or question candidate does not prove when the displayed interaction is resolved. Hook data also does not produce live Error or RateLimited; Codex rate-limit records remain quota metadata only. A root open tool also remains Unknown: Codex can run PreToolUse before a separately configurable PermissionRequest, so an open hook/rollout call does not prove that execution has begun. abtop never substitutes elapsed time, low CPU, or file mtime for a missing event.

Codex uses one root session_id for the root and every descendant hook. A child agent_id identifies subagent lifecycle within that shared root; abtop folds those records into one root state and never treats agent_id as a separate Codex session.

Before abtop starts, the POSIX launcher first uses mktemp to exclusively create an empty mode-0600 marker named launch-<shell-pid>-pending.<16-alphanumeric-nonce> in the embedded private fault directory. Only if that unique allocation fails does it try the 16 fixed no-clobber launch-<slot>-abtopv1.pending fallback names; exhaustion leaves the persistent overflow.json sentinel. The helper anchors the directory, adopts only the exact marker/inode, and enriches it with bounded content-free identity plus a fresh random 128-bit per-adoption commit ID before attestation, ancestor resolution, parsing, and folding. A missing or rejected token also attempts an independent hook-<id>.json marker. A successful fold records both the marker basename and commit ID in state before removing that same marker, closing the fold/delete crash window. Valid commit proofs survive clean startup, resume, and clear boundaries; a reused fixed fallback basename therefore cannot impersonate another invocation. Legacy basename-only proofs fail closed. A timeout, crash, malformed input, or helper that never starts therefore leaves evidence that poisons affected generations to Unknown instead of preserving stale work. Fault artifacts are bounded. Before generation state can be deleted, the writer persists its first GC-side confirmation that the exact process incarnation is gone. That maintenance observation does not authorize Done; it preserves an observation opportunity for the collector. Deletion requires a later writer pass strictly more than 30 seconds afterward plus a fresh exact-incarnation gone check. Capacity pressure starts this sequence only after a terminal generation is at least 30 seconds old or a crashed nonterminal generation is strictly older than 24 hours; normal cleanup runs on a later SessionEnd and requires the strict 24-hour gate for either. Once the collector has independently observed the required supported live-to-gone transition, its bounded, content-free, non-actionable in-memory tombstone preserves the 30-second Done row even if generation state disappears. After draining its payload, every later ingest may also reclaim stale state/fault temporary files, malformed or abandoned fixed-slot markers, and ordinary fault markers only when they are strictly older than 24 hours, the complete validated state snapshot is unchanged across out-of-lock process probes, and every affected process incarnation is confirmed gone. Collector reads never delete artifacts, overflow.json remains permanent and monotonic, and a clean SessionStart does not delete failure evidence.

JSON and detail views make the distinction auditable with content-free reasons such as HookToolOpen, HookSubagentActive, HookTurnOpen, HookTurnComplete, HookInteractionResolutionUnavailable, HookEventGap, HookConfigChanged, HookStateMalformed, and HookIntegrationUnverified. Hook evidence always has connection_generation = 0.

The helper binds each hook event to the nearest eligible native Codex ancestor and its exact process start identity. Shared daemon hooks, app-server/MCP/Desktop/remote-control hosts, PID ambiguity, and session/action ownership ambiguity fail closed. An unknown or inactionable row cannot be killed or terminal-jumped. Codex without the plugin remains discoverable for rollout metrics but has Unknown live status. When plain Codex uses a local or remote shared app-server daemon, its hooks run below that shared host instead of the client TUI, so abtop cannot bind them to the client PID and deliberately reports Unknown.

Windows uses that unmanaged behavior too: rollout and process metadata remain available, but secure native-hook state is currently macOS/Linux-only and lifecycle evidence stays Unknown / Unavailable.

OpenCode

OpenCode reads the local SQLite database at ${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db; on Windows it also probes %LOCALAPPDATA%\opencode and %APPDATA%\opencode. It requires a sqlite3 CLI on PATH that supports both -readonly and -json. Discovery considers the 20 most recently updated database sessions. An explicit --session/-s process argument or a unique one-process/one-row cwd group can confirm lifecycle ownership; ambiguous same-cwd groups become Unknown. Process kill and terminal jump remain disabled because OpenCode has no durable actionable PID/session registry.

Persisted pending/running question and tool rows are not authoritative current lifecycle: SQLite may expose them before execution or retain them after memory state has moved on. abtop therefore never promotes those rows to Wait or Exec. A fresh incomplete assistant record can provide heuristic Think, a completed assistant record heuristic Idle, and a current failure heuristic Error. Live permission waits exist only in process memory and are not observable from the database. The displayed current task is therefore a generic status label rather than a persisted tool name. Context percentage uses an estimated 200,000-token window, or 1,000,000 when the model name contains [1m].

Grok

Grok reads active_sessions.json and per-session summary.json, signals.json, updates.jsonl, optional events.jsonl, and plan_mode.json under ${GROK_HOME:-~/.grok}. Permission requests, structured questions, and plan approvals become Wait when their unresolved local lifecycle records are present. Grok can also emit lifecycle RateLimited, even though it exposes no account-level quota gauge.

One Grok process can own multiple registered sessions. abtop shows every logical session, attributes memory, children, and ports only once, and warns that killing the shared PID stops all of them. Positive lifecycle signals remain usable, but a quiescent row cannot be proven individually idle while the PID is shared, so provider Idle is downgraded to Unknown / OwnershipUnconfirmed. Headless sessions must be registered, for example with GROK_TRACK_HEADLESS; abtop does not guess them from cwd alone.

Kimi Code

Kimi support targets the current Kimi Code CLI and its persisted wire protocol 1.4. It reads session_index.jsonl, per-session state.json, and agent wire.jsonl under ${KIMI_CODE_HOME:-~/.kimi-code}. Unsupported, malformed, incomplete, or stale wire state fails closed to Unknown. Retired MoonshotAI/kimi-cli data under ~/.kimi is not scanned.

Every unresolved AskUserQuestion, whether foreground or background, and every validated running question task, including detached tasks, becomes Wait until an exact resolution, cancellation, tool completion, or terminal task snapshot clears it. Wire protocol 1.4 does not persist ordinary tool-approval prompts, so those remain Exec rather than being guessed from elapsed time or inactivity. A long-running tool without an explicit interaction record likewise remains Exec.

Kimi has no authoritative PID/session registry and can rewrite its process title to bare kimi-code. An explicit visible session association can provide Provider ownership; cwd plus post-start activity can provide useful heuristic display status but never authorizes kill or jump. Idle old resumes, ambiguous same-root/cwd groups, and bare-title host ambiguity remain Unknown and non-actionable. Visible plugin-runner, ACP, web, and server host modes are excluded instead of shown as sessions.

For custom Grok or Kimi homes, launch abtop with the same GROK_HOME or KIMI_CODE_HOME environment as the agent. abtop also attempts a platform-specific read of candidate process environments, but operating-system permissions can prevent that fallback. Grok and Kimi context percentages appear only when their signals or model configuration provide a reliable window. The account-quota panel remains limited to Claude and Codex.

Themes

12 built-in themes, including 4 colorblind-friendly options (high-contrast, protanopia, deuteranopia, tritanopia). Press t to cycle and persist a theme, or use --theme <name> for a launch-only override. The config overlay can also change and persist the theme.

btop (default) dracula catppuccin
btop dracula catppuccin
tokyo-night gruvbox nord
tokyo-night gruvbox nord

Colorblind-friendly themes:

high-contrast protanopia
high-contrast protanopia
deuteranopia tritanopia
deuteranopia tritanopia

Light themes (light — Solarized cream, white — GitHub-style pure white) for bright terminals:

light white
light white

Configuration

abtop uses the platform config directory returned by the operating system:

Platform Config file
Linux ${XDG_CONFIG_HOME:-~/.config}/abtop/config.toml
macOS ~/Library/Application Support/abtop/config.toml
Windows %APPDATA%\abtop\config.toml

Configuration is loaded at launch. Theme and panel-visibility changes made in the TUI are written back immediately; unrelated and unknown lines are preserved. The M MCP-session suppression toggle is runtime-only and is not stored.

Supported keys are:

theme = "btop"

# Hide specific agent CLIs from the TUI (case-insensitive).
# Supported IDs: claude, codex, opencode, grok, kimi.
hidden_agents = []

# Additional Claude Code profile roots to scan.
# abtop also auto-discovers ~/.claude and ~/.claude-* roots that contain
# both sessions/ and projects/.
claude_config_dirs = []

# Panel visibility. Every key defaults to true.
show_context = true
show_quota = true
show_tokens = true
show_projects = true
show_ports = true
show_sessions = true
show_mcp = true

For example, use hidden_agents = ["codex", "grok"] to hide those providers or claude_config_dirs = ["~/.claude-personal", "~/.claude-work-team"] to add profile roots.

Codex hook integration is intentionally separate from this platform config. It lives under the active CODEX_HOME and is managed with --setup-codex, --uninstall-codex, and --codex-integration-status.

Key Bindings

Key Action
/, k/j Select the previous or next visible session.
Enter Jump to the selected actionable session terminal after fresh process validation.
/ Enter session-filter input mode. Type to filter, use Backspace to delete, Enter to keep the filter and leave input mode, or Esc to clear it.
x Request a kill confirmation; press x again within two seconds to kill the same freshly validated session/process incarnation.
X Freshly rescan and validate, then kill all processes still owning displayed orphan ports.
r Force refresh. Disabled in demo mode.
q Quit, or close the config overlay while it is open.
t Cycle and persist the theme.
T Toggle the subagent tree view.
l / L Toggle the selected-session timeline.
f / F Toggle the selected-session file audit.
17 Toggle and persist Context, Quota, Tokens, Projects, Ports, Sessions, or MCP visibility.
M Toggle suppression of mcp-server-owned rollouts in the Sessions panel for this run.
c Open/close configuration. Inside it, select with / or k/j, change with Enter/Space, and close with Esc, q, or c.
v Open/close the view menu.
Esc Close the view menu, or clear a retained nonempty session filter outside filter-input mode.
? Show keybinding help; any key closes it.

In the narrow tabbed layout:

Key Action
/, Shift+Tab/Tab Cycle visible Work, Usage, and System tabs.
w, u, s Select the Work, Usage, or System tab directly.
+ / = Maximize the active section.
- Restore the split sections.

In demo mode, the keyboard actions r, x, X, and Enter are disabled. Do not treat --demo --mouse as a destructive-action safety boundary: the mouse orphan-port cleanup target is still active.

Library / JSON snapshot

abtop is also a library crate, so local tools can reuse its collection and state APIs in-process and serialize the same state the TUI renders.

abtop --json    # one-shot JSON snapshot for scripts

For long-running consumers, build an App, refresh it with App::tick_no_summaries() (which never spawns claude --print, so it doesn't touch your Claude quota), and call App::to_snapshot(interval_ms) to get a JSON-serializable Snapshot:

use abtop::app::App;
use abtop::{config, theme::Theme};

let cfg = config::load_config();
let mut app = App::new_with_config_and_claude_dirs(
    Theme::default(), &cfg.hidden_agents, cfg.panels, &cfg.claude_config_dirs,
);
app.tick_no_summaries();
let json = serde_json::to_string(&app.to_snapshot(2_000)).unwrap();

App is not Send (it owns the collectors), so keep it on one thread and pass the serialized JSON elsewhere. abtop-web-ui is a reference consumer: a local-first web dashboard built on exactly this API.

Privacy

abtop collectors read local files and local process/open-file metadata, including the Claude, Codex, OpenCode, Grok, and Kimi Code session stores. They need no provider API keys and do not send collected records to provider APIs. abtop starts no Codex relay or daemon, attaches to no Codex daemon, and uses no provider API or transport credential. Native Codex can independently choose a shared local or remote app-server daemon; those sessions deliberately remain Unknown. Codex otherwise continues to run directly with the caller's executable, arguments, standard streams, and environment; abtop does not inspect or persist provider credentials.

The Codex hook helper uses a 4 MiB streaming JSON parser and never materializes the raw payload as one buffer. It accepts at most 256 root fields, 512 bytes per lifecycle ID, 16 KiB of cwd, and the other small allowlisted lifecycle scalars; every unrecognized or sensitive value is skipped directly by the deserializer. It attempts to drain to EOF even after malformed JSON, subject to the hard stream cap. Prompt text, tool input and output, the last assistant message, raw commands and arguments, environment and authentication data, transcript paths, and arbitrary provider text never enter state. Private state contains only schema/helper/install identities, session/turn/tool/subagent identifiers, canonical event and tool classes, cwd when needed for correlation, timestamps, exact PID/start incarnations, lifecycle faults/open sets, and at most 128 content-free samples.

Codex plugin data directories use mode 0700 and files use mode 0600 on Unix. State writes reject symlinks and ownership mismatches, lock updates, and atomically replace a same-directory file. Malformed input, event gaps, changed hook/helper identities, unsafe paths, stale state, or ambiguous native-process ancestry become sticky Unknown evidence. The launch marker is created before the helper starts, adopted and enriched before validation, and removed only after its basename and fresh random 128-bit per-adoption commit ID are durably committed by a successful fold. The POSIX launcher normally allocates a unique launch-<shell-pid>-pending.<16-alphanumeric-nonce> marker; 16 no-clobber fixed names are a bounded fallback only. Valid commit proofs survive clean generation boundaries, so even reuse of a fallback basename cannot hide a different failed invocation. A helper timeout, crash, rejected record, or failed launch therefore cannot leave stale positive evidence. Missing-token fallback markers, bounded ordinary faults, and persistent overflow prevent unbounded artifacts while preserving fail-closed evidence. Before deleting generation state, a writer persists its first GC-side exact-incarnation gone confirmation; that timestamp is only a deletion grace anchor and never authorizes Done. Removal requires a later pass strictly more than 30 seconds afterward and a fresh exact-incarnation gone check. Capacity pressure starts that sequence only after a terminal generation is at least 30 seconds old or a crashed nonterminal generation is strictly older than 24 hours; normal cleanup runs on a later SessionEnd and requires the strict 24-hour gate for either. The collector separately requires an already observed exact supported live-to-gone transition and retains a bounded, content-free, non-actionable 30-second in-memory tombstone, so proven Done survives later source-state disappearance. A collector whose first observation is already gone, numeric-PID reuse without exact incarnation continuity, or an unavailable scan cannot create that proof. Once its payload is drained, each later ingest can reclaim strictly older-than-24-hour temporary files, malformed or abandoned fixed-slot markers, and ordinary faults only from a complete validated state snapshot that remains unchanged across out-of-lock process-death probes, with every affected incarnation confirmed gone. Collector reads never remove artifacts and overflow.json remains permanent and monotonic. These guarantees are a content boundary, not a claim that lifecycle metadata such as cwd and stable IDs is nonsensitive.

abtop --setup-codex can create the absolute CODEX_HOME when it is absent, then writes the isolated marketplace/plugin source bundle, the retained private $CODEX_HOME/.abtop-codex-plugin.lock, the content-free installation.json attestation and states/faults tree under plugin data, Codex's installed plugin cache and native marketplace/plugin registration, and the content-free stable migration lock described above on macOS/Linux. Generated launchers contain the exact absolute abtop executable and private plugin-data paths, but no provider content. It never modifies global hooks.json, notify, OpenTelemetry, unrelated plugins, Claude configuration, PATH, or the Codex executable. During migration it may remove exact legacy abtop wrapper marker blocks from shell startup files; it does not remove arbitrary aliases or functions. Uninstall uses the same exact-marker rule, unconditionally removes and then verifies absence of the reserved plugin ID, verifies marketplace absence before deleting the owned source tree, and preserves both the retained root setup lock and the content-free plugin-data tree and attestation. It removes a legacy source-local abtop/.setup.lock only as part of verified owned-source cleanup. The helper identity in the declared hook command deliberately retriggers Codex trust review after meaningful updates.

Codex hook setup and secure state collection are currently available only on macOS and Linux. Windows setup fails before mutation; ordinary Windows Codex collection remains read-only and reports lifecycle status as Unknown.

abtop --setup writes abtop-statusline.sh inside the active Claude config root and registers the script in that root's settings.json. When StatusLine input contains rate_limits, the hook extracts only quota percentages and reset timestamps through local python3, adds the fixed source claude and current local update time, and writes abtop-rate-limits.json. It persists no prompt or message content. abtop does not add a network request to that hook.

abtop uses the operating system's cache directory:

Platform abtop cache directory
Linux ${XDG_CACHE_HOME:-~/.cache}/abtop/
macOS ~/Library/Caches/abtop/
Windows %LOCALAPPDATA%\abtop\

The directory can contain summaries.json and codex-rate-limits.json. The latter stores only the last locally observed Codex account quota windows and timestamps. Codex hook lifecycle state is kept separately at ${CODEX_HOME:-~/.codex}/plugins/data/abtop-abtop-local; it contains only the bounded content-free fields described above.

The normal TUI and --once generate missing session titles by passing up to 200 characters from the first user text and up to 200 characters from the first assistant text to the locally installed claude --print. That CLI may call Anthropic. The summary cache's summaries.json stores only the derived title or sanitized 80-character fallback for each session, not the full source records; those cached values can still contain sensitive project context. App::tick_no_summaries() does not launch summary jobs or pass excerpts to claude --print; neither does abtop --json.

The TUI and --once do not deliberately render full local files or raw tool results, but they do show safe path previews, bounded tool-argument and child-command previews, and bounded session summaries. The selected-session detail can also render the collected initial_prompt field and a bounded, redacted tail of recent user and assistant chat messages. Prompts or chat can themselves contain pasted file content. The JSON snapshot includes richer local dashboard data such as summary, bounded/redacted chat_messages, working directories, config roots, tool-call previews, child process commands, token counts, and port metadata. All of these outputs and caches can reveal project context; treat them as private data and do not expose them through shared logs or a network without your own access controls.

Acknowledgements

Huge thanks to @tbouquet for driving much of abtop's recent shape — themes, config overlay and panel toggles, session filtering, subagent tree view, the context window gauge with compaction detection, plus a steady stream of fixes and security hardening along the way.

License

MIT

About

Like htop, but for GitHub Actions.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages