Spec Studio

A guard ends the groups a harness turn started and it has seen, even when the sidecar is killed

spec:cc-agents.work-containmentUse Case / Behavior · featureready floor ready

Packs: none

Design: 3 design entries · 3 pinned declarations · no decisions

Findings: no errors, no warnings

specs/runner/work-containment.sdp.md

1 open question and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.

The guard is plugin/sidecar/guard.mjs, with the process-group records in plugin/sidecar/groups.mjs. It runs one harness process in a process group it leads, sharing its stdio with the sidecar, so the group's id stays unique while anything of the work runs.

Intent
actor
The sidecar and the slot that records a turn's work.
problem
A harness runs commands in process groups of its own, and a sidecar killed outright cannot clean up after itself.
outcome
When the harness process exits or the sidecar is gone, the guard's own group and every other group the guard has seen are ended, and the work is known to have ended only when those groups no longer exist.
value
A stopped or crashed agent leaves nothing running in a group the guard knew, and capacity is not handed back while any such group still exists.

Open questions

  • non-blocking · question.detachedBeforeScan line 22 · specs/runner/work-containment.sdp.md:22 · A process that leaves the guard's group and is reparented to the system between two scans is in no record, so the guard neither ends it nor counts it. Should the guarantee grow to cover it?Decider: ownerProvisional: No. The guarantee covers the guard's group and the groups a scan recorded; a descendant that detaches and is orphaned within one scan interval, two seconds by default, escapes cleanup and accounting. Covering it needs a code change, such as a process-tree watcher or an operating-system containment feature, and none is made here.
Behavior
rule.guardEndsWork line 28 · specs/runner/work-containment.sdp.md:28
When the command exits or the sidecar that started the guard is gone, even after a SIGKILL, the guard sends SIGTERM, then SIGKILL to what ignores it, ends its own group and the groups it has recorded, the own group last, and exits only once those groups are gone.

no example exercises it

rule.nestedGroups line 29 · specs/runner/work-containment.sdp.md:29
The guard looks at its process tree every few seconds and records each other process group that a descendant is in, so commands a harness runs in groups of their own are ended too. A descendant that leaves the tree before a scan reaches it is not recorded (see #detachedBeforeScan).

no example exercises it

rule.recordsOutliveGuard line 30 · specs/runner/work-containment.sdp.md:30
The record of those groups lives in a file named for the guard, with each group's leader start time, so a guard killed with its sidecar leaves the groups counted as running and the reaper ends them.

no example exercises it

rule.stoppedFirst line 31 · specs/runner/work-containment.sdp.md:31
An interrupt the harness does not confirm ends the turn only once the processes of its group and of the groups recorded are gone.

no example exercises it

rule.liveSidecarFinishesTheJob line 32 · specs/runner/work-containment.sdp.md:32
A guard killed under a live sidecar frees the turn's slot only once the sidecar has ended the commands the guard had recorded.

no example exercises it

0 unkeyed rules.

Design
invocation line 36 · specs/runner/work-containment.sdp.md:36
node guard.mjs <command> [args...]

no citation recorded

recordFile line 37 · specs/runner/work-containment.sdp.md:37
<state>/guards/<guard pid>.json, holding the guard's pid and start and each recorded group's id and leader start.

no citation recorded

environment line 38 · specs/runner/work-containment.sdp.md:38
CC_AGENTS_GUARD_DIR names the records' folder, CC_AGENTS_GUARD_GRACE_MS and CC_AGENTS_GUARD_SCAN_MS set the grace and the scan interval.

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.
Requirement drawing for spec:cc-agents.work-containment
The diagram as text
  • spec:cc-agents.work-containment: A guard ends the groups a harness turn started and it has seen, even when the sidecar is killed · declared Spec
  • spec:cc-agents.runner: Other model families run as real Claude Code agents · declared Spec
  • impl:cc-agents.groups: records the process groups of a guarded turn and tells whether its work still runs · anchored code · plugin/sidecar/groups.mjs:13
  • impl:cc-agents.guard: runs one harness process in a group it leads and ends everything the turn started · anchored code · plugin/sidecar/guard.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.work-containment refines spec:cc-agents.runner · declared
  • impl:cc-agents.groups satisfies spec:cc-agents.work-containment · anchored
  • impl:cc-agents.guard satisfies spec:cc-agents.work-containment · anchored
  • test:cc-agents.sidecar-suite verifies spec:cc-agents.work-containment · 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.groups · records the process groups of a guarded turn and tells whether its work still runs · plugin/sidecar/groups.mjs:13

    Uses

    None.

  • impl:cc-agents.guard · runs one harness process in a group it leads and ends everything the turn started · plugin/sidecar/guard.mjs:16

    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.work-containment
The diagram as text
  • spec:cc-agents.codex-adapter: GPT runs through the user's Codex, one app-server per turn
  • 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.steering-and-stop: A message reaches the running turn at once, and a stop ends the harness turn
  • 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.work-containment refines spec:cc-agents.runner · declared
  • spec:cc-agents.codex-adapter dependsOn spec:cc-agents.work-containment · declared — the Codex app-server runs under the guard, and its process group is the turn's work
  • 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.steering-and-stop dependsOn spec:cc-agents.work-containment · declared — what an interrupted turn leaves running is bounded by the groups the guard recorded
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

  • 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.cross-session-slots

    Implementing units

    • impl:cc-agents.sidecar · plugin/sidecar/server.mjs:12
    • impl:cc-agents.slots · plugin/sidecar/slots.mjs:16

    Referencing units

    None.

    Enabled verifiers: test:cc-agents.sidecar-suite

    Packs: None

  • spec:cc-agents.steering-and-stop

    Implementing units

    • impl:cc-agents.mod · plugin/hooks/register.js:9
    • impl: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 2

  • spec:cc-agents.hq-links

    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:7
    • impl:cc-agents.sidecar · plugin/sidecar/server.mjs:12

    Referencing units

    None.

    Enabled verifiers: test:cc-agents.sidecar-suite

    Packs: None

Distance 3

  • 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:5
    • impl: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:9
    • impl:cc-agents.relay-header · plugin/sidecar/relay-header.mjs:9
    • impl: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

Distance 4

  • spec:cc-agents.adapter-contract

    Implementing units

    • impl:cc-agents.codex · plugin/sidecar/adapters/codex.mjs:15
    • impl:cc-agents.opencode · plugin/sidecar/adapters/opencode.mjs:26
    • impl: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.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.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:5
    • impl: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

Relations

Relation and directionOther endClaimReasonExercised keys
refines · outgoingOther model families run as real Claude Code agents
spec:cc-agents.runner · resolves
declaredNoneNone
dependsOn · incomingGPT runs through the user's Codex, one app-server per turn
spec:cc-agents.codex-adapter · resolves
declaredthe Codex app-server runs under the guard, and its process group is the turn's workNone
dependsOn · incomingA cap on concurrent turns holds across every Claude session on the machine
spec:cc-agents.cross-session-slots · resolves
declareda slot is free only once the work recorded in it has endedNone
dependsOn · incomingA message reaches the running turn at once, and a stop ends the harness turn
spec:cc-agents.steering-and-stop · resolves
declaredwhat an interrupted turn leaves running is bounded by the groups the guard recordedNone

Bindings

Implementation binding: present

  • impl:cc-agents.groups · records the process groups of a guarded turn and tells whether its work still runs · plugin/sidecar/groups.mjs:13
  • impl:cc-agents.guard · runs one harness process in a group it leads and ends everything the turn started · plugin/sidecar/guard.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.