Repository navigation
[Bug]: CLI - a long-running command started by the agent can take the whole session down under memory pressure #542
Description
Product or interface
CLI - interactive TUI
Version
0.6.12
Platform
Linux
OS version and architecture
Ubuntu 24.04.3 LTS x86_64
Issue area
Tool call / permission / sandbox
Desktop log upload ID (optional)
No response
Steps to reproduce
- On Linux with cgroup v2 (systemd 255 or later), ask the agent to start a long-running,
memory-hungry process locally — a model server, a training run, a tokeniser over a large file. - Let the agent start it and keep working while it runs.
- Push the machine into memory pressure, so the user's session cgroup crosses the oomd threshold.
- Watch which scope gets killed.
The child is started as an ordinary child of the CLI, so it inherits the CLI's cgroup. On a machine with a desktop, once the user session's cgroup comes under memory pressure, systemd-oomd picks the largest scope in the session and kills it. The CLI's scope is the aggregate of everything the agent has started, so it is very often the largest one — and it gets killed, taking the session and every running job with it.
For reference, the machine I hit this on: Ubuntu 24.04.3 LTS, kernel 7.0.0-38-generic x86_64, systemd 255, cgroup v2, 46.75 GiB RAM, 2× RTX 3090, tmux 3.4, Node v24.19.0. The workload was a local GGUF inference server plus a LoRA fine-tune of a 4B model (Python 3.11.15, torch 2.4.0+cu121, transformers 5.5.0, trl 0.24.0, peft 0.21.0).
Expected and actual behavior
Expected: the long-running child is what gets killed under memory pressure, and the session survives.
Actual: the whole session is killed — the CLI, the shell, and every job the agent had started.
Nothing crashed, and this was not a kernel OOM. memory.events for the user slice reads:
oom 0
oom_kill 0
oom_group_kill 0so the kernel OOM killer never fired once. Every one of these kills was systemd-oomd, with the reason:
Killed .../tmux-spawn-<uuid>.scope due to memory pressure for
/user.slice/user-1000.slice/user@1000.service being 64.94% > 50.00% for > 20s
with reclaim activityI hit this repeatedly over six days: nine kills of the agent session, seven of them the session scope itself, 64 to 76 processes in a single kill. The relevant systemd configuration was:
user-1000.slice ManagedOOMMemoryPressure=auto MemoryHigh=infinity
user@1000.service ManagedOOMMemoryPressure=kill MemoryHigh=infinity
ManagedOOMMemoryPressureLimit=2147483648 # 2 GiB exemption floorThe 2 GiB exemption is the important part: a scope under 2 GiB is never a kill candidate. So a session whose own footprint is around a gigabyte is already safe — the only reason it was not safe is that the agent's heavy work was sitting inside it.
What was in the killed scope
The CLI process itself is small. On this host it ran at 884 MB after 40 minutes of a heavy session, and the scope it sat in reported 987 MiB of anon — well inside the 2 GiB exemption on its own. What pushed the scope over the line was the agent's child:
$ cat /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/<scope>/memory.stat
file 1554 MiB # page cache
anon 987 MiB # the CLI itself
kernel 40 MiBand the child was one of the things the agent had been asked to run — a local GGUF inference server, or a training job's tokenisation pass over a large corpus. A single kill took 64 to 76 processes with it.
For completeness, the nine kills over six days, with the slice's memory pressure at the moment of each one and the number of processes in the scope that was killed:
Oct 23 17:42 pressure 70.59% 66 processes
Oct 24 14:39 pressure 66.11% 76 processes
Oct 24 14:40 pressure 61.02% 2 processes (a GNOME notifier scope)
Oct 24 14:40 pressure 73.77% 2 processes (a GNOME notifier scope)
Oct 24 14:42 pressure 65.85% 15 processes
Oct 24 16:07 pressure 54.03% 9 processes
Oct 24 16:18 pressure 59.12% 33 processes
Oct 24 16:38 pressure 55.35% 33 processes
Oct 25 04:25 pressure 64.94% 64 processesSeven of the nine were the agent's own scope. The two that were not were GNOME notifier scopes that happened to be the largest at that instant — which is the point: oomd always takes the largest scope, and the agent's scope is reliably the largest because it contains everything the agent started.
Redacted error summary
# the two launch methods, same command, cgroup of the resulting process
setsid nohup <cmd> -> .../user@1000.service/tmux-spawn-<uuid>.scope
systemd-run --user --unit=probe <cmd> -> .../user@1000.service/app.slice/probe.service
# the first one is the same cgroup as the CLI, which is the whole problem
# the kill, as it appears in the journal
$ journalctl --user | grep "systemd-oomd killed"
tmux-spawn-<uuid>.scope: systemd-oomd killed 64 process(es) in this unit.What I would like
When the CLI starts a long-running or background process, put it in its own scope, for example:
systemd-run --user --scope --unit=<name> -- <cmd>so that
- the child is what gets killed under memory pressure, not the session, and
- the session's memory stays proportional to the conversation rather than to whatever workloads the agent happens to be running.
A user cannot do this for the agent's processes themselves — there is no way to influence the cgroup of a process the CLI spawned.
Before submitting
- I have searched existing issues.
- I have included my version and removed sensitive information.
Activity