docs: clarify ACP session identity and simplify coverage doc
This commit is contained in:
parent
08728dcf96
commit
b2a19bfb1d
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user