Repository navigation
fix(server): closing a Claude session no longer leaves plugin MCP servers running - #19322
Conversation
The Claude CLI stops the MCP servers it starts, but not their children, so a plugin's `bun server.ts` outlived its `bun run` wrapper and the session, spinning on a pipe nobody read. The adapter now starts the CLI as its own process group leader and SIGKILLs the rest of the group when the CLI exits. Diagnosis from #19045. Fixes #3089. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — The PR changes the default POSIX Claude process lifecycle, including process-group termination and loss of CLI stderr diagnostics, and adds a targeted cleanup test. It also adds line-level and file-level static-analysis suppression directives, so human review is required. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
…vers running (pingdotgg#19322) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 3213a0c)
## What's Changed * chore(deps): Effect 4.0.4 and OpenCode 2.0.28, dropping the patches they made unnecessary by @juliusmarminge in pingdotgg/t3code#19213 * fix(server): a Claude 403 no longer tells you to log in again by @shivamhwp in pingdotgg/t3code#15872 * fix(server): persist only changed pull request links by @juliusmarminge in pingdotgg/t3code#19248 * fix(server): delegate_task explains that supervised runtime modes pause the child by @saphid in pingdotgg/t3code#14416 * fix(server): Claude subagent progress no longer re-stores the unchanged prompt by @Gigioxx in pingdotgg/t3code#18375 * fix(server): thread list reads no longer freeze the server on large databases by @t3dotgg in pingdotgg/t3code#19226 * perf(server): streamed events no longer rewrite the whole thread row by @Baker-Harrison in pingdotgg/t3code#18890 * docs: close PRs written by Gemini or Muse Wonder by @t3dotgg in pingdotgg/t3code#19286 * fix: update all no longer runs agents twice or loses background work by @t3dotgg in pingdotgg/t3code#19291 * fix(server): enforce one database owner and guard update rollback by @maria-rcks in pingdotgg/t3code#16102 * perf(server): reuse stored turn item positions by @tannerpolley in pingdotgg/t3code#19230 * perf(server): avoid quadratic resource history replay by @saphid in pingdotgg/t3code#18825 * fix(server): repair ownership UUID generation by @t3dotgg in pingdotgg/t3code#19298 * fix(client-runtime): slow config snapshots no longer drop working connections by @saphid in pingdotgg/t3code#14518 * fix(server): bound activity publishes so stalled responses release the worker by @saphid in pingdotgg/t3code#18830 * perf(shared): cached SQLite statements no longer hold large parameters by @t3dotgg in pingdotgg/t3code#19305 * fix(provider-cursor): Cursor text generation no longer leaks SQLite file handles on every call by @t3dotgg in pingdotgg/t3code#19310 * fix(server): make SQLite checkpoints durable on macOS by @t3dotgg in pingdotgg/t3code#19304 * perf(server): Codex plan streaming no longer commits every token by @t3dotgg in pingdotgg/t3code#19317 * fix(server): large file edits no longer store their full diff twice by @t3dotgg in pingdotgg/t3code#19316 * fix(web): settings save again after a stored value fails decode by @t3dotgg in pingdotgg/t3code#19312 * fix(server): HTML and Markdown attachments no longer fail OpenCode turns by @t3dotgg in pingdotgg/t3code#19319 * fix(server): worktree paths no longer vanish on git before 2.36 by @t3dotgg in pingdotgg/t3code#19315 * fix(acp): custom models now reach the agent instead of failing to open by @t3dotgg in pingdotgg/t3code#19313 * fix(server): Claude no longer shows unavailable when its health check can't run in $HOME by @t3dotgg in pingdotgg/t3code#19320 * fix(server): stalled OAuth token requests no longer block credential calls by @t3dotgg in pingdotgg/t3code#19321 * fix(server): steered Claude turns no longer undercount token usage by @t3dotgg in pingdotgg/t3code#19314 * fix(server): closing a Claude session no longer leaves plugin MCP servers running by @t3dotgg in pingdotgg/t3code#19322 * fix(client-runtime): T3 Connect link timeouts explain the relay 504 by @t3dotgg in pingdotgg/t3code#19329 * fix(web): settle shortcut moves to the next thread like the sidebar by @t3dotgg in pingdotgg/t3code#19328 * fix(acp): Copilot's default agent no longer disappears from the Agent menu by @t3dotgg in pingdotgg/t3code#19330 * perf(server): SQLite checkpoints no longer block the event loop by @t3dotgg in pingdotgg/t3code#19324 * fix(mobile): incompatible environments now say whether to update the app or the host by @t3dotgg in pingdotgg/t3code#19331 * fix(web): live reasoning stays scrolled to the newest text while it streams by @t3dotgg in pingdotgg/t3code#19334 * fix(server): T3 Connect no longer stays down after a network change by @t3dotgg in pingdotgg/t3code#19335 * fix(clients): host images say when the connection lacks file access by @t3dotgg in pingdotgg/t3code#19337 * fix(clients): a resumed subagent no longer moves the later turn's Worked for row by @t3dotgg in pingdotgg/t3code#19338 * fix: Claude and Codex no longer time out behind mise wrappers by @t3dotgg in pingdotgg/t3code#19340 * perf(server): turns no longer re-read merged PRs from GitHub by @t3dotgg in pingdotgg/t3code#19344 * docs(settings): explain that provider update checks also gate the model catalog by @fixfon in pingdotgg/t3code#18208 * fix(web): an unsaved citation comment survives a question or approval by @t3dotgg in pingdotgg/t3code#19350 * fix(server): changing Claude effort no longer fails while background agents run by @t3dotgg in pingdotgg/t3code#19341 * fix(server): service updates no longer fail on full disks or large databases by @t3dotgg in pingdotgg/t3code#19311 ## New Contributors * @Baker-Harrison made their first contribution in pingdotgg/t3code#18890 * @tannerpolley made their first contribution in pingdotgg/t3code#19230 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261014.3093...v0.0.46-nightly.20261014.3105 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261014.3105
## What's Changed * chore(deps): Effect 4.0.4 and OpenCode 2.0.28, dropping the patches they made unnecessary by @juliusmarminge in pingdotgg/t3code#19213 * fix(server): a Claude 403 no longer tells you to log in again by @shivamhwp in pingdotgg/t3code#15872 * fix(server): persist only changed pull request links by @juliusmarminge in pingdotgg/t3code#19248 * fix(server): delegate_task explains that supervised runtime modes pause the child by @saphid in pingdotgg/t3code#14416 * fix(server): Claude subagent progress no longer re-stores the unchanged prompt by @Gigioxx in pingdotgg/t3code#18375 * fix(server): thread list reads no longer freeze the server on large databases by @t3dotgg in pingdotgg/t3code#19226 * perf(server): streamed events no longer rewrite the whole thread row by @Baker-Harrison in pingdotgg/t3code#18890 * docs: close PRs written by Gemini or Muse Wonder by @t3dotgg in pingdotgg/t3code#19286 * fix: update all no longer runs agents twice or loses background work by @t3dotgg in pingdotgg/t3code#19291 * fix(server): enforce one database owner and guard update rollback by @maria-rcks in pingdotgg/t3code#16102 * perf(server): reuse stored turn item positions by @tannerpolley in pingdotgg/t3code#19230 * perf(server): avoid quadratic resource history replay by @saphid in pingdotgg/t3code#18825 * fix(server): repair ownership UUID generation by @t3dotgg in pingdotgg/t3code#19298 * fix(client-runtime): slow config snapshots no longer drop working connections by @saphid in pingdotgg/t3code#14518 * fix(server): bound activity publishes so stalled responses release the worker by @saphid in pingdotgg/t3code#18830 * perf(shared): cached SQLite statements no longer hold large parameters by @t3dotgg in pingdotgg/t3code#19305 * fix(provider-cursor): Cursor text generation no longer leaks SQLite file handles on every call by @t3dotgg in pingdotgg/t3code#19310 * fix(server): make SQLite checkpoints durable on macOS by @t3dotgg in pingdotgg/t3code#19304 * perf(server): Codex plan streaming no longer commits every token by @t3dotgg in pingdotgg/t3code#19317 * fix(server): large file edits no longer store their full diff twice by @t3dotgg in pingdotgg/t3code#19316 * fix(web): settings save again after a stored value fails decode by @t3dotgg in pingdotgg/t3code#19312 * fix(server): HTML and Markdown attachments no longer fail OpenCode turns by @t3dotgg in pingdotgg/t3code#19319 * fix(server): worktree paths no longer vanish on git before 2.36 by @t3dotgg in pingdotgg/t3code#19315 * fix(acp): custom models now reach the agent instead of failing to open by @t3dotgg in pingdotgg/t3code#19313 * fix(server): Claude no longer shows unavailable when its health check can't run in $HOME by @t3dotgg in pingdotgg/t3code#19320 * fix(server): stalled OAuth token requests no longer block credential calls by @t3dotgg in pingdotgg/t3code#19321 * fix(server): steered Claude turns no longer undercount token usage by @t3dotgg in pingdotgg/t3code#19314 * fix(server): closing a Claude session no longer leaves plugin MCP servers running by @t3dotgg in pingdotgg/t3code#19322 * fix(client-runtime): T3 Connect link timeouts explain the relay 504 by @t3dotgg in pingdotgg/t3code#19329 * fix(web): settle shortcut moves to the next thread like the sidebar by @t3dotgg in pingdotgg/t3code#19328 * fix(acp): Copilot's default agent no longer disappears from the Agent menu by @t3dotgg in pingdotgg/t3code#19330 * perf(server): SQLite checkpoints no longer block the event loop by @t3dotgg in pingdotgg/t3code#19324 * fix(mobile): incompatible environments now say whether to update the app or the host by @t3dotgg in pingdotgg/t3code#19331 * fix(web): live reasoning stays scrolled to the newest text while it streams by @t3dotgg in pingdotgg/t3code#19334 * fix(server): T3 Connect no longer stays down after a network change by @t3dotgg in pingdotgg/t3code#19335 * fix(clients): host images say when the connection lacks file access by @t3dotgg in pingdotgg/t3code#19337 * fix(clients): a resumed subagent no longer moves the later turn's Worked for row by @t3dotgg in pingdotgg/t3code#19338 * fix: Claude and Codex no longer time out behind mise wrappers by @t3dotgg in pingdotgg/t3code#19340 * perf(server): turns no longer re-read merged PRs from GitHub by @t3dotgg in pingdotgg/t3code#19344 * docs(settings): explain that provider update checks also gate the model catalog by @fixfon in pingdotgg/t3code#18208 * fix(web): an unsaved citation comment survives a question or approval by @t3dotgg in pingdotgg/t3code#19350 * fix(server): changing Claude effort no longer fails while background agents run by @t3dotgg in pingdotgg/t3code#19341 * fix(server): service updates no longer fail on full disks or large databases by @t3dotgg in pingdotgg/t3code#19311 ## New Contributors * @Baker-Harrison made their first contribution in pingdotgg/t3code#18890 * @tannerpolley made their first contribution in pingdotgg/t3code#19230 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261014.3093...v0.0.46-nightly.20261014.3105 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261014.3105
Closing or deleting a Claude session left plugin MCP servers running. The Claude CLI stops the MCP servers it starts, but not their children. So a plugin's
bun run startwrapper died and itsbun server.tskept running, writing to a pipe nobody read, and pinned a CPU core untilkill -9(#3089).Fix
On macOS and Linux, the adapter gives the SDK a
spawnClaudeCodeProcessthat starts the CLI as the leader of its own process group. When the CLI exits for any reason, the adapter SIGKILLs the rest of that group. The SDK's close path is unchanged (stdin EOF, then SIGTERM, then SIGKILL on the CLI).nohup sleep &job had its own group and survived close, both before and after this change.Tradeoff: the SDK reads stderr only from its own spawn, where it redacts credentials before it adds the tail to exit errors. This spawn sends stderr to
/dev/null, so on macOS and Linux a CLI crash logs only its exit code or signal. Copying the stderr without the SDK's redaction would put tokens in server logs. This text only reached server logs, not the UI.Proof
New test in
ClaudeAgentSdkQueryRunner.test.tsruns the real SDK against a fake CLI that leaves a child running. It fails onmain(the child never dies) and passes with the fix. It passed 15 times in a row. The child holds a FIFO open, so the test waits for end-of-file, not a poll.Real Claude CLI 2.1.296 through
layerQueryRunner, with an MCP server in the real plugin shape (bun run --cwd <plugin> --shell=bun --silent start→bun server.ts):bun server.tsprocess groupmainSame result through the Linux agent scope wrapper, with and without
systemd-run --user --scope.ClaudeAdapterV2.test.ts+ClaudeAgentSdkQueryRunner.test.ts: 255/255.apps/servertypecheck clean.Not run: macOS and Windows. The macOS path uses the same POSIX calls as Linux, and the Pi adapter already uses the same detach-and-group-kill pattern.
The diagnosis is from #19045 (closed). This code is new and written from scratch. Fixes #3089.
Reviewed with sol-loop: 2 rounds with GPT-6.1-Sol on high.
Model and harness: Claude Opus 5.5 in Claude Code via T3 Code.
🤖 Generated with Claude Code