# Five simplification opportunities
Recalled from the 2026-08-09 investigation session, revised after unused ACP protocol/client code was removed from the product path. Shared helpers that Cursor/Prime still need remain under `src/acp/` (errors, IO options, trace coalesce, process-group teardown); that rename/split is optional cleanup, not one of the five ideas below.
Suggested order: (5) + (1 core) first — then (3) shrinks with them; (2) and (4) are independent.
---
## 1. Factor the shared Cursor/Prime SDK core
**tl;dr:** Merge the near-duplicate `cursor_sdk` / `prime_sdk` cores into one parameterized bridge client; keep provider-specific auth, spawn, and node resolve.
**Still true after ACP removal:** The product path is only Cursor vs Prime. Pairwise similarity remains high on the cores (`log_adapter_tool` ~0.97 normalized, `session` ~0.92, `client` high). Auth / timing / node_resolve still diverge, so this is a *core* merge, not a full-tree rename.
**Simplify by:** One `bridge_sdk` (or `SdkClient<P: BridgeProvider>`) with a small provider trait for auth, spawn, resume, and optional `modelsJsonPath`. That also shrinks `AgentBackend`’s two arms (idea 3).
---
## 2. Type the diffuse “model id” concept
**tl;dr:** Carry `ParsedModel` (or a `ModelId` newtype) after CLI/config parse instead of bare `String` plus re-parse helpers.
**Revised:** ACP clients that held `model: String` are gone. The diffuse concept remains on the live path: `SharedOpts.model`, `CursorSdkClient.model`, `PrimeSdkClient.model`, config, and emit structs are still `String`. `ParsedModel` / `ModelBackend` exist in `src/model_id.rs` but are not stored in production structs outside that module. Call sites still re-detect with `uses_prime_backend`, `uses_prime_local_backend`, and `uses_local_backend` (the last two are the same predicate).
**Simplify by:** Store `ParsedModel` after parse; derive the canonical string only at wire/config boundaries; delete the duplicate local-backend predicate pair.
---
## 3. Collapse `AgentBackend` match fan-out
**tl;dr:** Stop re-dispatching every operation through a thin enum; prefer one client surface (trait or unified SDK type).
**Revised:** The ACP arm is gone. `AgentBackend` is now `CursorSdk | PrimeSdk` only (`src/agent_backend/backend.rs`). Match soup remains: on the order of 13 `match` sites across `backend.rs` + `backend_ops.rs`, with paired Cursor/Prime arms (~14 each). Unique logic is thinner than when there were three arms; leftover ACP-only builders (`build_agent` / `new_agent_client`) are already gone. Stale names such as `max_acp_retries` and `run_inspire_acp` are naming debt from the old path.
**Simplify by:** After (1), a trait (or single SDK client) so workflows call one API. Two-arm matches become one implementation.
---
## 4. Extract shared one-shot session prep for `--do` / `inspire`
**tl;dr:** Factor the duplicated bootstrap choreography; leave only prompt rendering and tee/DM flags per command.
**Still true:** `prepare_do_run` and `prepare_inspire_run` still share the same shape: build backend → resolve request → `RunArtifacts` → auth → prompts log dir → begin session → run prompt → end / restore / timing. A shared checklist of those steps still hits both flows. Local differences that should stay: prompt construction, tee/DM flags, startup emit. The inspire runner is still named `run_inspire_acp` despite using the SDK backend.
**Simplify by:** A `OneShotSessionPrep` (artifacts + backend + backups + prompt) and a shared `run_one_shot_coder_prompt(...)` helper.
---
## 5. Unify bridge protocol types (`BridgeRequest` / `BridgeEvent`)
**tl;dr:** One shared protocol module for the JSONL bridge; optional fields for provider-shaped request diffs.
**Still true:** `BridgeEvent` and `PrimeBridgeEvent` remain parallel type trees (`src/cursor_sdk/protocol.rs`, `src/prime_sdk/protocol.rs`). Request divergence is still optional/provider-shaped (Cursor resume / `force_stuck`; Prime `modelsJsonPath`). Encode/decode stay duplicated under different names.
**Simplify by:** One `bridge_protocol` module with `skip_serializing_if` for optional fields. Pair with (1) so log adapters and session I/O stop being forked.
---
## Summary
| 1 | Factor Cursor/Prime SDK core | Unchanged opportunity; product path is clearer (only two SDKs) |
| 2 | Type model id (`ParsedModel`) | Still open; ACP `String` clients gone, live path still `String` |
| 3 | Collapse `AgentBackend` dispatch | Still open but smaller (2-arm, not 3); ACP builders already removed |
| 4 | Shared `--do` / `inspire` prep | Unchanged; stale `*_acp` names remain |
| 5 | Shared bridge protocol types | Unchanged |
**Not claimed as one of the five:** Kiss coverage witness sprawl under `src/coverage_kiss/` / `*_kiss_cov*.rs` is another large target, but only after the structural merges above.