{"id":50767473,"url":"https://github.com/stablekernel/opencode-cursor","last_synced_at":"2026-06-16T20:00:58.407Z","repository":{"id":363909889,"uuid":"1265154372","full_name":"stablekernel/opencode-cursor","owner":"stablekernel","description":"An opencode plugin that adds a Cursor provider backed by the official Cursor SDK (@cursor/sdk).","archived":false,"fork":false,"pushed_at":"2026-06-11T22:27:04.000Z","size":185,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T19:33:12.630Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stablekernel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-10T14:10:09.000Z","updated_at":"2026-06-15T18:50:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/stablekernel/opencode-cursor","commit_stats":null,"previous_names":["stablekernel/opencode-cursor"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/stablekernel/opencode-cursor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fopencode-cursor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fopencode-cursor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fopencode-cursor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fopencode-cursor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stablekernel","download_url":"https://codeload.github.com/stablekernel/opencode-cursor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fopencode-cursor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34417416,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-11T15:00:34.140Z","updated_at":"2026-06-16T20:00:58.350Z","avatar_url":"https://github.com/stablekernel.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @stablekernel/opencode-cursor\n\n[![npm version](https://img.shields.io/npm/v/@stablekernel/opencode-cursor.svg)](https://www.npmjs.com/package/@stablekernel/opencode-cursor)\n[![CI](https://github.com/stablekernel/opencode-cursor/actions/workflows/ci.yml/badge.svg)](https://github.com/stablekernel/opencode-cursor/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n\nAn [opencode](https://opencode.ai) plugin that adds **Cursor** as a native provider. Your Cursor models appear in the model picker; you chat with them the same way you use any other provider.\n\nIt uses the [official Cursor SDK](https://cursor.com/docs/sdk/typescript) (`@cursor/sdk`) to list your account's models live and run chats through Cursor's local agent runtime. For delegated or background workflows it also ships two permission-gated tools (`cursor_delegate`, `cursor_cloud_agent`) — see [Delegation tools](#delegation-tools).\n\n\u003e ⚠️ **Security.** When you chat with a `cursor/*` model, Cursor runs its own tools — including\n\u003e `shell`, `write`, `edit`, and `delete` — directly in your working directory, **outside opencode's\n\u003e permission system**. Read [Security](#security) before you use it.\n\n## Requirements\n\n- **opencode 1.17+**\n- **Node.js 22+ on your `PATH`** — opencode runs on [Bun](https://bun.sh); the plugin needs a\n  Node sidecar to host the Cursor SDK (see [Runtime](#runtime-bun-and-the-node-sidecar)).\n- A **Cursor account and API key** (from the Cursor dashboard).\n\n## Install\n\n### One line\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/stablekernel/opencode-cursor/main/install.sh | bash\n```\n\nRegisters the plugin in your global `opencode.json` (`~/.config/opencode/opencode.json`), checks\nfor Node.js 22+, and offers to set `CURSOR_API_KEY`. Flags:\n\n- `--project` — write `./opencode.json` in the current directory instead.\n- `--yes` / `-y` — non-interactive.\n\n[Review the script first.](./install.sh)\n\n### Manual\n\n```bash\nnpm install @stablekernel/opencode-cursor\n```\n\nAdd to your `opencode.json`:\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"plugin\": [\"@stablekernel/opencode-cursor\"]\n}\n```\n\nThe plugin injects the `provider` block automatically. If you need explicit control:\n\n```json\n{\n  \"provider\": {\n    \"cursor\": {\n      \"npm\": \"@stablekernel/opencode-cursor\",\n      \"name\": \"Cursor\",\n      \"options\": { \"apiKey\": \"{env:CURSOR_API_KEY}\" }\n    }\n  }\n}\n```\n\n## Authenticate\n\n```bash\nopencode auth login   # choose \"Cursor\", paste your key from the Cursor dashboard\n```\n\nOr set the environment variable:\n\n```bash\nexport CURSOR_API_KEY=\"key_...\"\n```\n\nThe key is validated on first use (model discovery / first call), not at login time.\n\n## Use\n\n- `opencode models` (or the model picker) lists your Cursor models as `cursor/\u003cid\u003e`.\n- Pick a model and chat — the Cursor local agent runs in your project directory.\n- Run the `cursor_refresh_models` tool to force a live catalog refresh.\n\nThe plugin also registers two **delegation tools**:\n\n- `cursor_delegate` — hand a discrete subtask to a local Cursor agent as a permission-gated tool\n  call (your primary model stays in control).\n- `cursor_cloud_agent` — launch a Cursor cloud agent on a remote repo that can run for minutes and\n  optionally open a PR.\n\n## Security\n\n\u003e ⚠️ **The provider path is unsandboxed and not gated by opencode permissions.**\n\u003e When you chat with a `cursor/*` model, Cursor runs its own tools — including `shell`, `write`,\n\u003e `edit`, and `delete` — directly in your working directory. opencode's `permission` rules (e.g.\n\u003e `edit: deny`, `bash: ask`) do **not** apply to them.\n\u003e\n\u003e Options if you need a permission boundary:\n\u003e - Set `sandbox: true` in `provider.cursor.options` to run Cursor's tools in Cursor's sandbox.\n\u003e - Use `cursor_delegate` instead of the provider path — it is gated by opencode's `permission`\n\u003e   config.\n\nSee [SECURITY.md](./SECURITY.md) for the full threat model.\n\n## Configuration\n\n| Option (`provider.cursor.options`) | Default | Meaning |\n| --- | --- | --- |\n| `apiKey` | `CURSOR_API_KEY` | Cursor API key |\n| `cwd` | `process.cwd()` | Directory the local agent operates in |\n| `mode` | `\"agent\"` | Default conversation mode (`\"agent\"` or `\"plan\"`) |\n| `params` | — | Default model params, e.g. `{ thinking: \"high\" }` |\n| `settingSources` | — | Cursor settings layers to load: `[\"project\",\"user\",\"all\",...]` — pulls in your Cursor skills, rules, and `.cursor/mcp.json` |\n| `sandbox` | — | Run the agent's tools in Cursor's sandbox |\n| `agents` | — | Cursor subagent definitions |\n| `session` | `\"auto\"` | Session reuse strategy — see [Session reuse](#session-reuse-session) |\n| `forwardMcp` | `true` | Forward opencode's configured MCP servers to the Cursor agent |\n| `mcpServers` | — | Extra MCP servers (Cursor `McpServerConfig` shape); merged with forwarded ones |\n| `toolDisplay` | `\"blocks\"` | How Cursor's internal tool activity is shown — see [Tool display](#tool-display) |\n\n| Environment variable | Default | Meaning |\n| --- | --- | --- |\n| `CURSOR_API_KEY` | — | API key fallback |\n| `OPENCODE_CURSOR_MODEL_CACHE_TTL_MS` | `86400000` | Model-list cache lifetime (ms) |\n| `OPENCODE_CURSOR_DEBUG` | — | Set to `1` for trace logging on stderr |\n| `OPENCODE_CURSOR_SIDECAR` | — | `1` = always use Node sidecar; `0` = never |\n\n### Session reuse (`session`)\n\nopencode re-sends the full conversation transcript on every turn. `session: \"auto\"` (the default)\nfingerprints the conversation and resumes the same Cursor agent when nothing has changed, so you\nonly pay for the new message. It falls back to a fresh agent + full transcript on edits, reverts,\nor compaction.\n\n| Situation | What happens |\n| --- | --- |\n| First turn | Fresh agent, full transcript, pool it |\n| System prompt differs (title gen, other side calls) | Ephemeral fresh agent; pooled agent untouched |\n| Clean continuation (one new user message) | `Agent.resume` — sends only the new message |\n| Forwarded MCP server set changed | Fresh agent + full transcript, re-pooled |\n| Message edited/reverted or conversation compacted | Fresh agent + full transcript, re-pooled |\n\n`session: true` is an alias for `\"auto\"`. `session: false` disables reuse (always fresh agent,\nfull transcript every turn).\n\nFingerprint records persist to `~/.cache/opencode-cursor/session-pool.json`, so session reuse\nsurvives opencode restarts.\n\n### Per-request controls (`mode`, thinking level)\n\nThe plugin auto-generates model variants for each reasoning/effort level a model advertises.\nSelecting a variant in the model picker sends its settings through `providerOptions.cursor`.\n\nopencode's **plan agent** (`Tab`) maps to Cursor's plan mode automatically — no manual config\nneeded.\n\nTo set controls statically per model:\n\n```json\n{ \"provider\": { \"cursor\": { \"models\": {\n  \"composer-2.5\": { \"options\": { \"params\": { \"thinking\": \"high\" } } }\n} } } }\n```\n\n## MCP servers\n\nWith `forwardMcp: true` (default), the Cursor agent uses the same MCP servers configured in\nopencode. The server list is updated live per turn, so enabling or disabling an MCP server takes\neffect on the next message.\n\n| opencode `config.mcp` | → Cursor |\n| --- | --- |\n| `{ type: \"local\", command: [cmd, ...args], environment }` | `{ type: \"stdio\", command, args, env }` |\n| `{ type: \"remote\", url, headers }` | `{ type: \"http\", url, headers }` |\n| Remote with registered OAuth `clientId` | `{ type: \"http\", url, auth: { CLIENT_ID, … } }` |\n\nDisabled entries (`enabled: false`) are skipped. Remote servers requiring OAuth without a\nshareable `clientId` are also skipped (a one-time toast says which). Disable forwarding with\n`forwardMcp: false`.\n\n\u003e **Note:** This forwards MCP **servers**. opencode's own skills and subagents are not exposed to\n\u003e the Cursor agent. To load your local Cursor skills/rules, use\n\u003e `settingSources: [\"project\",\"user\"]`.\n\n## Delegation tools\n\nBoth tools resolve the API key from your `opencode auth login` session (or `CURSOR_API_KEY`) and\nare gated by opencode's `permission` config:\n\n```json\n{ \"permission\": { \"cursor_delegate\": \"ask\", \"cursor_cloud_agent\": \"ask\" } }\n```\n\n### `cursor_delegate` (local)\n\nRuns one Cursor turn as a permission-gated tool call. Your primary opencode model hands off a\ndiscrete subtask and gets the result back.\n\n| Arg | Required | Meaning |\n| --- | --- | --- |\n| `prompt` | ✅ | The subtask to delegate |\n| `model` | ✅ | Cursor model id |\n| `mode` | — | `\"agent\"` or `\"plan\"` |\n| `thinking` | — | Thinking level (e.g. `\"high\"`) |\n| `cwd` | — | Working directory |\n| `sandbox` | — | Run in Cursor's sandbox |\n| `agentId` | — | Resume a specific Cursor agent |\n\n### `cursor_cloud_agent` (cloud)\n\nLaunches a background Cursor cloud agent on a remote repo. Can run for minutes and optionally\nopen a PR.\n\n| Arg | Required | Meaning |\n| --- | --- | --- |\n| `prompt` | ✅ | The task |\n| `repoUrl` | ✅ | Target repository URL (e.g. `https://github.com/owner/repo`) |\n| `startingRef` | — | Branch/ref to start from |\n| `model` | — | Cursor model id |\n| `mode` | — | `\"agent\"` or `\"plan\"` |\n| `thinking` | — | Thinking level |\n| `autoCreatePR` | — | Open a PR when finished |\n| `workOnCurrentBranch` | — | Operate on the current branch instead of a new one |\n\n## Tool display\n\n`toolDisplay` controls how Cursor's internal tool activity appears in opencode:\n\n- **`\"blocks\"` (default)** — structured, collapsible tool blocks with inputs and outputs. Common\n  Cursor tools are mapped to their opencode equivalents (`edit` → diff viewer, `shell` → bash\n  console, etc.). Requires opencode 1.17+.\n- **`\"reasoning\"`** — compact inline lines (`[tool] write {\"path\":…}`). Works on any host; use\n  this on older opencode versions.\n\nTo force the fallback:\n\n```json\n{ \"provider\": { \"cursor\": { \"options\": { \"toolDisplay\": \"reasoning\" } } } }\n```\n\n## Runtime: Bun and the Node sidecar\n\nopencode runs on [Bun](https://bun.sh), which has an `node:http2` incompatibility with the Cursor\nSDK's streaming RPC. The plugin transparently hosts the Cursor SDK in a short-lived **Node child\nprocess** when running under Bun. Under Node it runs in-process.\n\nThis is why **Node.js 22+ on your `PATH`** is required. If Node isn't found, the plugin warns once\nand falls back to in-process (native Cursor tools will misbehave until Node is available).\n\nOverride with `OPENCODE_CURSOR_SIDECAR=1` (always sidecar) or `OPENCODE_CURSOR_SIDECAR=0` (never).\n\n## Troubleshooting\n\n- **Native Cursor tools hang / \"Tool execution aborted\" (`NGHTTP2_FRAME_SIZE_ERROR`).** Node isn't\n  on your `PATH`. Install Node.js 22+, or force the sidecar with `OPENCODE_CURSOR_SIDECAR=1`.\n- **\"Running under Bun without a usable Node sidecar\" warning.** Install Node.js 22+, or set\n  `OPENCODE_CURSOR_SIDECAR=0` to accept in-process behavior and silence the warning.\n- **\"Could not locate the bindings file\" / `node_sqlite3.node` not found.** The `@cursor/sdk`\n  native sqlite3 addon was skipped during Bun install. The plugin self-heals on first load (needs\n  Node on `PATH`). If that fails, `cd` into the printed sqlite3 directory and run\n  `npx prebuild-install -r napi`.\n- **Plugin enabled but no `cursor` provider/models appear.** Stale opencode plugin cache. Pin an\n  exact version (`@stablekernel/opencode-cursor@\u003cversion\u003e`) or delete\n  `~/.cache/opencode/packages/` and restart.\n- **Only the four fallback models appear.** The live catalog loads after the first authenticated\n  use. Restart opencode once after login, or run `cursor_refresh_models`.\n- **Invalid or expired key.** Validated on first use — that's where the error surfaces.\n- **Need more detail?** Set `OPENCODE_CURSOR_DEBUG=1`.\n\n## Contributing\n\nIssues and pull requests are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for dev setup,\ntest/typecheck/build commands, and the release process. Report bugs at the\n[issue tracker](https://github.com/stablekernel/opencode-cursor/issues); for security reports\nsee [SECURITY.md](./SECURITY.md).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablekernel%2Fopencode-cursor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstablekernel%2Fopencode-cursor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablekernel%2Fopencode-cursor/lists"}