@tduyng/pi-cursor
Cursor models in Pi through the official Cursor SDK: one warm agent per session, Pi's own prompt and tools, resumed instead of replayed.
Package details
Install @tduyng/pi-cursor from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@tduyng/pi-cursor- Package
@tduyng/pi-cursor- Version
0.0.5- Published
- Nov 10, 2026
- Downloads
- 833/mo · 661/wk
- Author
- tienduy-nguyen
- License
- Apache-2.0
- Types
- extension
- Size
- 82 KB
- Dependencies
- 3 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@tduyng/pi-cursor
Cursor models inside pi, through the official Cursor SDK. The SDK runs the agent loop, and everything above the transport stays pi's: system prompt, tools, approvals, compaction and session tree.
Tools are callbacks, not a server
LocalAgentOptions.customTools registers one in-process callback per tool, and a tool call does not end the Cursor run. The callback waits, pi executes the named tool through its normal pipeline, and the next streamSimple call resolves the callback with the result. The same run continues, so the model sees the result in the same conversation.
The extension switches Cursor's own harness off: AgentOptions.tools: ['mcp'] leaves only pi's custom tools, and local.settingSources: [] drops Cursor's rules, skills and MCP servers. No HTTP MCP server, no Hono server, no tool-name rewriting.
A restart resumes the agent
At the end of every clean turn the extension records the agent id with the working folder, prompt and tool hashes, the pi message count and its own hash of that prefix, in ~/.pi/agent/pi-cursor-agents.json. The next process calls Agent.resume when all of those still match and the pending turn is a single new user message. A stale id, a diverged fork, or a turn killed mid tool round falls back to the replay. The ledger keeps the last 20 sessions.
A message typed while a tool runs goes out with Run.steer, so the model reads it before its next step. Images attached to such a message become a one-line note, because steering carries only text.
Use
/model cursor/gpt-5.5
The provider id is cursor and model ids are Cursor's own. The list comes from Cursor.models.list(), cached after the last successful read in ~/.pi/agent/pi-cursor-models.json at mode 0600 and keyed by the credential. Startup registers the cache with no network call, session start refreshes it, and a small built-in list is the fallback.
A model that offers several context windows is registered once per window: the plain id uses the smallest, and cursor/gpt-5.5@1m asks for 1M. Cursor bills the larger windows as Max Mode, so the small default is the cheap one.
| Command | Effect |
|---|---|
/cursor status |
Account, fast mode, prompt path, models |
/cursor login |
The SDK browser flow |
/cursor logout |
Removes the stored key and the resume ledger |
/cursor models |
Every registered id, per context window |
/cursor fast on|off |
Cursor's fast parameter on every model that exposes it |
/cursor clear |
Drops the resume ledger |
/cursor fast is a billing choice, so it stays off until asked.
Thinking levels map to Cursor model parameters from the live catalog: a thinking on/off switch, and the first of effort, reasoning_effort or reasoning for the level. A model shows only the levels Cursor serves for it, so Grok 4.7 offers low to xhigh and a switch-only model offers off and high.
Wire cost
Measured on the account this extension was built on, gpt-5.5 with auto-smart and thinking off:
| Call | Prompt tokens | Of which cached | Wall time |
|---|---|---|---|
| First call of an agent | 11.9k | 2.6k | 4.8 to 5.5s |
| Plain follow-up turn | 12.9k | 12.7k | 2.2s |
| Call after a tool round | 36.9k | 36.0k | 4.4 to 13s |
The tool-round number is Cursor's, not the tool result. The SDK re-prefills its own context around the custom tool callback, so one tool call costs about three plain calls. The same 32k prompt appears with an empty working directory, so it is not workspace scanning. Fewer, wider tool calls per turn is the lever that exists.
The extension adds no tool, no prompt block and no schema. What it saves on the wire is the replay: a normal turn sends only the new user message, a tool round sends nothing, and a restarted pi process resumes the same agent.
Install
- Pi 1.4 or newer.
- Node 24 or newer.
- A Cursor account.
@cursor/sdk1.0.40, installed by the workspace as a 25 MB dependency with optional platform packages.
pi install npm:@tduyng/pi-cursor
Local checkout: pi install /path/to/dotfiles/pi/agent/extensions/pi-cursor
No Cursor CLI is installed or called. Login is the SDK browser flow, which mints a stored Cursor key under ~/.cursor/sdk/auth.json:
/cursor login
If the browser does not open, the command prints the URL. CURSOR_API_KEY overrides the stored login, and the key is read by the SDK rather than copied into pi's auth.json.
Cursor bills SDK traffic under its own terms, and this extension cannot tell whether a run is plan-included. Check the Cursor dashboard for the account's SDK usage.
~/.pi/agent/pi-cursor.json holds the two preferences: fast, from /cursor fast, and noSystemPrompt, once Cursor has refused pi's prompt for this account.
Limits
Cursor owns the agent loop and its context management, so pi's compaction does not reach inside a live agent.
AgentOptions.systemPromptis server-gated. A rejected prompt comes back as a failed run about 20 seconds in, not fromAgent.create, so that turn is retried with the prompt prepended to the first message.The rejection is recorded as
noSystemPrompt, and every later agent skips the doomed attempt. The fallback works but spends more tokens, because the Cursor harness prompt remains.A failed run reaches pi as an error message, so an empty answer means a broken transport rather than a silent backend rejection.
The model list is refetched at most once every ten minutes across all pi processes, read from the modification time of
pi-cursor-models.json. Cursor throttles that endpoint at 30 requests a minute per account,Agent.createcalls it too, and every pi start used to fetch it, so a gate run or a burst of subagents surfaced asCursor agent could not start: You have exceeded the rate limit of 30 requests per minute for the get_models endpoint. A failed refresh counts against the interval too, because the throttle counts requests rather than successes./cursor loginalways refetches.An agent that cannot be started, or whose SDK gives up resuming it after repeated attempts, leaves a record nobody can recover: that failure drops the record, so the next attempt replays the transcript to a fresh agent instead of resuming a stuck one. The message says so, because the SDK's own wording names no remedy.
A run that sends no event for 10 minutes is aborted and fails with a timeout, which pi retries on a fresh agent. The SDK stream can stop without erroring, and nothing else ends the wait: one recorded run sat silent past eight minutes until it was killed by hand.
Cursor reports input and cache tokens once per run, in a single
turn-endedevent summed over every model call, and a run spans every tool round until the final answer. Each message that ends in a tool call carries the output tokens counted fromtoken-deltaevents, and the final message carries the run's input, cache and remaining output. Cursor counts cached tokens inside its input count, so pi's input is what remains after the cache.The context size pi shows and compacts on is pi's own estimate of the transcript, because the summed run input once read 13M on a 200k window and compacted 17 times in one session. It leaves out Cursor's harness prompt, about 10k to 30k tokens. Pi shows zero money cost because Cursor bills outside pi.
A replay replaces earlier images with an
[image: mime]placeholder and keeps only the pending message's images, so reattach one to ask about it again after a restart.A model id Cursor no longer serves fails at
send, not at selection.A long pi tool run is held open by the Cursor local runtime, and the SDK documents no timeout for custom tools.