The OpenCode harness manages a child OpenCode server process, validating its binary version, configuring model providers, and translating between QM's internal tool and message formats and OpenCode's wire protocol. Session tokens are HMAC-SHA-256 digests of the session ID, and Bearer token comparison uses constant-time comparison to prevent timing attacks.
opencode-harness.ts pins the OpenCode binary version it expects at OPENCODE_VERSION = "1.17.18", refusing to run against a different build.[1] The OpenCode harness waits up to OPENCODE_STARTUP_TIMEOUT_MS = 90_000 ms (90 seconds) for the OpenCode server process to become ready before failing a turn.[1] After OPENCODE_IDLE_WAIT_MS = 30 * 60_000 ms (30 minutes) of inactivity, the harness kills the idle OpenCode child process.[1]
openCodeHarnessConfigOptions maps the flat Config object into OpenCodeHarnessOptions, propagating modelId as defaultModelId, anthropicApiKey as apiKey, and openaiApiKey directly.[1] resolveCustomProviders on OpenCodeHarnessOptions is called once when the OpenCode server starts; registrations made while a server is already running only take effect on the next server start.[1]
modelRef resolves a model id string into a { providerID, modelID } pair; custom-registered model ids (which may contain slashes, e.g. bedrock/claude-x) are matched first against the custom-provider registry to avoid mis-routing on the slash.[1] When no slash or custom registration is found, modelRef falls back to provider "openai" for ids starting with "gpt-" and to "anthropic" for everything else.[1]
bridgeToolName renames three core pi-tools when they are surfaced to the OpenCode bridge: execute → workspace_execute, read → workspace_read, write → workspace_write; all other names pass through unchanged.[1] replayMessages converts the internal tape history into OpenCode's message wire format, pairing each tool-call part with its immediately-following toolResult entry and consuming it from the source array (i++) to avoid double-processing.[1] stripDataUrls removes data: URI parts from OpenCode messages before storing or forwarding them, replacing each removed part with { omitted: true } to preserve the part slot.[1]
Session tokens for the OpenCode bridge are HMAC-SHA-256 digests of the session ID, keyed with the shared secret and encoded as base64url.[1] Bearer token comparison in the bridge uses timingSafeEqual to prevent timing-based secret leakage.[1] The HTTP bridge rejects request bodies larger than 16 MiB with an error and destroys the request socket.[1]
Sources