Expand description
OS-level process introspection for the Inspector pane’s PROCESSES section.
Walks the descendant tree of the spawned claude binary at the
operating-system level via the sysinfo crate, returning a
sorted snapshot of “interesting” descendants: shells, compilers,
task runners, monitors - anything claude’s tool flow spawned
that’s still alive at scan time.
Why not key off the wire alone? The wire’s task_started /
task_updated pair covers Bash with run_in_background:true, a
foreground call that outlives a beat, and the Monitor tool’s
streaming watcher, but it doesn’t surface:
- A foreground Bash that ends within a beat, which leaves no frame.
- Grandchild processes the spawned shell forks off (e.g. a
cargo buildthat fans out intorustcworkers). - Anything that detaches from claude’s tool registry but stays in the process tree.
macOS and Linux are first-class, via sysinfo. Windows falls back
to an empty snapshot: shell-process names (cmd.exe /
powershell.exe) need a recogniser nobody has asked for yet.
The snapshot is consumed by forge-workspace’s seat walk (thin
mediator), which passes the session’s live background commands
through so the scan can adopt matching OS processes by cmdline
lookup (a backgrounded local_bash sits outside claude’s tree).
Re-exports§
use std::time::Duration;🔒use std::time::SystemTime;🔒use forge_primitives::McpServerStatus;🔒use sysinfo::Pid;🔒use sysinfo::ProcessRefreshKind;🔒use sysinfo::ProcessesToUpdate;🔒use sysinfo::System;🔒
Structs§
- Configured
McpServer - A configured MCP server distilled to what the process matcher needs:
the configured
nameplus the stdio launchcommand+argsused to match it against a live process cmdline. - Infra
Label - Friendly display name + kind for a recognized known-infra process.
- Process
Entry - One descendant process the scanner found alive. Field shape is
driven by what a view’s process row builder needs (PID + cmdline +
memory for the metadata line) + the cmdline-matching needed for
wire-tracked overlay (
process_cmdline_matches_tool_input). - Process
Snapshot - Snapshot of
claude’s descendant processes at one point in time. Always succeeds - failures (sysinfo errors, process gone) collapse to an emptyprocessesvec. - Root
Process - One depth-0 process the elimination join may consider, with whether an alive wire tool call already claims it.
Constants§
- INTERPRETERS 🔒
- Executables an stdio MCP server’s live process image runs under, matched on
the
argv[0]basename so a server thatexeced out of its configuredsh -cwrapper still qualifies. - SCAN_
STALENESS - How old a snapshot may be before another walk replaces it.
Functions§
- basename_
exe - Strip the executable’s directory from a cmdline headline so the row
reads
cargo nextest run, not/opt/homebrew/bin/cargo nextest run. Only the FIRST token (the executable) is basenamed; args are kept verbatim (they carry the distinguishing detail). A first token with no/(e.g. apostgres: walwriterprocess title) is unchanged. - classify_
known_ infra - Friendly name for a known-infra process (MCP servers today), derived
from its cmdline.
Nonewhen unrecognized. - cmdline_
haystack - The normalized cmdline text a process is matched on: the unwrapped inner command for a shell wrapper, else the cmdline itself.
- cmdline_
needle - The normalized command text a wire-tracked tool call is matched on.
normalize_wsalready trims, so a whitespace-only command yields the empty string and the caller can treat that as “no needle”. - configured_
mcp_ servers - Extract the stdio-launched configured MCP servers from an mcp-status
snapshot. A server contributes
(name, command, args)only when itsconfigblob carries a stringcommand(the stdio shape); url-only (http/sse) servers have no local process, so they’re skipped. - configured_
server_ 🔒matches - True when
haystack(a whitespace-normalized process cmdline) contains every match token ofserver. Leadingnpx/npmpassthrough flags (e.g.-y) are dropped first:npx -y <pkg>re-execs intonpm exec <pkg>with the flag stripped, so the tokens are the package spec (the first non-flag arg) plus everything after it - where the real distinguisher--cdp-endpoint <url>lives and survives into the process cmdline. Empty / all-flag args fall back to the barecommand. Substring containment tolerates the process-side@versionsuffix. - configured_
text_ match - The configured server whose command + args uniquely text-match
cmdline.Nonewhen none matches or several do - the ambiguous case declines rather than guesses. - elect_
unmatched_ server - Pair the sole unmatched
Connectedstdio server with the sole unmatched candidate process, returning that process’s pid and the name its row takes. - extract_
inner_ command - Unwrap a shell-wrapper cmdline to the user command inside it.
Recognizes the shape claude wraps Bash tool calls in (captured via
ps -axww):/bin/zsh -c source <snapshot> ... && eval '<CMD>' < /dev/null && pwd -P >| /tmp/claude-<hash>-cwd. The inner command is single-quoted betweeneval 'and' < /dev/null. ReturnsNonewhencmdlineis not a recognized wrapper (non-shell processes pass through unchanged at the call site). - include_
subtree 🔒 - Insert every descendant of
root(notrootitself) intoincluded, walking theparent -> childrenindex. - is_
elimination_ 🔒candidate - True when a root process may stand in for an unmatched server: its
argv[0]is one ofINTERPRETERS. Keeps transient tool processes (anrgfrom a Grep) out of the pool, which would otherwise decline the pairing on any scan where one was alive and flicker the row. - live_
candidates 🔒 - Build a
ProcessEntryfor every live, interesting process in the table, dropping the scanner’s own pid, zombies/dead, and the one-shotps/sysinfoself-probes. - mcp_
friendly_ 🔒name - Friendly MCP name from a parsed
(scope, name), orNonewhen the package isn’t a recognized MCP server: - mcp_
name_ 🔒from_ node node /opt/foo-mcp-server.js→foo. Requires anodeargv[0]and a later token whose basename (sans.js/@version) resolves viamcp_friendly_name(scope-less, so a baremcpdoesn’t match).- mcp_
name_ 🔒from_ npm npm exec @playwright/mcp@latest→playwright. Requires the literalnpm+execargv prefix; the package spec must resolve to an MCP name viamcp_friendly_nameor this returnsNone.- normalize_
ws 🔒 - Collapse every run of ASCII whitespace (spaces, tabs, newlines) to a
single space and trim the ends.
sysinfo’sproc.cmd()joins argv with single spaces, so a multi-line / multi-space wire command never matches the captured cmdline byte-for-byte; normalizing both sides first makes the substring check robust. - parse_
npm_ 🔒pkg - Parse an npm package spec into
(scope, name)with the@versionstripped.@playwright/mcp@latest->(Some("playwright"), "mcp");@upstash/context7-mcp->(Some("upstash"), "context7-mcp");context7-mcp@1.0->(None, "context7-mcp"). - process_
cmdline_ matches_ tool_ input - True when
process_cmdplausibly matches the shell command captured in a wire-tracked tool’sraw_input.command. Used by a view’s process row builder (path A+) to overlay wire-tracked task descriptions onto OS-detected processes when both refer to the same work. - resolve_
infra_ label - Friendly label for a known-infra process: the CONFIGURED MCP server name
when the process’s command + args uniquely match one of
configured, else the package-derived name fromclassify_known_infra.Nonewhen neither produces a name - the process isn’t a recognized MCP server. - scan
- Walk
claude_pid’s descendant tree plus any command-matched backgroundedlocal_bashand build a sorted snapshot. Always returns successfully - sysinfo failures, missing processes, or empty trees all collapse to an empty snapshot with a freshscanned_at. - select_
snapshot 🔒 - Select the processes that belong in the snapshot: the descendants of
claude_pid, plus any candidate whose cmdline matches one ofextra_commandstogether with ITS descendants (a backgroundedlocal_bashliving outside claude’s tree). Pure overcandidatesso the adoption logic is unit-testable without a live process table. - strip_
plugin_ namespace - The bare server name inside a plugin-namespaced configured name. The CLI
exposes a plugin-provided MCP server as
plugin:<plugin>:<server>, which reads worse than the package-derived name; anything else (including a plain name that merely contains a colon) is returned verbatim.