| 1 | <!-- English translation of adr/0016-agent-client-protocol-external-agent.md. Canonical Russian: ../../adr/0016-agent-client-protocol-external-agent.md --> |
| 2 | |
| 3 | # ADR 0016: External agent using Agent Client Protocol (stdio, Cursor CLI) |
| 4 | |
| 5 | **Status:** Accepted · Implemented |
| 6 | **Date:** 2026-04-05 |
| 7 | ## Related ADRs |
| 8 | |
| 9 | | ADR | Role | |
| 10 | |-----|------| |
| 11 | | [0008](0008-mcp-contracts-and-testable-infrastructure.md) | MCP - **other** circuit: IDE tool server; not to be confused with ACP | |
| 12 | |
| 13 | ### Outside ADR |
| 14 | |
| 15 | | Document | Role | |
| 16 | |----------|------| |
| 17 | | [note-acp-cascade-cursor-v1.md](../ui-ux/note-acp-cascade-cursor-v1.md) | terminology and specification links | |
| 18 | | [concept-pfd-mfd-cascade-v1.md](../ui-ux/concept-pfd-mfd-cascade-v1.md) | concept pfd mfd cascade v1 | |
| 19 | |
| 20 | ### Implementation snapshot |
| 21 | |
| 22 | | Element | Meaning | |
| 23 | |---------|----------| |
| 24 | | — | Cursor ACP / stdio in chat and settings; orthogonal to MCP - see text | |
| 25 | |
| 26 | --- |
| 27 | ## Context |
| 28 | |
| 29 | You need to connect the built-in CascadeIDE chat with an **external** agent (primarily **Cursor** via the official CLI and ACP mode), without embedding the UI Cursor and without your own wire “from scratch”. |
| 30 | |
| 31 | **Agent Client Protocol (ACP)** is an open client↔agent contract (JSON-RPC by string, typical transport **stdio**). PoC passed: chat responses, Russian text, session and callbacks to the IDE (fs, terminal) according to the specification. |
| 32 | |
| 33 | ## Solution |
| 34 | |
| 35 | 1. **Transport:** subprocess `cursor-agent` (or equivalent from the dist-package) with argument **`acp`**, **stdin/stdout** for protocol, no console window (`CreateNoWindow`), stream redirection. |
| 36 | |
| 37 | 2. **Encoding:** for **Windows** explicitly set **UTF-8** for redirected stdin/stdout/stderr of the agent process (and for child ACP-terminal processes), otherwise responses in Russian are decoded in OEM and give “crazy messages”. |
| 38 | |
| 39 | 3. **Client SDK:** library **AgentClientProtocol** (community, upstream [acp-csharp](https://github.com/nuskey8/acp-csharp)) - **vendor** in `externals/acp-csharp/` as sources, connected via `ProjectReference`. Sources under `externals/**/*.cs` are **not** compiled in the main IDE assembly (`Compile Remove` in `CascadeIDE.csproj`) so that the nested sandbox with top-level `Main` does not intercept the application entry point. |
| 40 | |
| 41 | 4. **Integration into the product:** separate chat provider (**Cursor ACP**), setting the path to `cursor-agent.cmd` or to the directory with `dist-package`; ACP session lifecycle and terminal/fs mirroring - in `Services/CursorAcp/`. |
| 42 | |
| 43 | 5. **Cursor authentication:** not interactive inside WinExe chat on first launch; the user passes the **`agent login` / API key** in a normal terminal or through environment variables (as in the Cursor documentation). Agent errors before UI - as development progresses, stderr can be duplicated into chat/log (not part of this ADR). |
| 44 | |
| 45 | 6. **Boundaries:** ACP is about **dialogue with an external agent**. The MCP server IDE (`--mcp-stdio`, agent tools) remains a separate loop ([0008](0008-mcp-contracts-and-testable-infrastructure.md)); combining scenarios with subsequent iterations. |
| 46 | |
| 47 | ## Consequences |
| 48 | |
| 49 | - Upstream `acp-csharp` updates - conscious merge/vendoring; when changing the major ACP specification - checking compatibility with `cursor-agent`. |
| 50 | - Dependency on CLI Cursor format (argument `acp`); when Cursor documentation changes - manual regression or smoke script. |
| 51 | - Duplication of types when erroneously including SDK sources and package references - prevented by `Compile Remove` for `externals`. |
| 52 | |
| 53 | ## Rejected alternatives |
| 54 | |
| 55 | - **Ollama only / local LLM only without ACP** - remains a different provider; does not cover the “same agent as in Cursor” scenario. |
| 56 | - **Own binary protocol over stdio** - rejected in favor of the ACP standard and a ready-made client SDK. |
| 57 | - **Embedding webview Cursor** is outside the scope of the ACP desktop client. |
| 58 | |
| 59 | ## Discussion (does not block Accepted) |
| 60 | |
| 61 | - Submodule instead of vendoring `externals/acp-csharp` - migration is possible when the update process stabilizes. |
| 62 | - Output stderr of the agent in the chat UI in case of errors and “Authentication required”. |