Skip to content

feat: add Cursor Agent CLI support#301

Open
brettchien wants to merge 10 commits intoopenabdev:mainfrom
brettchien:feat/cursor-agent-cli
Open

feat: add Cursor Agent CLI support#301
brettchien wants to merge 10 commits intoopenabdev:mainfrom
brettchien:feat/cursor-agent-cli

Conversation

@brettchien
Copy link
Copy Markdown

@brettchien brettchien commented Apr 13, 2026

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

Discord mention
      │
      ▼
openab (Rust) ── spawn("cursor-agent", ["acp", "--model", "auto"])
      │
      ▼
cursor-agent acp                    ← native ACP, stdio JSON-RPC
      │
      ├─ initialize                 → agentCapabilities: { loadSession: true }
      ├─ session/new                → sessionId
      └─ session/prompt             → session/update stream → stopReason: end_turn

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 acpx runtime plugin drives harnesses via /acp spawn <agentId> and sessions_spawn({ runtime: "acp" }) (docs/tools/acp-agents.md).

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).

Takeaway: OpenClaw ships the closest analog but through a heavier acpx router (and the Cursor path has known gateway bugs). Hermes doesn't do this at all yet. OpenAB's existing direct spawn(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/:

File Change Description
Dockerfile.cursor NEW Multi-stage: rust:1-bookworm builder + debian:bookworm-slim runtime; pinned tarball from downloads.cursor.com; agent user (uid 1000)
docs/cursor.md NEW Setup guide: architecture, config, Docker, auth, Helm, model selection, limitations
config.toml.example MOD Commented cursor-agent [agent] block
README.md MOD Cursor row in the agent backends table
.github/workflows/build.yml MOD -cursor variant in all 3 CI matrix sections
RELEASING.md MOD cursor (and missing copilot) in image variants, count 4 → 6
charts/openab/values.yaml MOD Commented cursor example block
charts/openab/templates/NOTES.txt MOD cursor-agent login auth instructions

Why This Approach

Native ACP over adapter. cursor-agent acp speaks ACP directly over stdio JSON-RPC. Our existing src/acp/connection.rs already sends protocolVersion: 1 as an integer, which matches the Cursor response verbatim — no shim required. Verified against cursor-agent v2026.04.08-a41fba1:

→ initialize  { protocolVersion: 1, clientInfo: { name: "test", version: "0.1" } }
← { protocolVersion: 1,
    agentCapabilities: { loadSession: true,
      mcpCapabilities: { http: true, sse: true },
      promptCapabilities: { audio: false, embeddedContext: false, image: true } },
    authMethods: [{ id: "cursor_login", name: "Cursor Login" }] }

debian:bookworm-slim base, not node:22. The Cursor tarball is self-contained — it bundles its own node binary 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-a41fba1 pins the version for reproducible builds.

Tradeoffs: (1) Cursor Agent CLI requires interactive cursor-agent login for 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

Alternative Rejected because
node:22 base image + npm install -g Cursor isn't published on npm; node:22 adds ~170 MB of runtime the self-contained tarball doesn't need
Third-party ACP adapter (like codex-acp pattern) Cursor ships native ACP — adding an adapter would be strict regression in surface area and latency
cursor-agent exec (non-interactive mode) Loses ACP session persistence, streaming, and tool-call plumbing that openab already relies on
Bundling Cursor into the default Dockerfile Would force all users to pull Cursor even if they use Kiro/Claude/Codex; separate Dockerfile.cursor keeps the default image lean

Validation

  • cargo check passes (no src/ changes, but verified clean — 45.09s cold)
  • cargo test passes — 34 passed, 0 failed (ran locally on this branch)
  • Docker build: docker build -f Dockerfile.cursor -t openab-cursor:local . succeeds
  • K8s deploy: Helm install with agents.cursor values on OrbStack + hostPath auth mount
  • ACP handshake: JSON-RPC initialize round-trip verified against cursor-agent v2026.04.08-a41fba1 (see response above)
  • End-to-end: Octocat bot mentioned in Discord, spawned cursor-agent acp --model auto, streamed reply back to thread ✅
  • CI matrix (.github/workflows/build.yml) will run on merge — local act run not attempted

Manual test steps (reproducible):

# 1. Build
docker build -f Dockerfile.cursor -t openab-cursor:local .

# 2. Deploy (OrbStack k8s)
helm upgrade --install openab openab/openab -n openab --create-namespace \
  --set agents.cursor.enabled=true \
  --set agents.cursor.image=openab-cursor:local \
  --set agents.cursor.command=cursor-agent \
  --set 'agents.cursor.args={acp,--model,auto}' \
  --set agents.cursor.discord.botToken=$TOKEN

# 3. Auth (one-time, device flow)
kubectl exec -it deployment/openab-cursor -n openab -- cursor-agent login
kubectl rollout restart deployment/openab-cursor -n openab

# 4. Test
#    In Discord: @Octocat who are you?
#    → thread opens, streams reply from Cursor agent

@brettchien brettchien requested a review from thepagent as a code owner April 13, 2026 18:12
brettchien and others added 4 commits April 14, 2026 02:56
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>
@brettchien brettchien force-pushed the feat/cursor-agent-cli branch from c99665d to 94ed603 Compare April 13, 2026 18:56
@thepagent thepagent added p1 High — address this sprint p2 Medium — planned work labels Apr 14, 2026
Copy link
Copy Markdown
Contributor

@masami-agent masami-agent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  1. Zero src/ changes — pure configuration integration, lowest risk
  2. Dockerfile.cursor — correct pattern: debian:bookworm-slim base (not node), pinned tarball, agent user (uid 1000), pgrep healthcheck
  3. CI matrix — all 3 sections updated consistently (build, merge-manifests, chart-version)
  4. docs/cursor.md — comprehensive: architecture, config, Docker, auth, Helm, model selection, limitations
  5. RELEASING.md — updated image count 4 → 6 (also adds missing copilot entry)
  6. ACP handshake verifiedprotocolVersion: 1 integer match confirmed against cursor-agent v2026.04.08-a41fba1

🔴 Must fix before merge

1. values.yaml cursor example has wrong workingDir

#   workingDir: /home/node

Cursor uses debian:bookworm-slim (not node:22), so the user is agent with home at /home/agent. This should be:

#   workingDir: /home/agent

The 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.
@github-actions github-actions bot added the closing-soon PR missing Discord Discussion URL — will auto-close in 3 days label Apr 15, 2026
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.
@brettchien
Copy link
Copy Markdown
Author

@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. values.yaml cursor example workingDir38628bf

Changed /home/node/home/agent. Cursor uses debian:bookworm-slim with a self-created agent user (uid 1000), not the node user baked into node:22-bookworm-slim.

2. Dockerfile.cursor missing procps654b743

Added procps to the runtime apt install so pgrep -x openab in the HEALTHCHECK actually resolves. Same fix pattern as pending #234 for the other Dockerfiles — scoped here to Dockerfile.cursor only.

🟡 Non-blocking (items 3 & 4 done, item 5 already in PR)

3. Cursor tarball URL stability comment — eeb122e

Added a 4-line comment above the ARG CURSOR_VERSION pointing maintainers at the URL pattern and Cursor's official downloads page. If the URL scheme changes, the build fails with a curl 404 at build time so the failure is obvious.

4. Default --model auto in example args — 20fcd10, 146a2f2

  • config.toml.example: args = ["acp"]args = ["acp", "--model", "auto", "--workspace", "/home/agent"]
  • charts/openab/values.yaml cursor example: added matching --model auto + --workspace /home/agent

Aligned with docs/cursor.md and the Helm example in the PR body.

5. RELEASING.md copilot

Already in the PR (line 150 ghcr.io/openabdev/openab-copilot # copilot + 6 multi-arch image count). Keeping as a bonus fix — happy to split out if strictly preferred.

🆕 Bonus — MCP usage documentation — 2a1167f

Added a "MCP Usage (ACP mode caveats)" section to docs/cursor.md covering:

  • How --workspace anchors both .cursor/mcp.json lookup and the mcp-approvals.json slug
  • --approve-mcps is a no-op in ACP mode (interactive CLI only) — confirmed against cursor-agent v2026.04.08-a41fba1 and the Cursor community forum
  • Two ways to approve MCP servers (pre-create file / interactive approve + persist)
  • How openab's session/request_permission auto-reply (allow_always in src/acp/connection.rs) interacts with the approval file
  • How to verify with cursor-agent mcp list

Commits in this update

2a1167f docs(cursor): add MCP usage and --workspace / approval quirks
146a2f2 docs(config): align cursor example args with runtime defaults
20fcd10 docs(config): add --model auto to cursor example args
eeb122e docs(docker): document Cursor tarball URL source in Dockerfile.cursor
654b743 fix(docker): add procps to Dockerfile.cursor for pgrep healthcheck
38628bf fix(chart): cursor example workingDir /home/node → /home/agent

Verified locally: cursor-agent in pod reports playwright: ready, ACP handshake still passes, CI is green on the latest push.

@github-actions github-actions bot removed the closing-soon PR missing Discord Discussion URL — will auto-close in 3 days label Apr 15, 2026
Copy link
Copy Markdown
Contributor

@masami-agent masami-agent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — PR #301

All 5 items from my initial review have been addressed. Verified the latest diff:

✅ Must-fix (resolved)

  1. values.yaml workingDir/home/node/home/agent
  2. Dockerfile.cursor procps — added to runtime apt install ✓

✅ Non-blocking (resolved)

  1. Tarball URL stability comment — clear 4-line comment above ARG CURSOR_VERSION
  2. Default --model auto — aligned across config.toml.example, values.yaml, and docs/cursor.md
  3. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p1 High — address this sprint p2 Medium — planned work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants