You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Resource awareness, per-agent budgets and enforcement: stop a runaway agent and everything it spawned / 资源感知、按 agent 额度与强制执行:停掉失控的 agent 及其派生的全部进程
#11006
[Agent terminated by resource limit]
Process tree exceeded memory limit 16 GB (peak 19.4 GB). Terminated to protect the host.
Reduce concurrency or batch size and retry.
This is not a report about DeepSeek Harness's own memory use or leaks. It is about what the model does with the machine. Once an agent can run commands, it can start work with no resource ceiling: unbounded parallelism, tight retry loops, fork storms, runaway output, background processes it never cleans up. As far as I can tell, DeepSeek Harness has per-call timeouts and output caps but no notion of how much of the host an agent is using, which agent is using it, or when to stop one.
Reports already filed against anthropics/claude-code, each a different resource, all the same missing layer:
Today the only ceiling on a command is its timeout. A timeout bounds time, not memory, CPU, processes or disk, and it does not reliably kill the process tree. The OS's own response is blunt: on macOS everything is charged to the app that started it, so under memory pressure the only option offered is to force-quit that app, which ends every session, including agents that did nothing wrong.
OOM is simply the incident that made this visible. The same gap shows up with CPU, process count, disk and swap.
Proposal
A resource supervisor inside the harness, working per agent (main session, each sub-agent, each background task, each MCP server it started), not per machine.
Harness (main process)
│ spawns
▼
┌─────────────────────────────────────────────────────────┐
│ Resource supervisor: samples each agent's process tree │
│ memory footprint · CPU · process count · fds · │
│ disk written / free space · host swap and pressure │
└───────────┬───────────────────────────┬──────────────────┘
within budget over hard limit
│ │
agent keeps running 1. terminate that agent's whole tree
(warnings at soft limits) 2. main process and other agents untouched
3. report to the user and to the model
Awareness (all resources, per agent). Sample the shell plus all descendants every couple of seconds. macOS: proc_pid_rusage (ri_phys_footprint). Windows: Job Object per agent. Linux: cgroup v2 / procfs. Track memory, CPU, process count, open files, disk written and free space on the working volume, plus host-level swap and pressure so one agent's share can be judged against the whole.
Budgets with tiers. User-configurable soft (warn) and hard limits per resource, with defaults, optionally scaled to a fraction of the machine. Example: "limits": {"memory": {"warn": "8G", "kill": "16G"}, "processes": {"kill": 500}, "diskFreeMin": "15G"}. Sub-agents can inherit or be given smaller budgets than the parent.
The model knows its budget. Surface remaining headroom and warnings to the agent (tool result or system reminder), so it can choose smaller batches or lower concurrency before it hits a wall, instead of learning from a crash.
Act before the OS does. If host pressure rises and no single agent has crossed its own line, warn the user with the top consumers named; if it keeps rising toward the OS force-quit panel, stop the largest agent rather than let the whole app be killed.
Clean failure. Restore terminal modes (cursor, mouse reporting, bracketed paste, alternate screen) after a forced stop, keep the session resumable, and return a structured result to the model instead of a bare exit code 137/144:
[Agent terminated by resource limit]
Process tree exceeded memory limit 16 GB (peak 19.4 GB). Terminated to protect the host.
Reduce concurrency or batch size and retry.
The supervisor must not become a leak. Fixed-size history (ring buffers), bounded overhead.
Alternatives considered
Step or turn limits: do not help when one command is the problem.
Containers: heavy for local native toolchains, and an OOM-killed container loses the shell and its state.
External pkill / systemd-run -p MemoryMax: Linux-only, or blind to which agent caused it, and leaves terminal modes corrupted.
Context
I maintain Polter, a terminal app. You run Claude Code and other agent CLIs in its tabs the way you would in any terminal; on top of that, one agent can supervise the others through a shared task panel and group chat. We hit this twice in one day on a 32 GB Mac, with Claude Code and other agent CLIs running in Polter's tabs: a script written by the agent did frame-by-frame OCR with multiprocessing.Pool(7) on a ~5,400-frame screen recording. The system's jetsam report listed seven Python workers at roughly 22 GB each (about 160 GB combined; that counter likely includes compressed pages), while the terminal app itself was under 1 GB. macOS showed the "out of application memory" panel, whose only option was to force-quit the terminal app, which ended every tab and agent in it, including ones unrelated to the script. We never found which line made each worker grow; the point is that nothing between "the model ran a command" and "the OS kills the app" had a ceiling.
Polter now samples each terminal's process tree every two seconds, lets the supervising agent set memory and process limits per worker, and on breach stops only that worker like a ctrl+c, resets the terminal modes and tells the supervisor. It started with memory because that was the incident; the design is meant to take more resources. Happy to share what we learned about the sampling edge cases.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
(English version below / 英文版在下方)
问题
这不是在报 DeepSeek Harness 自身的内存占用或泄漏,而是关于模型拿机器做了什么。agent 一旦能执行命令,就可能在没有任何资源上限的情况下开工:无节制的并行、紧循环重试、fork 风暴、失控的输出、从不清理的后台进程。据我所见,DeepSeek Harness 有单次调用的超时和输出上限,但不知道某个 agent 占用了多少主机资源、是哪个 agent 在占用、以及什么时候该停掉它。
anthropics/claude-code 里已经有这类报告,每条是不同的资源,缺的是同一层:
pytest,一个有 bug 的测试无限分配内存,超时的调用留下孤儿进程;一个进程达到 144.9 GB,总和超过 500 GB,128 GB 的 Mac 因看门狗超时 panic。wc的 Bash 调用把主机 fork 炸了;触达每用户进程数上限,三个不相关的claude会话一起死掉。find/grep进程树;Defender 扫描它们打开的文件,占住 16 核机器约一半算力好几个小时,模型对此毫不知情。目前对一条命令唯一的上限就是超时。超时只限制时间,不限制内存、CPU、进程数或磁盘,也不能可靠地杀掉整棵进程树。操作系统自己的应对很生硬:在 macOS 上,所有占用都记在启动它的那个应用头上,内存吃紧时只给一个选项:强退这个应用,于是所有会话一起结束,包括什么都没做错的 agent。
OOM 只是让问题变得可见的那次事故。同样的缺口在 CPU、进程数、磁盘和 swap 上都会出现。
建议
在 harness 内部加一个资源监督层,按 agent 工作(主会话、每个子 agent、每个后台任务、它启动的每个 MCP server),不是按机器。
proc_pid_rusage(ri_phys_footprint,不要用 RSS,因为内存压缩会把膨胀的页从 RSS 里藏起来)。Windows:每个 agent 一个 Job Object。Linux:cgroup v2 / procfs。统计内存、CPU、进程数、打开文件数、工作卷上的磁盘写入量和剩余空间,再加上整机的 swap 和内存压力,以便拿单个 agent 的份额和整体对比。"limits": {"memory": {"warn": "8G", "kill": "16G"}, "processes": {"kill": 500}, "diskFreeMin": "15G"}。子 agent 继承父级额度或获得更小的额度,这样扇出不会把占用成倍放大。考虑过的替代方案
pkill/systemd-run -p MemoryMax:只适用于 Linux,或者看不出是哪个 agent 造成的,还会让终端模式处于损坏状态。背景
我维护 Polter,一个终端应用。你可以像在任何终端里一样,在它的标签页里运行 Claude Code 和其他 agent CLI;在此之上,一个 agent 可以通过共享的任务面板和群聊监管其他 agent。我们在一天之内在一台 32 GB 的 Mac 上遇到两次这种情况,当时 Polter 的标签页里跑着 Claude Code 和其他 agent CLI:agent 写的一个脚本对一段约 5400 帧的录屏做逐帧文字识别,用了
multiprocessing.Pool(7)。系统的 jetsam 报告列出七个 Python worker,每个约 22 GB(合计约 160 GB;这个计数很可能包含压缩页),而终端应用本身不到 1 GB。macOS 弹出「应用程序内存不足」面板,唯一的选项是强退终端应用,于是其中所有标签页和 agent 一起结束,包括与那个脚本无关的。我们始终没查到每个 worker 具体是哪一行代码让内存涨起来的;重点在于,从「模型运行了一条命令」到「操作系统杀掉整个应用」之间,没有任何一层有上限。Polter 现在每两秒采样一次每个终端的进程树,让监管 agent 为每个 worker 设置内存和进程数上限,越线时只像 ctrl+c 一样停掉那个 worker,复位终端模式并通知监管者。它从内存做起,是因为那次事故是内存;设计上是要接入更多资源的。很乐意分享我们在采样和终端复位方面踩过的边界情况。
English
Problem
This is not a report about DeepSeek Harness's own memory use or leaks. It is about what the model does with the machine. Once an agent can run commands, it can start work with no resource ceiling: unbounded parallelism, tight retry loops, fork storms, runaway output, background processes it never cleans up. As far as I can tell, DeepSeek Harness has per-call timeouts and output caps but no notion of how much of the host an agent is using, which agent is using it, or when to stop one.
Reports already filed against anthropics/claude-code, each a different resource, all the same missing layer:
pytest; a buggy test allocated without bound and timed-out calls left orphans; one process reached 144.9 GB, the sum exceeded 500 GB, and a 128 GB Mac panicked on the watchdog.wcfork-bombed the host; the per-user process limit was hit and three unrelatedclaudesessions died.find/greptrees running on Windows; Defender scanning their file opens held about half of a 16-core machine for hours, invisible to the model.Today the only ceiling on a command is its timeout. A timeout bounds time, not memory, CPU, processes or disk, and it does not reliably kill the process tree. The OS's own response is blunt: on macOS everything is charged to the app that started it, so under memory pressure the only option offered is to force-quit that app, which ends every session, including agents that did nothing wrong.
OOM is simply the incident that made this visible. The same gap shows up with CPU, process count, disk and swap.
Proposal
A resource supervisor inside the harness, working per agent (main session, each sub-agent, each background task, each MCP server it started), not per machine.
Awareness (all resources, per agent). Sample the shell plus all descendants every couple of seconds. macOS:
proc_pid_rusage(ri_phys_footprint). Windows: Job Object per agent. Linux: cgroup v2 / procfs. Track memory, CPU, process count, open files, disk written and free space on the working volume, plus host-level swap and pressure so one agent's share can be judged against the whole.Budgets with tiers. User-configurable soft (warn) and hard limits per resource, with defaults, optionally scaled to a fraction of the machine. Example:
"limits": {"memory": {"warn": "8G", "kill": "16G"}, "processes": {"kill": 500}, "diskFreeMin": "15G"}. Sub-agents can inherit or be given smaller budgets than the parent.The model knows its budget. Surface remaining headroom and warnings to the agent (tool result or system reminder), so it can choose smaller batches or lower concurrency before it hits a wall, instead of learning from a crash.
Enforcement by the main program, not the OS. When an agent crosses its hard limit, the harness itself stops that agent: SIGTERM to its process group, SIGKILL after a grace period (Job Object on Windows), covering orphans and background shells it started. The main process and sibling agents keep running. Timeouts do the same: kill the tree instead of backgrounding it (Bash tool timeout does not terminate the child process tree — orphaned processes keep running indefinitely anthropics/claude-code#90672).
Act before the OS does. If host pressure rises and no single agent has crossed its own line, warn the user with the top consumers named; if it keeps rising toward the OS force-quit panel, stop the largest agent rather than let the whole app be killed.
Clean failure. Restore terminal modes (cursor, mouse reporting, bracketed paste, alternate screen) after a forced stop, keep the session resumable, and return a structured result to the model instead of a bare exit code 137/144:
The supervisor must not become a leak. Fixed-size history (ring buffers), bounded overhead.
Alternatives considered
pkill/systemd-run -p MemoryMax: Linux-only, or blind to which agent caused it, and leaves terminal modes corrupted.Context
I maintain Polter, a terminal app. You run Claude Code and other agent CLIs in its tabs the way you would in any terminal; on top of that, one agent can supervise the others through a shared task panel and group chat. We hit this twice in one day on a 32 GB Mac, with Claude Code and other agent CLIs running in Polter's tabs: a script written by the agent did frame-by-frame OCR with
multiprocessing.Pool(7)on a ~5,400-frame screen recording. The system's jetsam report listed seven Python workers at roughly 22 GB each (about 160 GB combined; that counter likely includes compressed pages), while the terminal app itself was under 1 GB. macOS showed the "out of application memory" panel, whose only option was to force-quit the terminal app, which ended every tab and agent in it, including ones unrelated to the script. We never found which line made each worker grow; the point is that nothing between "the model ran a command" and "the OS kills the app" had a ceiling.Polter now samples each terminal's process tree every two seconds, lets the supervising agent set memory and process limits per worker, and on breach stops only that worker like a ctrl+c, resets the terminal modes and tells the supervisor. It started with memory because that was the incident; the design is meant to take more resources. Happy to share what we learned about the sampling edge cases.
All reactions