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
Child processes (gh, claude -p) are left running after the app exits #12507
Version: 0.0.42 (t3code-bin on Arch / Omarchy), Linux, Wayland.
After closing T3 Code, subprocesses it spawned keep running, reparented to systemd --user.
I found ten of them on my machine: gh pr list --head ... --json ..., gh pr view <n> --repo ... --json ..., and claude -p --output-format json --json-schema {...} --model claude-haiku-4-5 ... (the title generation call). Some were two days old. They were still inside the app's app-com.t3tools.T3Code-<pid>.scope cgroup while the main T3 Code process was long gone, and the cgroup only got released once I killed them by hand:
app-com.t3tools.T3Code-3219097.scope: Consumed 4d 21h 57min CPU time over 1d 4h 26min wall clock time
app-com.t3tools.T3Code-2913047.scope: Consumed 21h 38min CPU time over 7h 39min wall clock time
No crash was involved: coredumpctl shows no T3 Code crash in that window, so this was a normal quit.
In my case each child got stuck in a loop caused by a wrapper script in my PATH (not T3 Code's fault), which is why they each burned about 12% of a core for days. But the leak itself happens regardless of that: anything gh or claude blocks on (network, auth prompt, a hung helper) will outlive the app.
Expected: the app kills, or at least signals, its child processes on quit, and/or spawns these helper calls with a timeout.
Thanks for the write-up — the leftover gh / claude -p processes after a normal quit look like a real bug.
What we found
Those commands match in-tree helper spawns:
gh pr list --head … / gh pr view … from apps/server/src/sourceControl/GitHubCli.ts via VcsProcess / apps/server/src/processRunner.ts
claude -p --output-format json --json-schema … from apps/server/src/textGeneration/ClaudeTextGeneration.ts (thread title generation)
On Linux, Effect’s Node spawner defaults to detached: true, so each helper is its own process group. Desktop quit SIGTERMs the backend and escalates to SIGKILL after ~2s (DesktopBackendManager). That does not signal those detached groups. If the backend is hard-killed before its child-scope finalizers run, gh / claude stay in app-com.t3tools.T3Code-<pid>.scope and keep the cgroup alive — which matches what you saw.
There are timeouts (gh 30s, Claude 180s), but neither path sets forceKillAfter. Scope cleanup sends SIGTERM, waits one second, and never SIGKILLs. A wrapper that ignores SIGTERM (or anything else that stays up) can leak while the app is still running, then outlive quit. Your wrapper explains the 12% CPU spin; the leak itself does not depend on it.
Fixed by #12513, which just merged. On a normal quit or a request timeout, helper processes like gh and claude -p are now force-killed one second after SIGTERM, including their descendants. A hard crash or SIGKILL of the backend is still out of scope.
Activity
juliusmarminge commentedon Sep 18, 2026
Thanks for the write-up — the leftover
gh/claude -pprocesses after a normal quit look like a real bug.What we found
Those commands match in-tree helper spawns:
gh pr list --head …/gh pr view …fromapps/server/src/sourceControl/GitHubCli.tsviaVcsProcess/apps/server/src/processRunner.tsclaude -p --output-format json --json-schema …fromapps/server/src/textGeneration/ClaudeTextGeneration.ts(thread title generation)On Linux, Effect’s Node spawner defaults to
detached: true, so each helper is its own process group. Desktop quit SIGTERMs the backend and escalates to SIGKILL after ~2s (DesktopBackendManager). That does not signal those detached groups. If the backend is hard-killed before its child-scope finalizers run,gh/claudestay inapp-com.t3tools.T3Code-<pid>.scopeand keep the cgroup alive — which matches what you saw.There are timeouts (
gh30s, Claude 180s), but neither path setsforceKillAfter. Scope cleanup sends SIGTERM, waits one second, and never SIGKILLs. A wrapper that ignores SIGTERM (or anything else that stays up) can leak while the app is still running, then outlive quit. Your wrapper explains the 12% CPU spin; the leak itself does not depend on it.Not a duplicate of
bun server.tsnot killed on conversation closegit.exe/tasklist) while the app is still runningNo open PR covers Linux app-quit process-tree cleanup for these helpers. #6318 was Windows-only and did not land.
Next step
Treat this as process-tree hygiene on quit (and on timeout):
detached: falseso they die with the backend process group.forceKillAfteronProcessRunnerand Claude text-generation so a stuck child is SIGKILL’d.Agree this is not your wrapper’s fault. Leaving this open as an accepted bug.
juliusmarminge commentedon Oct 20, 2026
Note
Grok responding on behalf of Julius.
Fixed by #12513, which just merged. On a normal quit or a request timeout, helper processes like
ghandclaude -pare now force-killed one second after SIGTERM, including their descendants. A hard crash or SIGKILL of the backend is still out of scope.