Conversation
OpenCode treats a StructuredOutput call as the end of the request and never sends a tool result back, so the parked bridge was never resumed and its Claude Code process leaked, one per structured request. Close the bridge when nothing resumed it within a grace period (60s, override with OPENCODE_CLAUDE_STRUCTURED_OUTPUT_REAP_MS).
JosueGalRe
added a commit
to JosueGalRe/opencode-claude
that referenced
this pull request
Sep 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When OpenCode runs a structured-output request (a JSON-schema
format, as used by memory plugins like opencode-mem), it injects aStructuredOutputtool. It ends the request as soon as the model calls that tool, and it never sends a tool result back. Onclaude-code/*the bridge parks on that call, waiting for a result that never arrives. Its Claude Code process stays alive until the whole server restarts.We hit this with opencode-mem: every memory capture left one
claudeprocess behind. After a day we had dozens of idle CLIs underopencode serve, and the machine was swapping.Fix: when a turn parks and every pending tool is
StructuredOutput, schedule a reaper. If the same calls are still pending after the grace period, the reaper closes the bridge withdeleteBridge. The default grace period is 60s, adjustable withOPENCODE_CLAUDE_STRUCTURED_OUTPUT_REAP_MS. Turns parked on any other tool are not affected. If OpenCode does send a result within the grace period, the normal resume path runs and the reaper does nothing.Test:
test/structured-output-reap-regression.tsuses a mock SDK turn that calls a bridged tool through the real MCP server and then waits. AStructuredOutputpark gets closed; onmainit isn't, and the test fails. Abashpark stays open.bun test/smoke.tsandtsc --noEmitpass.Related but out of scope: other abandoned parks (a user starts a new session instead of answering) also stay alive until the server restarts. A general idle-park TTL might be worth adding separately.