mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 19:28:46 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The native Runner supervises the harness and tool processes for each run > - A launcher can put a memory limit on those processes > - When a process goes above the limit, the kernel kills it, and the agent sees only exit code 137 > - Any SIGKILL gives that code, so the agent cannot know the cause > - The agent can then run the same command again and fail again, and the people who read the run see no reason > - Only the launcher knows if a limit applies, so Runner must not assume one > - The kernel gives the limit and the kill count in cgroup files > - This pull request adds an optional `--task-memory-cgroup` flag that names the task's cgroup > - The benefit is that the agent knows the limit before it starts, the agent can confirm a kill, and the run shows each kill ## Linked Issues or Issue Description Related: #18730. That pull request lets the kernel kill large tool processes under Runner. This pull request tells the agent when that occurs because of a memory limit. **What happened?** A tool process on a VM with a 6 GiB task limit went above the limit. The kernel killed it, and Runner and the agent continued. The agent received exit code 137 and no other data. It ran the same type check in different forms, and the kernel killed it five times. **Expected behavior** The agent knows about the limit. It can confirm that the limit killed its process. It can then reduce the work or report a blocker. The run shows the kills. **Steps to reproduce** Start Runner under a memory limit. Start a tool process that goes above the limit. The agent and the run show only exit code 137. **Deployment mode** Native Runner on Linux, when the launcher gives the flag. ## What Changed - Add the optional `--task-memory-cgroup <path>` flag to `paperclip-runnerd`. Runner has no default value. - Runner reads the limit from `memory.max` on the parent of that cgroup. Runner reads the kill count from `oom_kill` in `memory.events` on that cgroup. - When a limit exists, add a note to the Codex and ACPX instructions at launch. The note gives the limit, the meaning of exit code 137, the paths of the files to read, and what to do after a kill. - Record a `provider.notice.recorded` warning when `oom_kill` increases. Runner watches `memory.events` for the kernel's change signal, so an idle Runner does not read it. Runner takes the starting count before it executes commands. It does not report kills from before it started. - Without the flag, or when the parent has no limit, the instructions do not change. Without the flag, Runner does not read the files and records no notice. - Add unit and integration tests. ## Verification Tests ran in `rust:1-bookworm` on Linux arm64: - `cargo fmt --all` - `cargo clippy -p paperclip-runner-core --bin paperclip-runnerd --lib` has no warnings in the new module. - `cargo test -p paperclip-runner-core --lib -- task_memory restores_settled_session_for_explicit_run_attachment_only`: The task memory tests pass. The second filter covers the note in the ACPX session configuration. - `cargo test -p paperclip-runner-core --test task_memory`: this test uses a separate process. It checks that no note and no monitor exist before the flag value is set. It then checks the note in the Codex `thread/start` and `thread/resume` requests. The tests use files in a temporary directory that have the format of the cgroup files. In a separate test on a real kernel, a kill above a limit on a parent cgroup increased `oom_kill` in the cgroup of the killed process. It did not increase `oom_kill` in the other child. On a real kernel, an unprivileged process that watched `memory.events` through a read-only mount received the change signal at the kill. I did not run the complete suite locally. CI runs it. I did not run this with a real launcher or on a real VM. The notice payload has the same fields as other Runner notices, but no test sends it through the control plane. ## Risks - The note adds text to each provider's instructions when the launcher gives the flag. If the text makes the instructions go above the provider limit, Runner does not add the note. - The task must be able to read the cgroup files. If it cannot, the note is absent or the agent cannot read the paths, and the run continues as it does now. - A kill while the run is not ready gives a notice later. A kill after Runner records 64 notices gives no notice. The agent can still read the file. - This pull request does not send a message into an active turn, because most ACPX profiles do not support this. The agent must read the file to confirm a kill. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass: targeted tests only, as listed above - [x] I have added or updated tests where applicable - [ ] I have updated relevant documentation to reflect my changes: not applicable, because no document lists the `paperclip-runnerd` flags - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>