feat: add Cursor Agent CLI support#301
Conversation
Add Cursor Agent CLI as a new agent backend using native ACP support (`cursor-agent acp`). Includes Dockerfile with pinned version download, CI matrix entries, Helm chart config, and documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align with kiro Dockerfile conventions: - Rename user from 'node' to 'agent' (uid 1000) - Use cp instead of symlink for cursor-agent binary - Pre-create ~/.cursor/ directory - Fix docs/cursor.md token path from ~/.cursor-agent/ to ~/.cursor/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cursor-agent creates the directory on first run. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract tarball directly to /opt, rename dist-package to cursor-agent - Remove preview warning from README agent table - Add Model Selection section to docs/cursor.md - Fix workingDir in Helm example (/home/node → /home/agent) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
c99665d to
94ed603
Compare
masami-agent
left a comment
There was a problem hiding this comment.
Review — PR #301
Excellent work, @brettchien. This is a well-researched, config-only integration with thorough documentation and end-to-end validation. The prior art analysis (OpenClaw, Hermes) and the live ACP handshake verification are particularly valuable.
✅ What looks good
- Zero
src/changes — pure configuration integration, lowest risk - Dockerfile.cursor — correct pattern:
debian:bookworm-slimbase (not node), pinned tarball,agentuser (uid 1000),pgrephealthcheck - CI matrix — all 3 sections updated consistently (build, merge-manifests, chart-version)
- docs/cursor.md — comprehensive: architecture, config, Docker, auth, Helm, model selection, limitations
- RELEASING.md — updated image count 4 → 6 (also adds missing copilot entry)
- ACP handshake verified —
protocolVersion: 1integer match confirmed against cursor-agent v2026.04.08-a41fba1
🔴 Must fix before merge
1. values.yaml cursor example has wrong workingDir
# workingDir: /home/nodeCursor uses debian:bookworm-slim (not node:22), so the user is agent with home at /home/agent. This should be:
# workingDir: /home/agentThe config.toml.example and docs/cursor.md correctly use /home/agent — just values.yaml is inconsistent.
2. Dockerfile.cursor missing procps
The healthcheck uses pgrep -x openab, but procps is not installed. Same issue as #232 / PR #234. Add procps to the apt-get install line:
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl procps && rm -rf /var/lib/apt/lists/*🟡 Non-blocking
3. Cursor tarball URL stability
downloads.cursor.com/lab/${CURSOR_VERSION}/linux/${ARCH}/agent-cli-package.tar.gz — is this URL documented/stable, or could it change without notice? If Cursor changes their distribution path, the Dockerfile breaks silently. A comment in the Dockerfile noting the source would help future maintainers.
4. --model auto not in default args
config.toml.example uses args = ["acp"] without --model. The docs mention --model auto as an option. Consider whether the default should include --model auto for consistency with the Helm example in the PR description.
5. RELEASING.md copilot addition
Adding the missing openab-copilot line is correct but technically out of scope for this PR. Not blocking — just noting it's a bonus fix.
📝 Summary
| Priority | Item | Status |
|---|---|---|
| 🔴 | values.yaml workingDir should be /home/agent |
Needs fix |
| 🔴 | Dockerfile.cursor missing procps for healthcheck |
Needs fix |
| 🟡 | Tarball URL stability comment | Non-blocking |
| 🟡 | Default --model auto consideration |
Non-blocking |
| 🟡 | RELEASING.md copilot bonus fix | Non-blocking |
Two small fixes and this is ready to approve. Great contribution!
Cursor uses debian:bookworm-slim base with `agent` user (uid 1000, home /home/agent), not node:22 like other agents. The example comment in values.yaml was copy-pasted from node-based agents. Addresses review comment on PR openabdev#301 from @masami-agent.
HEALTHCHECK uses `pgrep -x openab`, which requires procps. Debian slim does not ship with it, so the healthcheck was silently failing (command not found) and the pod would enter Unhealthy state. Same fix pattern as pending PR openabdev#234 for the other Dockerfiles. Addresses review comment on PR openabdev#301 from @masami-agent.
Add a comment explaining the Cursor tarball URL pattern (downloads.cursor.com/lab/<version>/linux/<arch>/...) and that it's scraped from the official downloads page — there's no apt/yum package. If Cursor changes the URL scheme, the build will fail with a curl 404 at build time, so future maintainers have a hint of where to check. Addresses non-blocking review comment on PR openabdev#301 from @masami-agent.
Align config.toml.example with docs/cursor.md and the Helm example in PR openabdev#301, both of which use `--model auto`. `auto` is Cursor CLI's built-in classifier router and is the safest default (users can override via helm values). Addresses non-blocking review comment on PR openabdev#301 from @masami-agent.
Add `--workspace /home/agent` to cursor example args in both charts/openab/values.yaml and config.toml.example. Rationale: pinning the workspace explicitly makes cursor-agent use /home/agent for .cursor/ config/approvals lookup. Without it, cursor-agent auto-detects from cwd, which also lands on /home/agent in containers but can differ in interactive/local runs. Explicit is safer and matches the runtime config used in production deployments. Part of PR openabdev#301 polish.
Document how MCP servers are configured in cursor-agent ACP mode: - The `--workspace` flag determines which `.cursor/mcp.json` is loaded and which approvals slug is used — explicit is safer than relying on cwd auto-detection. - `--approve-mcps` does NOT apply in ACP mode (interactive CLI only); MCP load gating uses an approval file at .cursor/projects/<slug>/mcp-approvals.json. - Two paths to approve: pre-create the file, or approve once interactively so Cursor persists it. - openab auto-replies session/request_permission with allow_always, so once loaded, subsequent tool calls pass without prompting. - Verify with `cursor-agent mcp list`. Part of PR openabdev#301 polish.
|
@masami-agent Thanks for the thorough review! Addressed all 5 items below. Discord Discussion URL: https://discord.com/channels/1491295327620169908/1493798720142180473 🔴 Must-fix (both addressed)1.
|
masami-agent
left a comment
There was a problem hiding this comment.
Re-review — PR #301
All 5 items from my initial review have been addressed. Verified the latest diff:
✅ Must-fix (resolved)
values.yamlworkingDir —/home/node→/home/agent✓Dockerfile.cursorprocps — added to runtime apt install ✓
✅ Non-blocking (resolved)
- Tarball URL stability comment — clear 4-line comment above
ARG CURSOR_VERSION✓ - Default
--model auto— aligned acrossconfig.toml.example,values.yaml, anddocs/cursor.md✓ - RELEASING.md copilot line — already present, image count updated to 6 ✓
✅ Bonus: MCP documentation
The new "MCP Usage (ACP mode caveats)" section in docs/cursor.md is thorough and well-researched — covers --workspace anchoring, --approve-mcps no-op in ACP mode, approval file mechanics, and interaction with openab allow_always. This is genuinely useful for anyone deploying Cursor with MCP servers.
Code quality
- Dockerfile follows the established multi-stage pattern
- CI matrix additions are consistent with existing variants
- Helm values example is properly commented out
- Documentation is clear and complete
LGTM. Approving as agent reviewer.
What problem does this solve?
OpenAB supports several ACP-compatible coding CLIs (Kiro, Claude Code, Codex, Gemini, Copilot) but not Cursor Agent CLI. Cursor ships native ACP support (
cursor-agent acp) and access to 80+ models (Claude, GPT-5, Gemini 3, Grok 4, Kimi K2, Composer,auto) behind one subscription, which is strictly additive for users who already pay for Cursor.Ref #18
Discord Discussion URL: https://discord.com/channels/1491295327620169908/1493798720142180473
At a Glance
No changes to
src/— this is a configuration-only integration.Prior Art & Industry Research
OpenClaw (openclaw/openclaw) — personal AI assistant gateway across 20+ messaging platforms. Coding‑CLI story is explicitly ACP‑based: a bundled
acpxruntime plugin drives harnesses via/acp spawn <agentId>andsessions_spawn({ runtime: "acp" })(docs/tools/acp-agents.md).acpxruntime.src/acp/*,extensions/acpx/); a separate text-only "CLI Backends" path exists as fallback but is not ACP.acpx-registered harness is swappable byagentId.cursor-agent acpworks from CLI but dies via gateway — "queue owner unavailable"), [Bug]: ACP server rejects MCP protocolVersion: 2025-11-25 from VS Code 1.113 / Cursor openclaw/openclaw#56102 (MCPprotocolVersion: 2025-11-25rejection from VS Code/Cursor).Hermes Agent (NousResearch/hermes-agent) — Nous Research's self-hosted agent across Telegram/Discord/Slack/WhatsApp/Signal/Email + CLI. Uses ACP in the opposite direction from openab: runs as an ACP server for editors via
hermes acp(docs/acp-setup.md).agent/copilot_acp_client.py). Generalizing it is still an open proposal — feat: Generalized ACP client for multi-agent CLI orchestration NousResearch/hermes-agent#5257 (open, unmerged) and Feature: Agent Migration System — Auto-Detect & Import Settings from Claude Code, Codex, Gemini CLI, Cursor, Aider, Roo Code & Others on First Install NousResearch/hermes-agent#524 (Cursor config import, also open).hermes_cli/providers.py); coding CLIs are not first-class backends.Takeaway: OpenClaw ships the closest analog but through a heavier
acpxrouter (and the Cursor path has known gateway bugs). Hermes doesn't do this at all yet. OpenAB's existing directspawn(cli, ["acp"])→ stdio JSON-RPC pattern is already well-aligned; this PR just adds Cursor as one more entry in the same pluggable model.Proposed Solution
Add Cursor as a first-class agent backend alongside the existing five, without touching
src/:Dockerfile.cursordownloads.cursor.com;agentuser (uid 1000)docs/cursor.mdconfig.toml.examplecursor-agent[agent]blockREADME.md.github/workflows/build.yml-cursorvariant in all 3 CI matrix sectionsRELEASING.mdcharts/openab/values.yamlcharts/openab/templates/NOTES.txtcursor-agent loginauth instructionsWhy This Approach
Native ACP over adapter.
cursor-agent acpspeaks ACP directly over stdio JSON-RPC. Our existingsrc/acp/connection.rsalready sendsprotocolVersion: 1as an integer, which matches the Cursor response verbatim — no shim required. Verified against cursor-agent v2026.04.08-a41fba1:debian:bookworm-slim base, not node:22. The Cursor tarball is self-contained — it bundles its own
nodebinary and JS chunks. A Node base image would add ~170 MB of runtime we'd never use.Pinned tarball, not npm/npx. Cursor Agent CLI is not published on npm; the canonical distribution is
downloads.cursor.com/lab/{version}/linux/{arch}/agent-cli-package.tar.gz.ARG CURSOR_VERSION=2026.04.08-a41fba1pins the version for reproducible builds.Tradeoffs: (1) Cursor Agent CLI requires interactive
cursor-agent loginfor auth — same story as kiro-cli; PVC persistence required. (2) Cursor is a separate distribution from Cursor Desktop; version upgrades happen on Cursor's cadence, not ours.Alternatives Considered
node:22base image +npm install -gnode:22adds ~170 MB of runtime the self-contained tarball doesn't needcodex-acppattern)cursor-agent exec(non-interactive mode)DockerfileDockerfile.cursorkeeps the default image leanValidation
cargo checkpasses (nosrc/changes, but verified clean — 45.09s cold)cargo testpasses — 34 passed, 0 failed (ran locally on this branch)docker build -f Dockerfile.cursor -t openab-cursor:local .succeedsagents.cursorvalues on OrbStack + hostPath auth mountinitializeround-trip verified against cursor-agent v2026.04.08-a41fba1 (see response above)cursor-agent acp --model auto, streamed reply back to thread ✅.github/workflows/build.yml) will run on merge — localactrun not attemptedManual test steps (reproducible):