actorEvery other family runs through the user's OpenCode service
spec:cc-agents.opencode-adapterPacks: none
Design: 5 design entries · 5 pinned declarations · no decisions
Findings: no errors, no warnings
specs/runner/opencode-adapter.sdp.md
3 open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The adapter is plugin/sidecar/adapters/opencode.mjs. It runs a turn as a session on the user's OpenCode background service and never starts a server of its own: subscription sign-ins live only in that service. Every call goes through opencode api, which finds the service, starts it when it is not running and authenticates itself, so the adapter creates no credential. Because that command cannot stream, a running turn reads its session's transcript once a second.
Intent
- A user who wants Kimi, Grok, GLM or another family as a Claude Code agent.
problem- OpenCode reaches many providers whose quota errors, retries and permissions behave differently, and its work can outlive the process that asked for it.
outcome- A turn runs a named model under a mode the session's permission rules enforce, ends only when OpenCode says the run is over, and leaves nothing running when the sidecar is gone.
value- One adapter serves every provider the user's OpenCode reaches, on the user's own sign-ins.
Open questions
- non-blocking ·
question.pollingCostline 25 · specs/runner/opencode-adapter.sdp.md:25· Reading the transcript once a second means text arrives a paragraph at a time and each read is a process; a streaming transport that needs a stored pairing credential was not adopted.Decider: ownerProvisional: Polling stays, and the adapter holds no credential. - non-blocking ·
question.fakeServiceline 28 · specs/runner/opencode-adapter.sdp.md:28· These behaviours are exercised against a fake OpenCode service; a real service is exercised only by the live scripts under tests/live, outside the graph and the gate.Decider: ownerProvisional: The unit evidence stands for the protocol; the live scripts remain the check against a real service. - non-blocking ·
question.yoloRefusedline 31 · specs/runner/opencode-adapter.sdp.md:31· OpenCode refuses the mode yolo, which the Relay-compatible job header accepts for every backend, so a Kimi, Grok or ZCode job that states yolo is refused by the check; no test pins that pairing.Decider: ownerProvisional: Described as built.
Behavior
rule.viaApiline 37 ·specs/runner/opencode-adapter.sdp.md:37- Every call to OpenCode goes through
opencode api, and the adapter makes no credential and reads no password.no example exercises it
rule.modelRequiredline 38 ·specs/runner/opencode-adapter.sdp.md:38- There is no default model: a check with none is refused, an unknown model or provider is refused with what exists, and so is a model that is not available or an effort outside the model's variants.
no example exercises it
rule.sessionPerAgentline 39 ·specs/runner/opencode-adapter.sdp.md:39- An agent is one OpenCode session, and a follow-up resumes it with the model and mode it asks for, after first ending what an earlier turn of that session left running.
no example exercises it
rule.modesAsPermissionsline 40 ·specs/runner/opencode-adapter.sdp.md:40- Read-only denies everything except reading, searching and fetching tools and skills, write allows everything, both refuse interactive questions, the last matching rule wins, and a permission question is refused for the session and its subagents.
no example exercises it
rule.capPerProviderline 41 ·specs/runner/opencode-adapter.sdp.md:41- The cap key is
opencode:<provider>with a default of three concurrent turns.no example exercises it
rule.streamsByTranscriptline 42 ·specs/runner/opencode-adapter.sdp.md:42- A running turn emits text as paragraphs arrive, one line for each tool call, the turn's usage and, at the end, the final text unchanged, including an answer over 64 KiB read while the sidecar is busy.
no example exercises it
rule.steerAfterPromptline 43 ·specs/runner/opencode-adapter.sdp.md:43- The prompt and every steer go into the session's inbox, the prompt first and steers one at a time after it, and a steer sent as the run ends is not lost.
no example exercises it
rule.endsWhenOpenCodeSaysSoline 44 ·specs/runner/opencode-adapter.sdp.md:44- The turn ends only when OpenCode says the run is over, lost contact with a silent service ends nothing, a stop OpenCode does not confirm leaves the turn open, and a service that never comes back fails it.
no example exercises it
rule.quotaIsQuotaline 45 ·specs/runner/opencode-adapter.sdp.md:45- An error OpenCode files as a rate limit but that is a quota, suspended-account or balance failure is classified as quota, and the turn stops at the first retry instead of waiting out ten.
no example exercises it
rule.workIsReapableline 46 ·specs/runner/opencode-adapter.sdp.md:46- Each turn keeps a lease file and a detached watcher that reaps the work when the sidecar is gone, and
reapcan be called from any session, stops the run and the shells OpenCode ran for it, and answers ended only when nothing remains.no example exercises it
rule.otherSessionsUntouchedline 47 ·specs/runner/opencode-adapter.sdp.md:47- After a crash the turn ends only the shells it recorded, never another session running the same command, and a follow-up never takes over a session that is running something no lease of ours names, failing explicitly instead.
no example exercises it
0 unkeyed rules.
Design
binaryline 51 ·specs/runner/opencode-adapter.sdp.md:51opencode, or the path inCC_AGENTS_OPENCODE_BIN.no citation recorded
capKeyline 52 ·specs/runner/opencode-adapter.sdp.md:52opencode:<provider>no citation recorded
modesline 53 ·specs/runner/opencode-adapter.sdp.md:53read-only,write.no citation recorded
needsModelline 54 ·specs/runner/opencode-adapter.sdp.md:54true, exported so the sidecar and the status text can say that an agent must name its model.no citation recorded
modelFormline 55 ·specs/runner/opencode-adapter.sdp.md:55provider/model, for examplexai/grok-4.3.no citation recorded
Verification
Verifier bindings
- test:cc-agents.opencode-suite · the OpenCode adapter against a fake OpenCode service · anchored · test anchor binding present ·
tests/adapters/opencode.test.mjs:4
Design view
Requirement drawing
- Declared verifying examples: no declared verifying example.
The diagram as text
- spec:cc-agents.opencode-adapter: Every other family runs through the user's OpenCode service · declared Spec
- spec:cc-agents.runner: Other model families run as real Claude Code agents · declared Spec
- impl:cc-agents.opencode: the OpenCode adapter: a session on the user's service, polled by transcript, reaped by lease · anchored code ·
plugin/sidecar/adapters/opencode.mjs:26 - test:cc-agents.opencode-suite: the OpenCode adapter against a fake OpenCode service · anchored test binding · binding present ·
tests/adapters/opencode.test.mjs:4 - spec:cc-agents.opencode-adapter refines spec:cc-agents.runner · declared
- impl:cc-agents.opencode satisfies spec:cc-agents.opencode-adapter · anchored
- test:cc-agents.opencode-suite verifies spec:cc-agents.opencode-adapter · anchored
Mermaid source
Copyable source; the Studio draws static SVG.
Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.
Decisions
No decision record named.
Runtime
impl:cc-agents.opencode· the OpenCode adapter: a session on the user's service, polled by transcript, reaped by lease ·plugin/sidecar/adapters/opencode.mjs:26Uses
None.
Runtime observation: not tracked.
Evidence
Runtime observation: not tracked.
Build attestations: not tracked.
Deployments: not tracked.
Bills of materials: not tracked.
Impact
The diagram as text
- spec:cc-agents.adapter-contract: One adapter module per harness, behind one contract
- spec:cc-agents.hq-links: The one tie between this repository's Specs and HQ's design
- spec:cc-agents.opencode-adapter: Every other family runs through the user's OpenCode service
- spec:cc-agents.runner: Other model families run as real Claude Code agents
- spec:cc-agents.opencode-adapter dependsOn spec:cc-agents.adapter-contract · declared — the OpenCode adapter is one implementation of the contract
- spec:cc-agents.opencode-adapter refines spec:cc-agents.runner · declared
- spec:cc-agents.hq-links dependsOn spec:cc-agents.opencode-adapter · declared — every other family occupies a lane beside Claude
Mermaid source
Copyable source; the Studio draws static SVG.
Preferred syntax: flowchart. Chosen syntax: labelled flowchart, preserving exact relations, claims and folds.
Rests on
- refines · spec:cc-agents.runner · stated defined, floor ready
- dependsOn · spec:cc-agents.adapter-contract · stated ready, floor ready
Rested on by
Distance 1
- spec:cc-agents.hq-links
Implementing units
None.
Referencing units
None.
Enabled verifiers: None
Packs: None
Relations
| Relation and direction | Other end | Claim | Reason | Exercised keys |
|---|---|---|---|---|
| dependsOn · outgoing | One adapter module per harness, behind one contractspec:cc-agents.adapter-contract · resolves | declared | the OpenCode adapter is one implementation of the contract | None |
| refines · outgoing | Other model families run as real Claude Code agentsspec:cc-agents.runner · resolves | declared | None | None |
| dependsOn · incoming | The one tie between this repository's Specs and HQ's designspec:cc-agents.hq-links · resolves | declared | every other family occupies a lane beside Claude | None |
Bindings
Implementation binding: present
impl:cc-agents.opencode· the OpenCode adapter: a session on the user's service, polled by transcript, reaped by lease ·plugin/sidecar/adapters/opencode.mjs:26
Design reference: none
Verifier binding: present
- test:cc-agents.opencode-suite · the OpenCode adapter against a fake OpenCode service · anchored ·
tests/adapters/opencode.test.mjs:4· test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
Composing (0)
Composing needs the script.