authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-28 18:26:13-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-05 23:00:41-08:00
logafad39d125a319e5fa22e15bbc8615b3a6267aa4
treef3c649bd5f2415bb47e7208b2e77941611341b88
parentf97916f371ab2480a47f62efa17d42c64a253501

Revise Cursor provider plan for ACP JSON-RPC integration

- Switch plan from `agent -p` stream-json to `agent acp` JSON-RPC transport - Document ACP session, permission, event-mapping, and interrupt/recovery behavior - Update implementation phases, tests, and delivery checklist for ACP-first design

1 files changed, 227 insertions(+), 210 deletions(-)

.plans/18-cursor-agent-provider.md+227-210
...@@ -1,248 +1,260 @@...@@ -1,248 +1,260 @@
1# Plan: Cursor CLI (`agent`) Provider Integration1# Plan: Cursor ACP (`agent acp`) Provider Integration
22
3## Goal3## Goal
44
5Add Cursor as a first-class provider in T3 Code using Cursor CLI stream JSON mode (`agent -p --output-format stream-json`), with robust session lifecycle handling and canonical `ProviderRuntimeEvent` projection.5Add Cursor as a first-class provider in T3 Code using ACP (`agent acp`) over JSON-RPC 2.0 stdio, with robust session lifecycle handling and canonical `ProviderRuntimeEvent` projection.
66
7---7---
88
9## 1) Exploration Findings (from live CLI runs)9## 1) Exploration Findings (from live ACP probes)
1010
11### 1.1 Core invocation shape11### 1.1 Core invocation and transport
1212
131. Binary is `agent` on PATH (`2026.02.27-e7d2ef6` observed).131. Binary is `agent` on PATH (`2026.02.27-e7d2ef6` observed).
142. Non-interactive streaming mode:142. ACP server command is `agent acp`.
15 - `agent -p --trust --output-format stream-json --stream-partial-output ...`153. Transport is newline-delimited JSON-RPC 2.0 over stdio.
163. Session continuity:164. Messages:
17 - `agent create-chat` returns a chat UUID.17 - client -> server: requests and responses to server-initiated requests
18 - `--resume <chatId>` and `--continue` preserve history.18 - server -> client: responses, notifications (`session/update`), and server requests (`session/request_permission`)
19 - Stream `session_id` equals chat UUID.19
2020### 1.2 Handshake and session calls observed
21### 1.2 Stream JSON event families observed21
22221. `initialize` returns:
231. `system/init`23 - `protocolVersion`
242. `user`24 - `agentCapabilities` (`loadSession`, `mcpCapabilities`, `promptCapabilities`)
253. `thinking/delta`, `thinking/completed`25 - `authMethods` (includes `cursor_login`)
264. `assistant` (partial and final)262. `authenticate { methodId: "cursor_login" }` returns `{}` when logged in.
275. `tool_call/started`, `tool_call/completed`273. `session/new` returns:
286. `result/success` (`is_error: false` in all successful process exits)28 - `sessionId`
297. Previously observed under load/rate-limit:29 - `modes` (`agent`, `plan`, `ask`)
30 - `connection/reconnecting`, `connection/reconnected`304. `session/load` works and requires `sessionId`, `cwd`, `mcpServers`.
31 - `retry/starting`, `retry/resuming`315. `session/prompt` returns terminal response `{ stopReason: "end_turn" | "cancelled" }`.
32 - followed by non-JSON terminal line `v: [resource_exhausted] Error` and process exit code `1`32
3333Important sequence note:
34### 1.3 Tool call variants observed341. ACP currently allows `session/new` even without explicit `initialize`/`authenticate` when local auth already exists.
35352. For adapter consistency and forward compatibility, we should still send `initialize` and `authenticate` during startup.
361. `shellToolCall`36
372. `readToolCall`37### 1.3 `session/update` event families observed
383. `editToolCall`38
394. `grepToolCall`39Observed `params.update.sessionUpdate` values:
405. `globToolCall`40
41411. `available_commands_update`
42Tool completion outcomes observed:422. `agent_thought_chunk`
43433. `agent_message_chunk`
441. `result.success`444. `tool_call`
452. `result.failure` (non-zero exit, stderr)455. `tool_call_update`
463. `result.rejected` (permission denied by Cursor approval layer)46
4747Observed payload behavior:
48### 1.4 Critical protocol quirks48
49491. `agent_*_chunk` provides `content: { type: "text", text: string }`.
501. `tool_call.call_id` contains embedded newline characters (must sanitize for IDs).502. `tool_call` may be emitted multiple times for same `toolCallId`:
512. Startup failures are plain text, not JSON:51 - initial generic form (`title: "Terminal"`, `rawInput: {}`)
52 - invalid model -> plain error + exit `1`52 - enriched form (`title: "\`pwd\`"`, `rawInput: { command: "pwd" }`)
53 - invalid API key -> plain warning + exit `1`533. `tool_call_update` statuses observed:
543. `result.subtype` can be `success` even when tool calls failed/rejected inside the turn.54 - `in_progress`
554. Running multiple `agent` commands concurrently can race on `~/.cursor/cli-config.json` writes (`ENOENT rename ...cli-config.json.tmp` observed).55 - `completed`
56564. `tool_call_update` on completion may include `rawOutput`:
57Fixtures recorded in repo:57 - terminal: `{ exitCode, stdout, stderr }`
5858 - search/find: `{ totalFiles, truncated }`
591. `.tmp/cursor-observations/*.ndjson`59
602. `.tmp/cursor-observations/startup-invalid-*.txt`60### 1.4 Permission flow observed
61
621. ACP server sends `session/request_permission` (JSON-RPC request with `id`).
632. Request shape includes:
64 - `params.sessionId`
65 - `params.toolCall`
66 - `params.options` (`allow-once`, `allow-always`, `reject-once`)
673. Client must respond on same `id` with:
68 - `{ outcome: { outcome: "selected", optionId: "<one-option-id>" } }`
694. Reject path still results in tool lifecycle completion events (`tool_call_update status: completed`), typically without `rawOutput`.
70
71### 1.5 Error and capability quirks
72
731. `session/cancel` currently returns:
74 - JSON-RPC error `-32601` Method not found
752. Error shape examples:
76 - unknown auth method: `-32602`
77 - `session/load` missing/invalid params: `-32602`
78 - `session/prompt` unknown session: `-32603` with details
793. Parallel prompts on same session are effectively single-flight:
80 - second prompt can cause first to complete with `stopReason: "cancelled"`.
814. `session/new` accepts a `model` field (no explicit echo in response).
82
83Probe artifacts:
841. `.tmp/acp-probe/*/transcript.ndjson`
852. `.tmp/acp-probe/*/summary.json`
863. `scripts/cursor-acp-probe.mjs`
6187
62---88---
6389
64## 2) Integration Constraints for T390## 2) Integration Constraints for T3
6591
661. T3 requires adapter contract support for:921. T3 adapter contract still requires:
67 - `startSession`, `sendTurn`, `interruptTurn`, `respondToRequest`, `readThread`, `rollbackThread`, `stopSession`, `listSessions`, `hasSession`, `stopAll`, `streamEvents`.93 - `startSession`, `sendTurn`, `interruptTurn`, `respondToRequest`, `readThread`, `rollbackThread`, `stopSession`, `listSessions`, `hasSession`, `stopAll`, `streamEvents`.
682. Orchestration depends on canonical runtime events (`ProviderRuntimeEvent`) only.942. Orchestration consumes canonical `ProviderRuntimeEvent` only.
693. Current `ProviderCommandReactor` ignores `thread.turn-start-requested.payload.provider` and prefers existing provider/session; this must be fixed for reliable provider selection (including Cursor).953. `ProviderCommandReactor` provider precedence fix remains required (respect explicit provider on turn start).
704. Cursor CLI currently has no external approval callback API; approvals are internal to CLI behavior.964. ACP now supports external permission decisions, so Cursor can participate in T3 approval UX via adapter-managed request/response plumbing.
7197
72---98---
7399
74## 3) Proposed Architecture100## 3) Proposed Architecture
75101
76## 3.1 New server components102### 3.1 New server components
77103
781. `apps/server/src/provider/Services/CursorAdapter.ts` (service contract/tag only for DI parity)1041. `apps/server/src/provider/Services/CursorAdapter.ts` (service contract/tag + ACP event schemas).
792. `apps/server/src/provider/Layers/CursorAdapter.ts` (single implementation unit; owns Cursor process lifecycle + stream parsing + runtime projection)1052. `apps/server/src/provider/Layers/CursorAdapter.ts` (single implementation unit; owns ACP process lifecycle, JSON-RPC routing, runtime projection).
803. No separate `cursorCliManager.ts` abstraction in v1.1063. No manager indirection; keep logic in layer implementation.
81107
82### 3.2 Session model108### 3.2 Session model
83109
841. T3 `ProviderSessionId` = synthetic UUID managed by adapter (stable for T3 APIs).1101. One long-lived ACP child process per T3 Cursor provider session.
852. Cursor chat UUID stored as:1112. Track:
86 - `ProviderSession.resumeCursor = { chatId: string }`112 - `providerSessionId` (T3 synthetic ID)
87 - `ProviderSession.threadId = ProviderThreadId(chatId)` for adapter contract compatibility.113 - `acpSessionId` (from `session/new` or restored via `session/load`)
883. Adapter keeps runtime map:114 - `cwd`, `model`, in-flight turn state
89 - `sessionId -> { chatId, cwd, model, activeChildProcess?, activeTurnId?, turnLog }`115 - pending permission requests by JSON-RPC request id
1163. Resume support:
117 - persist `acpSessionId` in provider resume metadata and call `session/load` on reattach.
90118
91### 3.3 Command strategy119### 3.3 Command strategy
92120
931. `startSession`:1211. `startSession`:
94 - call `agent create-chat` unless `resumeCursor.chatId` exists.122 - spawn `agent acp`
95 - validate provider is `cursor` when provided.123 - `initialize`
124 - `authenticate(cursor_login)` (best-effort, typed failure handling)
125 - `session/new` or `session/load`
962. `sendTurn`:1262. `sendTurn`:
97 - spawn `agent -p --trust --output-format stream-json --stream-partial-output --resume <chatId>`.127 - send `session/prompt { sessionId, prompt: [...] }`
98 - add `--model` when provided.128 - consume streaming `session/update` notifications until terminal prompt response
99 - map runtime mode:
100 - `approvalPolicy = never` -> include `--force`
101 - otherwise omit `--force` (commands may be rejected by CLI).
102 - use `--workspace <cwd>` when available.
1033. `interruptTurn`:1293. `interruptTurn`:
104 - terminate active child process for session (`SIGINT` then hard kill fallback).130 - no native `session/cancel` today; implement fallback:
131 - terminate ACP process + restart + `session/load` for subsequent turns
132 - mark in-flight turn as interrupted/failed in canonical events
1334. `respondToRequest`:
134 - map T3 approval decision -> ACP `optionId`
135 - reply to exact JSON-RPC request id from `session/request_permission`
105136
106### 3.4 Effect-first implementation style (required)137### 3.4 Effect-first implementation style (required)
107138
1081. Keep adapter logic inside `CursorAdapterLive` layer constructor (no manager indirection).1391. Keep logic inside `CursorAdapterLive`.
1092. Use Effect process primitives first:1402. Use Effect primitives:
110 - `ChildProcessSpawner` + `ChildProcess.make` from `effect/unstable/process` for `agent` execution.141 - `Queue` + `Stream.fromQueue` for event fan-out
1113. Use Effect concurrency/state primitives:142 - `Ref` / `Ref.Synchronized` for session/process/request state
112 - `Queue` for adapter event queue, `Stream.fromQueue` for `streamEvents`143 - scoped fibers for stdout/stderr read loops
113 - `Ref` / `Ref.Synchronized` for session maps and active-turn process handles1443. Typed JSON decode at boundary:
114 - `Effect.scoped` + `Effect.forkScoped` for worker fibers and cleanup145 - request/response envelopes
1154. Use Effect stream parsing path for stdout/stderr:146 - `session/update` union schema
116 - decode bytes -> line buffer -> JSON parse -> typed projection147 - permission-request schema
117 - keep non-JSON lines on a fallback branch that emits `runtime.error`1484. Keep adapter errors in typed error algebra with explicit mapping at process/protocol boundaries.
1185. Keep errors in typed adapter error algebra (`ProviderAdapter*Error`) via `Effect.mapError` boundaries, not ad-hoc exceptions.
119149
120---150---
121151
122## 4) Canonical Event Mapping Plan152## 4) Canonical Event Mapping Plan (ACP -> ProviderRuntimeEvent)
123153
124For each parsed NDJSON line, emit zero or more `ProviderRuntimeEvent`s:1541. `session/update: agent_message_chunk`
125155 - emit `message.delta` for assistant stream
1261. `system/init`1562. prompt terminal response (`session/prompt` result `stopReason: end_turn`)
127 - emit `session.started` (once per adapter session lifecycle)157 - emit `message.completed` + `turn.completed`
128 - emit `thread.started` if thread not yet emitted1583. `session/update: agent_thought_chunk`
1292. `assistant` partial chunks159 - initial mapping: emit thinking activity (or ignore if we keep current canonical surface minimal)
130 - emit `message.delta` with stable per-turn synthetic `itemId`1604. `session/update: tool_call`
1313. final `assistant` message161 - first-seen `toolCallId` emits `tool.started`
132 - emit `message.completed`162 - subsequent `tool_call` for same ID treated as metadata update (no duplicate started event)
1334. `tool_call/started`1635. `session/update: tool_call_update`
134 - emit `tool.started`164 - `in_progress`: optional progress activity
135 - map kind:165 - `completed`: emit `tool.completed` with summarized `rawOutput` when present
136 - shell -> `command`1666. `session/request_permission`
137 - edit -> `file-change`167 - emit `approval.requested` with mapped options
138 - read/grep/glob -> `other`168 - when client decision sent, emit `approval.resolved`
1395. `tool_call/completed`1697. protocol/process error
140 - emit `tool.completed`
141 - include summary detail from nested payload (`command`, `path`, stderr fragment, rejection reason)
1426. `thinking/*`
143 - initial version: ignore for canonical events (optional later: map to `tool.*` “Thinking”)
1447. `result/success`
145 - emit `turn.completed` with `status: completed` unless unrecoverable parse/process error already set failure
1468. non-JSON stdout/stderr protocol line
147 - emit `runtime.error`170 - emit `runtime.error`
148 - emit `turn.completed` with `status: failed`171 - fail active turn/session as appropriate
1499. `connection/*` + `retry/*` (when present)
150 - emit `tool.started/completed` with `toolKind: other`, title like “Connection retry”
151 - if final failure follows, also emit `runtime.error`
152172
153Synthetic IDs:173Synthetic IDs:
1541741. `turnId`: T3-generated UUID per `sendTurn`.
1551. `turnId`: adapter-generated UUID per `sendTurn`.1752. `itemId`:
1562. `itemId`: `${turnId}:assistant` for assistant stream; `${turnId}:${sanitizedCallId}` for tool calls.176 - assistant stream: `${turnId}:assistant`
1573. `call_id` sanitization: replace whitespace (including newline) with `_`.177 - tools: `${turnId}:${toolCallId}`
158178
159---179---
160180
161## 5) Approval and Checkpoint Behavior (explicit limitations)181## 5) Approval, Resume, and Rollback Behavior
162182
163### 5.1 Approvals183### 5.1 Approvals
164184
1651. Cursor CLI approval is internal; adapter cannot accept/reject mid-turn via `respondToRequest`.1851. Cursor ACP permission requests are externally controllable; implement full `respondToRequest` path in v1.
1662. Plan for v1:1862. Decision mapping:
167 - `respondToRequest` returns `ProviderAdapterRequestError` (“Cursor CLI does not expose external approval response API”).187 - allow once -> `allow-once`
168 - approval-required runtime uses no `--force`, so dangerous commands become `tool_call.result.rejected`.188 - allow always -> `allow-always`
1693. Future:189 - reject -> `reject-once`
170 - if Cursor exposes approval RPC/hooks, implement `approval.requested` + `approval.resolved` fully.190
191### 5.2 Resume
171192
172### 5.2 Rollback / thread read1931. `session/load` is available and should be first-class for adapter restart/reconnect.
1942. Must send required params: `sessionId`, `cwd`, `mcpServers`.
173195
1741. Cursor CLI has no observed equivalent to `thread/read` or `thread/rollback`.196### 5.3 Rollback / thread read
197
1981. ACP currently has no observed rollback API.
1752. Plan for v1:1992. Plan for v1:
176 - `readThread` returns adapter-maintained in-memory turn snapshot.200 - `readThread`: adapter-maintained snapshot projection
177 - `rollbackThread` returns `ProviderAdapterRequestError` unsupported.201 - `rollbackThread`: explicit unsupported error
1783. Product guard:2023. Product guard:
179 - disable checkpoint revert for Cursor threads until rollback is implemented.203 - disable checkpoint revert for Cursor threads in UI until rollback exists.
180204
181---205---
182206
183## 6) Required Contract and Runtime Changes207## 6) Required Contract and Runtime Changes
184208
185## 6.1 Contracts209### 6.1 Contracts
186210
1871. `packages/contracts/src/orchestration.ts`2111. Add `cursor` to `ProviderKind`.
188 - add `cursor` to `ProviderKind`.2122. Add Cursor provider start options (`providerOptions.cursor`), ACP-oriented:
1892. `packages/contracts/src/provider.ts`213 - optional `binaryPath`
190 - add `CursorProviderStartOptions` under `providerOptions.cursor`:214 - optional auth/mode knobs if needed later
191 - `binaryPath?`2153. Extend model options for Cursor list and traits mapping.
192 - `apiKey?` (optional; default login auth)2164. Add schemas for ACP-native event union in Cursor adapter service file.
193 - `trust?` (default true for headless)217
1943. `packages/contracts/src/model.ts`218### 6.2 Server orchestration and registry
195 - add `cursor` provider model options baseline.219
196 - initial set should mirror observed supported IDs that are stable enough for UX.2201. Register `CursorAdapter` in provider registry and server layer wiring.
1974. Update related contract tests.2212. Update provider-kind persistence decoding for `cursor`.
1982223. Fix `ProviderCommandReactor` precedence to honor explicit provider in turn-start command.
199## 6.2 Server orchestration and registry223
200224### 6.3 Web
2011. Add `CursorAdapter` to provider registry and server layer wiring.225
2022. Update provider-kind decoding in:2261. Cursor in provider picker and model picker (already partially done).
203 - `apps/server/src/provider/Layers/ProviderSessionDirectory.ts`2272. Trait controls map to concrete Cursor model identifiers.
204 - persistence schemas that currently literal-match provider kinds.2283. Surface unsupported rollback behavior in UX.
2053. Fix provider selection in `ProviderCommandReactor`:
206 - honor `thread.turn-start-requested.payload.provider` as highest precedence.
207 - fallback to existing session provider, then default.
208
209## 6.3 Web
210
2111. Enable Cursor in provider selector (`apps/web/src/session-logic.ts`).
2122. Add Cursor label/icon treatment.
2133. Add optional Cursor settings fields if using per-user overrides (binary path/api key).
2144. Ensure thread/provider display and legacy mapping code handles `cursor`.
215229
216---230---
217231
218## 7) Implementation Phases232## 7) Implementation Phases
219233
220### Phase A: Protocol-safe adapter skeleton234### Phase A: ACP process and protocol skeleton
221235
2221. Implement `CursorAdapter` service/layer with all runtime logic in `CursorAdapterLive` (no CLI manager), plus session map + event queue.2361. Implement ACP process lifecycle in `CursorAdapterLive`.
2232. Implement robust NDJSON parser with:2372. Implement JSON-RPC request/response multiplexer.
224 - line buffering2383. Implement `initialize`/`authenticate`/`session/new|load` flow.
225 - tolerant non-JSON handling2394. Wire `streamEvents` from ACP notifications.
226 - explicit process-exit mapping.
2273. Wire into registry and server layers.
228240
229### Phase B: Event projection completeness241### Phase B: Runtime projection and approvals
230242
2311. Map assistant/tool/result events to canonical runtime events.2431. Map `session/update` variants to canonical runtime events.
2322. Add synthetic ID strategy and item lifecycle consistency.2442. Implement permission-request bridging to `respondToRequest`.
2333. Add runtime error and retry handling.2453. Implement dedupe for repeated `tool_call` on same `toolCallId`.
234246
235### Phase C: Provider selection and UX247### Phase C: Turn control and interruption
236248
2371. Fix `ProviderCommandReactor` provider precedence.2491. Implement single in-flight prompt protection per session.
2382. Enable Cursor provider in web UI.2502. Implement interruption fallback (process restart + reload) because `session/cancel` unavailable.
2393. Add Cursor model defaults/options.2513. Ensure clean state recovery on ACP process crash.
240252
241### Phase D: Safeguards and unsupported surfaces253### Phase D: Orchestration + UX polish
242254
2431. Explicit unsupported errors for `respondToRequest` and `rollbackThread` (v1).2551. Provider routing precedence fix.
2442. Guard checkpoint-revert path for Cursor threads.2562. Cursor-specific UX notes for unsupported rollback.
2453. Document limitations in UI/help text.2573. End-to-end smoke and event log validation.
246258
247---259---
248260
...@@ -252,59 +264,64 @@ Follow project rule: backend external-service integrations tested via layered fa...@@ -252,59 +264,64 @@ Follow project rule: backend external-service integrations tested via layered fa
252264
253### 8.1 Unit tests (`CursorAdapter`)265### 8.1 Unit tests (`CursorAdapter`)
254266
2551. stream JSON parse and mapping:2671. JSON-RPC envelope parsing:
256 - assistant partial/final268 - response matching by id
257 - each tool type269 - server request handling (`session/request_permission`)
258 - shell success/failure/rejected270 - notification decode (`session/update`)
259 - non-JSON line failure2712. Event projection:
2602. process lifecycle:272 - `agent_message_chunk` / `agent_thought_chunk`
261 - start/send/interrupt/stop273 - `tool_call` + `tool_call_update` dedupe/lifecycle
262 - stale session errors274 - permission request -> approval events
2633. ID sanitization:2753. Error mapping:
264 - `call_id` with newline.276 - unknown session
277 - method-not-found (`session/cancel`)
278 - invalid params
265279
266### 8.2 Provider service/routing tests280### 8.2 Provider service/routing tests
267281
2681. Registry resolves `cursor`.2821. Registry resolves `cursor`.
2692. Session directory persistence reads/writes `cursor` provider.2832. Session directory persistence reads/writes `cursor`.
2703. ProviderService fan-out/order with Cursor events.2843. ProviderService fan-out ordering with Cursor ACP events.
271285
272### 8.3 Orchestration tests286### 8.3 Orchestration tests
273287
2741. `thread.turn.start` with `provider: cursor` routes to Cursor adapter.2881. `thread.turn.start` with `provider: cursor` routes to Cursor adapter.
2752. checkpoint revert on Cursor thread returns controlled failure activity.2892. approval response command maps to ACP permission response.
2763. approval response command on Cursor session surfaces “unsupported approval API”.2903. checkpoint revert on Cursor thread returns controlled unsupported failure.
277291
278### 8.4 Smoke/integration harness292### 8.4 Optional live smoke
279293
2801. Optional local smoke behind env flag (`CURSOR_SMOKE=1`) to run real `agent`:2941. Env-gated ACP smoke:
281 - create session295 - start session
282 - send simple turn296 - run prompt
283 - verify message delta/completion + turn completion.297 - observe deltas + completion
298 - exercise permission request path with one tool call
284299
285---300---
286301
287## 9) Operational Notes302## 9) Operational Notes
288303
2891. Do not run concurrent `agent` processes per workspace by default; serialize per adapter session to avoid config races.3041. Keep one in-flight turn per ACP session.
2902. Keep native event NDJSON logs for Cursor similar to Codex adapter logs.3052. Keep per-session ACP process logs/NDJSON artifacts for debugging.
2913. Treat startup plain-text failures as process-level errors and surface full message.3063. Treat `session/cancel` as unsupported until Cursor ships it; avoid relying on it.
3074. Preserve resume metadata (`acpSessionId`) for crash recovery.
292308
293---309---
294310
295## 10) Open Questions311## 10) Open Questions
296312
2971. Should Cursor provider expose full model list dynamically (`agent --list-models`) or use curated static list in contracts?3131. Should we call `authenticate` always, or only after auth-required errors?
2982. Should T3 keep strict approval UX parity with Codex, or accept Cursor’s current non-interactive approval limitation in v1?3142. Should model selection be passed at `session/new` only, or can/should we support model switching mid-session if ACP adds API?
2993. Is checkpoint revert required for initial Cursor release, or can it ship as explicitly unsupported?3153. For interruption UX, do we expose “hard interrupt” semantics (process restart) explicitly?
300316
301---317---
302318
303## 11) Delivery Checklist319## 11) Delivery Checklist
304320
3051. Contracts updated (`ProviderKind`, provider start options, models).3211. Plan/documentation switched from headless `agent -p` to ACP `agent acp`.
3062. Cursor adapter + layer implemented and registered.3222. Contracts updated (`ProviderKind`, Cursor options, model/trait mapping).
3073. Provider selection precedence fixed in `ProviderCommandReactor`.3233. Cursor ACP adapter layer implemented and registered.
3084. Cursor enabled in web provider picker.3244. Provider precedence fixed in orchestration router.
3095. Tests added for adapter mapping, routing, and orchestration behavior.3255. Approval response path wired through ACP permission requests.
3106. Lint + test suite green.3266. Tests added for protocol decode, projection, approval flow, and routing.
3277. Lint + tests green.