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.
- 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.
- Install
- Quick Start
- Command Reference
- Codex Hook Integration
- Interface
- Supported Agents
- Status and Evidence
- Themes
- Configuration
- Key Bindings
- Library / JSON snapshot
- Privacy
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.
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/graykode/abtop/releases/latest/download/abtop-installer.sh | shBuilding or installing from source requires Rust 1.88 or newer.
cargo install abtopNative 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.
Pre-built binaries for all platforms are available on the GitHub Releases page.
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.
Launch the monitor immediately after installation:
abtopNo setup is required for ordinary local session discovery. Two optional setup commands enable data that providers do not otherwise expose reliably.
abtop --setupThis 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.
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-codexSetup 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 --yoloSetup 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 | 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.
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.
The numbered panels can be toggled with 1–7; 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.
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 paneThe 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.
✅ 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 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 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 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 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 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 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.
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 |
|---|---|---|
![]() |
![]() |
![]() |
| tokyo-night | gruvbox | nord |
|---|---|---|
![]() |
![]() |
![]() |
Colorblind-friendly themes:
| high-contrast | protanopia |
|---|---|
![]() |
![]() |
| deuteranopia | tritanopia |
|---|---|
![]() |
![]() |
Light themes (light — Solarized cream, white — GitHub-style pure white) for bright terminals:
| light | white |
|---|---|
![]() |
![]() |
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 = trueFor 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 | 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. |
1–7 |
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.
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 scriptsFor 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.
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.
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.
MIT












