---
name: "Zombie process accumulation from unrereaped child processes"
---

# Bug 452: Zombie process accumulation from unrereaped child processes

## Description

Storkit accumulates zombie processes over time from unrereaped child and grandchild processes. Observed 101 zombies in Docker container, 27 on macOS host. Breakdown: 51 esbuild, 36 echo, 5 claude, 5 sh, 2 bash, 1 cargo.

Root cause: storkit does not reap orphaned grandchild processes. The zombies are mostly grandchildren (`esbuild`, `echo`, `sh`, `cargo`) spawned by `npm run build`, `cargo test`, etc. during worktree setup and gate checks. This happens both natively (observed 27 zombies on macOS host) and in Docker containers. When the intermediate parent exits, these grandchildren get reparented to storkit (or PID 1 in Docker) and become zombies because nobody calls `waitpid` for them.

Additionally, `llm/providers/claude_code.rs` has two code paths that call `child.kill()` without a following `child.wait()` (the cancel path at line 286 and the timeout kill at line 367), leaving direct-child zombies. `agents/pty.rs` correctly calls `child.wait()` after `child.kill()`.

The fix should include:
1. Add a background reaper thread/task in storkit that periodically calls `waitpid(-1, WNOHANG)` to clean up orphaned processes (handles both native and Docker)
2. Add missing `child.wait()` calls after `child.kill()` in `claude_code.rs`
3. Optionally use `tini` or `dumb-init` as the Docker entrypoint as a belt-and-suspenders measure

## How to Reproduce

Run several agent sessions. Check with `ps -eo stat,comm | grep Z | awk '{print $2}' | sort | uniq -c | sort -rn`.

## Actual Result

Zombie processes accumulate continuously. Never reaped.

## Expected Result

No zombie accumulation during normal operation.

## Acceptance Criteria

- [ ] Zombie processes do not accumulate during normal operation (including grandchildren from npm/cargo)
- [ ] `child.wait()` is called after `child.kill()` in all code paths in `claude_code.rs`
- [ ] Verified with `ps aux | grep '<defunct>'` after running multiple agent sessions
