actorOne adapter module per harness, behind one contract
spec:cc-agents.adapter-contractPacks: none
Design: 4 design entries · 4 pinned declarations · no decisions
Findings: no errors, no warnings
specs/runner/adapter-contract.sdp.md
3 open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
An adapter is one module, plugin/sidecar/adapters/<harness>.mjs; the harness name is also the agent type's name. The sidecar imports it by that name and knows nothing else about the harness. The prose of the contract lives in plugin/sidecar/adapters/CONTRACT.md; this Spec holds what the code does, and the questions below hold where the two differ.
Intent
- The author of an adapter for a new harness, and the sidecar that drives it.
problem- Harnesses differ in how they start, steer, stop, fail and leave work behind, and the sidecar must stay free of every one of them.
outcome- A harness is added by writing one module that exports a few functions and emits a closed set of neutral events.
value- The mod and the sidecar never change when a harness is added or fixed.
Open questions
- non-blocking ·
question.capKeyMeaningline 22 · specs/runner/adapter-contract.sdp.md:22· CONTRACT.md says the cap key names the account a turn spends, while the code keys Codex by one machine-wide bucket named codexand OpenCode byopencode:<provider>, which does not identify distinct accounts.Decider: ownerProvisional: The key is whatevercapForreturns; nothing establishes credential identity. - non-blocking ·
question.extraArgumentsline 25 · specs/runner/adapter-contract.sdp.md:25· The sidecar also passes optionstocheckfor a job andoptionsandlogto the turn constructor, which CONTRACT.md does not list; OpenCode ignores them.Decider: delegatedProvisional: The contract grows anoptionsargument described by the Relay-compatible job type. - non-blocking ·
question.olderDescriptionline 28 · specs/runner/adapter-contract.sdp.md:28· Early reports describe a four-method adapter without preparation and reaping; the current contract and code add both.Decider: delegatedProvisional: Only the current contract is described here.
Contract
ruleline 34 ·specs/runner/adapter-contract.sdp.md:34- An adapter module exports
capFor,checkand one function namedcreate<Harness>Turn, and may exportreapandneedsModel, and the sidecar finds the constructor by its name. ruleline 35 ·specs/runner/adapter-contract.sdp.md:35- The function
capFortakes the model and returns a cap key and a default number of concurrent turns, which the user's caps option can replace. ruleline 36 ·specs/runner/adapter-contract.sdp.md:36- The function
checktakes the working directory, model, effort and mode before anything starts, and answers the values the turn will run with, or a refusal that says what would work. ruleline 37 ·specs/runner/adapter-contract.sdp.md:37- A mode the harness cannot enforce is refused by
check, so no turn runs under a mode that is not enforced. ruleline 38 ·specs/runner/adapter-contract.sdp.md:38- The turn constructor returns
prepare,run,steer,interruptandkill, andprepareruns first and names the turn's work as plain JSON before anything executable has been submitted. ruleline 39 ·specs/runner/adapter-contract.sdp.md:39- A turn that the harness accepts emits
turnonce, and before it onlystatuslines about setting up the thread; after it come any oftext,tool,status,messageandusage. A turn that fails, is refused or is cancelled before the harness accepts it emits noturn. Every turn emitsfinalonce, thenendonce with a status of completed, interrupted or failed, and nothing afterend. ruleline 40 ·specs/runner/adapter-contract.sdp.md:40- The
finalevent carries the answer exactly as the harness produced it, andusageis the turn's own, not the thread's. ruleline 41 ·specs/runner/adapter-contract.sdp.md:41- A steer resolves once the harness accepted the text, rejects when it cannot, and rejects after an interrupt has begun.
ruleline 42 ·specs/runner/adapter-contract.sdp.md:42- An interrupt resolves once
endwas emitted, or when the adapter's own confirmation wait runs out with the turn still open, and theendfollows only when termination is confirmed. The wait is the adapter's, in phases, and has no single deadline: OpenCode first waits for the turn's startup submission to settle and then confirms for ten seconds, and Codex waits up to three seconds for the stop request, one and a half for the end and eight for its process group, 12.5 seconds in all. ruleline 43 ·specs/runner/adapter-contract.sdp.md:43- The
endevent reports the outcome to the agent and does not free capacity, which comes back only when the turn's work is confirmed ended, by the work's process group or by the adapter'sreap. ruleline 44 ·specs/runner/adapter-contract.sdp.md:44- An error is null or carries a kind of capacity, rate-limit, quota, auth or other, a message and whether trying later could help, and the sidecar never replays a turn.
11 unkeyed rules.
Design
eventKindsline 48 ·specs/runner/adapter-contract.sdp.md:48turn,text,tool,status,message,usage,final,end.no citation recorded
errorKindsline 49 ·specs/runner/adapter-contract.sdp.md:49capacity,rate-limit,quota,auth,other.no citation recorded
workShapesline 50 ·specs/runner/adapter-contract.sdp.md:50{ pgid }for a process group that a guard leads, and any other plain JSON thatreap(work)understands.no citation recorded
turnConstructorline 51 ·specs/runner/adapter-contract.sdp.md:51create<Harness>Turn({ cwd, model, effort, mode, threadId, prompt, emit })returning{ prepare, run, steer, interrupt, kill }.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 - test:cc-agents.sidecar-suite · the sidecar, the Codex adapter, the slots and the guard against a fake Codex app-server · anchored · test anchor binding present ·
tests/sidecar.test.mjs:4
Design view
Requirement drawing
- Declared verifying examples: no declared verifying example.
The diagram as text
- spec:cc-agents.adapter-contract: One adapter module per harness, behind one contract · declared Spec
- spec:cc-agents.runner: Other model families run as real Claude Code agents · declared Spec
- impl:cc-agents.codex: the Codex adapter: one guarded app-server per turn, sandbox modes, MCP off · anchored code ·
plugin/sidecar/adapters/codex.mjs:15 - 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 - impl:cc-agents.sidecar: the per-session sidecar: owns each harness turn, its events and its slot, and drives every adapter through the contract · anchored code ·
plugin/sidecar/server.mjs:12 - test:cc-agents.opencode-suite: the OpenCode adapter against a fake OpenCode service · anchored test binding · binding present ·
tests/adapters/opencode.test.mjs:4 - test:cc-agents.sidecar-suite: the sidecar, the Codex adapter, the slots and the guard against a fake Codex app-server · anchored test binding · binding present ·
tests/sidecar.test.mjs:4 - spec:cc-agents.adapter-contract refines spec:cc-agents.runner · declared
- impl:cc-agents.codex satisfies spec:cc-agents.adapter-contract · anchored
- impl:cc-agents.opencode satisfies spec:cc-agents.adapter-contract · anchored
- impl:cc-agents.sidecar satisfies spec:cc-agents.adapter-contract · anchored
- test:cc-agents.opencode-suite verifies spec:cc-agents.adapter-contract · anchored
- test:cc-agents.sidecar-suite verifies spec:cc-agents.adapter-contract · 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.codex· the Codex adapter: one guarded app-server per turn, sandbox modes, MCP off ·plugin/sidecar/adapters/codex.mjs:15Uses
None.
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.
impl:cc-agents.sidecar· the per-session sidecar: owns each harness turn, its events and its slot, and drives every adapter through the contract ·plugin/sidecar/server.mjs:12Uses
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.codex-adapter: GPT runs through the user's Codex, one app-server per turn
- 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.sidecar: One sidecar per Claude session owns the session's harness turns
- spec:cc-agents.adapter-contract refines spec:cc-agents.runner · declared
- spec:cc-agents.codex-adapter dependsOn spec:cc-agents.adapter-contract · declared — the Codex adapter is one implementation of the contract
- spec:cc-agents.opencode-adapter dependsOn spec:cc-agents.adapter-contract · declared — the OpenCode adapter is one implementation of the contract
- spec:cc-agents.runner dependsOn spec:cc-agents.adapter-contract · declared — the seam that keeps every harness out of the other two layers
- spec:cc-agents.sidecar dependsOn spec:cc-agents.adapter-contract · declared — the sidecar drives every harness only through the adapter contract
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
Rested on by
Distance 1
- spec:cc-agents.codex-adapter
Implementing units
impl:cc-agents.codex·plugin/sidecar/adapters/codex.mjs:15
Referencing units
None.
Enabled verifiers: test:cc-agents.sidecar-suite
Packs: None
- spec:cc-agents.opencode-adapter
Implementing units
impl:cc-agents.opencode·plugin/sidecar/adapters/opencode.mjs:26
Referencing units
None.
Enabled verifiers: test:cc-agents.opencode-suite
Packs: None
- spec:cc-agents.runner
Implementing units
None.
Referencing units
None.
Enabled verifiers: None
Packs: None
- spec:cc-agents.sidecar
Implementing units
impl:cc-agents.launch·plugin/sidecar/launch.mjs:7impl:cc-agents.sidecar·plugin/sidecar/server.mjs:12
Referencing units
None.
Enabled verifiers: test:cc-agents.sidecar-suite
Packs: None
Distance 2
- spec:cc-agents.cross-session-slots
Implementing units
impl:cc-agents.sidecar·plugin/sidecar/server.mjs:12impl:cc-agents.slots·plugin/sidecar/slots.mjs:16
Referencing units
None.
Enabled verifiers: test:cc-agents.sidecar-suite
Packs: None
- spec:cc-agents.exact-answer
Implementing units
impl:cc-agents.mod·plugin/hooks/register.js:9
Referencing units
None.
Enabled verifiers: test:cc-agents.mod-suite
Packs: None
- spec:cc-agents.hq-links
Implementing units
None.
Referencing units
None.
Enabled verifiers: None
Packs: None
- spec:cc-agents.installation
Implementing units
None.
Referencing units
impl:cc-agents.harness-options·plugin/hooks/harnesses.js:5
Enabled verifiers: None
Packs: None
- spec:cc-agents.machine-guard
Implementing units
impl:cc-agents.machine·plugin/sidecar/machine.mjs:20
Referencing units
impl:cc-agents.sidecar·plugin/sidecar/server.mjs:12
Enabled verifiers: test:cc-agents.machine-suite, test:cc-agents.sidecar-suite
Packs: None
- spec:cc-agents.mod-layer
Implementing units
impl:cc-agents.mod·plugin/hooks/register.js:9
Referencing units
None.
Enabled verifiers: test:cc-agents.mod-suite
Packs: None
- spec:cc-agents.model-templates
Implementing units
impl:cc-agents.harness-options·plugin/hooks/harnesses.js:5impl:cc-agents.mod·plugin/hooks/register.js:9
Referencing units
impl:cc-agents.sync-templates·scripts/sync-templates.mjs:10
Enabled verifiers: test:cc-agents.mod-suite
Packs: None
- spec:cc-agents.pane
Implementing units
impl:cc-agents.harness-options·plugin/hooks/harnesses.js:5impl:cc-agents.pane·plugin/hooks/pane.js:13
Referencing units
None.
Enabled verifiers: test:cc-agents.mod-suite, test:cc-agents.pane-suite
Packs: None
- spec:cc-agents.relay-job-type
Implementing units
impl:cc-agents.mod·plugin/hooks/register.js:9impl:cc-agents.relay-header·plugin/sidecar/relay-header.mjs:9impl:cc-agents.sidecar·plugin/sidecar/server.mjs:12
Referencing units
None.
Enabled verifiers: test:cc-agents.mod-suite, test:cc-agents.sidecar-suite
Packs: None
- spec:cc-agents.steering-and-stop
Implementing units
impl:cc-agents.mod·plugin/hooks/register.js:9impl:cc-agents.sidecar·plugin/sidecar/server.mjs:12
Referencing units
None.
Enabled verifiers: test:cc-agents.mod-suite, test:cc-agents.sidecar-suite
Packs: None
- spec:cc-agents.work-containment
Implementing units
impl:cc-agents.groups·plugin/sidecar/groups.mjs:13impl:cc-agents.guard·plugin/sidecar/guard.mjs:16
Referencing units
None.
Enabled verifiers: test:cc-agents.sidecar-suite
Packs: None
Relations
| Relation and direction | Other end | Claim | Reason | Exercised keys |
|---|---|---|---|---|
| refines · outgoing | Other model families run as real Claude Code agentsspec:cc-agents.runner · resolves | declared | None | None |
| dependsOn · incoming | GPT runs through the user's Codex, one app-server per turnspec:cc-agents.codex-adapter · resolves | declared | the Codex adapter is one implementation of the contract | None |
| dependsOn · incoming | Every other family runs through the user's OpenCode servicespec:cc-agents.opencode-adapter · resolves | declared | the OpenCode adapter is one implementation of the contract | None |
| dependsOn · incoming | Other model families run as real Claude Code agentsspec:cc-agents.runner · resolves | declared | the seam that keeps every harness out of the other two layers | None |
| dependsOn · incoming | One sidecar per Claude session owns the session's harness turnsspec:cc-agents.sidecar · resolves | declared | the sidecar drives every harness only through the adapter contract | None |
Bindings
Implementation binding: present
impl:cc-agents.codex· the Codex adapter: one guarded app-server per turn, sandbox modes, MCP off ·plugin/sidecar/adapters/codex.mjs:15impl:cc-agents.opencode· the OpenCode adapter: a session on the user's service, polled by transcript, reaped by lease ·plugin/sidecar/adapters/opencode.mjs:26impl:cc-agents.sidecar· the per-session sidecar: owns each harness turn, its events and its slot, and drives every adapter through the contract ·plugin/sidecar/server.mjs:12
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 - test:cc-agents.sidecar-suite · the sidecar, the Codex adapter, the slots and the guard against a fake Codex app-server · anchored ·
tests/sidecar.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.