Local-subprocess implementation of the @deepseek-ai/dsh-process manager seam: LocalProcessManager spawns each spec's argv as a detached process group, collects bounded output with size-limited full-stream spill files, and escalates kills SIGTERM→SIGKILL across the whole group. It has no config: every limit and directory arrives on the spawn spec, so the deployment-varying knobs stay with the calling seam's config (dsh-bash-local today).
detached (own process group); kills send SIGTERM to the group, then SIGKILL after the spec's grace (OpenCode's escalation; pipelines and subshells die with the parent). After the leader exits, inherited stdout/stderr pipes receive the same bounded drain grace so a surviving descendant cannot hold the spawn open indefinitely. ESRCH is tolerated; daemons that re-parent away from the group can still survive — the same caveat as the surveyed tools.0600 with random names under a lazily-created 0700 per-process directory.DSH_* merge — process.env minus credential-shaped vars (*KEY*/*SECRET*/*TOKEN*) and all ambient DSH_* names; a spec's ordinary env merges after the scrub but rejects DSH_*; managed dshEnv rejects ordinary names and merges last, preventing stale nested-harness identity. Supplied stdin is written and closed; otherwise fd 0 is /dev/null. See the stdin/env Agent Note and managed environment Agent Note.ProcessHandle readers return deltas in whole-stream byte coordinates; the manager never holds a cursor, so consumer-owned cursors (the bash background read path) and full-stream re-reads coexist.Indirectly, through consumer seams (today the bash executor family behind dsh-tool-bash), which own all model-facing rendering of process output and lifecycle.
No direct invalidation; the named consumers own any request-prefix changes.
*KEY*/*SECRET*/*TOKEN* only; differently-named secrets (e.g. *PASSWORD*) pass through, and a whitelist for over-scrubbed vars is noted future work.The raw process handling lives in src/spawn.ts; src/index.ts is the service wiring.