actorA cap on concurrent turns holds across every Claude session on the machine
spec:cc-agents.cross-session-slotsPacks: none
Design: 4 design entries · 2 pinned declarations · no decisions
Findings: no errors, no warnings
specs/runner/cross-session-slots.sdp.md
1 open question and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The slots are plugin/sidecar/slots.mjs, used by the sidecar. For each cap key a directory holds, for each index below the cap, a lock file and a record. A turn holds an index by holding an exclusive lock on its lock file through a small perl process, because Node has no flock; the kernel drops the lock when the holder dies, even by SIGKILL.
Intent
- Every sidecar on one machine.
problem- Several Claude sessions start turns of the same account at once, and a cap kept inside one process cannot hold, nor can capacity be handed back while a dead holder's work still runs.
outcome- At most the cap of turns of one key run on the machine, and capacity returns only when the turn's work is confirmed gone.
value- A busy machine and a provider's concurrency limit are protected from several sessions each trusting its own count.
Open questions
- non-blocking ·
question.harnessWideCapline 25 · specs/runner/cross-session-slots.sdp.md:25· The caps option also accepts a bare harness name, which the code applies to every key of that harness not named itself; no test pins that fallback.Decider: delegatedProvisional: As built.
Behavior
rule.capHoldsline 31 ·specs/runner/cross-session-slots.sdp.md:31- At most the cap's number of turns of one cap key run on the machine across all sessions and sidecars, and two sidecars taking the last slot at once, one of them stalled, never both get it.
no example exercises it
rule.lockDiesWithHolderline 32 ·specs/runner/cross-session-slots.sdp.md:32- A slot is held by an exclusive lock that the kernel releases when its holder dies, and a paused holder keeps its slot, so nobody can take it from a live holder.
no example exercises it
rule.holderByStartline 33 ·specs/runner/cross-session-slots.sdp.md:33- A holder is told apart by its process id and its process start time, so a slot whose id now belongs to another process is not held.
no example exercises it
rule.releaseWhenEndedline 34 ·specs/runner/cross-session-slots.sdp.md:34- A turn's end reports its outcome to the agent and frees no capacity: the slot is released only when the turn's work is confirmed ended, and a sidecar that stops mid-turn leaves the slot taken until the work has ended.
no example exercises it
rule.orphansAreReapedline 35 ·specs/runner/cross-session-slots.sdp.md:35- A record whose holder is dead and whose work still runs counts against the cap, and a reaper, holding the index's lock so that only one acts, ends or confirms the work and then marks the record released, asking the adapter when the work is not a process group.
no example exercises it
rule.reserveAtSpawnline 36 ·specs/runner/cross-session-slots.sdp.md:36- A spawn reserves a slot before its agent starts, a spawn stopped while it waits takes none, an agent stopped before its first turn gives its slot back, and a reservation no turn binds within a minute is released without being taken back from a turn that got its slot.
no example exercises it
rule.capsOptionline 37 ·specs/runner/cross-session-slots.sdp.md:37- The caps option is a list such as
codex=2, opencode:xai=1, and a key not named takes the default its adapter gives.no example exercises it
0 unkeyed rules.
Design
slotFilesline 41 ·specs/runner/cross-session-slots.sdp.md:41<state>/slots/<cap key>/slot-<i>.lockandslot-<i>.json.no citation recorded
recordFieldsline 42 ·specs/runner/cross-session-slots.sdp.md:42- The holder's session, agent, harness, model, effort, mode, process id and start, the turn's
work, the cap, and a released flag. reservationTtlline 43 ·specs/runner/cross-session-slots.sdp.md:43- 60 seconds, changed for tests by
CC_AGENTS_RESERVATION_MS. slotStatesline 44 ·specs/runner/cross-session-slots.sdp.md:44heldfor a live holder andorphanedfor a dead holder whose work has not ended.no citation recorded
Verification
Verifier bindings
- 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.cross-session-slots: A cap on concurrent turns holds across every Claude session on the machine · declared Spec
- spec:cc-agents.runner: Other model families run as real Claude Code agents · declared Spec
- 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 - impl:cc-agents.slots: the machine-wide cap on concurrent turns, held with OS locks that die with their holder · anchored code ·
plugin/sidecar/slots.mjs:16 - 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.cross-session-slots refines spec:cc-agents.runner · declared
- impl:cc-agents.sidecar satisfies spec:cc-agents.cross-session-slots · anchored
- impl:cc-agents.slots satisfies spec:cc-agents.cross-session-slots · anchored
- test:cc-agents.sidecar-suite verifies spec:cc-agents.cross-session-slots · 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.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.
impl:cc-agents.slots· the machine-wide cap on concurrent turns, held with OS locks that die with their holder ·plugin/sidecar/slots.mjs:16Uses
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.cross-session-slots: A cap on concurrent turns holds across every Claude session on the machine
- 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.work-containment: A guard ends the groups a harness turn started and it has seen, even when the sidecar is killed
- spec:cc-agents.cross-session-slots dependsOn spec:cc-agents.work-containment · declared — a slot is free only once the work recorded in it has ended
- spec:cc-agents.cross-session-slots refines spec:cc-agents.runner · declared
- spec:cc-agents.sidecar dependsOn spec:cc-agents.cross-session-slots · declared — a turn starts only with a slot of its cap key
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.work-containment · stated ready, floor ready
Rested on by
Distance 1
- 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.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.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.runner
Implementing units
None.
Referencing units
None.
Enabled verifiers: None
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
Distance 3
- spec:cc-agents.adapter-contract
Implementing units
impl:cc-agents.codex·plugin/sidecar/adapters/codex.mjs:15impl:cc-agents.opencode·plugin/sidecar/adapters/opencode.mjs:26impl:cc-agents.sidecar·plugin/sidecar/server.mjs:12
Referencing units
None.
Enabled verifiers: test:cc-agents.opencode-suite, test:cc-agents.sidecar-suite
Packs: None
- 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.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.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.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.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 |
|---|---|---|---|---|
| dependsOn · outgoing | A guard ends the groups a harness turn started and it has seen, even when the sidecar is killedspec:cc-agents.work-containment · resolves | declared | a slot is free only once the work recorded in it has ended | None |
| refines · outgoing | Other model families run as real Claude Code agentsspec:cc-agents.runner · resolves | declared | None | None |
| dependsOn · incoming | One sidecar per Claude session owns the session's harness turnsspec:cc-agents.sidecar · resolves | declared | a turn starts only with a slot of its cap key | None |
Bindings
Implementation binding: present
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:12impl:cc-agents.slots· the machine-wide cap on concurrent turns, held with OS locks that die with their holder ·plugin/sidecar/slots.mjs:16
Design reference: none
Verifier binding: present
- 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.