Spec Studio

Every other family runs through the user's OpenCode service

spec:cc-agents.opencode-adapterUse Case / Behavior · featureready floor ready

Packs: 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
actor
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.pollingCost line 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.fakeService line 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.yoloRefused line 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.viaApi line 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.modelRequired line 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.sessionPerAgent line 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.modesAsPermissions line 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.capPerProvider line 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.streamsByTranscript line 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.steerAfterPrompt line 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.endsWhenOpenCodeSaysSo line 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.quotaIsQuota line 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.workIsReapable line 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 reap can 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.otherSessionsUntouched line 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
binary line 51 · specs/runner/opencode-adapter.sdp.md:51
opencode, or the path in CC_AGENTS_OPENCODE_BIN.

no citation recorded

capKey line 52 · specs/runner/opencode-adapter.sdp.md:52
opencode:<provider>

no citation recorded

modes line 53 · specs/runner/opencode-adapter.sdp.md:53
read-only, write.

no citation recorded

needsModel line 54 · specs/runner/opencode-adapter.sdp.md:54
true, exported so the sidecar and the status text can say that an agent must name its model.

no citation recorded

modelForm line 55 · specs/runner/opencode-adapter.sdp.md:55
provider/model, for example xai/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.
Requirement drawing for spec:cc-agents.opencode-adapter
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:26

    Uses

    None.

Runtime observation: not tracked.

Evidence

Runtime observation: not tracked.

Build attestations: not tracked.

Deployments: not tracked.

Bills of materials: not tracked.

Impact
Relations of spec:cc-agents.opencode-adapter
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

Rested on by

Distance 1

Relations

Relation and directionOther endClaimReasonExercised keys
dependsOn · outgoingOne adapter module per harness, behind one contract
spec:cc-agents.adapter-contract · resolves
declaredthe OpenCode adapter is one implementation of the contractNone
refines · outgoingOther model families run as real Claude Code agents
spec:cc-agents.runner · resolves
declaredNoneNone
dependsOn · incomingThe one tie between this repository's Specs and HQ's design
spec:cc-agents.hq-links · resolves
declaredevery other family occupies a lane beside ClaudeNone

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.