Show HN: Watch all the AI agents on your machine Developer Mark Wylde released @markwylde/all-your-agents, an open-source tool that watches every coding agent session on a machine without polling, tracking harnesses including Claude, Grok, Codex, and omp. The package requires Node.js 20 or later on macOS and Linux and is installed via npm, with a full-screen live view available through npx. The tool lists live sessions, surfaces sessions waiting on user input first, and lets users press H for finished sessions and t to read their transcripts. Watch every coding agent on this machine, and inspect the sessions they leave behind. Subagents covers start, end, background and nested. 1. claude -p writes no live index entry, so a print-mode run appears in history only. 2. Grok's tool started carries no call id, so the current tool is identified by name. Two tools with the same name running at once show as one. 3. A failed turn is reported as failed , but Grok records no error message for it, so activity.error is usually empty. 4. grok -p registers as live only when GROK TRACK HEADLESS is set. Otherwise it appears in history only. 5. Codex does not persist approval requests, so a session blocked on an approval reads as running . A launched Codex with no prompt yet has no rollout. A /resume after watch started appears on its first append. A VS Code thread unloaded without touching another file stays listed until the next event for that pid. 6. omp writes no transcript until the first reply of a new session ends. That first turn is read from omp's prompt history, which needs SQLite: Node ≥ 22.13, or your own sqlite reader. Without it a new session reads idle until its transcript appears. 7. A pending ask tool reads waiting . Permission approvals never reach disk, so a session blocked on one reads running omp's default approval mode asks for none . 8. omp names a run after the terminal on its stdin, in print mode too: omp -p typed in a terminal is live and reads interactive . Piped or detached, it has no terminal and appears in history only. Nothing on disk marks a run headless . python import AllYourAgents, { builtInProviders } from '@markwylde/all-your-agents'; const aya = AllYourAgents { providers: ...builtInProviders , } ; aya.on 'session:create', session = { console.log session.harness, session.id, session.pid ; } ; aya.start ; No polling, ever ADR 0001 https://github.com/markwylde/all-your-agents/blob/main/docs/adr/0001-never-poll.md . start watches the files each harness already writes and the processes that write them. Bursts are coalesced per path about 25 ms quiet, at most 1 s behind . stop drops every file and process watch. On macOS, where opening one fs.watch can make the others miss an event, each watch re-checks what it covers once after any watch opens or closes see the ADR ; a custom fs can opt in with onWatchChurn . npm install @markwylde/all-your-agents Node.js ≥ 20, macOS and Linux. Pass { fs, processes } to observe a remote machine. Run straight from source on Node ≥ 22.18 no build step : node ./demo/list.ts every session, live and historical, as a table node ./demo/list.ts --live only live sessions node ./demo/watch.ts stream session events as they happen Ctrl+C to stop all-your-agents is top for coding agents. It lists every live session, puts the ones waiting on you first, and updates as they change. Press H for every session on the machine, finished ones included, and t to read what any of them said. npx @markwylde/all-your-agents full-screen live view npx @markwylde/all-your-agents --once print a table and exit also when piped npx @markwylde/all-your-agents --json print live sessions as JSON and exit npx @markwylde/all-your-agents --all also show sessions that close while it is open npx @markwylde/all-your-agents --history start with every session, not only live ones npx @markwylde/all-your-agents --json --history every session as JSON, live ones first | Key | Action | |---|---| | ↑ ↓ / k j , Home End , PgUp PgDn | Move the selection | | Enter | Details: full title and folder, what it is waiting for, current tool, last error, subagents | | / | Filter by title, folder, harness, model, or pid. Esc clears | | s / < , r | Next / previous sort column, reverse | | c | Show or hide closed sessions | | H | Show or hide history: every session the providers know, in the same table | | t | Transcript of the selected session: prompts, replies, tools, outcomes. Follows a live session. t or Esc closes | | ? h | Help | | q Ctrl+C | Quit and restore the terminal | The screen redraws only when an agent changes, a key is pressed, or the terminal resizes. History is read once when you press H ; a transcript is one event stream, closed when you leave it. Times are clock times 14:31:02 , not ticking durations, so nothing runs on a timer. NO COLOR is honoured. Live sessions have a pid . Historical ones do not. kind is interactive or headless . python import type { Session, SessionActivity, Subagent, Turn, SessionEvent } from '@markwylde/all-your-agents'; session.activity is the current or last turn tool , lastTurn , error , openSubagents , separate from status . session.subagents lists launched subagents. transcript yields Turn s; events tails normalized SessionEvent s until you stop iterating or call close on it both work while it is waiting user , assistant , tool , tool-result , title , turn-end , subagent , subagent-end , error , other . Each item keeps the original record on raw . Two kinds of waiting. status: 'waiting' means either that the session is blocked on you a permission prompt, a question , or that its turn is over while a background shell command or monitor it started is still running and will wake it. The second kind always has waitingFor 'shell' or 'monitor' , so session.status === 'waiting' && session.waitingFor == 'shell' && session.waitingFor == 'monitor' is "needs the user". Such a session is not idle until that work ends; its finished turn is on activity.lastTurn meanwhile. A background subagent on its own leaves the session idle and shows on subagents . Title precedence , highest first: user custom title harness generated process session-file name prompt first real user prompt . session:update fires only when the effective title, cwd, or model changes. | Event | When | |---|---| | session:create | A live process owns a conversation that did not already have a journal. | | session:open | A live process owns a conversation that already had a journal. | | session:status | Status changed running \| waiting \| idle . | | session:update | Effective title, cwd, or model changed. | | session:activity | session.activity changed. | | session:close | The process no longer holds it. pid is unset; history remains. | | subagent:start / subagent:end | A subagent launched or finished. | | ready | Catch-up from start finished. | | error | A provider failed { source: 'provider', provider, error } or one of your listeners threw { source: 'listener', event, error } . Never thrown into the library. | Subscribe before start . Catch-up events carry { catchUp: true } , then ready , then { catchUp: false } . A listener that throws never stops updates. Register an error listener to receive the failure; without one it is rethrown asynchronously as an uncaught exception, so it is never lost. aya.running ; await aya.sessions { harness, cwd, live, kind, since } ; await aya.get id ; await aya.reconcile pid ; // one-shot re-validation; never schedules since is epoch ms matched against updatedAt fallback startedAt . kind is interactive | headless . sessions works without start . transcript , events and subagents are always served by the provider named in session.provider . Closed sessions stay in memory for the 1000 most recent; older ones come from their provider's history. AllYourAgents { providers: ...builtInProviders , fs, // default: local filesystem processes, // default: local ps/proc + kqueue/pidfd via optional koffi sqlite, // default: node:sqlite where the runtime has it; false for none debounce: { quietMs: 25, maxLatencyMs: 1000 }, } ; reconcile pid? is for hosts that already know a process exited a terminal emulator . Without koffi , processes.watch is unsupported and each provider re-validates on the next change to its live index or on reconcile . Provider id claude-code , harness ClaudeCode . Home is $CLAUDE CONFIG DIR if set, otherwise ~/.claude , overridable via claudeCode { home } . Live index: