docs/SESSION-ADAPTER-CONTRACT.md
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.
ECC has multiple session sources:
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.
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
}
}
}
| 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 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.
The contract intentionally keeps session.state and workers[].state flexible
enough for multiple harnesses, but current adapters use these values:
dmux-tmux
active, completed, failed, idle, missingrunning or
completedclaude-history
recordedrecordedConsumers MUST treat unknown state strings as valid adapter-specific values and degrade gracefully.
schemaVersion is the only compatibility gate. Consumers MUST branch on it.
ecc.session.v1workers[].artifactsIf any of those happen, the producer MUST emit a new version string such as
ecc.session.v2.
Every ECC session adapter MUST:
schemaVersion: "ecc.session.v1" exactly.null for unknown optional scalar values and empty arrays for unknown
list values.runtime, artifacts, or other
documented nested objects.aggregates.workerCount === workers.length.aggregates.states matches the emitted worker states.aggregates.healths matches the emitted worker health values.scripts/lib/state-store and falls
back to a JSON recording file only when the state store module is not
available yet.Consumers SHOULD:
ecc.session.v1adapterId, session.kind, and runtime.kind as routing hints rather
than exhaustive enumsworkers[].artifactsConsumers MUST NOT:
dmux-tmuxscripts/lib/orchestration-session.jsorchestratedtmux-panestatusFile, taskFile, handoffFileclaude-historyscripts/lib/session-manager.jshistory.tmp session fileclaude-session### Context to LoadsessionFile, contextThe repo implementation validates:
Adapters should treat validation failures as contract bugs, not user input errors.
The JSON fallback recorder is a temporary compatibility shim for the period before the dedicated state store lands. Its behavior is:
This keeps session-inspect and other polling-style reads from growing
unbounded history for the same unchanged session snapshot.