feat(cursor): add experimental Cursor model provider with native Rust HTTP/2 - #1349
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Implementation NotesTask: Fix the 6 remaining review blockers in the experimental Cursor provider implementation (GitHub issue #1286), then ship the PR. CONTEXT: A previous ralph run implemented the Cursor provider in this worktree (10 commits on top of origin/main, ~4,829 insertions, mainly packages/cursor/** plus coding-agent registration, docs, changelogs, tests). Validation (bun run typecheck, bun run lint, bun run test:unit) passes, but the final review round rejected the patch with 6 concrete stream-lifecycle/protocol defects confirmed by targeted repros. Do NOT redesign or rewrite the provider — fix only these blockers and add regression tests. First, read these files — they are the source of truth for this round:
SCOPE (tight — only these six fixes plus their regression tests):
DONE CRITERIA (verifiable):
VALIDATION STEPS (from the worktree root; Bun only — never node/npm/npx/yarn/pnpm):
REPO RULES: follow AGENTS.md (Bun >= 1.3.14, bun:test + node:assert/strict, strict TS, no any/unknown, .js import extensions). Commit with conventional-commit messages. PR STAGE: once reviewers approve, push the branch (e.g. feat/cursor-provider) from this worktree and create the PR to main titled for issue #1286 (e.g. "feat: add experimental Cursor provider (#1286)"), with a body summarizing the full Cursor provider feature (not just these fixes) and linking the issue with "Closes #1286". Running Notes
Iteration 1/6 implementation update — 2026-06-12
|
PR Review: Experimental Cursor provider (#1286)Thorough, well-structured contribution. The transport boundary is cleanly isolated, secrets are wrapped and redacted consistently, dependency injection makes the code highly testable, and ~1,950 lines of tests cover auth, transport framing, stream lifecycle, conversation state, model mapping, and provider registration. Docs + CHANGELOG are updated and the build wiring ( Potential bugs / correctness
Performance
Code quality / cleanup
Security (looks solid)
TestsStrong coverage for the injected-fake layer (timeouts, abort, idle cleanup, resume, orphan tool results, usage deltas, model grouping). Two gaps: (a) Overall: high-quality, defensively written, clearly experimental-scoped. Resolving/confirming #1 and #2 is the main thing before this is relied on for tool-using sessions. Reviewed against CLAUDE.md conventions. Note: I could not run |
cadbf3d to
0ed759b
Compare
|
Thanks for the thorough review — addressed the actionable correctness/cleanup items in 0ed759b (
I’m intentionally leaving the HTTP/2 session pooling and O(n²) frame-buffering notes as follow-ups for the experimental provider hardening backlog, rather than expanding this PR further. Validation run locally from the Cursor worktree:
Note: while committing/pushing this follow-up, the known release-docs hook-env bug reproduced locally and wrote |
Review:
|
PR Review:
|
|
Addressed the feedback from this review in
Validation run locally from the Cursor worktree:
I used |
|
Code Review — feat(cursor): add experimental Cursor model provider Nice work. This is a large but well-structured addition: clean dependency-injection seams ( Potential bugs / correctness
Performance
Cost / UX accuracy
Maintainability
Style / minor
Conventions / tests
Overall a high-quality, carefully-isolated provider. None of the above is a hard blocker; the raw-argument coercion in (Automated review — I could not run |
|
Addressed the feedback from this review in
Validation run locally from the Cursor worktree:
I left HTTP/2 session pooling, non-MCP allocation churn, and cost-estimation policy as follow-ups/non-blocking product decisions per the review severity. Commit/push used |
Review:
|
|
Addressed the actionable items from this review in
Left as follow-ups/product decisions per review severity:
Validation run locally from the Cursor worktree:
Commit/push used |
|
Review: feat(cursor): add experimental Cursor model provider Thorough, well-structured PR. The isolation of the private Cursor wire format behind injectable codec/transport seams is the right call, secret redaction is applied consistently, and the test surface (~67 tests / ~2.3k lines across 6 files) is strong for an experimental provider. The proto/README.md field-provenance notes and manual smoke-test procedure are excellent. Comments below are mostly robustness/perf; none are merge-blockers given the experimental labeling. ROBUSTNESS / POTENTIAL BUGS
MINOR
THINGS DONE WELL
TEST COVERAGE Nice work overall — the experimental boundary is clearly drawn and the protocol notes make this maintainable as the Cursor API drifts. Reviewed by Claude (Opus 4.8). Could not run bun test / typecheck in this environment; relied on CI reported checks for those. |
|
Addressed both the user-reported runtime failure and this review in Root cause for: was the MCP tool Changes:
Validation run locally from the Cursor worktree:
Manual smoke test recommendation after this commit: retry |
|
Addressed the live runtime error: in Root cause: Atomic was sending Changes:
Validation run locally from the Cursor worktree:
Manual smoke-test ask: retry a simple Cursor chat turn ( |
Code Review:
|
|
Code Review: feat(cursor): add experimental Cursor model provider Thorough, well-structured first-party provider. The seam design (injectable Strengths
Correctness / robustness
Cleanup / dead code Performance Security Tests Overall this is high-quality, security-conscious code with appropriate experimental / private API labeling throughout. The findings above are refinements, not blockers. Generated with Claude Code |
|
Pushed Key fixes:
Validation run before push:
|
Review:
|
Assistant-model: OpenAI ChatGPT
Assistant-model: OpenAI Codex
Assistant-model: OpenAI ChatGPT
Assistant-model: OpenAI ChatGPT
Accumulate Cursor usage deltas without clearing checkpoint fields and surface Connect end-stream errors with sanitized classifications. Persist token-free live Cursor model catalogs so startup, refresh, and first authenticated use keep discovery best-effort around credential rotation. Assistant-model: ChatGPT
Assistant-model: OpenAI ChatGPT
Assistant-model: Codex
Bind Cursor stream open/read/resume deadlines to per-request timeouts, reset stalled streams on abort or timeout, safely clean up replaced paused turns, and tolerate non-MCP exec messages. Assistant-model: ChatGPT
Assistant-model: GPT-5.5
Assistant-model: GPT-5.5
Assistant-model: GPT-5.5
Assistant-model: GPT-5.5
Assistant-model: GPT-5.5
Assistant-model: GPT-5.5
Assistant-model: GPT-5.5
80297a5 to
3273ffc
Compare
Review:
|
Flush pending Cursor live model discovery during shutdown and only expose live-only models after the catalog cache is durably written. Also update Cursor provider protocol assets, docs, and regression coverage included in the current worktree. Assistant-model: GPT-5.5
Review:
|
Assistant-model: GPT-5.5
Code Review — feat(cursor): add experimental Cursor model providerThanks for this — it's a substantial, well-structured package. The redaction discipline, dependency-injection seams, atomic cache writes, and best-effort catalog discovery are all genuinely nicely done. A few things need attention before merge, including one that will break the published package. 🔴 Blocking1.
It works in the workspace because Bun hoists it to the root This is exactly the pattern 2. The PR description and docs claim there is no child-process bridge — but there is.
In reality, the default transport client is This isn't just a wording nit — the bridge has real operational consequences (below). Please correct the description and 🟠 Should address3. Hard dependency on a
4. Verify bridge resolution in the compiled binary.
5. The real network path has no test coverage. All of 🟡 Minor
✅ Things done well
Overall: solid implementation; (1) is a must-fix for the published artifact, and (2)/(3) are about making the experimental nature and Node requirement honest and discoverable for users. |
Declare @bufbuild/protobuf on @bastani/atomic so bundled Cursor can load from native release archives, add archive smoke coverage, and extend package metadata guards to include Cursor. Update Cursor docs/changelog/PR copy for the request-scoped Node bridge, stop sending the current working directory as previousWorkspaceUris by default, and back off transient login poll failures. Assistant-model: GPT-5.5
Review:
|
Native NAPI-RS transport avoids subprocess overhead and improves abort, timeout, and control-frame handling for Cursor agent streaming.
| this.#runtime.conversationState.pauseTurnForTools(activeConversationKey, runStream, pendingToolCalls, { signal: options?.signal, idleTimeoutMs: this.#runtime.pausedTurnIdleTimeoutMs }); | ||
| output.stopReason = "toolUse"; | ||
| stream.push({ type: "done", reason: "toolUse", message: output }); | ||
| terminalEventSent = true; |
Code Review —
|
* feat: add experimental cursor provider scaffold Assistant-model: OpenAI ChatGPT * fix: harden cursor provider transport boundary Assistant-model: OpenAI Codex * feat: add cursor protobuf transport codec Assistant-model: OpenAI ChatGPT * fix: harden cursor run streaming lifecycle Assistant-model: OpenAI ChatGPT * fix: refine cursor stream usage handling Accumulate Cursor usage deltas without clearing checkpoint fields and surface Connect end-stream errors with sanitized classifications. Persist token-free live Cursor model catalogs so startup, refresh, and first authenticated use keep discovery best-effort around credential rotation. Assistant-model: ChatGPT * fix: improve cursor protobuf fidelity Assistant-model: OpenAI GPT-5 * fix: preserve cursor live catalog fidelity Register cached and live Cursor catalogs exactly as advertised, keeping static composer defaults limited to estimated fallback metadata. Encode Atomic tools through Cursor's McpTools wrapper schema so tool advertisements match the live protocol. Assistant-model: OpenAI GPT-5 * fix: resume cursor tool result streams Assistant-model: OpenAI ChatGPT * fix: harden cursor tool protocol edge cases Assistant-model: Codex * fix: bound cursor provider edge cases * fix(cursor): harden stream lifecycle blockers Bind Cursor stream open/read/resume deadlines to per-request timeouts, reset stalled streams on abort or timeout, safely clean up replaced paused turns, and tolerate non-MCP exec messages. Assistant-model: ChatGPT * fix(cursor): address review feedback Assistant-model: GPT-5.5 * fix(cursor): harden review follow-ups Assistant-model: GPT-5.5 * fix(cursor): address protocol review notes Assistant-model: GPT-5.5 * fix(cursor): harden catalog and diagnostics Assistant-model: GPT-5.5 * fix(cursor): encode MCP schemas as protobuf values Assistant-model: GPT-5.5 * fix(cursor): avoid unsupported system prompt override Assistant-model: GPT-5.5 * fix(cursor): align run protocol with Cursor CLI Assistant-model: GPT-5.5 * fix(cursor): persist live model catalog across restarts Flush pending Cursor live model discovery during shutdown and only expose live-only models after the catalog cache is durably written. Also update Cursor provider protocol assets, docs, and regression coverage included in the current worktree. Assistant-model: GPT-5.5 * fix(cursor): restore saved custom model references Assistant-model: GPT-5.5 * fix(cursor): package protobuf runtime dependency Declare @bufbuild/protobuf on @bastani/atomic so bundled Cursor can load from native release archives, add archive smoke coverage, and extend package metadata guards to include Cursor. Update Cursor docs/changelog/PR copy for the request-scoped Node bridge, stop sending the current working directory as previousWorkspaceUris by default, and back off transient login poll failures. Assistant-model: GPT-5.5
Summary
Introduces
@bastani/cursor, a new experimental first-party bundled provider that routes requests through Cursor's private RPC API, and@bastani/atomic-natives, a new NAPI-RS Rust package providing an in-process native HTTP/2 client. Models are addressed ascursor/<model-id>(default:cursor/composer-2). The transport uses a bundled Rust/N-API binary — no localhost proxy, no Node subprocess required.Closes #1286
Key Changes
New package:
@bastani/cursorsrc/auth.ts): Browser-based PKCE/OAuth2 login with exponential-backoff token polling, credential refresh, JWT expiry parsing, and full credential/PKCE redaction in all diagnostics and error messages.src/transport.ts): Isolated HTTP/2 Connect transport backed by the native@bastani/atomic-nativesbinding; buffered frame decoding, bounded per-request stream deadlines, RST on abort/timeout,GetUsableModelslive model discovery, and injectable client/codec seams for testing.src/proto/protobuf-codec.ts): Minimal production-default protobuf codec for Cursor's private RPC protocol; supports protobufValuearguments and raw UTF-8/JSON fallback; JSON codec injectable for tests only.src/stream.ts): Writes the initial Connect frame before response headers; decodesexecServerMessage.mcpArgstool calls with field-order-independent exec IDs; correlates historical tool results with originating tool calls; accumulates token deltas/checkpoints; classifies Connect end-stream errors; tolerates non-MCP exec protocol messages without ending the assistant turn.src/conversation-state.ts): Stable conversation IDs, same-stream MCP tool-result resume viaExecClientMessage.mcp_result, paused-turn abort/idle timeout cleanup, and safe replacement-turn cleanup.src/model-mapper.ts): MapsModelOptionsto Cursor's Run request schema; preserves live model ID fidelity without static injection; fast/thinking as separate selector groups; effort-like suffixes (e.g.-max) treated as standalone model names without sibling catalog evidence.src/catalog-cache.ts): Token-free atomic writes to~/.atomic/agent/cursor-model-catalog.json; startup uses valid cached live catalog before estimated fallback; login/refresh/first-stream rediscovery is best-effort and non-blocking.src/provider.ts): Registerscursorin Atomic's provider registry withstreamSimpleadapter andMcpToolswrapper schema for tool advertisement; vision input rejected with a descriptive error.New package:
@bastani/atomic-nativescrates/atomic-natives/src/lib.rs): Native in-process HTTP/2 transport usingtokio,h2,rustls, andnapi-rs; exposescursorH2RequestUnary,cursorH2OpenStream, andcursorH2CancelOperationas N-API exports; supports per-operation cancellation via a static registry.x86_64/aarch64on Linux, macOS, and Windows via the@napi-rs/clitoolchain; prebuilt optionals ship as npm platform packages.packages/cursor/src/native-loader.ts): Lazy-loads@bastani/atomic-nativesat runtime, caches the result, and surfaces a diagnostic with reinstall instructions on load failure.Protocol alignment
Integration into
@bastani/atomic@bastani/cursoras a bundled workspace package inbuiltin-packages.ts.cursor: "composer-2"default model mapping inmodel-resolver.ts.resolveSavedModelReferencefrom model resolution so saved custom model references (e.g. live Cursor catalog models) are restored via fallback construction rather than failing a strict registry lookup — fixes session restores for models that aren't in the static registry.sdk.tsto useresolveSavedModelReferencewhen restoring a model from an existing session.showCancelHintoption to the login dialog'sshowAuthcall and aremoveAuthCancelHintcleanup method for OAuth flows that transition to manual input.scripts/copy-builtin-packages.tsentry for the cursor package.@bufbuild/protobufas a direct@bastani/atomicruntime dependency and extended package/archive smoke coverage so bundled Cursor loads from release archives.docs/providers.md,docs/models.md, anddocs/custom-provider.mdwith Cursor setup instructions and limitations.Test coverage
cursor-auth.test.ts— PKCE pair generation, JWT expiry parsing, login flow, refresh, and poll cancellation.cursor-transport.test.ts— Transport lifecycle, timeout/RST behavior, abortable writes, and error classification.cursor-stream.test.ts— Text/reasoning streaming, MCP tool-call decode (protobuf + raw UTF-8), usage accumulation, exec-id correlation, and non-MCP exec message tolerance.cursor-conversation-state.test.ts— Tool-result resume, abort/idle cleanup, paused-turn replacement, and cancellation safety.cursor-model-mapper.test.ts— Model option mapping, fast/thinking grouping, effort-suffix handling.cursor-registration.test.ts— Provider registration, model enumeration, and estimated vs. live catalog fallback behavior.cursor-native-loader.test.ts— N-API load success/failure paths and diagnostic formatting.model-resolver.test.ts— Added coverage forresolveSavedModelReferencewith fallback construction.Security
~/.atomic/agent/auth.json).@bastani/atomic-nativesRust binary.previousWorkspaceUrisby default so local absolute paths are not sent as workspace context.Limitations
cursor/<model-id>format (default:cursor/composer-2).Validation
bun run typecheck✓bun run lint✓bun run test:unit✓bun run test:integration✓cd packages/coding-agent && bun run build✓./scripts/build-binaries.sh --skip-deps --platform linux-x64+ archive path check for bundled Cursor/protobuf ✓