You're Running a Dozen Agents. Which One Is Stuck?
Once you're past one or two Claude Code sessions, you lose the thread. Five terminals, a few worktrees, an agent on the laptop and two on a server — and no single answer to "what's actually running right now, and is any of it stuck?" The IDE shows you the session you're looking at. There's no ps for the fleet.
There is, actually — you just have to read the right directory. Every session is a transcript under ~/.claude/projects/, and those transcripts carry enough metadata to reconstruct the whole picture. We wrote a 130-line tool, fleet-ps, that turns them into one screen.
What's on disk
Each project gets a directory under ~/.claude/projects/ (its name is your working dir with the slashes turned to dashes — a lossy slug). Inside are the session transcripts, one .jsonl per session. Two facts make a fleet view cheap:
- The file's mtime is the session's last activity. A
statper file — no parsing — tells you which sessions are live and which went quiet hours ago. - The transcript records its own context. Early lines carry
cwd,gitBranch, and the Claude Codeversion. So you don't have to decode the lossy slug — you read the real project path and branch straight out of the file.
That's the whole trick: stat everything (cheap), keep the recently-active ones, and read just the head (for cwd/branch) and the tail (for health) of those.
fleet-ps
$ fleet-ps
fleet-ps — 18 session(s) (active < 6h)
AGO HEALTH BRANCH PROJECT
0s ✓ ok research/8808-recover… …/ceo-workspace/deemwar-one-os-wt-research 6b59e853 · 10212KB
37s ✓ ok main …/ceo-workspace/deemwar-one-os b479053b · 4213KB
15m ✓ ok HEAD …/user/tmp 689f4ec0 · 39KB
2h ✓ ok feat/auto-demo-locale… …/deemwarworkspace/auto-demo 7d6497ba · 25176KB
2h ✓ ok feat/mobile-voice-int… …/products/mobile 45d3ce4a · 11313KB
…
That's a real run on one of our machines — eighteen sessions across a dozen projects, most-recently-active first, each with its branch, age, transcript size, and a health flag. It scans ~120 project directories in about half a second, because almost all of that is stat calls; only the recently-active handful get opened.
Three flags, that's the whole interface:
- default — sessions touched in the last 6 hours (the ones that matter right now),
--since 30— tighten the window to the last 30 minutes,--all— every session on the machine.
The health column is the point
AGO and SIZE are nice, but HEALTH is why we run it. It reads each session's tail and checks the one thing that silently bricks a Claude Code session: does the last assistant turn end in an orphaned thinking block? That's the thinking-block 400 wedge — an interrupted extended-thinking turn that gets re-sent and rejected on every continue. From inside the stuck session you can't tell what's wrong; from fleet-ps it's a red ⚠ wedged in a list, and the fix is one command away (claude-fleet rescue session fix …).
When you're babysitting one agent you'd notice it hang. When you've got a dozen, the wedged one just sits there quietly while you're looking at the other eleven. A fleet needs a fleet-level health check, and this is the cheapest one that exists: it's already in the file.
Why read the fleet, not just the session
This is the third tool we've made that starts by reading these transcripts, and the pattern is the point:
- per session — what did this run do? (turns, tools, files)
- per repo — which worktrees hold work a cleanup would delete?
- per machine — what's running, and is any of it stuck? ← this one
Each is a short script over data that's already local and plaintext. There's no agent-fleet dashboard you need to install and feed; the observability is sitting in ~/.claude/projects/, waiting for someone to stat it. As fleets get bigger — and ours runs a lot of parallel agents in production — the whole-machine view is the one you end up keeping open.
The honest caveats
gitBranch is read from the start of the transcript, so a session that switched branches mid-run shows the branch it began on — accurate to the record, occasionally stale to reality. The slug is genuinely lossy (a dir named -a-b-c could be /a/b/c or /a-b/c), which is exactly why we read cwd from the file instead of decoding it. And it's a snapshot, not a daemon — it answers "right now," so you run it when you want to know, not on a timer. The schema is undocumented, so a future version can rename a field; the reader counts unknown shapes rather than crashing on them.
The real lesson
The recurring theme across all of this: your agents' state is local, plaintext, and queryable — you do not need a SaaS to see your own fleet. A directory of JSON-lines files, a few stat calls, and the head and tail of the active ones is enough to answer the questions that actually matter when you're running many agents at once. ps for your fleet was always there; you just had to read the folder.
We build and run autonomous agent fleets on Claude Code in production. If you're scaling past a handful of parallel agents, talk to us.
Get the tool → fleet-ps in agent-ops — open source (MIT), a single dependency-free script, part of our toolkit for running coding agents in production.
Found this useful?
- You're Running Five Agents on One Repo. Who Stops Them Overwriting Each Other?
- Your Agent Did the Work, Then It Vanished. Here's How to Get It Back.
- Your Claude Code Session Is Permanently Stuck on a 400. Don't /clear — Do This.
- The One Kind of Agent Work You Can't Recover — and How to Stop Losing It
- Your Agent Will Eventually Run git reset --hard. Stop It at the Door.
- Your Agent Reads Text You Can't See. Frisk It First.
- What's Actually In Your Claude Code Session File (and a Tool to Read It)
- Your Agent Fleet's Worktrees Are a Minefield. Here's How to See It.
- The Agent Wrote the Code in Minutes. Reviewing It Takes Hours. Here's Why.
- Your Claude Agent Re-Reads Its Whole Prompt Every Turn. Here's the 10× You're Leaving On the Table.
- Your Agent Can Read Everything Your Shell Can. Have You Looked?
- The Loosest Line in Your Repo Is in .claude/settings.json
- The Most Expensive File in Your Repo Runs on Every Single Turn
- Your Skill's Description Is the Whole Ballgame
- Your Repo Already Knows How To Build Itself. Put That In the CLAUDE.md.
Related posts
The boring part: governance that enforces, not displays
Most "AI governance" is a dashboard. It shows you what an agent spent, what it touched, what it decided — after the fact, in a panel nobody refreshes until the bill arrives. A display is not a control. A control is the t…
Your Launch Deserves a Real Demo Video, Not a Screen Recording With Captions
Most product launches skip the demo video entirely, and the ones that don't ship one usually reach for the fastest option: a raw screen recording, maybe some auto-generated captions, posted as-is. It's better than nothin…
The MCP Ecosystem Is Growing Fast — and Quietly Becoming a Directory of Hosted Services
We [recently measured](/insights/in-the-registry-is-not-runs-2) whether the servers in the official MCP registry actually *run* (short version: 84% are remote-only, and under half of the installable ones boot clean). Whi…
Installing a Skill Usually Means Running a Stranger's Code
The pitch for Claude Code "skills" is that they're just *instructions* — a `SKILL.md` file with some markdown telling the agent how to do a task. That framing makes them feel safe to install. A prompt can't hurt you; wor…