Skip to main content

agent-ps

A process table for coding agent sessions, the way ps would look if it knew what a session was.

License: MIT Python 3.8+ macOS and Linux No dependencies 7 agents

agent-ps listing sessions from claude, hermes, codex, opencode, pi, commandcode and copilot side by side, each with its model, uptime, idle time, cpu, memory, disk and working directory, with two hermes background helpers at the bottom

ps aux | grep claude gives you PIDs. It will not tell you which one is the session you are talking to, what model it is spending on, whether it has been idle for three days, or which rows are background daemons that outlived the terminal that started them. It also misses the other six agents entirely.

agent-ps lists every session with its agent, model, working directory, uptime, idle time and disk footprint, then stops one process tree, every background helper, or the lot.

One file, no dependencies, reads local files only.

Install

One command

curl -fsSL https://raw.githubusercontent.com/mkhuda/agent-ps/main/install.sh | sh

Takes the latest release, checks it against the checksum published beside it, makes sure it runs, and puts the single file in ~/.local/bin. Set BIN_DIR to install elsewhere, or AGENT_PS_REF=v0.1.0 to pin a version.

With a package runner

uvx agent-ps                  # uv
pipx install agent-ps         # pipx
pip install agent-ps          # pip

npx @mkhuda/agent-ps          # npm
pnpm dlx @mkhuda/agent-ps     # pnpm
bunx @mkhuda/agent-ps         # bun

The Python packages install the program itself. The npm one carries the same executable and finds an interpreter for it, which is why it is scoped: the plain name is too close to an existing package. Either way the command is agent-ps.

Just the file

If you would rather not pipe a script into a shell, the executable is the whole program:

mkdir -p ~/.local/bin
curl -fsSL -o ~/.local/bin/agent-ps \
  https://github.com/mkhuda/agent-ps/releases/latest/download/agent-ps
chmod +x ~/.local/bin/agent-ps

Every release publishes a SHA256SUMS next to it.

From a clone

git clone https://github.com/mkhuda/agent-ps && cd agent-ps
./install.sh

Builds from the tree rather than downloading, so you install what you are looking at.

What it needs, and how to remove it

Python 3.8 or later and nothing from PyPI. Tested on 3.8, 3.9, 3.10 and 3.14. macOS and Linux; Windows is out because curses is not in its standard library. It shells out to ps, and on macOS to lsof, which is how a process is matched to a session everywhere except Claude Code.

rm -f ~/.local/bin/agent-ps

That is the whole uninstall. Nothing is written outside that directory, and agent-ps only ever reads the agents' own files.

Agents

Each agent keeps its own colour in the table, and the same colours label the legend above the keys.

Agent Sessions in Paired by Tokens Reopened with
Claude Code yellow JSONL the agent itself no claude --resume
Pi cyan JSONL directory no pi --session
CommandCode magenta JSONL directory no cmd --resume
Codex CLI green JSONL directory no codex resume
OpenCode blue SQLite directory yes opencode --session
Hermes red SQLite directory yes hermes --resume
GitHub Copilot white VS Code storage no process yes in the editor

Only Claude Code records which process is running which session, so every other pairing is matched on working directory and shown as a guess. OpenCode, Hermes and Copilot count tokens and cost, which the detail panel shows. Agents you have not installed are skipped, not reported as missing.

Copilot is the exception to everything. It runs inside the VS Code extension host, so it has no process of its own: no PID, no uptime, no CPU or memory, and nothing to stop. What it does have is the credits each turn spent, which the free tier meters and nothing else surfaces. A chat counts as open while its workspace is open in the editor.

Usage

Run without arguments for the live table:

agent-ps

It refreshes every two seconds and stays out of the way until you act on something.

Key Action
up, down move the selection
j, K down and up, since k is taken by stop
home, end jump to the first or last row
enter details for a live session, or reopen an ended one
s cycle the sort column
S reverse the direction
k stop the selected process and its children, after confirming
b stop every background helper, after confirming
y, n answer a confirmation
e show or hide ended sessions
/ filter by session, title, agent, model, directory, or PID
esc leave filter mode, or close the detail panel
space pause refreshing
r refresh now
q quit

Those keys live at the bottom of the screen, under a line naming every agent on screen in its own colour and, on the right, what the table is sorted by:

The bottom of the screen: a legend naming each agent in its own colour, the sort shown in words on the right, and the key bar beneath it

That middle line does three jobs. It is the key to the colours in the AGENT column, it says the sort order in words so the marked heading is never a guess, and it is where a note appears for a few seconds after you act on something.

Backspacing a filter down to nothing leaves filter mode, so the key bar comes back without reaching for escape.

Sorting

s cycles the sort column through agent, active, disk, cpu, mem, uptime, session and title. The sorted heading is marked in place, and the line above the keys names it in words:

PID     AGENT             SESSION         STATUS MODEL               UPTIME  ACTIVE    CPU   MEM    DISKv
31771   claude            benchmark       idle   sonnet-5            54m     54m ago   0.2%  51M    127M
-       claude            web-app         ended  sonnet-5            -       16d8h ago -     -      102M
-       claude            notes           ended  opus-5              -       2h22m ago -     -      84M

 agents  claude  codex  commandcode  copilot  hermes  opencode  pi        sorted by disk, high to low
 up/down select   enter details   k stop   b background   e hide ended   s sort   S reverse   / filter   q quit

v means descending and ^ ascending; S flips it. Numbers start at the largest, names start at A, and rows with nothing in that column go to the end either way.

Sorting covers running and ended sessions together, since "which session is the biggest" does not care whether its process is still alive. Press e to include ended sessions, then s until DISK is marked.

The detail panel

Enter on a live session opens everything known about it, including tokens and cost where the agent counts them:

 session details

       agent  hermes
     session  20260905_005254_2c9f4d
      status  idle
       model  nemotron-3.5-lightning-free
   directory  /Users/rg/projects/agent-ps
       title  halo are you hermes?
         pid  21098  (parent 17518)
      uptime  1h17m   last turn 1h15m ago
       usage  cpu 0.0%   memory 11M   disk 121K
      paired  matched by working directory, not reported
    provider  opencode-free
      tokens  in 24,608  out 242  reasoning 190
       calls  2 api, 6 messages, 0 tool calls
        cost  $0.0000 estimated
     command  /usr/bin/python3 /Users/rg/.hermes/hermes-agent/hermes

The paired line appears only when the pairing was inferred. The provider, tokens, calls and cost lines appear only for agents that record them, and are simply absent for the rest.

Enter on an ended session reopens it in a new terminal tab instead. Copilot chats live in the editor, so they have no reopen command and say so.

The advisory line

A line above the keys points out whatever is worth a look: background helpers left running, sessions untouched for a day, or ended sessions you could resume. It names the key that acts on it, and only ever shows one thing, since a wall of warnings teaches people to ignore the line.

Scripting

agent-ps list                     # print the table and exit
agent-ps list --all               # include ended sessions
agent-ps list --json              # machine readable, with idle seconds
agent-ps list --limit 100         # how many ended sessions (default 40)
agent-ps list --filter benchmark  # same match as the / key
agent-ps agents                   # which agents were found, and where
agent-ps --agent codex list       # one agent, or a comma separated list
agent-ps stop 32244               # stop one process tree
agent-ps stop 32244 --dry-run     # show what would be stopped
agent-ps stop-background          # stop daemons, warm spares, and servers
agent-ps stop-background --dry-run
agent-ps resume <session>         # a unique id prefix is enough
agent-ps resume <session> --print # print the command instead of running it
agent-ps --version

Piping works without a subcommand: with stdout not a terminal, agent-ps prints the table and exits.

What each column means

Column Meaning
PID the process, or a dash where there is none
AGENT which agent, and what sort of process when it is not a plain session
SESSION the directory the session was started in
STATUS busy, idle, ended, or a dash when nothing says
MODEL what answered the last turn, or the launcher's routing alias
UPTIME how long the process has been alive, from one ps call
ACTIVE how long since the session last wrote a turn
CPU, MEM the same ps call
DISK everything that session left on disk
DIR the working directory
TITLE the session title, or its opening prompt where the agent keeps none

UPTIME and ACTIVE often disagree, and that is the point. A process can be five days old and have answered a minute ago. UPTIME comes from the process table, ACTIVE from the modification time of the log, which is appended on every turn, so an ended session shows a dash under UPTIME and only ACTIVE says how stale it is.

Each agent gets its own colour in the AGENT column, assigned in registry order, and the same colours appear in the legend, which makes that line the key to the palette. A selected row keeps its own highlight rather than being broken up, so the cursor stays unmistakable. Terminals without colour fall back to plain text.

A PID marked with a question mark

Only Claude Code records which process is running which session, in <config dir>/sessions/<pid>.json. For every other agent the two have to be matched on working directory, and that cannot tell apart two sessions of the same agent started in the same folder.

So an inferred pairing is shown as one:

32244   claude    form-guardian   idle   opus-5        ...
9666?   codex     agent-ps        idle   gpt-5.6-luna  ...

9666? means the process is certain and the session beside it is a guess. The guess is the most recently active session in that directory, and where several processes of one agent share a directory they are paired newest with newest, so the process that started four minutes ago gets the session that has been active for four minutes rather than the one from an hour ago.

It is still a guess, so the stop confirmation names the directory and says when the pairing was inferred:

Stop 1 process(es) in ~/projects/agent-ps, session matched by directory?

Where no session matches at all, the row still appears with whatever the process itself can answer. Nothing is invented to fill the gap.

How it works

The parts that are not obvious have their own page: where each agent keeps its sessions, how busy and idle are decided per agent, which processes count as background helpers, how a shim is told apart from a real session, and what the DISK column is adding up.

Stopping behaviour

Processes are stopped depth first, children before parents, so a supervisor does not restart a worker you just killed. Each process gets SIGTERM, one second to exit, then SIGKILL if it is still there.

agent-ps never lists or stops itself, or the shell that launched it, so running it from inside an agent session is safe.

Exit status is zero when everything asked for was stopped, and one when something survived, which makes it usable in scripts.

When something is missing

Symptom Cause
An agent you use is not listed agent-ps only looks in the roots above. agent-ps agents prints what it found.
SESSION and MODEL are dashes on macOS pairing needs lsof to read a process working directory. Linux reads /proc.
A row paired to the wrong session see the question mark section above
No colour the terminal reported none, so every row falls back to plain text
A Copilot chat has no PID it never had one. Copilot runs inside VS Code.

Build

The executable is a zipapp, built from the package by the standard library:

./build.sh

That writes a single agent-ps file with no dependencies, which is what the curl install fetches. The build is reproducible: the same source always produces the same bytes, so the committed executable can be checked against the tree.

5045dee9f7c0a85a193886e0b5fcf37020a4c36f10537f36fa453d1020aff365  agent-ps

Adding an agent takes one class and one line in the registry. See CONTRIBUTING.md.

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_ps-0.2.0.tar.gz (42.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_ps-0.2.0-py3-none-any.whl (45.1 kB view details)

Uploaded Python 3

File details

Details for the file agent_ps-0.2.0.tar.gz.

File metadata

  • Download URL: agent_ps-0.2.0.tar.gz
  • Upload date:
  • Size: 42.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agent_ps-0.2.0.tar.gz
Algorithm Hash digest
SHA256 cdbf78bbf4fd6952a8b630a52e1efd86d49959c8818e45e3c4a5d8e22470adb1
MD5 41ac92f6cb7580fc0823204bb2ed875c
BLAKE2b-256 5861c741e8e36f9f3577d140177c88587865271de220c2f054150241be63398a

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_ps-0.2.0.tar.gz:

Publisher: release.yml on mkhuda/agent-ps

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agent_ps-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: agent_ps-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 45.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for agent_ps-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8a368e305455c3b1fb0de4180b22aaf36518ac38c2656c50d5cdcb358523c077
MD5 4d2b410a8c6ab2e1355ac83812f4ac80
BLAKE2b-256 c72ff9d17ab8fe1f9ae7d1bfc64c1a4aeeebd386ecc4633f2f739a1a566188b0

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_ps-0.2.0-py3-none-any.whl:

Publisher: release.yml on mkhuda/agent-ps

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

This release

0.2.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page