Skip to content

no-sandbox: reap the agent process tree on teardown (process-group kill) #766

Description

@mattpocock

Background

Follow-up split from #590 and documented in docs/adr/0019-completion-timeout-for-hanging-process.md.

The #590 fix introduces a completion timeout: once the agent emits the completion signal, Sandcastle waits one minute and, if the process is still silent (a hanging process — typically a spawned gh/git child or a long-lived MCP server holding the sandbox exec's stdout open), it force-completes the iteration successfully and abandons the process.

For container-based sandbox providers this is fine — container teardown (docker rm -f, src/sandboxes/docker.ts:238) kills the abandoned process. But for the no-sandbox provider, close() is a no-op (src/sandboxes/no-sandbox.ts:150-152) and there is no proc.kill() anywhere in the codebase, so the abandoned agent process and the child holding the fd leak on the host.

This leak already exists on the timeout/abort paths, but the #590 fix promotes it from a rare edge case to the common success path for no-sandbox users.

Why it's non-trivial

proc.kill() only reaps the direct sh -c child, not the grandchild holding the pipe. Reaping the whole tree means either:

  • spawning detached (detached: true) and signalling the process group via process.kill(-pid), or
  • a tree-kill approach,

plus tracking the active exec proc on the no-sandbox handle (not tracked today). Both carry their own failure modes — signal handling and detached-process semantics differ on Windows, which is a supported host.

Scope

  • Track the active exec process(es) on the no-sandbox handle.
  • On close() (and ideally on the completion-timeout/abort/idle paths), reap the process tree, not just the direct child.
  • Verify behaviour on Windows hosts.

Out of scope

The #590 completion-timeout behaviour itself — that ships independently and benefits all providers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageMaintainer needs to evaluate this issue

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions