Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

openclaw-cursor-cli

An OpenClaw CLI-backend plugin that registers the Cursor Agent CLI (cursor-agent) as a model provider — cursor-cli/<model>.

Why

OpenClaw's bundled acpx plugin already lets an agent spawn Cursor as a coding worker via ACP. That's a different thing from what this plugin does: this lets an agent's own reasoning — the part that reads a message and decides what to do — run on a Cursor subscription, the same way claude-cli lets it run on a Claude Code subscription.

The practical use case is resilience: if you have both a Claude and a Cursor subscription, you don't have to be locked into one running out of usage. Add cursor-cli/<model> as a fallback (agents.list.<id>.model.fallbacks) alongside your primary, and OpenClaw fails over automatically.

Requirements

  • Cursor Agent CLI installed and logged in (cursor-agent login) on the same host as the OpenClaw gateway.
  • OpenClaw with plugin support (any recent version — built against the cliBackends / registerCliBackend plugin API).

Install

openclaw plugins install /path/to/openclaw-cursor-cli
openclaw plugins enable cursor-cli

(Or point openclaw plugins install at this repo once it's published — git URL or npm spec both work with OpenClaw's plugin installer.)

Restart the gateway after enabling — CLI-backend registration needs a restart to take effect, same as any other plugin enable/disable.

Required extra step (third-party plugin limitation, not this plugin's bug)

As installed above, cursor-cli/<model> will fail every request with Unknown model: cursor-cli/<model> (or, if you've hit the variant of this bug, No API provider registered for api: ...). This isn't something register(api) can fix from inside the plugin — traced it live, with instrumented debug logging, all the way to OpenClaw's own resolveRuntimeCliBackends() (model-selection-*.js), which reads from loadPluginRuntime()?.getActivePluginRegistry()?.cliBackends. For a bundled CLI backend (claude-cli, google-gemini-cli) that registry is populated correctly. For a third-party/linked plugin — this one, and presumably any other non-bundled registerCliBackend plugin — it comes back empty at model-resolution time, even though openclaw plugins inspect correctly shows the backend as loaded. The bundled-only fallback path (resolveBundledSetupCliBackends) makes this explicit: it filters plugin.origin === "bundled", which a linked/npm-installed plugin never is.

The fix is a second, independent lookup path OpenClaw does support: statically declaring the backend's config directly under agents.defaults.cliBackends, which resolveCliBackendConfig consults before falling back to the (broken, for third-party plugins) registry-based lookup. Add this once, after installing the plugin:

openclaw config set 'agents.defaults.cliBackends' '{
  "cursor-cli": {
    "command": "cursor-agent",
    "args": ["--print", "--force", "--output-format", "stream-json"],
    "resumeArgs": ["--print", "--force", "--output-format", "stream-json", "--resume", "{sessionId}"],
    "output": "jsonl",
    "jsonlDialect": "claude-stream-json",
    "input": "stdin",
    "modelArg": "--model",
    "modelAliases": { "auto": "auto" },
    "sessionMode": "existing",
    "sessionIdFields": ["session_id"],
    "clearEnv": ["CURSOR_API_KEY", "CURSOR_API_ENDPOINT"],
    "serialize": true,
    "reliability": {
      "watchdog": {
        "fresh": { "noOutputTimeoutRatio": 0.8, "minMs": 180000, "maxMs": 600000 },
        "resume": { "noOutputTimeoutRatio": 0.3, "minMs": 60000, "maxMs": 180000 }
      }
    }
  }
}' --strict-json

(If you already have other entries under agents.defaults.cliBackends, merge rather than overwrite — this sets the whole map.) Restart the gateway after. This must stay in sync with src/index.js's buildCursorCliBackend() — if you change one, change the other. Verified live end-to-end after applying this: real cursor-agent subprocess spawn, correct output, and session --resume correctly reusing context across turns.

Configure

Optional plugin config, if cursor-agent isn't on the gateway's PATH:

{
  plugins: {
    entries: {
      "cursor-cli": {
        enabled: true,
        config: { command: "/absolute/path/to/cursor-agent" }
      }
    }
  }
}

Use

Set it as a primary or fallback model for any agent, scoped per-agent (don't use the --agent flag on openclaw models set/fallbacks add — it doesn't scope the write the way you'd expect; edit the agent's config path directly):

openclaw config set 'agents.list[N].model.fallbacks' '["cursor-cli/auto"]' --strict-json

Model ids pass straight through to cursor-agent --model. Run cursor-agent --list-models for the current catalog (it's large and moves fast — Claude, GPT, Gemini, Grok, Kimi, GLM variants, each with several effort tiers) — anything in that list works directly as cursor-cli/<id>. cursor-cli/auto (Cursor's own auto-routing) is the default and the safest choice if you don't want to hardcode a specific model that might age out.

How it works

cursor-agent --print --force --output-format stream-json emits newline-delimited JSON events shaped like Claude's own stream-json protocol (type/subtype, message.content[], a final result event with the answer text and token usage) with a session_id field on every line. This plugin declares that shape to OpenClaw's generic CLI-backend machinery — it's a small declarative config, not a custom parser.

One real difference from claude-cli: cursor-agent assigns its own session id on the first call (there's no flag to hand it one up front) and only accepts --resume <id> on later calls. That's sessionMode: "existing" here, versus "always" for claude-cli.

Known limitations

  • Requires the agents.defaults.cliBackends config step above. Not optional, not this plugin's bug — see "Required extra step" under Install for the root cause (OpenClaw's runtime CLI-backend registry doesn't pick up third-party/linked plugins the same way it picks up bundled ones).
  • No daemon/server mode. Unlike OpenAI's Codex (which ships an app-server protocol specifically for external tools like this), cursor-agent has no persistent process another tool can talk to — every turn is a fresh subprocess spawn, same as claude-cli. Works fine, just means no protocol-level session pinning beyond --resume.
  • --force auto-approves everything within the run (matches the same risk posture OpenClaw's bundled claude-cli backend already uses via --permission-mode bypassPermissions) — this is a reasoning backend for an already-trusted agent, not a sandboxed execution mode.
  • Model aliases are intentionally minimal. Cursor's model catalog is large and changes often; hardcoding friendly names beyond auto would go stale. Use literal model ids from cursor-agent --list-models.
  • Auth is whatever cursor-agent login already set up on the host — this plugin doesn't manage credentials itself. Concretely: registerProvider's auth array is empty and resolveSyntheticAuth returns a placeholder token purely so OpenClaw's "is this provider authenticated" check passes — no credential is ever read, stored, or exchanged by OpenClaw.
  • Both registerCliBackend and registerProvider are required for a cursor-cli/<model> ref to resolve at all — this wasn't obvious going in and is worth calling out for anyone extending this plugin. OpenClaw keeps two separate plugin registries: registerCliBackend only wires up how to run a model once one has already resolved (the subprocess command/args/ session handling below); registerProvider (specifically its resolveDynamicModel hook) is what makes cursor-cli/<model> resolve to a model object in the first place. A CLI backend with no matching provider fails every request with "Unknown model", regardless of agents.defaults.models allowlist entries (that's a separate permission gate, not model resolution). Every bundled CLI-backend plugin (claude-cli, google-gemini-cli, Codex's app-server) registers both together for this reason.

License

MIT

About

OpenClaw CLI-backend plugin for the Cursor Agent CLI — use a Cursor subscription for an OpenClaw agent's own reasoning.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages