@rahularya01/pi-cursor
Native Cursor provider for Pi Coding Agent (OAuth + Connect/protobuf streamSimple)
Package details
Install @rahularya01/pi-cursor from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@rahularya01/pi-cursor- Package
@rahularya01/pi-cursor- Version
1.4.29- Published
- Aug 29, 2026
- Downloads
- 2,000/mo · 1,180/wk
- Author
- rahularya01
- License
- MIT
- Types
- extension
- Size
- 327.4 KB
- Dependencies
- 1 dependency · 2 peers
Pi manifest JSON
{
"extensions": [
"./dist/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@rahularya01/pi-cursor
Use your Cursor subscription's models — Composer, Claude, GPT, Grok — inside the Pi Coding Agent.
pi-cursor plugs in a cursor model provider that talks to Cursor's own backend directly (native
Connect/protobuf streaming over HTTP/2), so there's no separate API key to buy and no Cursor CLI
process running in the background for every chat turn. If you're already logged into Cursor's app
or CLI, it just works — no setup beyond installing the package.
Unofficial integration. This project is not affiliated with or endorsed by Cursor / Anysphere. It uses reverse-engineered wire protocol details shared by community clients (see Attributions). Use it only with an account you are authorized to access, and review its source before granting OAuth permissions. Cursor may change wire protocol endpoints or formats at any time.
Contents
- Requirements
- Install
- Quick start
- Authentication
- Commands
- Models & reasoning effort
- Usage dashboard
- Troubleshooting
- Configuration (advanced)
- Architecture (advanced)
- Development
Requirements
| Pi Coding Agent / Pi AI | version 0.80.0 or later |
| Bun | version 1.4.0 or later — the only supported runtime |
| A Cursor account | with model access — signed in via the Cursor app, Cursor CLI, or browser login below |
Install
pi install npm:@rahularya01/pi-cursor
Then restart Pi (or run /reload) so the new provider is picked up.
Install the latest code straight from GitHub instead of npm:
pi install git:github.com/Rahularya01/pi-cursor
To update later:
pi update npm:@rahularya01/pi-cursor
Quick start
Sign in. If Cursor's desktop app or CLI (
cursor/agent) is already logged in on this machine,pi-cursordetects it automatically — skip to step 2. Otherwise, run:/login cursorThis opens a browser tab to sign in with your Cursor account.
Pick a model:
/model cursor/composer-2Start chatting. If anything looks off, run
/cursor.doctor— it prints which credential source is active, the current endpoint, and the last error, and is the first thing to check before filing an issue.
Authentication and resolution cascade
pi-cursor automatically resolves credentials using a 4-tier cascade:
1. CURSOR_ACCESS_TOKEN environment variable
2. Pi OAuth credentials store (~/.pi/agent/auth.json via /login cursor)
3. Cursor CLI credentials in macOS Keychain (cursor-access-token / cursor-refresh-token)
4. Cursor IDE local state DB (globalStorage/state.vscdb on macOS, Windows, Linux, or WSL)
/login cursor is preferred over Keychain/IDE harvest so an explicit Pi login is not silently overridden by another Cursor app account on the machine.
Automatic CLI & IDE login detection
If you are logged into the Cursor desktop app or Cursor CLI (cursor / agent), pi-cursor automatically extracts your session credentials so you can start chatting immediately without manual browser login.
On WSL (Windows Subsystem for Linux), pi-cursor reuses the current Windows user's Cursor IDE login (USERPROFILE / USERNAME → /mnt/c/Users/<you>/AppData/...). It does not scan other Windows profiles.
To opt out of Keychain / IDE / WSL credential reuse (OAuth or CURSOR_ACCESS_TOKEN only):
export PI_CURSOR_SYSTEM_CREDENTIALS=0
Deep-link PKCE browser login
When no local credentials exist, running /login cursor initiates browser sign-in:
/login cursoropenshttps://cursor.com/loginDeepControl?...- Pi polls
https://api2.cursor.sh/auth/polluntil authentication completes. - Access and refresh tokens are stored in Pi's auth store (
~/.pi/agent/auth.json). - Tokens are automatically refreshed via
https://api2.cursor.sh/auth/exchange_user_api_key.
Use /cursor.doctor to inspect which source is active (tokenSource=cli_keychain, tokenSource=ide_vscdb, tokenSource=pi_oauth, tokenSource=env).
Commands
| Command | Description |
|---|---|
/login cursor |
Sign in to Cursor via browser PKCE and refresh the live model catalog. |
/model cursor/<id> |
Choose a registered Cursor model. |
/cursor.models |
List active runtime models, context windows, and effort capabilities. |
/cursor.models all |
Include tab/chat internal model variants normally hidden from the picker. |
/cursor.usage |
Display visual TUI usage dashboard (included/auto/API quota bars, reset dates, on-demand spend). |
/cursor.doctor |
Show sanitized provider diagnostics, active token source, endpoint, and last error. |
Models and reasoning effort routing
pi-cursor discovers live account models via GetUsableModels and parameterized metadata. Reasoning effort levels (off, minimal, low, medium, high, xhigh, max) are mapped directly to Cursor's runtime model variants or reasoning parameters.
| Public model ID | Context | Thinking | Description / Routing |
|---|---|---|---|
cursor/composer-2 |
200,000 | Yes | Cursor's agentic model with fast reasoning effort options. |
cursor/composer-1.5 |
200,000 | Yes | Fast agent model optimized for code edit turns. |
cursor/claude-sonnet-5 |
200,000 | Yes | Anthropic Claude Sonnet via Cursor infrastructure. |
cursor/gpt-5.5 |
200,000 | Yes | OpenAI flagship model with parameterized reasoning levels. |
cursor/grok-4.5 |
200,000 | Yes | xAI Grok model via Cursor infrastructure. |
To restrict which models Pi displays, configure ~/.pi/agent/settings.json:
{
"enabledModels": ["cursor/composer-2", "cursor/claude-sonnet-5", "cursor/gpt-5.5"]
}
Usage quota and visual TUI dashboard
Running /cursor.usage displays a formatted terminal interface showing your current billing cycle, progress bars for included plan quota, auto/API usage, reset dates, and on-demand spend:
Usage • Pro Resets 5 Aug
Monthly plan and on-demand usage
Category Current Usage
Included 13% used ███░░░░░░░░░░░░░░░░░
Auto 12% used ███░░░░░░░░░░░░░░░░░
API 14% used ███░░░░░░░░░░░░░░░░░
On-Demand Disabled
------------------------------------------------------------
On-demand usage is off
View in dashboard: cursor.com/dashboard?tab=usage
Usage statistics are fetched directly from Cursor's native Connect period usage endpoint (POST https://api2.cursor.sh/aiserver.v1.DashboardService/GetCurrentPeriodUsage) using your active access token, with optional fallback to CURSOR_USAGE_SESSION_TOKEN.
Architecture & Wire Protocol
The rest of this README is reference material for troubleshooting, tuning, and contributing — nothing here is required for day-to-day use.
Pi Coding Agent → streamSimple (cursor-native)
→ h2-session.ts (in-process HTTP/2 client)
→ agent.v1.AgentService/Run (Connect + Protobuf over HTTP/2)
- Transport: Native Connect/protobuf streaming over HTTP/2, in-process via
h2-session.ts— no subprocess. - Infrastructure Context Normalization: Side-channel user messages (context-mode routing, post-compaction
<session_state>, and explicit[pi-lens automated … not a user request]notices) are safely normalized into the system prompt so Cursor models stay focused on your primary task. - Context-Efficient Tools: MCP schemas are compacted without changing callable constraints, and exact conversational-only turns (
hi,thanks, etc.) omit tools entirely. Actionable prompts always retain tools. - Cross-Platform: Tested and fully compatible with macOS, Linux, Windows, and WSL.
Configuration
Everything below is optional — pi-cursor works out of the box. These environment variables exist
for tuning timeouts, debugging, and edge-case overrides.
| Variable | Purpose |
|---|---|
PI_CURSOR_AGENT_URL / CURSOR_AGENT_URL |
Override agent base URL (default: https://agentn.us.api5.cursor.sh). |
CURSOR_ACCESS_TOKEN |
Static access token override. |
PI_CURSOR_CLIENT_VERSION |
Pin x-cursor-client-version header sent by the HTTP/2 bridge. |
PI_CURSOR_SYSTEM_CREDENTIALS |
0/false to disable Keychain/IDE credential reuse (default: allow). |
PI_CURSOR_RAW_MODELS |
Disable effort-suffix model collapse. |
PI_CURSOR_PROVIDER_DEBUG |
Enable verbose JSONL debug logging. |
PI_CURSOR_LIFECYCLE_LOG |
Always-on compact lifecycle log path (default: $TMPDIR/pi-cursor-lifecycle.jsonl). |
CURSOR_USAGE_SESSION_TOKEN |
Optional WorkosCursorSessionToken fallback cookie for /cursor.usage. |
PI_OFFLINE |
Skip live model discovery entirely; always use the bundled fallback catalog. |
PI_CURSOR_CACHE_DIR |
Where the model catalog and refresh back-off are cached (default: $XDG_CACHE_HOME/pi-cursor or ~/.cache/pi-cursor). Delete it to force a full rediscovery. |
PI_CURSOR_UNARY_BRIDGE |
1 forces unary RPCs (model discovery) through the general-purpose bridge transport instead of the dedicated one-shot in-process HTTP/2 client. Diagnostic escape hatch. |
PI_CURSOR_STREAM_IDLE_TIMEOUT_MS |
Silence safety net: ms with no upstream work before recover/retry/error. Default 180000 (3 min); 0 disables (turns run unbounded). Text/thinking/token deltas, tool-call events, and answered execs/queries reset it; heartbeats only prove the socket and do not hide an unanswered exec. It is paused during tool execution. On timeout, recovery continues from checkpoint even after partial output. |
PI_CURSOR_RESUME_IDLE_TIMEOUT_MS |
Same silence safety net after tool-result resume. Default 180000 (3 min); 0 disables. |
PI_CURSOR_STREAM_IDLE_MAX_RETRIES |
Auto-recovery attempts after silence/transport loss. Blind restart is skipped once text/thinking streamed unless a checkpoint is available for continuation. Default 5; 0 disables. |
PI_CURSOR_ACTIVE_BRIDGE_TTL_MS |
How long a mid-tool bridge stays parked waiting for tool results (default: 1 hour). |
PI_CURSOR_H2_CONNECT_TIMEOUT_MS |
h2-bridge initial connect kill (default: 30000; 0 disables). |
PI_CURSOR_H2_IDLE_TIMEOUT_MS |
h2-bridge activity idle kill. Default 0 (disabled). Parent heartbeats reset it when enabled. |
PI_CURSOR_SLIM_TOOLS |
Compact Cursor MCP tool definitions: concise function purpose, no annotation-only parameter prose, full callable schema constraints preserved. Default on; set 0/false for verbatim schemas. |
PI_CURSOR_MIDPAUSE_REBUILD_MAX_AGE_MS |
Max age of mid-pause metadata used for full-history rebuild (default: 15 min). |
PI_CURSOR_PROMPT_HISTORY |
Publish the system prompt and completed turns as Cursor prompt messages when a request is built without an upstream checkpoint. Default on; 0/false restores the pre-1.4.24 behavior, where a rebuilt conversation reached the model with no history and no Pi system prompt. |
Architecture notes
Stream modules are split under src/stream/:
| Module | Responsibility |
|---|---|
types.ts |
Shared structural types (no runtime code — safe for anyone to import) |
config.ts |
Agent URL + client version resolution |
tuning.ts |
Timeouts, retry budgets, and the stream idle watchdog |
debug-log.ts |
Debug / lifecycle / metric sinks with secret redaction |
images.ts |
Image decode + Cursor CLI format and size validation |
model-routing.ts |
Effort suffix / requested model resolution |
model-discovery.ts |
GetUsableModels unary RPCs + per-token model cache |
model-cache.ts |
Cross-process catalog cache read synchronously at startup |
context-normalize.ts |
Context-mode side-channel folding |
message-parsing.ts |
Pi/OpenAI message list → Cursor turn structures |
pi-adapter.ts |
Pi context/model types ↔ OpenAI-shaped request, usage accounting |
request-build.ts |
AgentRunRequest protobuf construction + blob store |
bridge-session.ts |
Active-bridge registry + h2-bridge lifecycle |
session-state.ts |
Conversation store, checkpoints, key derivation, session locks |
server-messages.ts |
Inbound KV / exec / interaction dispatch |
thinking-filter.ts |
Strips inline <think>-style tags from the text channel |
recovery.ts |
Tool-continuation recovery planner |
protocol.ts |
Auth/protocol error enhancement |
drift.ts |
Wire-drift detection (unknown message cases and protobuf fields) |
native-core.ts |
Native streamSimple runtime that drives all of the above |
Native streamSimple is the only chat path. The OpenAI-compatible local proxy that
used to sit alongside it was removed in favour of a single code path.
Startup
Extension activation does no network and no credential lookup. Models are registered
synchronously from the persisted catalog (PI_CURSOR_CACHE_DIR), falling back to the
catalog bundled in src/models/catalog.json on a first-ever launch. Live discovery runs
through pi's refreshModels hook — off the critical path, in the background, and again
whenever /model is opened — then persists its result for the next launch.
All Cursor HTTP/2 transport runs in-process via node:http2, which Bun implements natively — no
subprocess is spawned. Unary RPCs (both discovery calls) use a dedicated one-shot client
(h2-unary.ts); the bidirectional chat stream uses a persistent session (h2-session.ts) that
survives across turns. Unary calls fall back to the general-purpose bridge transport if the
one-shot client fails.
src/proto/agent_pb.ts is a large generated Connect/protobuf surface used by the wire
layer. Never hand-edit it — regenerate with bun run proto:gen (see
proto/README.md) when Cursor changes the agent schema.
Troubleshooting
No API provider registered for api: cursor-native: Update to the latestpi-cursor(pi update npm:@rahularya01/pi-cursor) and restart Pi (or/reload). This means the Agent tried to stream via Pi's globalstreamSimpledispatcher before the Cursor transport was registered there. Current builds registercursor-nativeon that registry during extension load.- Not logged in / 401: Ensure Cursor CLI or app is logged in, or run
/login cursoragain. Check/cursor.doctorto verify yourtokenSource. Tokens from CLI/IDE are re-resolved when near expiry; idle stream retries also force-refresh credentials. - Empty / hung stream: Cursor may have updated wire headers; verify network connectivity or bump
PI_CURSOR_CLIENT_VERSION./cursor.doctorprints the activeclientVersion. - Wire-protocol drift: Cursor can change
agent.v1at any time. Unrecognized server messages and unknown protobuf fields are no longer skipped silently — they are counted, written to the lifecycle log aswire_drift, appended to the failing turn's error message, and listed by/cursor.doctorunderwireDrift.wireDriftStranding=yesmeans an unanswered message could have parked the turn, which is the difference between "our schema is a bit behind" and "this is why it hung". RunCURSOR_ACCESS_TOKEN=... bun run smoke:wireto check the handshake and schema against the live endpoint without starting a chat turn, then seeproto/README.mdto resync the schema. - Stuck / dies after a few minutes of work: Cursor
InteractionQueryprompts are answered so the stream does not park. Web/search and unnamed proto fields are rejected (use Pi tools instead). Inspect$TMPDIR/pi-cursor-lifecycle.jsonlforinteraction_query/bridge_closeevents, and/cursor.doctorforlastStreamEvent. Full debug:PI_CURSOR_PROVIDER_DEBUG=1. - Tool continuation lost: The provider now prefers full-history rebuild when checkpoints are stale/mismatched. If recovery still skips,
/cursor.doctorshowslastRecoverySkipReason. Retry the turn or start a new chat. - WSL credential detection: Set
USERPROFILEorUSERNAMEso the Windows home directory is known, and ensure/mnt/c/Users/<you>/AppData/...is readable. Disable withPI_CURSOR_SYSTEM_CREDENTIALS=0if undesired. - Slow startup: Activation should be a few milliseconds.
/cursor.doctorreportscatalogCache(none(using bundled fallback)means every launch is starting cold — check thatcatalogCacheDiris writable) andunaryTransport. A stale Cursor CLI keychain entry no longer blocks startup: a refresh token that fails is remembered for 10 minutes so it is not retried on the next launch, and any valid locally stored token is always preferred over a network exchange. - Model list looks stale: It is the last successfully discovered catalog. Open
/modelto trigger a background refresh, or deletePI_CURSOR_CACHE_DIRto force full rediscovery.
Runtime
pi-cursor targets Bun only — no Node.js binary is required or spawned at any point. All
Cursor HTTP/2 transport (the bidirectional chat stream and the unary discovery RPCs) runs
in-process via node:http2, which Bun implements natively.
Earlier versions proxied the chat stream through a short-lived Node subprocess, because Bun's
node:http2 client was believed unable to carry a bidirectional Connect stream reliably. That
subprocess is gone: oh-my-pi, a Bun-hosted fork of Pi that
talks to the same Cursor RPC, demonstrates the same bidirectional pattern working fine in-process
under Bun. Its only documented Bun/H2 caveat is ALPN negotiation failing behind an
ALPN-stripping TLS-intercepting proxy (e.g. Zscaler) — an environment issue, not a
bidirectional-streaming bug — and /cursor.doctor's lastStderr/lifecycle log will name that
explicitly if it happens.
/cursor.doctor reports the runtime as runtime=bun <version>.
Development
The toolchain is Bun — package manager, script runner, test runner, and bundler. tsc still does
the typechecking, and ESLint and Prettier are unchanged.
bun install
bun run check
bun run check runs TypeScript typechecking, ESLint, Prettier format verification, security checks, the protobuf staleness check, and unit tests.
| Script | Purpose |
|---|---|
bun run proto:gen |
Regenerate src/proto/agent_pb.ts from proto/agent.proto. |
bun run proto:sync |
Rebuild proto/agent.proto from an updated generated file obtained upstream. |
bun run proto:check |
Fail if the generated protobuf is stale or hand-edited (part of bun run check). |
Attributions
Wire protocol and authentication patterns adapted from MIT community client lineage:
Package structure mirrors pi-antigravity.
Support the project
If pi-cursor is useful to you, consider sponsoring the project on GitHub.