Skip to content
Castellan
Pinder's icon

Concept · Pinder

Read as

How the Pinder decides what's a stray

The snapshot each round takes, the rules for orphans, squatters and runaways, the wrappers it looks through, what's never a stray, and how the local model's notes are written.

Article
1602
Applies to
Pinder 0.5.18
Last reviewed
For
For developers
Written for Pinder 0.5.18. Pinder is at 0.5.19 now (1 small release since: what changed).

The snapshot#

Each round takes one PowerShell snapshot, read-only:

  • Every process: its id, its parent's id, name, executable, command line, when it started, memory, and CPU time.
  • The listening TCP ports, and which process holds each.
  • A second CPU reading 3 seconds later, for each process's share of one core.

Plain code over that snapshot decides everything below.

The rules#

KindWhen
OrphanA runtime whose parent is gone, running for more than 30 minutes. "Gone" means no process has the parent's id, or the one that has it started after the child: Windows reused the id.
SquatterAn orphan that holds a listening port.
RunawayA runtime above 25% of one core in every reading for 10 minutes or more. A cool reading ends the run, and so does a gap in its readings longer than three rounds or 30 minutes. A reused process id starts afresh.

Runtimes are the only processes that can be strays: by default node, python, pythonw, dotnet, java, adb, emulator, qemu-system-, esbuild, vite, deno, bun, geniex, foundry and Inference.Service.Agent. Runtimes watched* in Settings changes the list.

Wrappers are looked through

Many tools run a command through a shell: bash -c, cmd /c, powershell -Command. When such a wrapper is still alive but the session above it is gone, the runtime under it is still an orphan.

A shell counts as a wrapper only when its command line runs one command (-c, /c, -Command, -File, -EncodedCommand, conhost --headless). An interactive shell is a real parent. Launchers in Settings lists the shells looked through.

Never a stray#

  • Windows: services (session 0), anything run from C:\Windows, and the core system processes.
  • Your allowlist, which Let it be adds to.
  • Anything with a live terminal or editor above it: Windows Terminal, VS Code, your coding assistant's sessions and the like (Never under these, a setting). A reused process id in the chain breaks it.
  • The manor's own agents, whatever else is true of them. Each round reads Castellan's staff, so an agent hired later counts at once. An agent's process is known by its installed copy, or by its page's port (and that port + 10000, for a development checkout) when something there answers /api/ping. Impounding refuses them too.
  • Shared servers, started detached by design: the local model's chat server (GenieX) and embedding server (npu-embed). They're listed as shared servers, never orphans, but can still be runaways.

The local model servers on graphics cards and the processor aren't runtimes it watches, so they're never listed.

What's shown on each stray#

  • Why code flagged it, in its own words.
  • Its children: impounding stops the process, not its tree.
  • Whether it holds the NPU's lock, or is waiting in its line. Stopping the lock holder leaves a stale lock, which the next agent to use the NPU clears.
  • Its command line, with secrets hidden: values of flags like --token, --password and --api-key; Bearer and Authorization: values; passwords in URLs; KEY=value secrets; and long random-looking strings. Paths, ports and ordinary flags stay readable.

The notes#

A one-line "what this probably is" on each stray. It decides nothing.

  1. The Porter first. For a program's executable, the Pinder asks the Porter for its note: only the path is sent, never the command line. If the Porter has one, that's the note, labelled note from the Porter. Script hosts (Node, Python, Java and the like) aren't asked about: the Porter's note on node.exe says what Node.js is, not what this one is doing.
  2. A manor agent's installed copy serving its page is named by code from its command line, labelled note from its command line.
  3. Otherwise the local model is given the stray's name, executable, hidden-secrets command line, ports, why code flagged it, and whether it runs from an installed copy or a checkout. It answers in a small fixed form (the program, what it's doing, and whether it's one of the manor's agents), which code turns into the note. An answer not in that form is dropped, and a later round asks again.

At most 10 new notes a round (Model calls per round). Each is kept, so a process is never asked about twice, even when its port, process id or temp folder changes each run.

The model runs on the NPU, a graphics card or the processor, taking its turn with the other agents (see Where the work runs). When they're all busy, the round's notes wait ("Busy: notes deferred to a later round"). Without the local AI, the strays are listed and impounded as usual, with a line saying why there are no notes.

Is this page right?

If something on it is wrong or out of date, tell us and we'll fix the page.

Still stuck? Write to support@castellan-software.com and mention article 1602. Every version of Pinder, and what changed in it, is in its release notes.