2026-10-11 16:38 UTC

Mark Wylde claims the released all-your-agents API and CLI normalize live status, subagents, and transcripts across four coding harnesses using event-driven file and process watches, reducing bespoke monitoring integration while retaining harness-specific visibility gaps.

state: corroboratedheat: lowuncertainty: mediumconvergesscott: mediumagent-harnesses agent-observability developer-toolsMark Wylde

What is this?

Per the case, Mark Wylde released a Show HN project ('all-your-agents') offering an event-driven, harness-neutral API and CLI that normalizes live agent status, subagent activity, and transcripts across four coding harnesses by watching agent files and processes, so developers don't write bespoke monitoring per tool. The supplied web snippets do not directly confirm Wylde or this specific release β€” they instead show the surrounding territory: Open Harness (openharness.ai) takes a related adapter-based 'universal API across agent harnesses' approach, pi-harness-agent does per-harness delegation, and curated lists like awesome-cli-coding-agents document a fragmented ecosystem of 130+ CLI agents and harnesses with no shared observability layer. The snippets are thin on the specific project; treat the case's claims as the Show HN author's own framing.

Why it matters to Scott

Wylde’s claimed release independently converges with Scott’s cross-harness transcript reconstruction in Search Conversations and externalised job-status tracking in Proposal Compiler, offering a candidate shared ingestion/inspection layer to evaluate rather than another generic observability example. The supplied material does not establish supported-harness overlap, transcript fidelity or reliable detection, so integration savings remain unverified; the radar tracks related tools such as Grafana agento11y, but not this specific development.
dev:project.search-conversationsdev:project.proposaldev:project.searchradar:concept.agent-observabilityradar:concept.agent-harnessesradar:grafana-agento11y-coding-observabilityradar:actualis-local-coding-agent-observability
queries asked of Scott's wikis
  • agent observability and session monitoring across multiple coding harnesses
  • harness-neutral normalization of agent transcripts, statuses, and subagents
  • event-driven file/process watching for tool or agent state detection
  • bespoke integration pain: per-harness APIs, hooks, and session formats in Scott's coding-agent projects
  • agent memory / agent-maintained wiki pipelines that consume session transcripts as input
  • approvals, permission gates, and human-in-the-loop visibility for autonomous agents

Measured heat

now 0 pts/hpeak 17 pts/hcomments 0/hpeers p14momentum: steady3 platformsage 461h
points/hour across evidence Β· reading as of 2026-10-12 02:59:37.977291+11:00 Β· deterministic, not a model opinion

How the heat travelled

09-22 13:23 (minted)⭐ origin echo-reconstructedAn event-driven, harness-neutral API and CLI for inspecting live and historical coding-agent sessions, with documented detection and approva
markwylde on github (echo) Β· attributed from hn.story.49799267 Β· published time unknown
β€”
09-22 10:57first on hacker news Β· published Β· lag ?Show HN: Watch all the AI agents on your machine
turblety
β€”
10-05 12:33first on r/ClaudeAI Β· published Β· lag ?I built a desktop app that shows all sessions and agents under one window
NaivePresentation449
β€”
09-22 10:57amplified on hacker news πŸ‘‘hn.story.49799267
turblety
peak 8 Β· 4 comments Β· 45% of case engagement
09-24 15:36amplified on hacker newshn.story.49832165
olouv
peak 1 Β· 0 comments Β· 4% of case engagement
10-03 02:55amplified on hacker newshn.story.49941003
HiteshBandhu
peak 2 Β· 1 comments Β· 11% of case engagement
10-05 12:33amplified on r/ClaudeAIreddit.post.1wy7dpa
NaivePresentation449
peak 11 Β· 2 comments Β· 28% of case engagement
10-07 14:04amplified on r/ClaudeAIreddit.post.1wzxel0
Dri_Water
peak 1 Β· 1 comments Β· 4% of case engagement
10-08 13:57amplified on hacker newshn.story.50005874
bearjb
peak 2 Β· 0 comments Β· 7% of case engagement
09-22 11:20our radar first saw it Β· lag ?discovery anchor: hn.story.49799267β€”
pace: p55 vs 1032 stories at the 336h mark (now 461h old) β€” ahead of breadcrumb-flight-recorder-agent-memory (1.1x), behind claude-subscriber-token-theft (1.0x)

Evidence (7) β€” ⭐ canonical anchor

sourceobjectauthorscorecomments
🟧 hnShow HN: Watch all the AI agents on your machine
Retrieved article excerpt

Open article Β· Retrieved 2026-09-23T12:21:58.388877+00:00

# all-your-agents

Watch every coding agent on this machine, and inspect the sessions they leave behind.

## Compatibility

[Compatibility matrix. Every agent fully supports live detection, status, titles, model, subagents, transcript and history. Partial: Grok Build tools and turn outcome; oh-my-pi waiting-for; print mode on Claude Code, Grok Build and oh-my-pi. None: Codex CLI waiting-for.](https://github.com/markwylde/all-your-agents/blob/main/docs/images/compatibility.svg)

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`.

## Usage

```
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`.

## Install

```
npm install @markwylde/all-your-agents
```

Node.js β‰₯ 20, macOS and Linux. Pass `{ fs, processes }` to observe a remote machine.

## Demos

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)
```

## CLI

`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.

## Session object

Live sessions have a `pid`. Historical ones do not. `kind` is `interactive` or `headless`.

```
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.

## Events

| 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.

## Query

```
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.

## Options

```
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`.

## Claude Code

Provider id `claude-code`, harness `ClaudeCode`. Home is `$CLAUDE_CONFIG_DIR` if set, otherwise `~/.claude`, overridable via `claudeCode({ home })`.

Live index: `<home>/sessions/<pid>.json`. Journals: `<home>/projects/<encoded-cwd>/<id>.jsonl`. Every non-alphanumeric character in the cwd becomes `-`, so `/Users/me/app/.claude/worktrees/x` is `-Users-me-app--claude-worktrees-x`.

Status: `busy` β†’ `running`, `waiting` β†’ `waiting`, `shell` β†’ `waiting` with `waitingFor: 'shell'` (the turn ended but a background shell will wake the session), `idle` β†’ `idle`. Unknown words omit `status`. `model` is the model of the latest assistant record in the journal. `.key` files and the messaging socket are never opened.

## Grok Build

Provider id `grok-build`, harness `Grok`. Home is `$GROK_HOME` if set, otherwise `~/.grok`, overridable via `grokBuild({ home })`. All four built-ins are in `builtInProviders`; pass `providers: [claudeCode()]` to watch Claude Code only.

Live index: `<home>/active_sessions.json`, an array of `{ session_id, pid, cwd, opened_at }`. One pid can hold several sessions. `grok -p` registers only when `GROK_TRACK_HEADLESS` is set; otherwise print-mode runs appear in history with `kind` `headless`. Sessions: `<home>/sessions/<encoded-cwd>/<id>/`. The cwd is percent-encoded like Rust `urlencoding` (everything but `A-Za-z0-9-._~`, so `/tmp/foo(bar)!` is `%2Ftmp%2Ffoo%28bar%29%21`); a cwd whose encoding exceeds 255 bytes is found by a one-level lookup for the session id.

Status comes from `events.jsonl`, Grok's phase log: `waiting_for_model`, `streaming_text`, `streaming_reasoning`, `tool_execution` β†’ `running`; `permission_prompt` β†’ `waiting` (with the tool named by `permission_requested`); no open turn β†’ `idle`, or `waiting` while a background task is still running, with `waitingFor` `monitor` if one of them is a monitor and `shell` otherwise. Those tasks are the only thing read from `updates.jsonl`: its `_x.ai/session/update` rows `background_tasks` and `task_completed`; every other row is skipped unparsed. Unknown phases omit `status`. Titles and `model` come from `summary.json`, the conversation from `chat_history.jsonl`, subagents from `subagents/<id>/meta.json`. `active_sessions.lock`, `*.tmp`, `auth.json` and the session-search sqlite are never opened.

## Codex CLI

Provider id `codex-cli`, harness `Codex`. Home is `$CODEX_HOME` if set, otherwise `~/.codex`, overridable via `codexCli({ home })`. VS Code Codex sessions that share that home are the same provider.

Live sessions are rollout files a process currently has open: `<home>/sessions/YYYY/MM/DD/rollout-<timestamp>-<thread-id>.jsonl`. There is no pid index. Status comes from persisted turn lifecycle events: `task_started` β†’ `running`; `task_complete` / `turn_aborted` β†’ `idle`. Codex does not persist approvals, and has no background work that wakes an ended turn (a unified exec process that outlives its turn is not recorded as running), so `waiting` is never reported. Titles come from `session_index.jsonl` then the first user prompt; the conversation from `response_item` records; subagents from child rollouts with `parent_thread_id`. A compressed `.jsonl.zst` thread is listed only when `session_index.jsonl` has a title for it
turblety84
🟧 echo.github ⭐An event-driven, harness-neutral API and CLI for inspecting live and historical coding-agent sessions, with documented detection and approvamarkwyldeβ€”β€”
🟧 hnShow HN: Armada – Every Claude Code and Codex session and limit, on one screenolouv10
🟧 hnShow HN: Hall Monitor. See all your agents across machines on your Mac's NotchHiteshBandhu21
🟠 redditI built a desktop app that shows all sessions and agents under one window
ClaudeAI
NaivePresentation44932
🟠 redditI built a live dashboard that shows what every Claude Code session and subagent is doing (read-only, no hooks)
ClaudeAI
Dri_Water01
🟧 hnShow HN: Porch – a Mac menu bar work log for Claude Code and Codex sessionsbearjb20

Interpretation history

Decision trace