Files
PaperClipAI/packages/paperclip-runner/runner
Nicky LeachandClaude Opus 5.5 2e37c73c05 Tell the agent about the launcher's memory limit (#18801)
## 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>
2026-11-03 09:02:19 -08:00
..