Why
PR #129 bounds leaked process/browser lifetime at terminal turn cleanup, but it deliberately does not kill resources while a valid turn is still running. A long-running turn can still accumulate several explicitly named agent-browser sessions or leave a memory-heavy tool child alive after the command item reports completion.
Observed on one 6 GiB production cgroup:
memory.events: oom=3, oom_kill=1, with thousands of max hits
- concurrent Chromium trees were the dominant live footprint
- multiple custom browser sessions were created by one chat while its inherited per-chat session already existed
- a naive whole-binary Python scan continued CPU-heavy after the parent shell/tool wrapper ended
No chat content or credentials are needed to reproduce or monitor this class.
Needed invariants
- Prefer/reuse the inherited
AGENT_BROWSER_SESSION; make an explicit second session opt-in and bounded per chat.
- Expose cgroup
memory.current, memory.max, memory.events, browser-session count, and owned descendant count on the operator health surface.
- Before starting discretionary heavy work (new browser tree, app build, additional agent turn), apply a pressure gate with hysteresis rather than waiting for kernel OOM.
- Attribute every live browser daemon and command descendant to a chat/turn; terminal/Stop cleanup must be idempotent and identity-keyed.
- Decide an active-turn policy for a command that has reported completion while descendants remain (kill by default, or require an explicit background-process lease with TTL).
- Do not kill a successor turn's resources or shared platform services.
Suggested verification
- adversarial command spawns a TERM-resistant child, exits its shell, and proves the child is reclaimed at the chosen boundary
- one chat creates multiple custom browser sessions; the configured cap/reuse path prevents unbounded Chrome trees
- two concurrent chats prove cleanup/admission is attribution-safe
- pressure-gate tests cover enter/high-water, remain-gated, low-water recovery, and unavailable-cgroup fallback
- Stop, graceful restart, OOM recovery, and normal terminal completion converge to no owned descendants
Related: #129.
Why
PR #129 bounds leaked process/browser lifetime at terminal turn cleanup, but it deliberately does not kill resources while a valid turn is still running. A long-running turn can still accumulate several explicitly named
agent-browsersessions or leave a memory-heavy tool child alive after the command item reports completion.Observed on one 6 GiB production cgroup:
memory.events:oom=3,oom_kill=1, with thousands ofmaxhitsNo chat content or credentials are needed to reproduce or monitor this class.
Needed invariants
AGENT_BROWSER_SESSION; make an explicit second session opt-in and bounded per chat.memory.current,memory.max,memory.events, browser-session count, and owned descendant count on the operator health surface.Suggested verification
Related: #129.