* feat: consolidate offline eval and operator workflows
Compose the retained framework, operator skill, roadmap and cleanup ranges on current main. Preserve current release dependencies and keep candidate execution disabled pending OS containment. Repair draft/DOCX behavior, obligation uniqueness, trusted send and audience guidance, runner provenance and eval diagnostics.
Source-PR: 2930 0abe3727d2b500c6e4830bdeb47ed67cae3f4785
Source-PR: 2931 992b49c44ed872def49675b791168b8fcd091df6
Source-PR: 2932 4a193dd13041cb7a6bebf4d2e910a0cd32bcc797
Source-PR: 2933 59cdfe500a91949ba1415f1edd7279620f21e804
Source-Base: ca185ef5f7
* fix: repair foundation CI and update js-yaml
* fix: reconcile pending-delete capsule locks after close
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
9.2 KiB
Session Adapter Contract
This document defines the canonical ECC session snapshot contract for
ecc.session.v1.
The contract is implemented in
scripts/lib/session-adapters/canonical-session.js. This document is the
normative specification for adapters and consumers.
Purpose
ECC has multiple session sources:
- tmux-orchestrated worktree sessions
- Claude local session history
- future harnesses and control-plane backends
Adapters normalize those sources into one control-plane-safe snapshot shape so inspection, persistence, and future UI layers do not depend on harness-specific files or runtime details.
Canonical Snapshot
Every adapter MUST return a JSON-serializable object with this top-level shape:
{
"schemaVersion": "ecc.session.v1",
"adapterId": "dmux-tmux",
"session": {
"id": "workflow-visual-proof",
"kind": "orchestrated",
"state": "active",
"repoRoot": "/tmp/repo",
"sourceTarget": {
"type": "session",
"value": "workflow-visual-proof"
}
},
"workers": [
{
"id": "seed-check",
"label": "seed-check",
"state": "running",
"health": "healthy",
"branch": "feature/seed-check",
"worktree": "/tmp/worktree",
"runtime": {
"kind": "tmux-pane",
"command": "codex",
"pid": 1234,
"active": false,
"dead": false
},
"intent": {
"objective": "Inspect seeded files.",
"seedPaths": ["scripts/orchestrate-worktrees.js"]
},
"outputs": {
"summary": [],
"validation": [],
"remainingRisks": []
},
"artifacts": {
"statusFile": "/tmp/status.md",
"taskFile": "/tmp/task.md",
"handoffFile": "/tmp/handoff.md"
}
}
],
"aggregates": {
"workerCount": 1,
"states": {
"running": 1
},
"healths": {
"healthy": 1
}
}
}
Required Fields
Top level
| Field | Type | Notes |
|---|---|---|
schemaVersion |
string | MUST be exactly ecc.session.v1 for this contract |
adapterId |
string | Stable adapter identifier such as dmux-tmux or claude-history |
session |
object | Canonical session metadata |
workers |
array | Canonical worker records; may be empty |
aggregates |
object | Derived worker counts |
session
| Field | Type | Notes |
|---|---|---|
id |
string | Stable identifier within the adapter domain |
kind |
string | High-level session family such as orchestrated or history |
state |
string | Canonical session state |
sourceTarget |
object | Provenance for the target that opened the session |
session.sourceTarget
| Field | Type | Notes |
|---|---|---|
type |
string | Lookup class such as plan, session, claude-history, claude-alias, or session-file |
value |
string | Raw target value or resolved path |
workers[]
| Field | Type | Notes |
|---|---|---|
id |
string | Stable worker identifier in adapter scope |
label |
string | Operator-facing label |
state |
string | Canonical worker state (lifecycle) |
health |
string | Canonical worker health (operational condition) |
runtime |
object | Execution/runtime metadata |
intent |
object | Why this worker/session exists |
outputs |
object | Structured outcomes and checks |
artifacts |
object | Adapter-owned file/path references |
workers[].runtime
| Field | Type | Notes |
|---|---|---|
kind |
string | Runtime family such as tmux-pane or claude-session |
active |
boolean | Whether the runtime is active now |
dead |
boolean | Whether the runtime is known dead/finished |
workers[].intent
| Field | Type | Notes |
|---|---|---|
objective |
string | Primary objective or title |
seedPaths |
string[] | Seed or context paths associated with the worker/session |
workers[].outputs
| Field | Type | Notes |
|---|---|---|
summary |
string[] | Completed outputs or summary items |
validation |
string[] | Validation evidence or checks |
remainingRisks |
string[] | Open risks, follow-ups, or notes |
aggregates
| Field | Type | Notes |
|---|---|---|
workerCount |
integer | MUST equal workers.length |
states |
object | Count map derived from workers[].state |
healths |
object | Count map derived from workers[].health |
Optional Fields
Optional fields MAY be omitted, but if emitted they MUST preserve the documented type:
| Field | Type | Notes |
|---|---|---|
session.repoRoot |
string | null |
Repo/worktree root when known |
workers[].branch |
string | null |
Branch name when known |
workers[].worktree |
string | null |
Worktree path when known |
workers[].runtime.command |
string | null |
Active command when known |
workers[].runtime.pid |
number | null |
Process id when known |
workers[].artifacts.* |
adapter-defined | File paths or structured references owned by the adapter |
Adapter-specific optional fields belong inside runtime, artifacts, or other
documented nested objects. Adapters MUST NOT invent new top-level fields without
updating this contract.
State Semantics
The contract intentionally keeps session.state and workers[].state flexible
enough for multiple harnesses, but current adapters use these values:
dmux-tmux- session states:
active,completed,failed,idle,missing - worker states: derived from worker status files, for example
runningorcompleted
- session states:
claude-history- session state:
recorded - worker state:
recorded
- session state:
Consumers MUST treat unknown state strings as valid adapter-specific values and degrade gracefully.
Versioning Strategy
schemaVersion is the only compatibility gate. Consumers MUST branch on it.
Allowed in ecc.session.v1
- adding new optional nested fields
- adding new adapter ids
- adding new state string values
- adding new health string values
- adding new artifact keys inside
workers[].artifacts
Requires a new schema version
- removing a required field
- renaming a field
- changing a field type
- changing the meaning of an existing field in a non-compatible way
- moving data from one field to another while keeping the same version string
If any of those happen, the producer MUST emit a new version string such as
ecc.session.v2.
Adapter Compliance Requirements
Every ECC session adapter MUST:
- Emit
schemaVersion: "ecc.session.v1"exactly. - Return a snapshot that satisfies all required fields and types.
- Use
nullfor unknown optional scalar values and empty arrays for unknown list values. - Keep adapter-specific details nested under
runtime,artifacts, or other documented nested objects. - Ensure
aggregates.workerCount === workers.length. - Ensure
aggregates.statesmatches the emitted worker states. - Ensure
aggregates.healthsmatches the emitted worker health values. - Produce plain JSON-serializable values only.
- Validate the canonical shape before persistence or downstream use.
- Persist the normalized canonical snapshot through the session recording shim.
In this repo, that shim first attempts
scripts/lib/state-storeand falls back to a JSON recording file only when the state store module is not available yet.
Consumer Expectations
Consumers SHOULD:
- rely only on documented fields for
ecc.session.v1 - ignore unknown optional fields
- treat
adapterId,session.kind, andruntime.kindas routing hints rather than exhaustive enums - expect adapter-specific artifact keys inside
workers[].artifacts
Consumers MUST NOT:
- infer harness-specific behavior from undocumented fields
- assume all adapters have tmux panes, git worktrees, or markdown coordination files
- reject snapshots only because a state string is unfamiliar
Current Adapter Mappings
dmux-tmux
- Source:
scripts/lib/orchestration-session.js - Session id: orchestration session name
- Session kind:
orchestrated - Session source target: plan path or session name
- Worker runtime kind:
tmux-pane - Artifacts:
statusFile,taskFile,handoffFile
claude-history
- Source:
scripts/lib/session-manager.js - Session id: Claude short id when present, otherwise session filename-derived id
- Session kind:
history - Session source target: explicit history target, alias, or
.tmpsession file - Worker runtime kind:
claude-session - Intent seed paths: parsed from
### Context to Load - Artifacts:
sessionFile,context
Validation Reference
The repo implementation validates:
- required object structure
- required string fields
- boolean runtime flags
- string-array outputs and seed paths
- aggregate count consistency
Adapters should treat validation failures as contract bugs, not user input errors.
Recording Fallback Behavior
The JSON fallback recorder is a temporary compatibility shim for the period before the dedicated state store lands. Its behavior is:
- latest snapshot is always replaced in-place
- history records only distinct snapshot bodies
- unchanged repeated reads do not append duplicate history entries
This keeps session-inspect and other polling-style reads from growing
unbounded history for the same unchanged session snapshot.