Why does this exist? Cursor published their own ACP client (docs), but using it in Zed was rough as I somehow had to permit tool calls the whole time.
Disclaimer: I am not affiliated with Cursor or Zed. This project is a personal experiment and should not be considered an official product of either company. I am a big fan of both products and wanted to combine what I like with both of them: An amazing editor and a great AI coding agent (and composer-1, holy this model flies xD).
An Agent Client Protocol (ACP) adapter for Cursor Agent CLI, enabling Cursor's AI coding assistant to be used within Zed and other ACP-compatible clients.
This is an ai-assisted personal project aimed at bringing Cursor's agent into Zed. It acts as a wrapper around native agent acp, auto-approving tool calls when you opt in and preserving compatibility features that the current native ACP server does not expose yet.
Based on claude-code-acp by Zed Industries - the original ACP adapter for Claude Code that served as the architectural foundation for this project.
- Native ACP backend: Uses
agent acpinstead of the olderagent --print --output-format stream-jsonwrapper path - Tool and message streaming: Forwards native ACP
session/updatenotifications to the client - Cursor extension RPCs: Forwards native
cursor/*extension methods and notifications (e.g.cursor/ask_question,cursor/update_todos) to the outer ACP client when supported - Cursor commands and skills: Relies on native ACP
available_commands_updatefor Cursor/user commands and skills - Native command precedence: When Cursor advertises a slash command, the adapter forwards that command to native ACP instead of intercepting it locally
- Mode switching: Maps wrapper modes to native
agent,ask, andplan
- ACP session lifecycle: Supports
new,resume, andfork(best-effort) session operations - Session persistence & history replay: Stores visible history locally and replays it on resume/load
- Session listing: Lists past local sessions with optional cwd filtering and pagination
- Model listing and best-effort model selection: Keeps
/modelsupport while native ACP has no stable model API - Authentication helpers:
/login,/logout,/status, plus terminal-auth metadata for ACP clients that support it - Prompt flattening for ACP clients: Keeps embedded context and image prompts working by converting them to text before forwarding to native ACP
- Optional Yolo mode (
yolo): Auto-approves native ACP permission requests when explicitly selected - Turn closing summary: Collects assistant text from all native
agent_message_chunkshapes we can decode; if a turn ends with tools but no streamed assistant text, emits a Composer-style markdown recap (per-file bullets plus recent shell output) so the client can show a final message block
- Native Cursor ACP on the currently validated CLI does not expose
session/list,session/resume, orsession/set_model - Resuming after restarting
cursor-acpuses nativesession/loadwhen a storedbackendSessionIdis available; if that fails, the adapter starts a new native session and replays local JSONL so visible history is preserved debugmode is intentionally not exposed in this phase
If you used an older cursor-acp that drove Cursor through the legacy agent --print --output-format stream-json path, upgrading changes behavior in ways that are easy to mistake for “bugs” unless you know what moved:
Earlier releases documented CURSOR_ACP_DEFAULT_MODE and CURSOR_ACP_DEFAULT_MODEL. Those environment variables are no longer read. Defaults now come from the ACP client’s session/new request, for example Zed’s inline default_mode / default_model fields on the custom agent entry.
Older builds accepted bypassPermissions and autoRunAllCommands as synonyms for yolo in default_mode and in /mode. Those names are no longer accepted—use yolo (or pick Yolo in the client).
- Execution model: The adapter now spawns native
agent acpand speaks ACP to Cursor’s server. Session traffic, slash-command routing, and tool permission flows follow native ACP, not the previous wrapper-only protocol. - Slash commands: If Cursor advertises a command name that matches a built-in wrapper command (for example
/model), the native command wins and is forwarded to the backend; the wrapper no longer always intercepts those names. - Permissions: Tool and action approval is mediated through native
requestPermissionnotifications. The adapter translates them to the outer ACP client unless you opt into Yolo (below). - Resume / listing: Resume uses native
session/loadwhen a stored backend session id is available; native Cursor ACP still does not expose everything the outer protocol can represent (see Known limitations). Expect differences versus the old stream-json session lifecycle.
- What it does now: Yolo only changes how the adapter answers native ACP permission requests—it auto-selects an allow-style option (preferring
allow_always, thenallow_once, then another allow). It does not introduce a separate native Cursor mode: both Default and Yolo map to nativeagent; the difference is whether permissions are surfaced to your client or approved inside the adapter. - Why that can break expectations: If you relied on the old wrapper’s auto-approval semantics (or on names like
bypassPermissions/autoRunAllCommands) as identical to “unrestricted agent” in the legacy path, behavior may differ because approvals are now tied to native permission options and to the ACP permission channel. - Configuration: Set
default_modetoyoloin your ACP client configuration (for example the Zed custom agent entry) to get automatic approval. Do not use legacy names likebypassPermissionsorautoRunAllCommands; see Legacy Yolo mode name aliases removed.
The same notice is linked from docs/breaking-changes.md.
| Command | Description |
|---|---|
/help |
Show available commands |
/model |
Switch or display the current model |
/mode |
Switch or display the current mode |
/status |
Show authentication and session status |
/login |
Authenticate with Cursor |
/logout |
Sign out of Cursor |
Other Cursor commands and skills are forwarded from native agent acp via available_commands_update.
If a native Cursor command collides with one of the wrapper commands above, the native command takes precedence.
bun install
bun run buildThis compiles the project and produces the cursor-acp binary entry point at ./dist/index.js.
For Zed to find the cursor-acp command, it needs to be available on your PATH. Choose one of the following options:
Option A — npm link (recommended)
Run npm link inside the repository root to symlink the cursor-acp binary globally:
npm linkOption B — manual symlink
Create a symlink manually:
ln -s "$(pwd)/dist/index.js" /usr/local/bin/cursor-acpVerify the binary is accessible:
which cursor-acpbun run startOr use the binary:
cursor-acpOpen your Zed settings file via the Command Palette (zed: open settings) and add a custom agent server entry under agent_servers:
{
"agent_servers": {
"Cursor": {
"type": "custom",
"command": "cursor-acp",
"args": [],
"default_mode": "yolo"
}
}
}If cursor-acp is not on your PATH, use the full absolute path to the entry point instead:
{
"agent_servers": {
"Cursor": {
"type": "custom",
"command": "/absolute/path/to/cursor-acp/dist/index.js",
"args": [],
"default_mode": "yolo"
}
}
}Zed can pass the initial mode and model through the ACP session/new request. Put them directly on the custom agent entry:
{
"agent_servers": {
"Cursor": {
"type": "custom",
"command": "cursor-acp",
"args": [],
"default_mode": "yolo",
"default_model": "gpt-5.4-mini-medium"
}
}
}default_mode— one ofdefault,yolo,plan, orask(legacy alias:acceptEdits→default)default_model— optional model ID forwarded from the ACP client when supported
Omit keys you do not need. There is no separate adapter-specific config file for these defaults anymore.
The mode picker in Zed (and other ACP clients) lists Default, Yolo, Ask, and Plan — including Yolo, which is implemented only in this adapter (Cursor’s native session still uses its usual Agent/Plan/Ask wiring under the hood).
- Open the Agent Panel with
Cmd+?(macOS) orCtrl+?(Linux) - Click the
+button in the top right and select Cursor - On first use, run the
/loginslash command to authenticate with Cursor - The default mode is
default; if you want tool execution without repeated prompts, set"default_mode": "yolo"on the Zed agent entry
You can also bind a keyboard shortcut to quickly open a new Cursor thread by adding the following to your keymap.json (open via zed: open keymap file):
[
{
"bindings": {
"cmd-alt-u": ["agent::NewExternalAgentThread", { "agent": "Cursor" }]
}
}
]If something isn't working, open Zed's Command Palette and run dev: open acp logs to inspect the ACP messages being sent between Zed and cursor-acp.
bun run devbun run test # Run tests in watch mode
bun run test:run # Run tests oncebun run lint # Check for linting issues
bun run lint:fix # Auto-fix linting issues
bun run format # Format code with oxfmt
bun run check # Run lint and format checks- See Breaking changes (native ACP & Yolo) for semantic and protocol differences when upgrading from the legacy stream-json wrapper.
default,yolo,ask, andplanare the advertised modesacceptEditsis a deprecated alias fordefault(still accepted). For Yolo, useyolo—bypassPermissionsandautoRunAllCommandsare no longer accepted (see Legacy Yolo mode name aliases removed)debugis not exposed- Custom commands and skills are forwarded from native
agent acp
src/
├── index.ts # CLI entry point
├── lib.ts # Library exports
├── cursor-acp-agent.ts # Outer ACP agent + compatibility layer
├── cursor-native-acp-client.ts # Native `agent acp` bridge
├── cursor-cli-runner.ts # Cursor CLI helpers (model listing)
├── prompt-conversion.ts # Flattens ACP prompts for native ACP forwarding
├── auth.ts # Authentication handling
├── settings.ts # Mode ids and normalization helpers
├── session-storage.ts # Session persistence and history replay
├── slash-commands.ts # Slash command handlers
├── tools.ts # Tool definitions
├── native-assistant-stream.ts # Assistant chunk parsing + end-of-turn recap
├── utils.ts # Utility functions
└── tests/ # Test files
The adapter now uses agent acp as its execution backend and keeps local compatibility logic for resume/list/model behavior that native ACP does not currently expose.
Sessions are persisted under ~/.cursor-acp/sessions/ (or $CURSOR_ACP_CONFIG_DIR/sessions/ if set). Each project has an encoded subdirectory; session history is stored as JSONL files with user and assistant messages for resume and replay.
- Zed
- Node.js 25.6.1+
- Bun (for package management and scripts)
- Cursor CLI installed and available in PATH
- Valid Cursor subscription
This project is based on claude-code-acp by Zed Industries. Their work on the original Claude Code ACP adapter provided the architectural patterns and protocol implementation that made this project possible.
Copyright 2026 Raphael Lüthy. Licensed under the Apache License, Version 2.0. See LICENSE for the full license text. Third-party attributions are listed in NOTICE.