Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate. (Closest: macOS desktop main process hangs under swap pressure from uncapped agent children on a 16 GB Mac (0.1.0) #24048 is the same symptom on macOS; Design: report Linux pressure stalls and make shared-provider recovery scope explicit #25918 is a closed design issue about reporting Linux pressure stalls; fix(server): agents run in their own systemd scopes so an OOM kill spares the server #17662 introduced the agents-slice limits. None covers protecting the Linux server's own memory.)
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Summary
On a 16 GB Linux host that also runs other services, the T3 server (t3code.service) freezes for minutes, once for two hours, while agent sessions run test suites. The server is not killed and nothing is logged except event-loop-stalls.ndjson. Every freeze shows the server's resident set shrinking while major page faults explode: the server is being swapped out, because it has no memory protection and the agents slice is allowed to push the host into reclaim.
Verified facts
Source (main, apps/server/src/process/agentScope.ts, apps/server/src/cloud/bootService.ts):
agentSliceMemoryLimits(total)sets the agents slice toMemoryHigh = total - 6 GiB,MemoryMax = total - 4 GiB. The comment says this leaves about 6 GB free "so the server, sshd, and tailscaled keep working". The formula assumes nothing else on the host uses that 6 GB.t3code.servicehasCPUWeight=1000,IOWeight=1000,ManagedOOMPreference=avoid. It has noMemoryLow/MemoryMin, so nothing stops the kernel from reclaiming the server's pages first or at the same rate as the agents'.- The agents slice has no CPU bound.
On the affected host (T3 0.1.2, 15.5 GiB RAM, 8 cores, 4 GiB swap file + 4 GiB zram added later):
- Agents slice before any local change:
MemoryHigh=10241781760,MemoryMax=12513174528(exactly the formula above). Other consumers on the same host: dockerd and buildkitd (about 1.4 GB RSS together), 14 small Postgres/Redis containers (about 1.7 GB), self-hosted GitHub runners. So "6 GB free" is used up before the agents hitMemoryHigh. ~/.t3/userdata/logs/event-loop-stalls.ndjsonhas 153 records between 2026-10-17 and 2026-10-27; 75 are 10 s or longer. The long ones, all with the server'srssMbat 230-430 MB (it is being paged out, not growing):
time delayMaxMs majorPageFaults rssMb
2026-10-20T22:04:23Z 238847 54478 413
2026-10-20T22:57:48Z 3110704 252683 397
2026-10-22T22:49:52Z 1352988 93415 370
2026-10-25T22:23:33Z 852625 702538 304
2026-10-26T05:38:50Z 7300444 6509327 275
2026-10-26T19:02:58Z 772631 456677 313
2026-10-27T14:06:17Z 50103 63107 304
- No kernel OOM kill in any of these windows (
oom_kill 0, noKilled processin the journal). The user rebooted the machine by hand after the freezes; the journal shows cleansystemd-rebootshutdowns, not crashes. - At the time of the report, 8 agent sessions were running
tsc,vitest,biome,go buildanddocker composein separate worktrees. Load average was 29 on 8 cores;/proc/pressure/cpu some avg10was 96%. - A local cap I had put on the whole
user-1000.slice(not T3's doing) made it worse, because the server shares that slice; that cap has been removed and is not the explanation for the earlier freezes (the rows before 2026-10-25 predate any local cap).
Hypotheses (not verified)
- Under sustained reclaim in the agents slice, the kernel also evicts the server's pages because they have no
memory.lowprotection; the server then page-faults on every event-loop turn.MemoryLowont3code.serviceshould keep its working set resident. The host mounts cgroup2 withmemory_recursiveprot, so a leafMemoryLowis effective without setting it on parent slices. - A fixed
total - 6 GiBthreshold is too loose on hosts that run other memory consumers. A limit based on what is actually available, or an override, would avoid it. - A default CPU bound on the agents slice would keep a build wave from starving sshd and the server's I/O threads; load 29 on 8 cores is the second symptom users notice.
Steps to reproduce
Not deterministic; the freezes follow bursts of parallel agent work.
- Linux host with 16 GB RAM, swap enabled, other services using about 3-4 GB (docker + a few containers).
- Run 6-8 agent sessions in separate git worktrees of a TypeScript monorepo, each running
tsc,vitest,biomeand a docker build at once. - Watch
~/.t3/userdata/logs/event-loop-stalls.ndjson:delayMaxMsclimbs to tens of seconds or more withmajorPageFaultsin the tens of thousands, the UI stops responding, and/proc/pressure/memoryshows sustainedsome.
Expected behavior
The server stays responsive while the agents slice is under pressure: agents are reclaimed and throttled first, and a stall that does happen is reported with its cause.
Actual behavior
The server is swapped out together with the agents, freezes for 1 minute to 2 hours, and recovers only after the load ends or the user restarts it.
Impact
Major degradation or frequent failure. It happens several times a day on this host, and the only recovery is a manual restart or reboot.
Suggested fix, in order of cost
- Add
MemoryLow=1G(or a size scaled to the server's RSS) to thet3code.serviceunit inbootService.ts. One line; testable with the reproduction above by comparingdelayMaxMsandmajorPageFaultswith and without it. - Let users override the agents slice limits (env or settings) and document the
total - 6 GiBassumption. - Optional default
CPUQuotafor the agents slice, or document the drop-in~/.config/systemd/user/app-t3code-agents.slice.d/. - Extend the stall record with
/proc/pressure/memoryand the agents slice'smemory.eventshighcount so a pressure stall is distinguishable from a code stall (follows Design: report Linux pressure stalls and make shared-provider recovery scope explicit #25918).
Version or commit
t3 v0.1.2 (server), code read at main as of 2026-10-27.
Environment
Ubuntu 24.04.5, kernel 6.8.0-147-generic, systemd 255, cgroup2 with memory_recursiveprot, Intel i5-9300HF 8 threads, 15.5 GiB RAM, swap 4 GiB file + 4 GiB zram, vm.swappiness=60. Claude Code 2.1.311 agents (Opus and Sonnet), 6-8 concurrent sessions.
Workaround
Applied locally, so far verified only by a few minutes of lower load:
# ~/.config/systemd/user/app-t3code-agents.slice.d/60-memory.conf
[Slice]
MemoryHigh=7G
MemoryMax=8G
MemorySwapMax=2G
# ~/.config/systemd/user/t3code.service.d/50-memory-low.conf
[Service]
MemoryLow=1G
then systemctl --user daemon-reload. After this, t3code.service reports memory.low=1073741824. I will add a comment here with the stall log after a few days under the same workload.
Acceptance criteria
- With the reproduction above and fix 1, no
delayMaxMsabove 10 s inevent-loop-stalls.ndjsonover a comparable 24-hour run, or a before/after capture showingmajorPageFaultsper stall dropping by an order of magnitude. - The stall record (fix 4) shows which cgroup was under reclaim.
Activity
seregatipich commentedon Oct 27, 2026
Cross-references for triage: #24048 (same symptom on macOS), #25918 (closed design issue on reporting Linux pressure stalls), #17662 (introduced the agents-slice limits).
satyalyadav commentedon Oct 28, 2026
Possibly related evidence from a smaller WSL2 host. I’ve seen repeated thread stalls where T3 continues showing “running” without apparent progress.
Environment: Windows desktop and WSL2 server on
0.1.4-nightly.20261028.3841, Linux kernel6.18.54.1-microsoft-standard-WSL2, Node26.12.1, 6.7 GiB RAM and 2 GiB swap.Read-only investigation on October 28 found:
3.2Gmemory and1.9Gswap before exiting at20:59:09 UTC.3.3–3.6Gand swap peaks up to1.9G. These are historical peaks, not necessarily simultaneous usage.This supports memory pressure as a possible contributor, but does not establish that the T3 server itself was swapped out. No timestamp-matched server stall trace or deterministic reproduction was captured.
This installation also differs from the original report: the WSL T3 server runs in
/non-systemd, rather thant3code.service, so the proposed service drop-in does not directly apply.No T3 source patches, database edits, or service configuration changes were made during triage.
Investigated with Codex,
gpt-6.1-sol, using the T3 triage playbook.JamesOBrien2 commentedon Oct 29, 2026
Note
🤖 gpt-6.1-sol responding on behalf of JamesOBrien2
Could a maintainer triage this report and confirm the scope of a focused fix: best-effort MemoryLow for the background service, plus local stall diagnostics identifying host/server/agent pressure?
I have an implementation and a bounded Debian/systemd/cgroup-v2 comparison. With adequate ancestor budgets, the controlled working set stayed resident; without protection it incurred about 16,400 major faults. These are probe faults, not T3 process faults. The original minutes-long freeze and the stated 24-hour/per-stall acceptance criteria remain unverified, so this is evidence for the protection mechanism rather than a claim that the issue is resolved.
t3dotgg commentedon Oct 31, 2026
Note
🤖 Claude Opus 5.5 responding on behalf of Theo
Closing: this is covered by #27239 and #27176, which landed. Reopen if an important part is still missing.