Use when changing subprocess execution, cancellation, process-tree cleanup, orphan reaping, or Windows child hardening.
Context, Concurrency, and Processes
context.Context through long-running, subprocess, and networked work; prefer exec.CommandContext; use derived contexts and timeouts for cleanup and HTTP calls.shellenv lifecycle configurator. Agents and other subprocesses use ConfigureShellCommand: it creates a process-tree boundary and installs cmd.Cancel to kill the whole tree, so grandchildren (test workers, build watchers) cannot outlive cancellation and hold the next run's worktree locked. Repository commands.* and custom gates use ConfigureCooperativeShellCommand: on Windows it sends targeted CTRL_BREAK, preserves up to a three-second cleanup window, then retains the same forced Job Object fallback. Regressions: TestConfigureCooperativeShellCommandCancelAllowsCleanup, TestConfigureCooperativeShellCommandCancelForcesNonCooperatingTree.cmd.Cancel covers only cancellation; on clean exit or error the group is not reaped, and leaked grandchildren accumulate until the OS OOM-kills the daemon (surfacing as daemon crashed during execution with no stack trace). Use shellenv.RunShellCommand / OutputShellCommand / CombinedOutputShellCommand for one-shot commands, or StartShellCommand plus TerminateShellCommandGroup when handling pipes manually; the helper doc comments in internal/shellenv own the details. ConfigureShellCommand also installs a 5s cmd.WaitDelay backstop so a grandchild holding an inherited pipe cannot wedge cmd.Wait forever. Regressions: TestCodexAgent_Run_ReapsLeakedGrandchildOnCleanExit, TestRunShellCommandWithEnv_ReapsGrandchildOnCleanExit, TestTerminateShellCommandGroup_*.setsid(2)/setpgid(2) (agent CLIs sandboxing their tool runners, any daemonizing worker script) leaves the group, and after its parent exits nothing lineage-based can name it again - it burns CPU and holds a deleted worktree's cwd forever. internal/procreap is the identity-based backstop: it matches a process by the run worktree its cwd resolves under (deliberately never argv, which a legitimate git worktree remove also carries), never touches pid<=1/itself/its ancestors, spares worktrees whose run is still pending or running, and escalates SIGTERM to SIGKILL only after a grace period. Reach is <NM_HOME>/worktrees by path shape plus exactly the run worktrees a caller names from run records (Options.Worktrees), never a configured worktree root by shape - an operator's own directory is unmatchable unless a run row names it. Every site that removes a run worktree sweeps it first through procreap.SweepRunWorktree(s) (run cleanup and setup failure via RunManager.removeRunWorktree, startup cleanup, eject), scoped and therefore without age floor or run-active check; the unscoped startup sweep in recoverOnStartup keeps the orphanProcessMinAge floor. All best effort. Windows needs none of this - job objects contain the whole tree - so the platform layer reports an empty table. Regressions: internal/procreap, TestSweepOrphanRunProcessesReapsFinishedRunAndSparesActiveOne, TestSweepRunWorktreeProcessesReapsLeakedChildAtRunCleanup, TestTerminateShellCommandGroup_AsksBeforeKilling, TestTerminateShellCommandGroup_EscalatesWhenSIGTERMIsIgnored.winproc.Harden(cmd) (no-op elsewhere, idempotent, preserves existing creation flags) or a console window flashes per child (#287). shellenv.ConfigureShellCommand already calls it; one-shot commands built directly must call it themselves. Regressions: TestHarden* in internal/winproc.14e8dd1
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.