A small macOS app that shows which Claude Code and Codex sessions — and the processes and sub-agents they spawn — are using your CPU and memory.
When you run many agent sessions in parallel, Activity Monitor shows dozens of claude, node, vitest, tsc
and npm processes with no hint of which session started them. Agent Meter groups them by session and labels each
group with the session's name.
- Claude Code and Codex sessions in one list, tagged by source and labeled with the session name
- CPU and memory totals per session, expandable to every process with its full command line
- Finds processes left running by sessions that have already ended, such as dev servers started in the background
- Codex sub-agents are nested under their parent thread
- End a session, its leftover processes or a single process, after a confirmation
- Clean Up in one click: ends the processes of sessions that are over, keeping shared services such as Colima
- Samples on demand: press Refresh (⌘R); nothing runs in the background between refreshes
- A Disk tab shows what each session leaves on disk (scratch files, worktrees, dependencies) as a ring chart you can click through, marks what can be deleted, and deletes it after a confirmation. Conversations are never deleted
- macOS 14 or later
- Xcode 26 or later to build (the app icon is an Icon Composer document compiled with
actool)
./build.sh # builds build/Agent Meter.app
./build.sh install # also copies it to ~/ApplicationsTo print the same data as plain text: swift build -c release && .build/release/AgentMeter --dump
(processes) or --dump-disk (disk usage).
- CPU: two samples 1.5 seconds apart, computed from accumulated CPU time. 100% means one core fully busy,
the same scale as
topand Activity Monitor. - Memory: physical footprint, the same figure as Activity Monitor's Memory column. It includes compressed and swapped-out memory, so the total across processes can exceed physical RAM.
- Only your own processes are visible; processes owned by root or system accounts cannot be read.
The first matching rule wins:
- The process is a Claude Code session process, registered in
~/.claude/sessions/<pid>.json. The session name comes from this file. - The process environment contains
CLAUDE_CODE_SESSION_IDorCODEX_THREAD_ID. Claude Code and Codex set these for the commands they run, so processes that outlived their parent (for example a dev server started in the background) are still attributed to the session that started them. For sessions that have ended, the name is read from the session transcript. - The Claude desktop app's
disclaimerlauncher belongs to the session it launched. - Otherwise, walk up the parent process chain.
- A detached process (parent 1) whose working directory is a Claude Code worktree, such as a supervisor that was
started with a cleared environment (
env -i): the running session that works in that worktree, or else a group named after the worktree. - Remaining processes of the Claude desktop app and the Codex / ChatGPT app are shown as the apps themselves; everything else is listed as Not attributed to any session.
A conversation that goes on under a new session ID (resumed, or continued after the old session ran out of room) is a
new session in Claude Code's registry. Agent Meter reads --resume=<id> from the running session's arguments and
treats the earlier session as the same conversation: its leftover processes, and in the Disk tab its transcript,
scratch files and worktrees, are shown with the session that continues it, not as a second, ended one. Its files
are not offered for deletion while the conversation is running, because the conversation still refers to them.
Chrome and apps built on Chromium (Lark, Claude, ChatGPT) run many helper processes. Those are labelled by what they are for, read from their flags: Page renderer, Extension renderer, GPU, Network service, Storage service and so on. Which page a renderer shows is not in its command line, so tabs cannot be told apart from outside.
Codex thread names and the parent of each sub-agent come from ~/.codex/state_5.sqlite. Sub-agents have no title
of their own, so they are shown under the task name their parent gave them (for example review billing logic), with the generated nickname in the details.
Only the two session ID variables are taken from a process environment. Every other variable, including tokens, is skipped and never stored or displayed. Nothing leaves your machine.
Select a row and press End… (⌘⌫), or right-click it:
| Row | What is ended |
|---|---|
| Claude Code session | The session process and every process attributed to it, including background services. The conversation can be resumed later: reopen it in the desktop app, or claude --resume |
| Ended session's leftovers | The processes it left running |
| Codex thread | The processes it and its sub-agents started. The thread itself lives in the Codex app and is not affected |
| Single process | Just that process |
| Claude desktop app, Codex / ChatGPT app | Not offered |
Clean Up ends, without asking, every process that meets both conditions:
- Its session is over:
- a Claude Code session whose session process has exited, or
- a Claude Code CLI session that has been idle for 6 hours. The whole session is ended, session process included;
resume it with
claude --resume. Sessions started with channels (--channels,--dangerously-load-development-channels) are message-driven bots that sit idle by design and are never ended. Desktop sessions are not ended this way, or - a Codex thread that is archived in the Codex app, or has had no activity for 24 hours. Codex threads run inside the app server and have no process of their own, so inactivity is the signal.
- It is not a shared service and does not run under one. A session sometimes happens to start a service that other
sessions and apps rely on, such as the Colima VM (
colima,limactl), Docker,ssh-agent,gpg-agentor theadbserver; these and their child processes are kept.
The button shows how many processes qualify, and the list marks them with a sparkle; kept shared services in a finished session show a lock. Clean Up takes a fresh sample before acting, so a session resumed since the last refresh keeps its processes, and a session that became busy again is left alone.
Agent Meter sends SIGTERM, waits up to 3 seconds, then sends SIGKILL to whatever is still running, and
refreshes. Before signaling, it checks each process's start time, so a PID that was reused since the last refresh
is left alone. It never ends itself.
The Disk tab lists every Claude Code session and Codex thread that occupies more than its conversation, and splits each into parts. Press Scan Disk (⌘R): it reads every file under the folders below, which takes 30 to 60 seconds, and runs only when you ask. Scanning changes nothing.
The chart and the list fill in while the scan runs, so there is something to look at after a couple of seconds; collecting and deleting wait until it is done. The strip between the chart and the list can be dragged to give the list more or less room.
The chart works like a disk analyzer. Its slices glide between views instead of jumping: opening a slice makes it expand into the middle, going back lets the middle grow out into a ring again, slices swell as a scan fills in, and the one under the pointer lifts a little. (With Reduce motion turned on in System Settings, they jump.) The middle names what you are looking at and its size; the rings around it show what is inside, from the inside out: sessions, their parts, the folders in each part, and folders below those.
- Bright slices can be deleted, dim ones are kept. The same colours mark the dots in the list on the right.
- Hover a slice or a row to see it named in the middle; the other side lights up too.
- Click a slice or a row to look inside it, or the middle to go back up. The bar at the top shows where you are, each step can be clicked, and ‹ › (⌘[ and ⌘]) go back and forward. Folders deeper than the scan recorded are measured when you open them.
- Drag a slice or a row into the tray at the bottom, or right-click and choose Add to Collection, to collect it; Add all collects everything that can be deleted, and never includes git-ignored files that are not disposable; those can only be collected on their own, and the tray marks them with a warning. The tray shows what each collected item would free.
- Delete in the tray (⌘⌫) asks for confirmation first. Only sessions and whole parts can be collected, not the folders inside them.
| Part | Where it lives | Counted as deletable |
|---|---|---|
| Scratch files | /tmp/claude-<uid>/<project>/<session id>/ |
Always, once the session is not running |
| Dependencies and caches | Git-ignored node_modules, .venv, __pycache__, dist, build, target, .terraform, dbt_packages, logs and local tool settings such as .claude/ or .user.yml inside a worktree |
Always, once the session is not running |
| Worktree files | <repo>/.claude/worktrees/<name> (Claude Code, including those sub-agents create) or ~/.codex/worktrees/<hash>/<repo> (Codex) |
Only if git reports no uncommitted changes, every commit is on some remote branch, and the worktree holds no git-ignored files besides the disposable ones above, since those would be lost with it |
| Ignored files | Any other git-ignored file or folder in a worktree, such as notes or copies of code kept for analysis | Not by default. They exist only on this Mac, so it is your call: collect the part yourself, or right-click a part or a whole session and choose Delete Ignored Files…, which deletes all the ignored files of that session's worktrees at once. The confirmation names what is in it. Greyed out, with the reason, while the session is running or a process is working in the worktree |
| Conversation history | ~/.claude/projects/.../<id>.jsonl and its folder, ~/.codex/sessions/.../rollout-*.jsonl |
Never: deleting it loses the ability to resume |
A part is held back, with the reason shown, while its session is running (a Codex thread counts as running if it
was active in the last hour) or while any process has its working directory inside it. Sizes are the space
allocated on disk, as du reports; hard-linked files count once.
A worktree shared by several sessions (a resumed conversation, or the sub-agents of a Codex thread) is shown under the one that was active last.
Some worktrees are nobody's working directory: Codex agents create them by hand (git worktree add ~/.codex/worktrees/<name>/<repo>), and Claude Code sessions sometimes make one for work they run from elsewhere.
Those are matched to the session that made them: among the sessions that were running when the directory was
created, the one whose conversation mentions its path first (a session that only listed the worktrees later does not
count). A Claude Code session's sub-agents are included in that search. The process list does the same to say which
session made a worktree that holds detached processes. Worktrees that still cannot be matched are listed under
their directory name with No session found.
Names can be selected in the panel's header, and Copy Name is in the right-click menu of every slice and row.
A dialog lists what will be removed and its size. Deleting is permanent and never touches conversations.
- Scratch files and dependency directories are deleted from disk.
- A worktree is removed with
git worktree remove; its branch and commits stay.
The scan can be minutes old, so each part is checked again right before it is deleted and skipped, with the reason
shown, if it is no longer safe: the session is running again, a process started in it, the worktree gained uncommitted
changes or unpushed commits, or a directory is no longer ignored by git. Only paths of the expected shapes are
deleted (/tmp/claude-<uid>/<project>/<session id>, <repo>/.claude/worktrees/<name>, ~/.codex/worktrees/<hash>/<repo>),
and never a symbolic link.
-
Disk usage: a branch that was squash-merged and deleted on the remote still has commits no remote branch contains, so its worktree is reported as having unpushed commits and is not counted as deletable.
-
Disk usage: space used by Codex outside the per-thread files, such as
~/.codex/thread_history_1.sqlite, is not attributed to any thread. -
macOS does not expose the environment of platform binaries (
/bin,/usr/bin, such assleeporbash). These are attributed through their parent while it is alive; once orphaned, they fall into Not attributed. -
Claude Code sub-agents run inside the session process, so their usage is counted on the session.
-
Session names rely on internal files of Claude Code and Codex (
~/.claude/sessions,~/.codex/state_5.sqlite), which may change between versions.
Resources/AppIcon.icon is an Icon Composer document: a gauge split into an orange (Claude) and a blue (Codex) arc.
Open it with Icon Composer to edit. build.sh compiles it into the app bundle.
Not affiliated with Anthropic or OpenAI. Claude and Codex are trademarks of their respective owners.