cursor-oauth-opencode
v0.7.9
Published
OpenCode plugin that connects Cursor's API to OpenCode via OAuth, model discovery, and a local OpenAI-compatible proxy.
Maintainers
Readme
cursor-oauth-opencode
OpenCode plugin that connects to Cursor's API, giving you access to Cursor models inside OpenCode with full tool-calling support.
Install
npx cursor-oauth-opencode setup --global
opencode auth login --provider cursorFor project-local setup:
npx cursor-oauth-opencode setup --project
opencode auth login --provider cursorThe setup command is idempotent. It adds the npm plugin entry and fallback
model registries for both provider.cursor and provider.cursor-code in
opencode.json, preserving existing user model overrides. Login stays on the
primary provider only (opencode auth login --provider cursor).
Providers
The plugin registers two OpenCode providers that share one OAuth login, proxy, and model catalog. Mode is selected in the model picker:
| Provider | Picker path | Behavior |
|----------|-------------|----------|
| Cursor | cursor/<model> | Native tool passthrough (code mode OFF) |
| Cursor Code | cursor-code/<model> | Single code sandbox tool (code mode ON) |
Breaking default: cursor/* is native-tools / code mode OFF. To keep the
previous sandbox-collapse behavior, pick cursor-code/<model>. There is no
auto-rewrite of a previously selected cursor/* model.
Fleet-wide kill switch (forces OFF even for cursor-code/*): set
CURSOR_OPENCODE_CODE_MODE=0 or provider.cursor.plugin.codeMode.enabled: false.
That knob is read only under provider.cursor.plugin — a block under
provider.cursor-code.plugin has no effect.
Reasoning variants
Reasoning-tier Cursor models are listed once in the picker; effort is chosen in OpenCode's Select variant menu (not as separate model slugs):
| Picker model | Variants | Notes |
|--------------|----------|--------|
| grok-4.5 / grok-4.5-fast | low / medium / high | Cursor slug suffixes are shifted (high → …-xhigh) |
| claude-4.6-opus, gpt-5.4, glm-5.2, … | only levels Cursor exposes | e.g. opus → high, gpt-5.4 → medium |
| composer-2.5 / composer-2.5-fast | default only | Non-effort axis; stay as separate models |
Legacy full slugs (grok-4.5-fast-high, …) still resolve as aliases. After
upgrade, re-run setup so opencode.json seeds the collapsed base ids.
Manual config
If you do not want to use the setup command, add this to
~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
"cursor-oauth-opencode@latest"
],
"provider": {
"cursor": {
"name": "Cursor",
"npm": "@ai-sdk/openai-compatible",
"api": "http://127.0.0.1:65535/v1",
"models": {
"composer-2.5-fast": {
"name": "Composer 2.5 Fast",
"reasoning": true,
"temperature": true,
"attachment": false,
"tool_call": true,
"limit": {
"context": 200000,
"output": 64000
}
}
}
},
"cursor-code": {
"name": "Cursor Code",
"npm": "@ai-sdk/openai-compatible",
"api": "http://127.0.0.1:65535/v1/code",
"models": {
"composer-2.5-fast": {
"name": "Composer 2.5 Fast",
"reasoning": true,
"temperature": true,
"attachment": false,
"tool_call": true,
"limit": {
"context": 200000,
"output": 64000
}
}
}
}
}
}The fallback API URLs are placeholders so OpenCode can list the providers
before login. After auth, the plugin starts a local proxy and replaces Cursor
models with live Cursor model discovery. cursor-code must keep the /v1/code
path suffix (merge-safety if a request falls back to provider.api).
Authenticate
opencode auth login --provider cursorThis opens Cursor OAuth in the browser. Tokens are stored in
~/.local/share/opencode/auth.json and refreshed automatically. Both
providers use that single cursor auth entry.
Use
Start OpenCode and select a model under Cursor (native tools) or
Cursor Code (sandbox code tool). The plugin starts a local
OpenAI-compatible proxy on demand and routes requests through Cursor's gRPC API.
How it works
- OAuth — browser-based login to Cursor via PKCE (
cursorprovider only). - Model discovery — queries Cursor's gRPC API for all available models.
- Local proxy — translates chat completions into Cursor's protobuf/HTTP/2
Connect protocol. Path selects mode:
/v1/*(native) vs/v1/code/*(sandbox). - Code mode (
cursor-code) — advertises a singlecodetool to the Cursor model; the model writes one async JavaScript program that the proxy runs in a Node child sandbox, bridging eachawait tools.X()wave to OpenCode's tools while the Cursor bridge stays parked.cursor/*passes client tools through directly as MCP tools.
HTTP/2 transport runs through a Node child process (h2-daemon.mjs / legacy
h2-bridge.mjs) because Bun's node:http2 support is not reliable against
Cursor's API.
Prompt shaping (caveman + reasoning containment)
On every outbound Cursor Run the proxy can:
- Caveman-compress tool-description prose and the OpenCode system prompt
(
plugin.caveman.level/CURSOR_OPENCODE_CAVEMAN, defaultfull; system inherits viaplugin.caveman.system/CURSOR_OPENCODE_CAVEMAN_SYSTEM). - Append a verbatim reasoning guard for runaway-reasoning models
(
claude-fable-5,claude-opus-4-8;CURSOR_OPENCODE_REASONING_GUARD=0). - Inject a coalesced harness appendix (interstitial text, overthink
<system-reminder>, throttled continuity, single-shot[reasoning tail]/[thinking exhaustion]notes) for those same models.
Savings counters live under CURSOR_OPENCODE_SAVINGS=1 (plugin log file).
Architecture
OpenCode --> /v1/chat/completions (cursor = code OFF)
--> /v1/code/chat/completions (cursor-code = code ON)
|
Bun.serve (proxy)
|
Node child (h2-daemon / h2-bridge)
|
HTTP/2 Connect stream
|
api2.cursor.sh gRPC
/agent.v1.AgentService/RunTool call flow (code mode, cursor-code)
1. Proxy advertises ONE code tool to the Cursor model (its description embeds
OpenCode's real tool catalog)
2. Model emits code({script}); proxy runs the script in a Node child sandbox
3. Each await tools.X() wave -> proxy emits OpenAI tool_calls SSE, parks BOTH
the Cursor bridge and the sandbox
4. OpenCode executes the tools, sends results in the follow-up request
5. Proxy feeds results to the parked sandbox; the next wave repeats step 3
6. Script returns -> its value becomes the code tool result; the Cursor bridge
resumes and streams the model's final answerWith cursor/* (or the kill switch forcing OFF) the proxy passes each client
tool through directly: the model calls a tool via mcpArgs, the proxy emits
OpenAI tool_calls, pauses the H2 stream, and resumes with mcpResult on the
follow-up request.
Develop locally
bun install
bun run build
bun test/smoke.tsLogs
Plugin diagnostics never print to the terminal (they would paint over the
OpenCode TUI). They land in ~/.cache/cursor-oauth-opencode/plugin.log.
Override the path with CURSOR_OPENCODE_LOG_FILE; set
CURSOR_OPENCODE_LOG_STDERR=1 to also mirror lines to stderr when debugging
outside the TUI.
