cmux NEXT: list agent runtimes (cmux agents runtimes, RFC #20149 phase 1)
First slice of RFC #20149, phase 1: cmux can now list the coding-agent processes running for this user. That includes ones no open tab owns, along with what cmux can prove about who started each one. It is read-only. Nothing is stopped or changed.
cmux agents runtimes (also: cmux agent runtime list)
What changed
- Scan (
cmux-tui-platform/src/process_inventory.rs): one scan of this user's processes per request. It reads/procon Linux, and libproc plusKERN_PROCARGS2on macOS.- Each process gets pid, ppid, process group, session, controlling tty, start time, executable path, CPU time and memory.
- Other users' processes are skipped.
- The scan is bounded to 4096 processes, and 32 arguments per process (4 KiB in all). The environment is never read.
- A cut or partly unreadable scan reports itself as incomplete.
- No timer or cache. A viewer that wants fresh numbers asks again.
- Classifier (
cmux-tui-core/src/runtime_inventory/): a pure function from one scan plus the live cmux terminals.- Adapters recognize Codex, Claude Code and OpenCode by executable name, or by the script a
node/bunlauncher runs. - Each gets a role:
cli,task,server,shared_server(Codex's managed app-server),updaterorlauncher. - Attribution:
verified: an unbroken parent chain from a live cmux terminal's PTY child, where each process started no earlier than its parent. A reused pid never adopts an older process.probable: reparented, but still in the session of a live cmux terminal whose leader is that same process generation.unattributed: everything else. A shared controlling terminal is never evidence on its own (#11004).
- For a server,
known_cmux_terminal_idslists the cmux terminals running a same-vendor client.total_clientsis alwaysnull: cmux sees processes, not connections, so zero known cmux clients never means zero clients. can_stop_safelyis always false in phase 1.
- Adapters recognize Codex, Claude Code and OpenCode by executable name, or by the script a
- Privacy (
redact.rs):- Arguments keep their shape only: the program name, flag names (
--model=<redacted>), and up to two leading subcommand words (app-server,mcp serve). Every other argument is<redacted>, since it may be a flag value or part of a prompt. - The home directory in paths shows as
~.
- Arguments keep their shape only: the program name, flag names (
- API: a new resource API v2 read operation,
agent.runtime.list, scoped likeagent.list(machine + session).- Pages are refused it (page access
ScreenRead). - cmux apps are refused it (app-host
NEVER). - MCP doesn't expose it (
CLI_ONLY), so a provider's tools never see host process data. - The remote relay already refuses every v2 frame.
- The catalog, envelope schema, inventory, class tables and seven SDK descriptors are updated, and the app-host files are regenerated.
- Pages are refused it (page access
Review fixes:
- A surface's pid outlives its child until the exit is noticed. So a terminal counts only while its child's parent is the daemon or a terminal host. A pid reused by another app can't adopt that app's tree; when lineage can't be shown, the result is a missing attribution, never a false one.
- argv[0] is kept only when it looks like a program name, since a process can rewrite it into any text.
- Short flags are kept only as one letter:
-Xsecretbecomes<redacted>. - Bare words are kept only when they are an adapter subcommand:
claude hellobecomesclaude <redacted>. - On Linux,
/proc/<pid>/cmdlineis read only up to the argument bound.
Known misses (never wrong attributions):
- A
node/bunlauncher with flags before the script path isn't recognized. - macOS zombies count as unreadable, so
completecan be false on a busy Mac.
Not in this PR (later slices of phase 1):
- A launch ledger, so a runtime keeps a
verifiedattribution after its tab closes. Today such a runtime readsunattributed, orprobablewhile its session leader lives. - The Background Runtimes section in the app.
- Phase 2 (stop actions) waits for a decision on #20149.
Testing
On fleet macOS hosts with scripts/ci/cmux-tui-rust-check.sh:
all inventoryat 38edddd07931:cargo fmt --check,cargo clippy --workspace --all-targets -D warnings, and 19 tests pass.- 7
process_inventorytests, including a live scan that must find the test process as one generation (pid plus start time), and the scan cap. - 12
runtime_inventorytests covering the RFC's cases plus redaction:- a shared server with clients in two terminals
- zero known cmux clients is not zero clients
- a reparented agent in the terminal session is only probable
- an agent that left with
setsidis unattributed - a same-tty PPID-1 process is not owned
- a reused terminal pid doesn't adopt an older process
- an incomplete scan is marked
- adapter roles and versions
- argument and path redaction
- 7
test agent_runtimes, a daemon test (tests/agent_runtimes.rs): a stand-incodexstarted in a cmux terminal must come backverifiedto that terminal, with redacted arguments. The same program started outside cmux must come backunattributed.- The first run (4a003391ac8b) failed in a useful way. The host was running a real Codex
app-server --listen …(ppid 1), which the inventory correctly reported as an unattributedserver, but the test took it for the stand-in. Fixed in the test, which now matches the stand-in by path. - Result at 38edddd07931: passes. A second fix along the way: public terminal ids start with
term_.
- The first run (4a003391ac8b) failed in a useful way. The host was running a real Codex
test noun_first/test mcp::(every operation has a CLI path, every read is an MCP tool or excluded): at 4a003391ac8b,noun_first(5 tests) andmcp::(25 tests) pass.- Locally:
check-resource-api-boundary.py,check-spec-inventory.py,check-sdk-schema.pyandscripts/cmux-next/crash_ratchet.pypass.
Windows: the usual Rust builder for the Windows check wasn't reachable from my machine, so this PR's build x86_64-pc-windows-gnu CI job is the Windows check. The scan returns nothing on Windows.
Not verified: manually, which identities each adapter finds on a real Mac with Codex, Claude Code and OpenCode installed. The RFC asks for that list, and I'll add it to #20149 once the CLI is in a nightly.
Changelog
Added: cmux agents runtimes lists the coding-agent processes running for you (Codex, Claude Code, OpenCode), including ones no open tab owns, and shows whether cmux launched them.
🤖 Generated with Claude Code