Skip to content

[Feature]: make processes Tinycast spawns identifiable in Activity Monitor #1069

Description

@FezVrasta

What should it do?

A process Tinycast starts should be identifiable as Tinycast's in Activity Monitor. Right now every one of them is an anonymous node row that looks exactly like everyone else's node.

The hierarchy is already correct, so this is narrower than it sounds. Every spawn in the app goes through Process().run() (MCPStdioTransport, ExtensionInstaller, ShellCommandRunner, ExtensionNodeShims, ToolRunner, CodexAppServerClient), so the child's ppid really is Tinycast and View > All Processes, Hierarchically already nests it. That just isn't the default view, and in the flat one there's nothing to go on.

What Activity Monitor shows for a non-bundled executable is p_comm, which the kernel sets from the basename of the file that was exec'd. I measured the three obvious ways to influence it, reading the field back with ps -o ucomm=:

approach resulting p_comm
symlink named tinycast-node node, the kernel resolves the link before setting it
process.title = "…" node, that rewrites argv, which only ps -o args reads
hard link named Tinycast (node) Tinycast (node)

So the hard link is the one that works. Same inode, no disk cost, and the code signature is untouched because it lives in the Mach-O rather than in the filename. Make it once under Application Support and exec the link instead of the resolved interpreter path.

Three things I'd suggest, smallest first:

  1. Hard-link the interpreter for the processes Tinycast keeps alive, which really means MCP servers and the installer's node. Not every execFile an extension makes.
  2. Keep tagging argv[0] and the environment. ExecutableLocator already passes tinycast-locator as argv[0] and sets TINYCAST=1 for its login-shell lookup. That's the right instinct and it makes pgrep work, it just never reaches Activity Monitor.
  3. Spawn the resolved binary, not a wrapper. This is the only case where the tree genuinely breaks: anything reached through something that exits (npx, a shell script that starts a server and returns) leaves the long-lived process reparented to launchd at ppid 1 with no link to Tinycast at all. ExecutableLocator already resolves to a real path, so this is mostly about making sure that path is what gets used.

Honest limits, so nobody is surprised later:

  • p_comm truncates hard at 16 characters. Tinycast (node) is 15 and fits. Tinycast Extension Host came back as Tinycast Extensi.
  • Hard links can't cross volumes. node under ~/.local/share/mise and Application Support under ~/Library are normally the same volume, but that isn't guaranteed, so it needs a fallback to the plain path rather than a hard failure.
  • The link goes stale when node is upgraded, since the inode changes. It has to be remade whenever the resolved path or its inode moves.
  • Only the top process gets the name. npm and npx shebangs re-exec the real node, so a grandchild is back to node.

One caveat on my own evidence: I read p_comm via ps -o ucomm=, which is the same field Activity Monitor displays for non-bundled executables. I did not open Activity Monitor and look, so if that distinction matters to you it's worth a ten-second check before any of this gets built.

Why does it belong in Tinycast?

Tinycast runs third-party extension code, and that code can spawn processes. When one of them leaks or pins a core, what the user sees is an unattributed node with no way to trace it back, not to Tinycast and certainly not to the extension that started it. An app whose whole job is running code it didn't write should make what it started legible. That's the argument, and it doesn't depend on anyone else having the feature.

It also closes a gap the project already cares about. The PR template requires a memory table and asks for it to be back to baseline after the palette closes. Processes Tinycast spawned don't appear anywhere in that accounting today, so the table is quietly less true than it reads. Making them identifiable is what lets anyone check it.

And the instinct is already in the codebase. ExecutableLocator tags argv[0] and the environment so its own shell lookup is recognisable. This is the same idea carried to the place a user actually looks.

The weight is low: a hard link and a changed exec path. No new process, no dependency, no UI, nothing to configure.

Contribution

  • I'm willing to implement this myself once this issue is labelled approved

I've already measured all of the above, so I know which approach survives contact. Happy to scope it to just (1) and (3) for the long-lived processes and leave extension execFile alone, which I think is the right size for it. Tell me if you'd rather it went differently.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

approvedGreen-lit. A PR may link this issue and will pass the gate.

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions