diff --git a/docs/ECC-2.0-GA-ROADMAP.md b/docs/ECC-2.0-GA-ROADMAP.md
index 4a3ccf5b..b789d622 100644
--- a/docs/ECC-2.0-GA-ROADMAP.md
+++ b/docs/ECC-2.0-GA-ROADMAP.md
@@ -30,7 +30,7 @@ As of 2026-05-12:
Linear project status updates remain the active tracking surfaces until the
workspace is upgraded or issue capacity is freed.
- `npm run harness:audit -- --format json` reports 70/70 on current `main`.
-- `npm run observability:ready` reports 14/14 readiness on current `main`.
+- `npm run observability:ready` reports 16/16 readiness on current `main`.
- `docs/architecture/harness-adapter-compliance.md` maps Claude Code, Codex,
OpenCode, Cursor, Gemini, Zed-adjacent, dmux, Orca, Superset, Ghast, and
terminal-only support to install paths, verification commands, and risk
@@ -153,7 +153,7 @@ As of 2026-05-12:
- Keep public PRs and issues below 20, with zero as the preferred release-lane
target.
-- Maintain 70/70 harness audit and 14/14 observability readiness after every
+- Maintain 70/70 harness audit and 16/16 observability readiness after every
GA-readiness batch.
- Do not publish release or social announcements until the GitHub release,
npm/package state, billing state, and plugin submission surfaces are verified
@@ -187,7 +187,7 @@ is not complete unless the evidence column exists and has been freshly verified.
| Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit | Needs recurring status updates after each merge batch |
| Flow separation and progress tracking | Flow lanes with owner artifacts and update cadence | This roadmap defines lanes below | Active |
| Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items | Needs workspace capacity/config rollout |
-| Observability for self-use | Local readiness gate, traces, status snapshots, risk ledger | `npm run observability:ready` reports 14/14 | Complete for local gate |
+| Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger | `npm run observability:ready` reports 16/16 | Complete for local gate |
| Proper release and notifications | Release tag, npm publish state, plugin state, social posts | Publication readiness gate exists | Not complete |
## Execution Lanes And Tracking Contract
@@ -275,7 +275,7 @@ Target: 2026-06-07
Acceptance:
-- Observability readiness remains 14/14 and is backed by JSONL traces, status
+- Observability readiness remains 16/16 and is backed by JSONL traces, status
snapshots, risk ledger, and exportable handoff contracts.
- HUD/status model covers context, tool calls, active agents, todos, checks,
cost, risk, and queue state.
diff --git a/docs/architecture/hud-status-session-control.md b/docs/architecture/hud-status-session-control.md
new file mode 100644
index 00000000..8b773e20
--- /dev/null
+++ b/docs/architecture/hud-status-session-control.md
@@ -0,0 +1,80 @@
+# HUD Status And Session Control Contract
+
+This contract defines the portable status payload ECC uses for local operator
+surfaces, handoffs, and future HUDs. It is intentionally harness-neutral: a
+Claude Code statusline, Codex pane, dmux session, OpenCode run, or terminal-only
+workflow can emit partial data without changing field names.
+
+The canonical example lives at
+[`examples/hud-status-contract.json`](../../examples/hud-status-contract.json).
+
+## Payload Shape
+
+Every status payload uses `schema_version: "ecc.hud-status.v1"` and keeps these
+top-level sections stable:
+
+| Field | Purpose | Primary Source |
+|---|---|---|
+| `context` | Model, harness, repo, branch, worktree, session id, and context-window pressure | statusline stdin, git, session adapters |
+| `toolCalls` | Recent tool counts, pending calls, stale calls, and last tool event | `loop-status`, `tool-usage.jsonl`, hook bridge |
+| `activeAgents` | Current workers/subagents, runtime state, branch, worktree, objective, and handoff paths | dmux/orchestration snapshots |
+| `todos` | Current in-progress task and todo counts | Claude todos, local task files, plan metadata |
+| `checks` | Local and remote validation status with command/check URLs when available | CI, local commands, release gates |
+| `cost` | Session spend, token counts, budget, and trend | cost tracker, metrics bridge |
+| `risk` | Attention state, conflict pressure, stale calls, dirty worktree, and manual-review flags | readiness gates, git, queue state |
+| `queueState` | GitHub PR/issue/discussion counts, conflict queue, merge queue, and stale-salvage queue | GitHub sync, work items |
+| `sessionControls` | Supported operator actions for the current target | ECC CLI, dmux, git/GitHub |
+| `sync` | Linear, GitHub, and handoff publication state | status updates, work items, handoff writer |
+
+Fields can be `null`, empty arrays, or `"unknown"` when a harness cannot expose
+the signal. Producers should not invent incompatible names. Consumers should
+render missing sections as unavailable, not as green.
+
+## Session Controls
+
+The minimum session-control vocabulary is:
+
+| Control | Meaning |
+|---|---|
+| `create` | Start a new isolated run, worktree, or orchestration plan |
+| `resume` | Reattach to an existing session or historical target |
+| `status` | Emit the current payload without mutating state |
+| `stop` | Request a graceful stop or mark the session completed |
+| `diff` | Show current working-tree or worker diff |
+| `pr` | Open or inspect the linked pull request |
+| `mergeQueue` | Show merge-ready, blocked, and waiting-check items |
+| `conflictQueue` | Show dirty/conflicting PRs or worktrees needing integration |
+
+`sessionControls.supported` lists the controls available for the current
+harness. `sessionControls.blocked` explains unavailable controls, for example a
+missing GitHub token, no tmux session, or a read-only adapter.
+
+## Sync Contract
+
+The sync section separates durable trackers:
+
+- `Linear` records project status update id, health, and whether issue creation
+ is blocked by workspace capacity.
+- `GitHub` records the current repo, PR/issue/discussion queue counts, and the
+ latest merged or open PR tied to the session.
+- `handoff` records the durable Markdown handoff path and whether it has been
+ written after the latest batch.
+
+This makes real-time progress tracking explicit without requiring every run to
+create Linear issues or GitHub comments. When Linear issue capacity is blocked,
+the status payload can still prove progress through project updates and repo
+handoffs.
+
+## Current Implementations
+
+- `ecc status --json` exposes readiness, active sessions, skill runs, install
+ health, governance, and linked work items from the SQLite state store.
+- `ecc loop-status --json --write-dir
` writes live transcript snapshots
+ and attention signals for long-running loops.
+- `ecc session-inspect --write ` emits canonical session
+ snapshots from dmux and Claude-history adapters.
+- `scripts/hooks/ecc-statusline.js` renders compact model, task, cost, tool,
+ file, duration, directory, and context pressure signals inside Claude Code.
+
+The `ecc.hud-status.v1` payload is the common outer contract these surfaces can
+project into before ECC grows a dedicated full-screen HUD.
diff --git a/docs/architecture/observability-readiness.md b/docs/architecture/observability-readiness.md
index 78f42c23..c0f0ce31 100644
--- a/docs/architecture/observability-readiness.md
+++ b/docs/architecture/observability-readiness.md
@@ -19,6 +19,10 @@ operator needs.
- Live status: `scripts/loop-status.js` can emit JSON, watch active loops, and
write snapshots for dashboards or handoffs.
+- HUD/status contract: `docs/architecture/hud-status-session-control.md` and
+ `examples/hud-status-contract.json` define the portable payload for context,
+ tool calls, active agents, todos, checks, cost, risk, queues, session
+ controls, and tracker sync.
- Session traces: `scripts/session-inspect.js` can inspect Claude, dmux, and
adapter-backed sessions, then write canonical snapshots.
- Harness baseline: `scripts/harness-audit.js` provides a repeatable scorecard
@@ -56,9 +60,11 @@ later, but only after the local event model is useful enough to trust.
scorecard.
3. Run `node scripts/loop-status.js --json --write-dir .ecc/loop-status`
during longer autonomous batches.
-4. Run `node scripts/session-inspect.js --list-adapters` to confirm which
+4. Review `examples/hud-status-contract.json` before wiring a new HUD or
+ operator dashboard.
+5. Run `node scripts/session-inspect.js --list-adapters` to confirm which
session surfaces are available.
-5. Use ECC2 tool logs for risky operations, conflict analysis, and handoff
+6. Use ECC2 tool logs for risky operations, conflict analysis, and handoff
review before increasing autonomy.
The end-state is practical: before asking ECC to run larger multi-agent loops,
diff --git a/docs/releases/2.0.0-rc.1/publication-readiness.md b/docs/releases/2.0.0-rc.1/publication-readiness.md
index 8066e115..847a85e4 100644
--- a/docs/releases/2.0.0-rc.1/publication-readiness.md
+++ b/docs/releases/2.0.0-rc.1/publication-readiness.md
@@ -45,7 +45,7 @@ Record the exact commit SHA and command output before any publication action:
| Clean release branch | `git status --short --branch` | On intended release commit; no unrelated files | Pending |
| Harness audit | `npm run harness:audit -- --format json` | 70/70 passing | Pending |
| Adapter scorecard | `npm run harness:adapters -- --check` | PASS | Pending |
-| Observability readiness | `npm run observability:ready` | 14/14 passing | Pending |
+| Observability readiness | `npm run observability:ready` | 16/16 passing | Pending |
| Root suite | `node tests/run-all.js` | 0 failures | Pending |
| Markdown lint | `npx markdownlint-cli '**/*.md' --ignore node_modules` | 0 failures | Pending |
| Package surface | `node tests/scripts/npm-publish-surface.test.js` | 0 failures | Pending |
diff --git a/examples/hud-status-contract.json b/examples/hud-status-contract.json
new file mode 100644
index 00000000..46867d24
--- /dev/null
+++ b/examples/hud-status-contract.json
@@ -0,0 +1,117 @@
+{
+ "schema_version": "ecc.hud-status.v1",
+ "generatedAt": "2026-05-12T00:00:00.000Z",
+ "context": {
+ "harness": "codex",
+ "model": "gpt-5",
+ "repo": "affaan-m/everything-claude-code",
+ "branch": "main",
+ "worktree": "/repo/everything-claude-code",
+ "sessionId": "session-active",
+ "contextWindow": {
+ "remainingPct": 62,
+ "pressure": "normal"
+ }
+ },
+ "toolCalls": {
+ "total": 47,
+ "pending": 0,
+ "stale": 0,
+ "lastTool": {
+ "name": "gh-pr-view",
+ "status": "success",
+ "finishedAt": "2026-05-12T00:00:00.000Z"
+ }
+ },
+ "activeAgents": [
+ {
+ "id": "worker-release-docs",
+ "state": "completed",
+ "branch": "codex/release-docs",
+ "worktree": "/tmp/ecc-release-docs",
+ "objective": "Update release readiness docs",
+ "handoffPath": "/tmp/ecc-release-docs/handoff.md"
+ }
+ ],
+ "todos": {
+ "inProgress": "Verify release publication matrix",
+ "counts": {
+ "pending": 2,
+ "inProgress": 1,
+ "completed": 6
+ }
+ },
+ "checks": {
+ "local": [
+ {
+ "command": "npm run observability:ready",
+ "status": "pass"
+ }
+ ],
+ "remote": [
+ {
+ "name": "CI",
+ "status": "pass",
+ "url": "https://github.com/affaan-m/everything-claude-code/actions"
+ }
+ ]
+ },
+ "cost": {
+ "sessionUsd": 1.23,
+ "budgetUsd": 10,
+ "trend": "within-budget"
+ },
+ "risk": {
+ "status": "attention",
+ "reasons": [
+ "release tag not published"
+ ],
+ "dirtyWorktree": false,
+ "conflicts": 0,
+ "manualReviewRequired": true
+ },
+ "queueState": {
+ "github": {
+ "openPullRequests": 0,
+ "openIssues": 0,
+ "openDiscussions": 0
+ },
+ "mergeQueue": [],
+ "conflictQueue": [],
+ "staleSalvageQueue": [
+ {
+ "sourcePullRequest": 1310,
+ "status": "landed"
+ }
+ ]
+ },
+ "sessionControls": {
+ "supported": [
+ "create",
+ "resume",
+ "status",
+ "stop",
+ "diff",
+ "pr",
+ "mergeQueue",
+ "conflictQueue"
+ ],
+ "blocked": []
+ },
+ "sync": {
+ "Linear": {
+ "project": "ECC 2.0 GA",
+ "health": "atRisk",
+ "issueCapacityBlocked": true,
+ "latestStatusUpdateId": "status-update-id"
+ },
+ "GitHub": {
+ "repo": "affaan-m/everything-claude-code",
+ "latestPullRequest": 1820
+ },
+ "handoff": {
+ "path": "~/.cluster-swarm/handoffs/ecc-update.md",
+ "written": true
+ }
+ }
+}
diff --git a/scripts/observability-readiness.js b/scripts/observability-readiness.js
index 537cd942..97d4bd15 100644
--- a/scripts/observability-readiness.js
+++ b/scripts/observability-readiness.js
@@ -103,6 +103,13 @@ function includesAll(text, needles) {
return needles.every(needle => text.includes(needle));
}
+function hasObjectKeys(value, keys) {
+ return value
+ && typeof value === 'object'
+ && !Array.isArray(value)
+ && keys.every(key => Object.prototype.hasOwnProperty.call(value, key));
+}
+
function buildChecks(rootDir) {
const packageJsonText = readText(rootDir, 'package.json');
const packageJson = safeParseJson(packageJsonText) || {};
@@ -116,6 +123,8 @@ function buildChecks(rootDir) {
const sessionStoreRust = readText(rootDir, 'ecc2/src/session/store.rs');
const sessionManagerRust = readText(rootDir, 'ecc2/src/session/manager.rs');
const readinessDoc = readText(rootDir, 'docs/architecture/observability-readiness.md');
+ const hudStatusContract = readText(rootDir, 'docs/architecture/hud-status-session-control.md');
+ const hudStatusFixture = safeParseJson(readText(rootDir, 'examples/hud-status-contract.json')) || {};
const quickstart = readText(rootDir, 'docs/releases/2.0.0-rc.1/quickstart.md');
const releaseNotes = readText(rootDir, 'docs/releases/2.0.0-rc.1/release-notes.md');
@@ -130,6 +139,50 @@ function buildChecks(rootDir) {
&& includesAll(loopStatus, ['--json', '--watch', '--write-dir']),
fix: 'Restore loop-status JSON/watch/write-dir support.'
},
+ {
+ id: 'hud-status-control-contract',
+ category: 'Live Status',
+ points: 2,
+ path: 'docs/architecture/hud-status-session-control.md',
+ description: 'HUD/status and session-control surfaces have a portable JSON contract',
+ pass: fileExists(rootDir, 'docs/architecture/hud-status-session-control.md')
+ && fileExists(rootDir, 'examples/hud-status-contract.json')
+ && includesAll(hudStatusContract, [
+ 'context',
+ 'toolCalls',
+ 'activeAgents',
+ 'todos',
+ 'checks',
+ 'cost',
+ 'risk',
+ 'queueState',
+ 'create',
+ 'resume',
+ 'status',
+ 'stop',
+ 'diff',
+ 'pr',
+ 'mergeQueue',
+ 'conflictQueue',
+ 'Linear',
+ 'GitHub',
+ 'handoff'
+ ])
+ && hudStatusFixture.schema_version === 'ecc.hud-status.v1'
+ && hasObjectKeys(hudStatusFixture, [
+ 'context',
+ 'toolCalls',
+ 'activeAgents',
+ 'todos',
+ 'checks',
+ 'cost',
+ 'risk',
+ 'queueState',
+ 'sessionControls',
+ 'sync'
+ ]),
+ fix: 'Add the HUD/status session-control contract doc and example JSON fixture.'
+ },
{
id: 'session-inspect-adapter-registry',
category: 'Session Trace',
diff --git a/tests/scripts/observability-readiness.test.js b/tests/scripts/observability-readiness.test.js
index 87df17d3..d2e1b6bf 100644
--- a/tests/scripts/observability-readiness.test.js
+++ b/tests/scripts/observability-readiness.test.js
@@ -62,6 +62,24 @@ function seedMinimalRepo(rootDir, overrides = {}) {
'ecc2/src/session/store.rs': 'insert_tool_log query_tool_logs',
'ecc2/src/session/manager.rs': 'sync_tool_activity_metrics tool-usage.jsonl',
'docs/architecture/observability-readiness.md': 'node scripts/observability-readiness.js --format json',
+ 'docs/architecture/hud-status-session-control.md': [
+ 'context toolCalls activeAgents todos checks cost risk queueState',
+ 'create resume status stop diff pr mergeQueue conflictQueue',
+ 'Linear GitHub handoff'
+ ].join('\n'),
+ 'examples/hud-status-contract.json': JSON.stringify({
+ schema_version: 'ecc.hud-status.v1',
+ context: {},
+ toolCalls: {},
+ activeAgents: [],
+ todos: {},
+ checks: {},
+ cost: {},
+ risk: {},
+ queueState: {},
+ sessionControls: {},
+ sync: {}
+ }, null, 2),
'docs/releases/2.0.0-rc.1/quickstart.md': 'observability-readiness.md',
'docs/releases/2.0.0-rc.1/release-notes.md': 'observability-readiness.md'
};
@@ -195,6 +213,23 @@ function runTests() {
}
})) passed++; else failed++;
+ if (test('missing HUD status contract fails without disturbing core tool checks', () => {
+ const projectRoot = createTempDir('observability-readiness-hud-fail-');
+
+ try {
+ seedMinimalRepo(projectRoot, {
+ 'examples/hud-status-contract.json': null
+ });
+ const report = buildReport(projectRoot);
+
+ assert.strictEqual(report.ready, false);
+ assert.ok(report.checks.some(check => check.id === 'hud-status-control-contract' && !check.pass));
+ assert.ok(report.checks.some(check => check.id === 'loop-status-live-signal' && check.pass));
+ } finally {
+ cleanup(projectRoot);
+ }
+ })) passed++; else failed++;
+
console.log('\nResults:');
console.log(` Passed: ${passed}`);
console.log(` Failed: ${failed}`);