docs: clarify ACP session identity and simplify coverage doc

This commit is contained in:
Onur 2026-02-25 09:17:18 +01:00 committed by Onur Solmaz
parent 08728dcf96
commit b2a19bfb1d
2 changed files with 141 additions and 199 deletions

View File

@ -1,32 +1,60 @@
---
title: ACP Spec Coverage Roadmap
title: ACP Spec Coverage
author: Bob <bob@dutifulbob.com>
date: 2026-02-19
---
# ACP Spec Coverage Roadmap
# ACP Spec Coverage
What acpx implements from the ACP spec today, what's missing, and the plan to
close the gaps.
What acpx implements from the ACP spec today and what is not yet implemented.
## Current State (v0.1.x)
## Supported Now
acpx implements the core prompt loop and session lifecycle. Enough to be a useful
CLI client for Codex, Claude, Gemini, OpenCode, and Pi.
| ACP Method | acpx Feature | Supported |
| ---------------------------- | ------------------------------------------------ | --------- |
| `initialize` | Handshake, capability negotiation | yes |
| `session/new` | `sessions new` | yes |
| `session/load` | Crash resume / reconnect | yes |
| `session/prompt` | `prompt`, `exec`, implicit prompt | yes |
| `session/update` | Streaming output (thinking, tools, text, diffs) | yes |
| `session/cancel` | Graceful cancel + `acpx <agent> cancel` | yes |
| `session/request_permission` | `--approve-all`, `--approve-reads`, `--deny-all` | yes |
| `session/set_mode` | `acpx <agent> set-mode <mode>` | yes |
| `session/set_config_option` | `acpx <agent> set <key> <value>` | yes |
| `fs/read_text_file` | ACP client file read handler | yes |
| `fs/write_text_file` | ACP client file write handler | yes |
| `terminal/create` | ACP client terminal spawn handler | yes |
| `terminal/output` | ACP client terminal output handler | yes |
| `terminal/wait_for_exit` | ACP client terminal wait handler | yes |
| `terminal/kill` | ACP client terminal kill handler | yes |
| `terminal/release` | ACP client terminal release handler | yes |
| `authenticate` | Auth handshake handling | yes |
### Implemented
### Supported Behavior Notes
| ACP Method | acpx Feature | Since |
| ---------------------------- | ------------------------------------------------ | ------ |
| `initialize` | Handshake, capability negotiation | v0.1.0 |
| `session/new` | `sessions new` | v0.1.0 |
| `session/load` | Crash resume / reconnect | v0.1.0 |
| `session/prompt` | `prompt`, `exec`, implicit prompt | v0.1.0 |
| `session/update` | Streaming output (thinking, tools, text, diffs) | v0.1.0 |
| `session/cancel` | Graceful cancel on SIGINT | v0.1.4 |
| `session/request_permission` | `--approve-all`, `--approve-reads`, `--deny-all` | v0.1.0 |
#### Session cancel and controls
### Not Implemented
- `acpx <agent> cancel` sends `session/cancel` through the queue path and keeps the session alive for follow-up prompts.
- This is intentionally different from process-level SIGINT behavior, which can tear down the running process.
- `session/set_mode` and `session/set_config_option` are exposed as `set-mode` and `set` commands and return agent-side validation errors when invalid.
#### Filesystem client methods
- acpx handles `fs/read_text_file` and `fs/write_text_file` as client-authority operations.
- Permission behavior follows selected mode (`--approve-all`, `--approve-reads`, `--deny-all`).
- Path sandboxing is applied to keep file operations scoped to cwd by default.
#### Terminal client methods
- acpx handles full terminal lifecycle: create, output, wait_for_exit, kill, release.
- The implementation includes process tracking, output buffering, and cleanup behavior for terminal IDs.
#### Authentication
- acpx handles `authenticate` when adapters request it.
- This keeps compatibility with adapters that rely on ACP auth handshake rather than out-of-band environment setup.
## Not Yet Supported
| ACP Method | What it does | Spec status |
| ------------------- | ----------------------------------- | ----------- |
@ -36,89 +64,15 @@ CLI client for Codex, Claude, Gemini, OpenCode, and Pi.
| `session/set_model` | Change model mid-session | unstable |
| `$/cancel_request` | Cancel any pending JSON-RPC request | unstable |
## Roadmap
### Not Yet Supported Notes
### Tier 1 — Cancel and Control (next release)
- `session/fork`: would allow branching one conversation into parallel alternatives.
- `session/list`: would expose adapter-side session inventory in addition to acpx local store listing.
- `session/resume`: distinct from `session/load`; expected to support resume semantics without replay-like behavior.
- `session/set_model`: mid-session model switching command surface.
- `$/cancel_request`: transport-level JSON-RPC cancellation beyond session-scoped cancel.
In-flight prompt management. Users need to stop generation and redirect without
killing the session.
- [x] **`acpx <agent> cancel`** — Send `session/cancel` to the running turn via
the queue socket. Agent stops generating, session stays alive, ready for next
prompt immediately. This is different from SIGINT (which tears down the process);
cancel is cooperative and keeps the connection open.
- [x] **`session/set_mode`** — `acpx <agent> set-mode <mode>`. Agents advertise
supported modes in their capabilities. Codex supports `plan` vs `execute` (or
equivalent). Simple JSON-RPC call, response is ack.
- [x] **`session/set_config_option`** — `acpx <agent> set <key> <value>`. Pass
arbitrary config to the agent (temperature, max tokens, etc.). Agent validates,
returns ack or error.
### Tier 2 — Filesystem Client Methods
The agent asks acpx (the client) to read/write files on its behalf. Today agents
handle their own filesystem access, but the ACP spec envisions the client as the
filesystem authority — the agent requests, the client decides.
This matters for:
- Sandboxed agents that can't touch the filesystem directly
- Fine-grained permission control (allow reads to `src/`, deny writes to `.env`)
- Audit logging of all file operations
Implementation:
- [x] **`fs/read_text_file`** — Agent sends path, client reads and returns content.
Respect permission mode: `--approve-reads` allows automatically, `--deny-all`
rejects. Could add path-based policies later.
- [x] **`fs/write_text_file`** — Agent sends path + content, client writes. Always
requires permission unless `--approve-all`. Show diff preview before approving.
- [x] Path sandboxing: restrict reads/writes to cwd subtree by default.
### Tier 3 — Terminal Client Methods
The agent asks acpx to manage terminal processes. Same philosophy as filesystem:
the client is the execution authority.
- [x] **`terminal/create`** — Agent requests a command to run. Client spawns the
process, returns a terminal ID. Permission check: similar to tool call approval.
- [x] **`terminal/output`** — Agent polls for terminal stdout/stderr. Client returns
buffered output.
- [x] **`terminal/wait_for_exit`** — Agent blocks until terminal exits. Client
returns exit code.
- [x] **`terminal/kill`** — Agent requests termination of a running terminal.
- [x] **`terminal/release`** — Agent releases terminal resources.
This is the heaviest lift. Requires:
- Terminal process lifecycle manager (spawn, track, buffer output, reap)
- Terminal ID allocation and cleanup
- Timeout handling for hung processes
- Integration with permission system
### Tier 4 — Authentication
- [x] **`authenticate`** — Handle auth handshake. Agent tells client what auth
it needs (API key, OAuth token, etc.), client provides it. Today agents manage
their own auth (env vars, config files). This would let acpx be the auth broker.
Lower priority because current agents work fine without it.
### Tier 5 — Unstable / Future
Only implement these once they stabilize in the spec:
- [ ] **`session/fork`** — Branch a session. Use case: try two approaches in
parallel. Would create two session files from one.
- [ ] **`session/list`** — Server-side session listing. We already have client-side
`sessions list`; this would query the agent for its view.
- [ ] **`session/resume`** — Resume a paused session (different from `session/load`
which replays history).
- [ ] **`session/set_model`** — `acpx <agent> set-model <model>`. Switch models
mid-conversation.
- [ ] **`$/cancel_request`** — Cancel any pending JSON-RPC request by ID. More
granular than `session/cancel`.
## Non-ACP Features
## ACP-Adjacent Features Not Yet Supported
Things acpx needs that aren't in the ACP spec:
@ -131,16 +85,3 @@ writes to .env`). Beyond the current all-or-nothing modes.
- [ ] **Session export/import** — Move sessions between machines.
- [ ] **Watch mode** — Re-run prompt on file changes.
- [ ] **Cost/token tracking** — Surface usage stats when agents/ACP expose them.
## Release Mapping
| Release | Tier | Key Features |
| ------- | ---------- | ------------------------------------------------------------------------------------------- |
| v0.2.0 | current | Config file, graceful cancel, crash resume, stdin/file input, session history, agent status |
| v0.3.0 | Tier 1 | `cancel` command, `set-mode`, `set-config-option` |
| v0.4.0 | Tier 2 | `fs/read_text_file`, `fs/write_text_file`, path sandboxing |
| v0.5.0 | Tier 3 | Terminal client methods (create, output, wait, kill, release) |
| v0.6.0 | Tier 4 | Authentication handshake |
| v1.0.0 | all stable | Full stable ACP spec coverage, production-ready |
Unstable methods land as they stabilize in the spec, likely post-1.0.

View File

@ -2,166 +2,167 @@
Status: Draft
Owner: acpx
Last updated: 2026-02-23
Last updated: 2026-02-25
## Context
`acpx sessions ensure --format json` currently returns:
`acpx` currently exposes overlapping session identifiers (`id` and `sessionId`) and an optional runtime/provider identifier (`runtimeSessionId`).
- `id`
- `sessionId`
- `name`
- `created`
This naming is ambiguous for orchestrators and users who need to reason about:
In current acpx behavior, `id` and `sessionId` are identical because acpx persists one identifier for both record identity and ACP session identity.
For orchestrators (for example OpenClaw), this is not enough to distinguish:
- acpx record/session identity
- runtime/provider-native identity (for example Codex/Claude internal session id) when available
- stable local record identity
- ACP wire/session identity
- inner harness/provider identity
## Problem Statement
When adapters expose an additional runtime/provider session identifier, acpx cannot currently preserve and expose it.
Current naming causes confusion and duplicate-looking values in downstream UX.
This causes downstream UX to show duplicated values and prevents precise diagnostics across layers.
When reconnect or fallback creates a new ACP session for an existing local record, the distinction is real, but not clearly named.
## Goals
1. Add first-class support for an optional runtime/provider session identifier.
2. Preserve backward compatibility for existing acpx consumers.
3. Keep behavior deterministic when runtime id is unavailable.
4. Avoid brittle scraping (logs, PTY parsing, out-of-band files).
1. Define explicit, unambiguous identifier names.
2. Keep behavior deterministic when inner harness id is unavailable.
3. Preserve resilience flows (load/reconnect/fallback) without identity confusion.
4. Keep adapter integration harness-agnostic.
## Non-Goals
1. Inventing a runtime/provider id when adapter does not expose one.
2. Requiring ACP spec changes for v1.
3. Changing existing `id` semantics for acpx record lookup.
1. Inventing an inner harness id when adapter does not expose one.
2. Requiring ACP spec changes.
3. Changing session lifecycle semantics.
## Proposed Data Model
## Canonical Identity Model
### SessionRecord
### SessionRecord fields
Extend `SessionRecord` with an optional field:
- `runtimeSessionId?: string`
- `acpxRecordId: string`
- `acpxSessionId: string`
- `agentSessionId?: string`
Semantics:
- `id`: acpx record id (stable local record key)
- `sessionId`: ACP session id used for ACP method calls
- `runtimeSessionId`: provider/runtime-native id if exposed via ACP metadata
- `acpxRecordId`: stable acpx local record key.
- `acpxSessionId`: ACP session id used for ACP method calls.
- `agentSessionId`: inner provider/harness session id (Codex/Claude/etc.) when exposed via adapter metadata.
### Output JSON
### Stability rules
Include optional `runtimeSessionId` in JSON payloads when known:
1. `acpxRecordId` SHOULD remain stable for the life of the local record.
2. `acpxSessionId` SHOULD remain stable while ACP `session/load` succeeds.
3. `acpxSessionId` MAY change if acpx must create a fresh ACP session after load/reconnect failure.
4. `agentSessionId` is optional and MUST NOT be synthesized.
## Output JSON Contract
JSON outputs should use canonical names:
- `sessions new --format json`
- `sessions ensure --format json`
- `status --format json`
- `sessions show --format json` (already full record; ensure field is present)
- `sessions show --format json`
If unknown, omit field (do not emit null/placeholder).
Rules:
## Source of Truth for runtimeSessionId
1. Always include `acpxRecordId` and `acpxSessionId`.
2. Include `agentSessionId` only when known.
3. Do not emit null placeholders for unknown optional ids.
acpx SHOULD extract runtime/provider id from ACP `_meta` on session setup responses:
## Source of Truth for agentSessionId
acpx should extract `agentSessionId` from ACP `_meta` on session setup responses:
- `newSession` response `_meta`
- if available, `loadSession` response `_meta` for reconciliation
- `loadSession` response `_meta` for reconciliation (when available)
### Metadata key contract
### Metadata key precedence
For interoperability, acpx will support this precedence list:
Use first non-empty string from:
1. `_meta.runtimeSessionId`
2. `_meta.providerSessionId`
3. `_meta.codexSessionId`
4. `_meta.claudeSessionId`
1. `_meta.agentSessionId`
2. `_meta.runtimeSessionId`
3. `_meta.providerSessionId`
4. `_meta.codexSessionId`
5. `_meta.claudeSessionId`
Notes:
- Keys are optional.
- First non-empty string wins.
- Unknown keys are ignored.
- This does not block future ACP standardization.
- This keeps adapter compatibility while converging on one canonical output field.
- Adapter-specific keys remain accepted as input aliases.
## Behavioral Requirements
1. acpx MUST keep existing behavior for `id` and `sessionId`.
2. acpx MUST persist `runtimeSessionId` when discovered.
3. acpx MUST NOT fail session creation/loading if runtime id is absent.
4. acpx SHOULD update stored `runtimeSessionId` on later session attach if newly discovered.
5. acpx SHOULD preserve an existing `runtimeSessionId` unless a new non-empty value is provided.
1. acpx MUST persist `acpxRecordId` and `acpxSessionId`.
2. acpx MUST persist `agentSessionId` when discovered.
3. acpx MUST NOT fail session creation/loading if `agentSessionId` is absent.
4. acpx SHOULD update stored `agentSessionId` on later attach if newly discovered.
5. acpx SHOULD preserve existing non-empty `agentSessionId` unless replaced by a new non-empty value.
## Implementation Plan (acpx)
1. Types
- Add `runtimeSessionId?: string` to `SessionRecord`.
- Rename session identity fields to canonical names in types and persistence interfaces.
2. Client layer
- Change `AcpClient#createSession` to return a structured object, not bare string:
- `{ sessionId: string; runtimeSessionId?: string }`
- Parse `_meta` with precedence list.
- Return structured session identity with canonical names.
- Normalize `_meta` keys into `agentSessionId`.
3. Session runtime
- Update `createSession(...)` flow to persist `runtimeSessionId`.
- Update reconnect/load paths to reconcile runtime id when metadata is available.
- Persist canonical fields during create/load/reconnect flows.
- Keep record/session divergence behavior explicit and intentional.
4. CLI JSON output
- Add optional `runtimeSessionId` in JSON event payloads for `sessions new`, `sessions ensure`, and `status`.
- Emit `acpxRecordId`, `acpxSessionId`, optional `agentSessionId`.
- Remove ambiguous `id`/`sessionId` naming from JSON outputs.
5. Persistence/migration
- No migration required.
- Existing session files remain valid; field is optional.
5. Persistence migration
- Read legacy files (`id`, `sessionId`, `runtimeSessionId`) and normalize in-memory.
- Write canonical fields on next save.
## Test Plan
1. Unit: metadata parsing
- `_meta.runtimeSessionId` maps correctly.
- precedence order is respected.
- precedence order resolves to `agentSessionId`.
- empty/non-string values are ignored.
2. Unit: session persistence
- record writes include `runtimeSessionId` when present.
- existing records without field load unchanged.
2. Unit: persistence and migration
- legacy files load and normalize correctly.
- canonical fields write correctly.
3. CLI tests (json mode)
- `sessions new` emits `runtimeSessionId` when available.
- `sessions ensure` emits `runtimeSessionId` when available.
- `status` emits `runtimeSessionId` from stored record.
- `sessions new` emits canonical identity fields.
- `sessions ensure` emits canonical identity fields.
- `status` emits canonical identity fields from stored record.
4. Regression
- all existing text/quiet outputs unchanged.
- all existing code paths pass when runtime id is absent.
- fallback/reconnect flows still work when `acpxSessionId` changes and `acpxRecordId` remains stable.
- behavior remains correct when `agentSessionId` is absent.
## OpenClaw Integration Impact
No protocol break is required.
OpenClaw should consume:
OpenClaw can consume:
- `acpxRecordId` as backend/local acpx identity
- `acpxSessionId` as ACP wire/session identity
- `agentSessionId` as inner harness identity when present
- `sessionId` as ACP id
- `id` as acpx id
- `runtimeSessionId` as inner/provider id (when present)
If `runtimeSessionId` is absent, OpenClaw should avoid implying a separate inner id.
If `agentSessionId` is absent, UX should avoid implying a distinct inner session id.
## Rollout
1. Implement field + JSON outputs in acpx.
2. Release acpx.
3. Update OpenClaw ACP runtime adapter to prefer `runtimeSessionId` from acpx output.
4. In OpenClaw thread intros, suppress duplicate lines when two IDs are equal.
1. Implement canonical naming in acpx internals and JSON outputs.
2. Add legacy-read compatibility for existing session files.
3. Update OpenClaw acpx runtime parser to read canonical fields.
4. Remove legacy field usage from tests/docs after transition is complete.
## Risks
1. Adapter metadata key variance.
- Mitigation: precedence list + optional field.
- Mitigation: precedence + alias support.
2. Consumers assuming `id === sessionId` forever.
- Mitigation: compatibility maintained; only additive optional field.
2. Downstream consumers pinned to old JSON field names.
- Mitigation: short compatibility window with documented migration.
3. False confidence when adapter provides no runtime id.
- Mitigation: explicit optional semantics and no synthetic IDs.
3. False confidence when adapter provides no inner id.
- Mitigation: optional semantics; no synthetic ids.