@emmaneugene/pi-cursor-sdk 0.3.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +99 -126
  3. package/dist/cursor-agents-context-registration.js +1 -3
  4. package/dist/cursor-agents-context.js +2 -2
  5. package/dist/cursor-config.js +2 -290
  6. package/dist/cursor-provider-errors.js +3 -58
  7. package/dist/cursor-provider-live-run-drain.js +0 -3
  8. package/dist/cursor-provider-run-finalizer.js +4 -7
  9. package/dist/cursor-provider-run-outcome.js +1 -1
  10. package/dist/cursor-provider-turn-finalize.js +3 -55
  11. package/dist/cursor-provider-turn-prepare.js +8 -144
  12. package/dist/cursor-provider-turn-runner.js +9 -23
  13. package/dist/cursor-provider-turn-send.js +8 -35
  14. package/dist/cursor-runtime-state.js +6 -268
  15. package/dist/cursor-sdk-billed-usage.js +3 -18
  16. package/dist/cursor-sdk-platform-package.js +88 -0
  17. package/dist/cursor-session-agent.js +18 -14
  18. package/dist/cursor-skill-tool.js +12 -22
  19. package/dist/cursor-state.js +5 -8
  20. package/dist/cursor-usage-accounting.js +1 -1
  21. package/docs/cursor-dogfood-checklist.md +4 -4
  22. package/docs/cursor-live-smoke-checklist.md +23 -23
  23. package/docs/cursor-model-ux-spec.md +27 -30
  24. package/docs/cursor-native-tool-replay.md +4 -4
  25. package/docs/cursor-native-tool-visual-audit.md +7 -7
  26. package/docs/cursor-testing-lessons.md +23 -16
  27. package/docs/cursor-tool-surfaces.md +2 -4
  28. package/docs/platform-smoke-implementation.md +5 -5
  29. package/docs/platform-smoke.md +27 -72
  30. package/package.json +3 -17
  31. package/platform-smoke.config.mjs +2 -1
  32. package/scripts/lib/local-resume-smoke-harness.mjs +0 -18
  33. package/scripts/platform-smoke/card-detect.mjs +1 -1
  34. package/scripts/platform-smoke/local-resume-runner.mjs +1 -1
  35. package/scripts/platform-smoke/scenarios.mjs +1 -1
  36. package/scripts/platform-smoke/targets.mjs +14 -5
  37. package/src/cursor-agents-context-registration.ts +0 -5
  38. package/src/cursor-agents-context.ts +1 -3
  39. package/src/cursor-config.ts +8 -379
  40. package/src/cursor-provider-errors.ts +2 -62
  41. package/src/cursor-provider-live-run-drain.ts +0 -3
  42. package/src/cursor-provider-run-finalizer.ts +4 -12
  43. package/src/cursor-provider-run-outcome.ts +0 -3
  44. package/src/cursor-provider-turn-finalize.ts +3 -61
  45. package/src/cursor-provider-turn-prepare.ts +8 -165
  46. package/src/cursor-provider-turn-runner.ts +15 -31
  47. package/src/cursor-provider-turn-send.ts +7 -38
  48. package/src/cursor-provider-turn-types.ts +9 -30
  49. package/src/cursor-runtime-state.ts +6 -345
  50. package/src/cursor-sdk-billed-usage.ts +3 -24
  51. package/src/cursor-sdk-platform-package.ts +106 -0
  52. package/src/cursor-session-agent.ts +16 -12
  53. package/src/cursor-skill-tool.ts +10 -26
  54. package/src/cursor-state.ts +5 -10
  55. package/src/cursor-usage-accounting.ts +1 -3
  56. package/dist/cursor-cloud-lifecycle.js +0 -650
  57. package/dist/cursor-cloud-local-state.js +0 -460
  58. package/dist/cursor-cloud-options.js +0 -145
  59. package/dist/cursor-cloud-reporting.js +0 -222
  60. package/dist/cursor-ripgrep-path.js +0 -27
  61. package/scripts/cloud-runtime-smoke.d.mts +0 -42
  62. package/scripts/cloud-runtime-smoke.mjs +0 -623
  63. package/scripts/lib/cloud-smoke-artifacts.d.mts +0 -16
  64. package/scripts/lib/cloud-smoke-artifacts.mjs +0 -94
  65. package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +0 -209
  66. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +0 -585
  67. package/scripts/lib/cloud-smoke-github.d.mts +0 -78
  68. package/scripts/lib/cloud-smoke-github.mjs +0 -331
  69. package/scripts/lib/cloud-smoke-pi-runner.d.mts +0 -42
  70. package/scripts/lib/cloud-smoke-pi-runner.mjs +0 -214
  71. package/scripts/lib/cloud-smoke-shutdown.d.mts +0 -67
  72. package/scripts/lib/cloud-smoke-shutdown.mjs +0 -133
  73. package/shared/cursor-cloud-lifecycle-constants.d.mts +0 -3
  74. package/shared/cursor-cloud-lifecycle-constants.mjs +0 -7
  75. package/src/cursor-cloud-lifecycle.ts +0 -733
  76. package/src/cursor-cloud-local-state.ts +0 -536
  77. package/src/cursor-cloud-options.ts +0 -182
  78. package/src/cursor-cloud-reporting.ts +0 -267
  79. package/src/cursor-ripgrep-path.ts +0 -32
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0 - 2026-09-06
4
+
5
+ Breaking: Cursor Cloud support is removed. Cursor SDK runs are local-only.
6
+
7
+ ### Fixed
8
+
9
+ - Pin `CURSOR_TREE_SITTER_VENDOR_DIR` from the installed `@cursor/sdk-<platform>-<arch>` package before local `Agent.create`. The SDK locates that vendor directory by walking from `process.argv[1]` and `process.execPath`, so a default `pi` launch never sees the package under `~/.pi/agent/npm` and disables shell command analysis.
10
+ - Point the same SDK locator at that platform package during local `Agent.create` / `Agent.resume` so `cursorsandbox` is found when sandbox is requested. The SDK has no path env var for this helper; without the host-entry, `Agent.create` throws that sandboxing is not supported.
11
+ - Isolate `cursor-provider-local-resume` tests from ambient `~/.pi/agent/cursor-sdk.json` and leaked `Agent.resume` mocks so local-resume assertions do not depend on the maintainer machine.
12
+
13
+ ### Changed
14
+
15
+ - Remove Cursor Cloud runtime support, including remote `bc-*` agents, cloud commands and configuration, lifecycle/reporting, and cloud smoke scripts. All Cursor SDK runs are now local. The footer now uses `cursor · fast:...` instead of `cursor:local · fast:...`.
16
+ - Rename `src/cursor-ripgrep-path.ts` to `src/cursor-sdk-platform-package.ts`. The module now owns ripgrep, tree-sitter vendor, and `cursorsandbox` resolution.
17
+ - Defer the Crabbox three-OS platform matrix as a release gate. Current fork evidence is unit tests, typechecks, package dry run, one live print-mode Cursor run, and visual smoke. Issue [#2](https://github.com/emmaneugene/pi-cursor-sdk/issues/2) tracks reintroduction. The retained matrix now uses the published scoped package name `@emmaneugene/pi-cursor-sdk`. Documented print-mode runs use `pi -ne` so a host `pi install` of this package does not collide with `-e .`.
18
+
3
19
  ## 0.3.7 - 2026-09-05
4
20
 
5
21
  First release of the maintained fork published as `@emmaneugene/pi-cursor-sdk`.
package/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # @emmaneugene/pi-cursor-sdk
2
2
 
3
- A pi provider extension that lets pi use Cursor models through the local-by-default `@cursor/sdk` agent runtime, with explicit minimal Cursor Cloud opt-in.
3
+ A pi provider extension that lets pi use Cursor models through the local `@cursor/sdk` agent runtime.
4
4
 
5
5
  This is a maintained fork of [fitchmultz/pi-cursor-sdk](https://github.com/fitchmultz/pi-cursor-sdk)
6
6
 
7
- Use this extension if you primarily use Cursor models inside pi and want Cursor's SDK agent loop preserved while pi adds native model selection, auth, thinking/context controls, session behavior, replay UI, optional local pi tool bridging, and explicit cloud runs when requested.
7
+ Use this extension if you primarily use Cursor models inside pi and want Cursor's SDK agent loop preserved while pi adds native model selection, auth, thinking/context controls, session behavior, replay UI, and optional pi tool bridging.
8
8
 
9
9
  ## Why use this instead of an OpenAI-compatible Cursor endpoint?
10
10
 
11
11
  Use `pi-cursor-sdk` when you primarily want to use Cursor models **inside pi**.
12
12
 
13
- This extension runs Cursor models through `@cursor/sdk` and keeps Cursor's agent loop intact. Local remains the default; explicit cloud runtime starts Cursor Cloud after acknowledgement and preflight. pi integrates around that loop: model discovery, model selection, context-window variants, thinking controls where Cursor exposes them, fast/slow aliases, Cursor mode, session handling, native replay cards, and the optional local pi tool bridge.
13
+ This extension runs Cursor models through the local `@cursor/sdk` agent runtime and keeps Cursor's agent loop intact. pi integrates around that loop: model discovery, model selection, context-window variants, thinking controls where Cursor exposes them, fast/slow aliases, Cursor mode, session handling, native replay cards, and the optional pi tool bridge.
14
14
 
15
15
  OpenAI-compatible Cursor proxies are useful when you want a generic `/v1/chat/completions` or `/v1/responses` endpoint for many clients such as curl, the OpenAI SDK, OpenCode, or other tools. That compatibility comes from translating Cursor behavior into OpenAI-shaped requests, responses, and tool calls.
16
16
 
@@ -94,10 +94,10 @@ For development from this repository:
94
94
 
95
95
  ```bash
96
96
  npm install # runs prepare, which compiles src/ into dist/ (the manifest entry pi loads)
97
- pi --approve -e . --model cursor/grok-4.6
97
+ pi -ne --approve -e . --model cursor/grok-4.6
98
98
  ```
99
99
 
100
- After editing `src/`, run `npm run build` before the next `pi -e .` run, or pi loads the previous build.
100
+ `-ne` keeps a host `pi install` of this package from colliding with `-e .`. After editing `src/`, run `npm run build` before the next `pi -e .` run, or pi loads the previous build.
101
101
 
102
102
  ## Configure your Cursor SDK API key
103
103
 
@@ -136,7 +136,7 @@ One-shot setup:
136
136
  pi --api-key "your-key" --model cursor/grok-4.6 --cursor-no-fast -p "Say ok only."
137
137
  ```
138
138
 
139
- Startup discovery intentionally does not parse Pi CLI arguments. It uses the stored `cursor` key in `~/.pi/agent/auth.json`, then `CURSOR_API_KEY`; without either, the bundled fallback catalog registers. Provider turns still receive Pi's resolved `--api-key`. `/cursor-refresh-models` and `/cursor-cloud` mutations ask Pi's ModelRegistry for provider `cursor`, so command-time auth follows Pi's provider-scoped resolution and is normalized through `CURSOR_API_KEY` placeholders before reaching the Cursor SDK.
139
+ Startup discovery intentionally does not parse Pi CLI arguments. It uses the stored `cursor` key in `~/.pi/agent/auth.json`, then `CURSOR_API_KEY`; without either, the bundled fallback catalog registers. Provider turns still receive Pi's resolved `--api-key`. `/cursor-refresh-models` asks Pi's ModelRegistry for provider `cursor`, so command-time auth follows Pi's provider-scoped resolution and is normalized through `CURSOR_API_KEY` placeholders before reaching the Cursor SDK.
140
140
 
141
141
  ### Model catalog cache
142
142
 
@@ -254,17 +254,16 @@ Composer 2 and Composer 2.5 can default to fast. Use `--cursor-no-fast` or a `:s
254
254
  In interactive mode, the footer shows Cursor status only while a Cursor model is active. Fast-capable models show fast state explicitly, and fast and plan mode share one Cursor status value so they do not overwrite each other:
255
255
 
256
256
  ```text
257
- cursor:local · fast:n/a
258
- cursor:local · fast:n/a · plan
259
- cursor:local · fast:off
260
- cursor:local · fast:on
261
- cursor:local · fast:off · plan
262
- cursor:local · fast:on · plan
263
- cursor:local · fast:on · http1
264
- cursor:cloud · fast:n/a
257
+ cursor · fast:n/a
258
+ cursor · fast:n/a · plan
259
+ cursor · fast:off
260
+ cursor · fast:on
261
+ cursor · fast:off · plan
262
+ cursor · fast:on · plan
263
+ cursor · fast:on · http1
265
264
  ```
266
265
 
267
- `cursor:local` / `cursor:cloud` shows the selected Cursor runtime. `fast:off` means fast mode is off. `fast:n/a` means the active runtime/model does not expose a local fast toggle. `http1` appears when HTTP/1.1/SSE transport is enabled for local Cursor SDK agents. If you do not see `plan`, Cursor SDK mode is the default `agent` mode.
266
+ `fast:off` means fast mode is off. `fast:n/a` means the active model does not expose a fast toggle. `http1` appears when HTTP/1.1/SSE transport is enabled for Cursor SDK agents. If you do not see `plan`, Cursor SDK mode is the default `agent` mode.
268
267
 
269
268
  ## Cursor SDK mode
270
269
 
@@ -313,20 +312,19 @@ pi --model cursor/grok-4.6 --cursor-local-force
313
312
 
314
313
  This maps to the next actual `agent.send(..., { local: { force: true } })` only. SDK load, agent acquire, prompt preparation, or a pre-send abort does not consume it. A consumed CLI flag is not rearmed by session reload/tree lifecycle events; the environment override remains once per process. It is not a retry loop and does not cancel another live process's existing run handle; use it only when you know the persisted local run is wedged.
315
314
 
316
- Branch-scoped local resume reattaches to recorded local SDK agents after a pi restart. It is on by default for local runtime and records agent IDs plus their SDK store identity only in pi session custom entries, never user/project config. Independently of resume, each local agent whose send is initiated is also recorded once per native pi session as a best-effort non-resumable `cursor-sdk-agent-lineage` custom entry at the `Agent.send()` boundary for forensic lineage; cloned/forked sessions record their own lineage under their new pi session ID. Disable resume per run with CLI/env, or persist an opt-out in config:
315
+ Branch-scoped local resume reattaches to recorded local SDK agents after a pi restart. It is on by default and records agent IDs plus their SDK store identity only in pi session custom entries, never user/project config. Independently of resume, each local agent whose send is initiated is also recorded once per native pi session as a best-effort non-resumable `cursor-sdk-agent-lineage` custom entry at the `Agent.send()` boundary for forensic lineage; cloned/forked sessions record their own lineage under their new pi session ID. Disable resume per run with CLI/env, or persist an opt-out in config:
317
316
 
318
317
  ```bash
319
318
  pi --model cursor/grok-4.6 --cursor-no-local-resume
320
319
  PI_CURSOR_LOCAL_RESUME=0 pi --model cursor/grok-4.6
321
320
  ```
322
321
 
323
- Resume is strict: the current pi session file/id, branch path prefix, cwd/repo root, model/API/tool-surface pool key, SDK store identity, and compaction generation must match. Each persisted pi session gets a SQLite store under `<getDefaultSdkStateRoot(cwd)>/pi-sessions/<session-hash>/`, and that same store is used for create/resume, transcript reads, checkpoint lookup, and exact-ID cleanup so parallel pi sessions do not contend on one workspace `index.db`. Fileless sessions use a unique OS-temporary store per acquisition, remove it on graceful disposal, and start a fresh agent after invalidation instead of reopening a disposed temporary store. Legacy resume entries still try the SDK's default workspace store; if that resume fails or the agent is later replaced, the new agent moves to the per-session store. A trailing user message already present at process startup is crash-ambiguous and invalidates the old handle; only a user message appended in the current process may span a recorded handle, preventing restart from resending an already-submitted prompt. A successful process reattachment bootstraps the current pi transcript once while retaining the resumed Cursor agent's native state; later in-process turns remain incremental. If `Agent.resume()` fails, pi bootstraps a new local Cursor agent from the current transcript and streams one display-only continuity note. Superseded local agents can be cleaned up explicitly with `/cursor-local-resume-cleanup --dry-run` and `/cursor-local-resume-cleanup --yes`; cleanup only deletes exact recorded `agent-*` IDs from their recorded store. Cloud resume remains disabled; `/cursor-cloud list|archive|delete` only manages recorded cloud agents.
322
+ Resume is strict: the current pi session file/id, branch path prefix, cwd/repo root, model/API/tool-surface pool key, SDK store identity, and compaction generation must match. Each persisted pi session gets a SQLite store under `<getDefaultSdkStateRoot(cwd)>/pi-sessions/<session-hash>/`, and that same store is used for create/resume, transcript reads, checkpoint lookup, and exact-ID cleanup so parallel pi sessions do not contend on one workspace `index.db`. Fileless sessions use a unique OS-temporary store per acquisition, remove it on graceful disposal, and start a fresh agent after invalidation instead of reopening a disposed temporary store. Legacy resume entries still try the SDK's default workspace store; if that resume fails or the agent is later replaced, the new agent moves to the per-session store. A trailing user message already present at process startup is crash-ambiguous and invalidates the old handle; only a user message appended in the current process may span a recorded handle, preventing restart from resending an already-submitted prompt. A successful process reattachment bootstraps the current pi transcript once while retaining the resumed Cursor agent's native state; later in-process turns remain incremental. If `Agent.resume()` fails, pi bootstraps a new local Cursor agent from the current transcript and streams one display-only continuity note. Superseded local agents can be cleaned up explicitly with `/cursor-local-resume-cleanup --dry-run` and `/cursor-local-resume-cleanup --yes`; cleanup only deletes exact recorded `agent-*` IDs from their recorded store.
324
323
 
325
- Config can also set non-secret defaults in `~/.pi/agent/cursor-sdk.json` or trusted `.pi/cursor-sdk.json`. Project config activates only when Pi's project-trust flow reached this extension and approved the project, or the run started with explicit `--approve`; Pi's implicit trust for a project with no recognized resources is not enough. Because Pi 0.84.0 loads project-local package extensions after the trust event, `pi install -l` users must pass `--approve` on every run that reads or writes `.pi/cursor-sdk.json`. A trust resource added after trust resolution requires restarting pi. `/cursor-runtime ... --save-project` requires the same trust provenance and does not create Pi trust resources automatically. Explicit runtime, fast-default, and HTTP transport saves preserve unrecognized fields, reject malformed or non-object JSON without rewriting it, and serialize concurrent writers. A completed global preference write is retained if Pi's subsequent session-journal append fails, because Pi may already have mutated the in-memory branch; the command reports that partial journal failure and ignores the uncertain session entry until a later successful save or session restart. If a process is force-killed during the tiny update window, the next save reports the `.lock` path; remove it only after confirming no pi process is writing that config.
324
+ Config can also set non-secret defaults in `~/.pi/agent/cursor-sdk.json` or trusted `.pi/cursor-sdk.json`. Project config activates only when Pi's project-trust flow reached this extension and approved the project, or the run started with explicit `--approve`; Pi's implicit trust for a project with no recognized resources is not enough. Because Pi 0.84.0 loads project-local package extensions after the trust event, `pi install -l` users must pass `--approve` on every run that reads or writes `.pi/cursor-sdk.json`. A trust resource added after trust resolution requires restarting pi. Fast-default and HTTP transport saves preserve unrecognized fields, reject malformed or non-object JSON without rewriting it, and serialize concurrent writers. A completed global preference write is retained if Pi's subsequent session-journal append fails, because Pi may already have mutated the in-memory branch; the command reports that partial journal failure and ignores the uncertain session entry until a later successful save or session restart. If a process is force-killed during the tiny update window, the next save reports the `.lock` path; remove it only after confirming no pi process is writing that config.
326
325
 
327
326
  ```json
328
327
  {
329
- "runtime": "local",
330
328
  "local": {
331
329
  "autoReview": true,
332
330
  "sandboxOptions": { "enabled": true },
@@ -340,101 +338,7 @@ Config can also set non-secret defaults in `~/.pi/agent/cursor-sdk.json` or trus
340
338
 
341
339
  `bridge.excludeTools` is a denylist of pi tool names for the pi tool bridge. Denylisted active pi tools are hidden from Cursor; everything else active stays exposed, so an unset list means no restriction, not zero exposure. Names must be strings; empty and malformed entries are dropped, which also means an explicitly empty list falls through to lower-precedence config instead of clearing a user denylist. Trusted project config wins over user config. Overlapping built-in pi tools (`read`, `bash`, `write`, `edit`, `grep`, `find`, `ls`) stay hidden unless `PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1`, and a denylist entry keeps hiding a tool even with that opt-in. A change to the resulting exposed surface splits the local agent pool, so the next turn creates a Cursor agent with the narrowed bridge snapshot.
342
340
 
343
- ### Cloud runtime and acknowledgement
344
-
345
- Cloud/runtime keys are minimal and explicit. Defaults stay local runtime with the loopback MCP bridge as the sole Pi-tool transport, no inline cloud MCP, and no local-state/env-file forwarding. SDK `customTools` remains deferred pending SDK cancellation/deadline support. Invalid non-empty `--cursor-runtime`, `--cursor-cloud-context`, `PI_CURSOR_RUNTIME`, or `PI_CURSOR_CLOUD_CONTEXT` values fail closed instead of falling through to lower-precedence config.
346
-
347
- If `runtime` is explicitly set to `cloud` with `--cursor-runtime cloud`, `PI_CURSOR_RUNTIME=cloud`, `/cursor-runtime cloud`, or config, the provider starts a Cursor cloud agent after preflight instead of silently running local.
348
-
349
- On first interactive use, `/cursor-runtime cloud` shows one confirmation covering remote execution, fresh context by default (explicit bootstrap opt-in), unavailable Pi-local tools/bridge and Pi env forwarding, Cursor's ability to branch/commit/push/open PRs, retained cloud agents, and Max Mode billing at Cursor API pricing (including possible spend-limit setup). Cancelling that first-use confirmation writes no session or config state.
350
-
351
- Use `/cursor-runtime cloud --save-user` for a persistent personal acknowledgement or `--cursor-cloud-ack` / `PI_CURSOR_CLOUD_ACK=1` for non-interactive runs; acknowledged CLI, environment, session, or user state is not prompted again.
352
-
353
- Project config may save a cloud runtime default but not first-use acknowledgement or repo/branch/env/context/direct-push/PR-control/local-state preferences.
354
-
355
- ### Cloud pull-request controls
356
-
357
- Cursor Cloud pull-request controls are strictly opt-in. Omit them to preserve the Cursor SDK's default behavior; when omitted, the extension sends neither SDK field.
358
-
359
- ```bash
360
- pi --model cursor/grok-4.6 --cursor-runtime cloud --cursor-cloud-ack \
361
- --cursor-cloud-repo https://github.com/your-org/your-repo \
362
- --cursor-cloud-branch main \
363
- --cursor-cloud-auto-create-pr --cursor-cloud-skip-reviewer-request
364
-
365
- PI_CURSOR_CLOUD_ACK=1 \
366
- PI_CURSOR_CLOUD_REPO=https://github.com/your-org/your-repo \
367
- PI_CURSOR_CLOUD_BRANCH=main \
368
- PI_CURSOR_CLOUD_AUTO_CREATE_PR=1 \
369
- PI_CURSOR_CLOUD_SKIP_REVIEWER_REQUEST=1 \
370
- pi --model cursor/grok-4.6 --cursor-runtime cloud
371
- ```
372
-
373
- User config uses `cloud.autoCreatePR` and `cloud.skipReviewerRequest`:
374
-
375
- ```json
376
- {
377
- "runtime": "cloud",
378
- "cloud": {
379
- "autoCreatePR": true,
380
- "skipReviewerRequest": true
381
- }
382
- }
383
- ```
384
-
385
- The resolver follows cloud precedence (CLI, environment, session, then user) with user safety denials; project config is excluded. The current public inputs are CLI/environment one-shot controls and user config—there is no PR-control session command.
386
-
387
- ### Cloud repository and local-state validation
388
-
389
- An explicit `--cursor-cloud-branch` / `PI_CURSOR_CLOUD_BRANCH` requires an explicit `--cursor-cloud-repo` / `PI_CURSOR_CLOUD_REPO` because the SDK exposes `startingRef` only on `cloud.repos` entries. Repository values must be HTTPS repository URLs without userinfo, query parameters, or fragments; invalid values fail before `Agent.create()`, and error scrubbing removes URL/SCP-style userinfo.
390
-
391
- When an explicit cloud repo matches local Git state, preflight requires exactly one remote whose effective fetch and push URLs identify that target plus a locally observable, non-symbolic remote-tracking ref uniquely covered by that remote's fetch refspec for the requested branch. Local HTTPS remotes can match the same HTTPS identity; equivalent GitHub SSH and scp-style remotes can also match. Other hosts retain transport-specific identity, and host/path matching remains conservative with GitHub-specific case and lowercase `.git` normalization.
392
-
393
- `refs/heads/<branch>` is normalized to `<branch>` for both inspection and SDK options; invalid Git branch names and other `refs/*` forms are rejected. An explicit repo without `startingRef` is unverifiable locally because the server default is unknown. Inside a Git worktree, full commit SHAs remain unverified and require the explicit local-state override because local tracking refs do not prove which matching remote contains that commit.
394
-
395
- Mismatch, ambiguity, missing refs, or Git errors fail closed. This is local tracking evidence rather than a fetch, so fetch before starting cloud work when remote state may have changed.
396
-
397
- Inspection ignores ambient Git repository/index/config environment redirection; ordinary user/system URL and refspec config may veto, but never authorize, a target match. It disables replacement-object ancestry and fails closed when local replacement or graft metadata makes ancestry ambiguous. File-mode forcing is POSIX-only. Sparse checkouts intentionally fail closed because skip-worktree entries require `--cursor-cloud-allow-local-state`. Stashes are intentionally outside validation because they are not active worktree, index, or `HEAD` state.
398
-
399
- Without an explicit repo, the current branch's locally observable remote-tracking upstream remains the comparison ref only when that remote's effective fetch and push URLs identify one repository and its fetch refspec uniquely owns that tracking ref. `--cursor-cloud-allow-local-state` / `PI_CURSOR_CLOUD_ALLOW_LOCAL_STATE=1` is the explicit override for accepting unverifiable, dirty, or unpushed local state; when active, launch skips local Git inspection while still validating the configured cloud repo/ref.
400
-
401
- ### Cloud context and managed environments
402
-
403
- Cloud runs use fresh context by default; pass `--cursor-cloud-context=bootstrap` / `PI_CURSOR_CLOUD_CONTEXT=bootstrap` to include prior pi context.
404
-
405
- Pass `--cursor-cloud-env-type=cloud|pool|machine` plus optional `--cursor-cloud-env-name=<name>` (or `PI_CURSOR_CLOUD_ENV_TYPE` / `PI_CURSOR_CLOUD_ENV_NAME`) to select a Cursor-managed cloud environment without forwarding local env values. Named `cloud` environments fail closed when combined with `--cursor-cloud-repo`; omit the repo or use a pool/machine environment.
406
-
407
- ### Cloud reporting and durable lifecycle
408
-
409
- When a pi session has a title, cloud agents are created with that title for easier dashboard/list matching.
410
-
411
- At cloud run completion, pi streams display-only cloud telemetry when Cursor reports it: agent/run IDs, pushed branch, repository and PR URL, passive artifact paths, and raw cloud usage.
412
-
413
- Cloud runtime requires a persisted pi session and rejects `--no-session` before `Agent.send()`.
414
-
415
- Immediately after `Agent.create()` returns—and before debug work or abort checks—Pi appends a branch-local lifecycle entry, fsyncs the existing Pi session JSONL anchor through a read-write descriptor, and then fsyncs a newline-framed sidecar keyed by the stable pi session ID (POSIX mode `0600`; Windows inherits the user session directory ACL) in the session directory.
416
-
417
- Existing session files use the exact lifecycle entry ID as the branch anchor; a fileless first turn uses an orphan marker so a restart with the same session ID can claim the record onto exactly one matching or replacement branch after its new timestamped JSONL is created. That durable claim then restores normal sibling-branch isolation. It adds the returned run ID before post-send abort handling or waiting and enriches successful runs with branch/PR metadata. Readers skip individually truncated records so one interrupted append cannot hide later valid cleanup IDs.
418
-
419
- If the agent intent cannot be persisted, pi does not send; if the returned run cannot be persisted, pi requests bounded cancellation. Both paths fail closed and direct you to the Cursor Cloud dashboard for manual cleanup.
420
-
421
- `/cursor-cloud list`, `/cursor-cloud archive <bc-agentId>`, and `/cursor-cloud delete <bc-agentId> --yes` only accept exact recorded `bc-` cloud IDs.
422
-
423
- Archive/delete require resolved Cursor auth, fsync a durable intent before the SDK mutation, and fsync a durable success result afterward; an unresolved intent blocks retries and directs manual dashboard inspection instead of guessing whether an irreversible request completed.
424
-
425
- ### Cloud boundaries
426
-
427
- Raw cloud usage is not copied into pi message usage, context occupancy, compaction, or cost totals. The pi bridge is local-only, and pi env forwarding is not implemented yet, so `--cursor-cloud-env` forwarding-name config fails closed with Cursor-native environment setup guidance.
428
-
429
- Cloud lifecycle commands are explicit and session-branch scoped:
430
-
431
- ```bash
432
- /cursor-cloud list
433
- /cursor-cloud archive <bc-agentId>
434
- /cursor-cloud delete <bc-agentId> --yes
435
- ```
436
-
437
- They only accept cloud agent IDs recorded in the current session branch or its branch-bound durable sidecar; agent intents are fsynced before send and returned run IDs are recorded before abort handling or waiting so rejected, failed, cancelled, or first-turn-crashed sends remain cleanup-eligible. Persistence failures fail closed with Cursor Cloud dashboard cleanup guidance.
341
+ ### Local resume cleanup
438
342
 
439
343
  Local resume cleanup is explicit and session-ledger scoped:
440
344
 
@@ -445,7 +349,7 @@ Local resume cleanup is explicit and session-ledger scoped:
445
349
 
446
350
  It only deletes superseded local `agent-*` IDs that this extension recorded as cleanup candidates, one exact ID at a time through the Cursor SDK using the candidate's recorded store identity (or the SDK default workspace store for legacy candidates without one), and protects agents still resumable from any session-tree branch. Before SDK deletion it verifies and fsyncs an exact intent in the Pi session JSONL, then verifies and fsyncs the result; a missing or non-durable intent prevents deletion, while a missing or non-durable result leaves the durable intent—and a conservative current-process marker—blocking automatic retry. A candidate with a recorded store identity that is invalid for the current session is durably marked non-retryable and excluded from later cleanup attempts. It does not sweep any SDK store or call lower-level empty delete filters. Removing a pi session file does not automatically remove its persisted store directory. After permanently retiring that session and confirming no pi process is using it, a recorded root may be removed manually only when it is the session-derived `<getDefaultSdkStateRoot(cwd)>/pi-sessions/<session-hash>/` path. Never manually remove the SDK default workspace root, which legacy entries may record and other sessions may share.
447
351
 
448
- Only enabled local safety values are passed to `Agent.create({ local })`; false/default values are omitted to preserve the current local-agent behavior. Local force is one-shot/manual-only through CLI/env and is passed only to the next `Agent.send({ local: { force: true } })`. Local resume is enabled by default for local runtime; opt out with `local.resume: false`, `--cursor-no-local-resume`, or `PI_CURSOR_LOCAL_RESUME=0`. Changes take effect on the next turn without recreating a healthy pooled agent.
352
+ Only enabled local safety values are passed to `Agent.create({ local })`; false/default values are omitted to preserve the current local-agent behavior. Local force is one-shot/manual-only through CLI/env and is passed only to the next `Agent.send({ local: { force: true } })`. Local resume is enabled by default; opt out with `local.resume: false`, `--cursor-no-local-resume`, or `PI_CURSOR_LOCAL_RESUME=0`. Changes take effect on the next turn without recreating a healthy pooled agent.
449
353
 
450
354
  ## Images
451
355
 
@@ -463,7 +367,7 @@ Local Cursor runs use two separate tool surfaces:
463
367
 
464
368
  Bridge capabilities are snapshotted from `pi.getActiveTools()` and `pi.getAllTools()` for each Cursor run, including per-tool prompt guidelines when pi exposes them. Cursor sees active bridgeable pi tools as collision-safe MCP names such as `pi__sem_reindex` only when they are exposed in that current run. When exposed, Cursor is instructed to prefer `pi__mcp` for MCP work and `pi__subagent` for delegation; Cursor-configured MCP and Cursor-native subagents are fallbacks when the matching pi tool is not exposed or is unavailable. Pi session output, tool cards, confirmations, hooks, renderers, history, and abort behavior use the real pi tool name, such as `sem_reindex`. The bridge queues Cursor's MCP call, emits a normal pi `toolCall`, waits for the matching pi `toolResult`, and resolves that result back into the same live Cursor SDK run without creating a new `Agent`, unless the run was disposed, aborted, or cancelled. The bridge does not call pi tool `execute()` handlers directly.
465
369
 
466
- Overlapping built-in pi tools (`read`, `bash`, `write`, `edit`, `grep`, `find`, `ls`) are hidden by default because Cursor local agents already have native equivalents. Extension/custom tools and non-overlapping active tools present in pi's active tool registry normally remain exposed. The bridge also exposes `cursor_ask_question` as `pi__cursor_ask_question` when enabled, allowing Cursor to ask the user through pi UI instead of silently choosing a default. For local runtime, when pi has visible Agent Skills loaded, the extension rewrites pi's skill catalog for Cursor and exposes `cursor_activate_skill` as `pi__cursor_activate_skill`; Cursor should call that bridge tool with a listed skill name to load the full `SKILL.md` and bundled resource list before applying the skill. If the local bridge is disabled, the catalog remains available and instructs Cursor to fall back to reading the listed `SKILL.md` path directly. Cloud runtime preserves Pi project instructions but omits Pi's local skill catalog and keeps `cursor_activate_skill` inactive because the bridge and local absolute skill paths are unavailable there.
370
+ Overlapping built-in pi tools (`read`, `bash`, `write`, `edit`, `grep`, `find`, `ls`) are hidden by default because Cursor local agents already have native equivalents. Extension/custom tools and non-overlapping active tools present in pi's active tool registry normally remain exposed. The bridge also exposes `cursor_ask_question` as `pi__cursor_ask_question` when enabled, allowing Cursor to ask the user through pi UI instead of silently choosing a default. When pi has visible Agent Skills loaded, the extension rewrites pi's skill catalog for Cursor and exposes `cursor_activate_skill` as `pi__cursor_activate_skill`; Cursor should call that bridge tool with a listed skill name to load the full `SKILL.md` and bundled resource list before applying the skill. If the bridge is disabled, the catalog remains available and instructs Cursor to fall back to reading the listed `SKILL.md` path directly.
467
371
 
468
372
  Cursor-native tool replay is separate from the bridge. Replay cards are display-only recorded Cursor SDK activity. They never re-run Cursor-side commands, reapply Cursor edits, call MCP servers, or mutate pi state. See [Cursor native tool replay](docs/cursor-native-tool-replay.md).
469
373
 
@@ -506,15 +410,23 @@ On bootstrap sends, a compact **callable tool surfaces** block is injected into
506
410
 
507
411
  `PI_CURSOR_ASK_QUESTION=0` disables only `cursor_ask_question`, leaving the rest of the pi bridge available; it is enabled by default. `PI_CURSOR_PI_TOOL_BRIDGE=0` is the supported rollback flag and disables the bridge entirely. Both flags treat `false`, `off`, `none`, `no`, and `disabled` as off; `1`, `true`, `on`, `yes`, and `enabled` as on. `PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1` opts in to exposing overlapping pi tool names that Cursor already has native equivalents for. The installed Cursor SDK uses a 60-second MCP protocol default with no public per-server timeout option. pi-cursor-sdk overrides that seam in two directions by default: MCP `callTool` requests are extended to 3600 seconds for long-running local MCP tools (including the pi bridge and configured Cursor MCP servers), and known MCP initialize/listTools requests on first send are shortened to 10 seconds so unavailable configured MCP servers fail fast instead of blocking for a full minute. Unknown Cursor SDK MCP protocol timeout stacks keep the SDK default instead of being shortened. Override tool-call timeouts with `PI_CURSOR_MCP_TOOL_TIMEOUT_MS` or `PI_CURSOR_MCP_TOOL_TIMEOUT_SECONDS`, and first-send initialize/listTools timeouts with `PI_CURSOR_MCP_CONNECT_TIMEOUT_MS` or `PI_CURSOR_MCP_CONNECT_TIMEOUT_SECONDS`. Bridged calls also have a local fail-closed deadline that defaults to the effective MCP tool timeout; lower it with `PI_CURSOR_PI_BRIDGE_CALL_TIMEOUT_MS` when a lost pi result should fail sooner. On expiry, the bridge rejects and removes the pending call and aborts active pi execution when available. The bridge's `listTools` handler returns its snapshot synchronously, so a Cursor UI label such as `GetMcpTools` does not by itself identify a `listTools` deadlock; the durable bridge waiter is `CallTool` awaiting its matching pi result.
508
412
 
509
- `PI_CURSOR_HTTP_1_1=true` maps to the Cursor SDK `Cursor.configure({ local: { useHttp1ForAgent: true } })` compatibility mode for corporate VPN/proxy environments where HTTP/2 streams fail. In interactive sessions, `/cursor-http on`, `/cursor-http off`, and `/cursor-http toggle` set the branch-scoped session preference and save the user default as `local.useHttp1ForAgent` in `~/.pi/agent/cursor-sdk.json`; `/cursor-http` with no argument reports the effective state. Precedence is session command/history, explicit `PI_CURSOR_HTTP_1_1`, user config, then the built-in unset default; project config is ignored for this user-level compatibility choice. Unset performs no SDK configuration, preserving the existing default path. Session shutdown clears extension-owned SDK transport state before module reload. Changing the effective setting splits the local agent pool so an agent created under another transport is not reused. When enabled, the local Cursor footer shows `http1` (for example `cursor:local · fast:on · http1`); cloud status never does. This affects Cursor SDK local-agent backend streams only; it does not configure HTTP proxies, TLS certificates, or HTTP/3.
413
+ `PI_CURSOR_HTTP_1_1=true` maps to the Cursor SDK `Cursor.configure({ local: { useHttp1ForAgent: true } })` compatibility mode for corporate VPN/proxy environments where HTTP/2 streams fail. In interactive sessions, `/cursor-http on`, `/cursor-http off`, and `/cursor-http toggle` set the branch-scoped session preference and save the user default as `local.useHttp1ForAgent` in `~/.pi/agent/cursor-sdk.json`; `/cursor-http` with no argument reports the effective state. Precedence is session command/history, explicit `PI_CURSOR_HTTP_1_1`, user config, then the built-in unset default; project config is ignored for this user-level compatibility choice. Unset performs no SDK configuration, preserving the existing default path. Session shutdown clears extension-owned SDK transport state before module reload. Changing the effective setting splits the local agent pool so an agent created under another transport is not reused. When enabled, the Cursor footer shows `http1` (for example `cursor · fast:on · http1`). This affects Cursor SDK local-agent backend streams, which are all provider streams. It does not configure HTTP proxies, TLS certificates, or HTTP/3.
510
414
 
511
415
  `PI_CURSOR_PI_TOOL_BRIDGE_DEBUG=1` is off by default and emits typed, allowlisted, scrubbed single-line JSONL records to `process.stderr`. These records are operational diagnostics, not anonymous telemetry: they intentionally include tool names, safe correlation IDs, bridge run state, exposed pi↔MCP name pairs, queued requests, result resolution, rejection, cancellation, and pending counts. They must not include endpoint URLs, endpoint path components, endpoint tokens, raw args/results, stdout/stderr payloads, file contents, Cursor settings output, API keys, bearer tokens, cookies, session credentials, or secrets. Do not enable or share bridge debug logs where tool names themselves are sensitive.
512
416
 
513
- ### Maintainer platform smoke release gate
417
+ ### Maintainer release evidence
514
418
 
515
- For Cursor provider/runtime changes, the canonical local release and pre-commit gate is the local platform smoke gate in [Platform smoke](docs/platform-smoke.md): run `npm run smoke:platform:all`, which runs doctor before the target matrix. Cloud-runtime changes must also run `npm run smoke:cloud`. The platform gate validates macOS, Ubuntu, and Windows native through Crabbox using packed installs, a required HTTP/1.1/SSE provider-turn lane, PTY/ConPTY ANSI capture, host-rendered xterm/PNG evidence, JSONL assertions, bridge diagnostics, usage/cache checks, abort cleanup, artifact manifests, and redaction scans. After each platform run, `.artifacts/platform-smoke/latest.json` points to the latest useful evidence paths. Do not mark a release ready with optional, deferred, mostly-passing, or unobserved platform smoke checks outstanding.
419
+ For Cursor provider/runtime changes, the current fork release evidence bar is:
516
420
 
517
- The older live smoke helpers remain useful for inner-loop debugging and focused visual audits, not as the release gate. Use [Cursor live smoke checklist](docs/cursor-live-smoke-checklist.md), `npm run smoke:visual`, `npm run smoke:live`, or direct `pi --approve -e . --cursor-no-fast --model cursor/grok-4.6` runs when iterating on a specific TUI/card/runtime issue before the full platform gate. `npm run smoke:visual` captures an offscreen PTY rendered through browser/xterm and saved as PNG screenshots with Playwright, or with `agent_browser` from the generated HTML when available. Its default matrix is native replay only: native replay registration is forced on, Cursor setting sources are disabled, the pi bridge is off, overlapping built-in pi tools are not exposed, and inherited Cursor SDK event-debug artifact env is cleared; `--event-debug` writes to a deterministic debug directory under the visual output directory. The visible TUI/output, rendered screenshots, scrubbed diagnostics, and persisted JSONL must agree. See [Cursor testing lessons](docs/cursor-testing-lessons.md) for auth.json seeding, isolated `/tmp` harness layout, JSONL replay-error scans, and other regression traps.
421
+ - `npm test`
422
+ - `npm run typecheck`
423
+ - `npm pack --dry-run`
424
+ - one live print-mode Cursor run with `cursor/grok-4.6:slow`
425
+ - `npm run smoke:visual -- --label release-check --prompt 'Read ./package.json and reply with its package name.'`
426
+
427
+ The visual smoke captures an offscreen PTY, renders it through browser/xterm, and saves PNG screenshots with Playwright or `agent_browser`. Its default matrix is native replay only: native replay registration is forced on, Cursor setting sources are disabled, the pi bridge is off, overlapping built-in pi tools are not exposed, and inherited Cursor SDK event-debug artifact env is cleared. The visible TUI/output, rendered screenshots, scrubbed diagnostics, and persisted JSONL must agree. See [Cursor live smoke checklist](docs/cursor-live-smoke-checklist.md) and [Cursor testing lessons](docs/cursor-testing-lessons.md).
428
+
429
+ The Crabbox-backed macOS, Ubuntu, and Windows native platform matrix is deferred. Issue [#2](https://github.com/emmaneugene/pi-cursor-sdk/issues/2) tracks the infrastructure and evidence needed to reintroduce it as a release gate.
518
430
 
519
431
  ### Maintainer Cursor SDK event capture
520
432
 
@@ -534,7 +446,6 @@ Actual Cursor runs still need a key from `/login`, `CURSOR_API_KEY`, or `--api-k
534
446
 
535
447
  ## Limits
536
448
 
537
- - **Cloud runtime is explicit and minimal.** Local remains the default. Cloud runs create Cursor cloud agents only after first-use acknowledgement and safety preflight, use fresh context by default, do not expose the pi bridge or local MCP, do not forward pi env vars, support explicit Cursor-managed environment selection, name agents from the pi session title when available, stream display-only agent/run/branch/PR/artifact/raw-usage telemetry when available, and record only explicit session-branch lifecycle commands for cleanup (`/cursor-cloud list|archive|delete`).
538
449
  - **The pi tool bridge is local and MCP-backed.** Bridgeable active pi tools are exposed to local Cursor agents through a tokenized `127.0.0.1` MCP endpoint; internal Cursor replay activity names are excluded, and overlapping built-in pi tools are hidden by default. Set `PI_CURSOR_PI_TOOL_BRIDGE=0` to disable it or `PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1` to expose overlapping built-ins too. Hide individual pi tools from Cursor with `bridge.excludeTools` in `~/.pi/agent/cursor-sdk.json` or trusted `.pi/cursor-sdk.json`.
539
450
  - **Cursor native tool replay is display-only.** Replay renders recorded Cursor SDK activity and never re-runs Cursor-side commands, reapplies Cursor edits, calls MCP servers, or mutates pi state. Workflow tools such as Cursor mode/task/todo/plan activity are not pi workflow controls. See [Cursor native tool replay](docs/cursor-native-tool-replay.md) for supported replay cards, ordering, conflict handling, and opt-out flags.
540
451
  - **Cursor run state can span tool-use turns.** Within a pi session, the extension reuses one Cursor SDK agent across compatible follow-up turns and sends incremental prompts when context still matches. It recreates the agent when context diverges, after compaction or `/tree` navigation, on API key changes, after send errors, after five minutes without a successful send, or on session shutdown. Idle recreate uses `Agent.create`, not `Agent.resume`. For bridged pi tools, the matching pi `toolResult` resolves into the same live Cursor SDK run without creating a new `Agent`, unless the run was disposed, aborted, or cancelled. Replay can also split one live Cursor SDK run across pi `toolUse` turns for display.
@@ -543,7 +454,69 @@ Actual Cursor runs still need a key from `/login`, `CURSOR_API_KEY`, or `--api-k
543
454
  - **AGENTS.md / CLAUDE.md are not duplicated on Cursor models when Cursor loads the same rules.** Pi discovers global and project context files (`AGENTS.md`, `CLAUDE.md`, and case variants) unless you start with `-nc`. On `cursor/*` models the extension removes only `<project_instructions>` blocks that overlap Cursor `settingSources` via the `before_agent_start` hook: `user` for `~/.pi/agent/AGENTS.md`, `project` for repo/parent `AGENTS.md` and `CLAUDE.md` (verified Cursor behavior: local agents load project `AGENTS.md` and `CLAUDE.md` alongside Cursor rules). `~/.pi/agent/CLAUDE.md` is not stripped (Cursor user rules use `~/.claude/CLAUDE.md`, not pi's agent dir). With `PI_CURSOR_SETTING_SOURCES=none` or `plugins`-only, pi context is left intact. Set `PI_CURSOR_PRESERVE_PI_AGENTS_MD=1` to keep duplicate injection.
544
455
  - **Max Mode is not a manual pi variant.** Cursor's SDK may enable Max Mode automatically for models that require it. This extension only advertises exact context-window variants that the SDK catalog exposes and otherwise uses conservative SDK-derived default/non-Max context windows.
545
456
  - **Output token limits are conservative.** Cursor SDK model metadata does not currently expose output token limits directly.
546
- - **Local token usage uses Cursor SDK data when safely attributable.** For local turns with in-time SDK usage, pi records the latest per-turn raw `turn-ended` `inputTokens`, `outputTokens`, `cacheReadTokens`, and `cacheWriteTokens`; that raw local shape keeps full-prompt `inputTokens` with cache as a partition (published SDK `toTokenUsage` totals differ), so pi maps disjoint components (`input = inputTokens - cacheRead - cacheWrite`, plus cache fields) and sets `totalTokens = inputTokens + outputTokens` for occupancy/compaction. If the local SDK reports no usage in time, the extension falls back to local `input/output` activity estimates while setting `totalTokens` to the current replayable context estimate so the footer/compaction percentage does not collapse after split tool turns. Later usage for that live run is ignored rather than risk applying stale usage to the wrong pi turn. Raw cloud usage remains display-only until its field semantics are independently captured. Cursor SDK cost is not exposed, so pi cost remains zero/absent.
457
+ - **Local token usage uses Cursor SDK data when safely attributable.** For local turns with in-time SDK usage, pi records the latest per-turn raw `turn-ended` `inputTokens`, `outputTokens`, `cacheReadTokens`, and `cacheWriteTokens`; that raw local shape keeps full-prompt `inputTokens` with cache as a partition (published SDK `toTokenUsage` totals differ), so pi maps disjoint components (`input = inputTokens - cacheRead - cacheWrite`, plus cache fields) and sets `totalTokens = inputTokens + outputTokens` for occupancy/compaction. If the local SDK reports no usage in time, the extension falls back to local `input/output` activity estimates while setting `totalTokens` to the current replayable context estimate so the footer/compaction percentage does not collapse after split tool turns. Later usage for that live run is ignored rather than risk applying stale usage to the wrong pi turn. Cursor SDK cost is not exposed, so pi cost remains zero/absent.
458
+
459
+ ## Environment variable reference
460
+
461
+ All `PI_CURSOR_*` overrides in one list. They are otherwise documented where each feature is explained; this section is the index. Boolean flags accept `1`, `true`, `on`, `yes`, `enabled` for on and `0`, `false`, `off`, `none`, `no`, `disabled` for off (case-insensitive); invalid boolean tokens fall back to each flag's default. Non-boolean variables use the parsing and error behavior stated in their row. For timeout pairs, a valid positive `_MS` value wins; an invalid or non-positive `_MS` value is ignored, allowing a valid `_SECONDS` value to apply. Many settings also have CLI flags, `/cursor-*` session commands, or `cursor-sdk.json` keys with their own precedence; see the linked sections.
462
+
463
+ ### Authentication and model catalog
464
+
465
+ | Variable | Default | Effect |
466
+ |---|---|---|
467
+ | `CURSOR_API_KEY` | Unset | Authenticates Cursor SDK requests. The stored `/login` credential is preferred; the env var is the fallback. See [Configure your Cursor SDK API key](#configure-your-cursor-sdk-api-key). |
468
+ | `PI_CURSOR_SDK_MODEL_CACHE_TTL_MS` | `86400000` (24h) | Fresh-cache lifetime for the discovered model catalog. Parsing uses a leading non-negative base-10 integer (`12.9` and `12junk` become `12`); negative values or values without a numeric prefix fall back to 24h. `0` disables fresh-cache hits but keeps the stale-cache fallback after a discovery failure. See [Model catalog cache](#model-catalog-cache). |
469
+ | `PI_CURSOR_SDK_DISABLE_MODEL_CACHE` | Off | Skips model-list cache reads and writes; discovery uses the live catalog when possible. |
470
+
471
+ ### Local runtime and agent behavior
472
+
473
+ | Variable | Default | Effect |
474
+ |---|---|---|
475
+ | `PI_CURSOR_LOCAL_FORCE` | Off | Passes `{ local: { force: true } }` to the next local `Agent.send()`; the override is consumed once. |
476
+ | `PI_CURSOR_LOCAL_RESUME` | On | Allows reuse of a matching persisted local agent. `PI_CURSOR_LOCAL_RESUME=0` opts out. |
477
+ | `PI_CURSOR_SANDBOX` | Off | Passes local sandbox enablement into Cursor SDK agent options. Only enabled values are sent. The SDK runs `cursorsandbox` from the platform package; the extension points the SDK locator at that package during local `Agent.create` / `Agent.resume`. |
478
+ | `PI_CURSOR_AUTO_REVIEW` | Off | Passes `autoReview: true` into Cursor SDK agent options. Only enabled values are sent. |
479
+ | `PI_CURSOR_HTTP_1_1` | Off | Forces Cursor SDK local-agent streams to HTTP/1.1/SSE for VPN/proxy environments. Session `/cursor-http` commands win over env; project config is ignored. See the `PI_CURSOR_HTTP_1_1` notes under [Cursor provider tool contract](#cursor-provider-tool-contract). |
480
+ | `PI_CURSOR_SETTING_SOURCES` | `all` | Cursor SDK setting sources. `all`, `1`, `true`, and `on` select all sources; `none`, `0`, `false`, `off`, `omit`, and `disabled` disable ambient sources. Other comma-separated names such as `project,user,plugins` narrow loading and are forwarded without validation. See [Limits](#limits) and [Cursor tool surfaces in pi](docs/cursor-tool-surfaces.md). |
481
+ | `PI_CURSOR_PRESERVE_PI_AGENTS_MD` | Off | Keeps pi `AGENTS.md`/`CLAUDE.md` context injection even when Cursor setting sources load the same rules. |
482
+ | `CURSOR_RIPGREP_PATH` | Bundled SDK `rg` when available | Ripgrep executable for the local SDK agent. Only an absolute path is honored; the extension sets the bundled default itself at turn prepare. |
483
+ | `CURSOR_TREE_SITTER_VENDOR_DIR` | Bundled SDK `vendor/` when available | Vendored tree-sitter natives for the local SDK agent. Only an absolute path is honored; the extension sets the bundled default itself at turn prepare. |
484
+
485
+ ### Pi tool bridge and tool surfaces
486
+
487
+ | Variable | Default | Effect |
488
+ |---|---|---|
489
+ | `PI_CURSOR_PI_TOOL_BRIDGE` | On | Master switch for exposing active pi tools to local Cursor agents through the loopback MCP bridge. `0` rolls back to Cursor SDK tools/settings/MCP only. |
490
+ | `PI_CURSOR_EXPOSE_BUILTIN_TOOLS` | Off | Also exposes overlapping pi built-ins (`read`, `bash`, `write`, `edit`, `grep`, `find`, `ls`) that Cursor already implements natively. |
491
+ | `PI_CURSOR_ASK_QUESTION` | On | Registers `cursor_ask_question` (surfaced as `pi__cursor_ask_question`) so Cursor can ask the user instead of guessing. Still requires a Cursor model with the bridge enabled. |
492
+ | `PI_CURSOR_TOOL_MANIFEST` | On | Injects the compact callable-surface guidance block on bootstrap sends. |
493
+ | `PI_CURSOR_MCP_TOOL_TIMEOUT_MS` / `PI_CURSOR_MCP_TOOL_TIMEOUT_SECONDS` | `3600000` (1h) | Overrides SDK MCP `callTool` timeout for bridged pi tools and configured Cursor MCP servers. Clamped to 60s–~24.8d. |
494
+ | `PI_CURSOR_MCP_CONNECT_TIMEOUT_MS` / `PI_CURSOR_MCP_CONNECT_TIMEOUT_SECONDS` | `10000` (10s) | Overrides known MCP initialize/listTools timeouts on first send so dead servers fail fast. Clamped to 1s–60s. Unknown MCP protocol stacks keep the SDK default. |
495
+ | `PI_CURSOR_PI_BRIDGE_CALL_TIMEOUT_MS` | Effective MCP tool timeout | Local fail-closed deadline for a stranded bridged `CallTool` awaiting its pi result. Lower it to fail sooner. |
496
+ | `PI_CURSOR_PI_TOOL_BRIDGE_DEBUG` | Off | Emits scrubbed single-line JSONL bridge diagnostics to stderr. Do not share logs where tool names are sensitive. |
497
+ | `PI_CURSOR_PI_TOOL_BRIDGE_DEBUG_FILE` | Unset | Appends the same JSONL bridge diagnostics to the given file path, independent of the stderr flag. |
498
+
499
+ See [Cursor provider tool contract](#cursor-provider-tool-contract) for the narrative version of this table.
500
+
501
+ ### Display and replay
502
+
503
+ | Variable | Default | Effect |
504
+ |---|---|---|
505
+ | `PI_CURSOR_NATIVE_TOOL_DISPLAY` | TTY/mode-dependent | Requests native rendering of Cursor tool cards. `tui`, `json`, and `rpc` default on; any other explicit mode defaults off. When no mode is supplied, the default follows `stdout.isTTY`. See [Cursor native tool replay](docs/cursor-native-tool-replay.md). |
506
+ | `PI_CURSOR_REGISTER_NATIVE_TOOLS` | Follows native-display request; always off in `print` mode | Registers Cursor-native replay tools. Setting it to true does not override `PI_CURSOR_NATIVE_TOOL_DISPLAY=0`; setting it to false disables registration everywhere. |
507
+ | `PI_CURSOR_TASK_PRESENTATION` | `subagent-meta` | Task activity titles and transcript headers: exact `task`, `subagent`, or `subagent-meta`. |
508
+
509
+ ### Maintainer debug capture
510
+
511
+ | Variable | Default | Effect |
512
+ |---|---|---|
513
+ | `PI_CURSOR_SDK_EVENT_DEBUG` | Off | Captures provider/SDK event artifacts (deltas, steps, replay/drain/bridge decisions) as files only, so the TUI stays normal. See [Maintainer Cursor SDK event capture](#maintainer-cursor-sdk-event-capture) and [Cursor testing lessons](docs/cursor-testing-lessons.md). |
514
+ | `PI_CURSOR_SDK_EVENT_DEBUG_DIR` | `.debug/cursor-sdk-events` under cwd | Base directory for debug session artifacts. |
515
+ | `PI_CURSOR_SDK_EVENT_DEBUG_RUN_DIR` | Unset | Pins one turn's artifacts to an exact directory, bypassing session grouping. |
516
+ | `PI_CURSOR_SDK_EVENT_DEBUG_SESSION_DIR` | Unset | Pins the session's turn grouping and manifest to an exact directory. |
517
+ | `PI_CURSOR_SDK_EVENT_DEBUG_STDERR` | Off | Also prints the debug summary (and discarded incomplete-tool records) to stderr. |
518
+
519
+ Not listed: `PI_CURSOR_BRIDGE_TOOL_CALL_ID` is an internal cancellation marker injected by the bridge on some platforms, not a user setting. `*_SMOKE_*` and `PLATFORM_*` names belong to maintainer smoke scripts, not the extension runtime.
547
520
 
548
521
  ## Troubleshooting
549
522
 
@@ -581,16 +554,16 @@ pi list
581
554
  Then reinstall if needed:
582
555
 
583
556
  ```bash
584
- pi install npm:pi-cursor-sdk
557
+ pi install npm:@emmaneugene/pi-cursor-sdk
585
558
  ```
586
559
 
587
560
  ### `pi --list-models` shows `thinking=no`
588
561
 
589
562
  That does not mean the model cannot think. It means the Cursor SDK does not expose a pi-controllable thinking parameter for that model. The model may still think internally and may still emit thinking deltas that pi renders natively.
590
563
 
591
- ### I do not see `cursor:local` / `cursor:cloud` or `plan` in the footer
564
+ ### I do not see `cursor` or `plan` in the footer
592
565
 
593
- The Cursor footer appears only while a Cursor model is active. Fast-capable local models show `cursor:local · fast:on` or `cursor:local · fast:off`; Cursor models without a fast parameter show `cursor:local · fast:n/a`. Cloud runtime shows `cursor:cloud · fast:n/a`. Cursor SDK mode is the default `agent` mode when `plan` is absent. When both are active, pi shows one combined Cursor status such as `cursor:local · fast:on · plan` or `cursor:cloud · fast:n/a · plan`.
566
+ The Cursor footer appears only while a Cursor model is active. Fast-capable models show `cursor · fast:on` or `cursor · fast:off`; Cursor models without a fast parameter show `cursor · fast:n/a`. Cursor SDK mode is the default `agent` mode when `plan` is absent. When plan mode is active, pi shows one combined Cursor status such as `cursor · fast:on · plan`.
594
567
 
595
568
  ### My Cursor app settings or rules do not seem to apply
596
569
 
@@ -712,7 +685,7 @@ Local development run:
712
685
 
713
686
  ```bash
714
687
  npm install
715
- CURSOR_API_KEY="your-key" pi --approve -e . --model cursor/grok-4.6
688
+ CURSOR_API_KEY="your-key" pi -ne --approve -e . --model cursor/grok-4.6
716
689
  ```
717
690
 
718
691
  After editing `src/`, run `npm run build` before the next `pi -e .` run, or pi loads the previous build.
@@ -1,14 +1,12 @@
1
1
  import { isCursorModel } from "./cursor-model.js";
2
2
  import { registerCursorModelLifecycle } from "./cursor-model-lifecycle.js";
3
- import { resolveEffectiveCursorConfigForContext } from "./cursor-runtime-state.js";
4
3
  import { resolveCursorFacingSystemPrompt } from "./cursor-agents-context.js";
5
4
  export function registerCursorAgentsContextDedup(pi) {
6
5
  registerCursorModelLifecycle(pi, {
7
6
  beforeAgentStart: (event, ctx) => {
8
7
  if (!isCursorModel(ctx.model))
9
8
  return undefined;
10
- const runtime = resolveEffectiveCursorConfigForContext(ctx).runtime.value;
11
- const resolved = resolveCursorFacingSystemPrompt(event.systemPrompt, ctx.model, event.systemPromptOptions, undefined, undefined, runtime);
9
+ const resolved = resolveCursorFacingSystemPrompt(event.systemPrompt, ctx.model, event.systemPromptOptions);
12
10
  if (resolved === event.systemPrompt)
13
11
  return undefined;
14
12
  return { systemPrompt: resolved };
@@ -99,8 +99,8 @@ export function removePiAgentsContextFromSystemPrompt(systemPrompt, contextFiles
99
99
  const replacementSection = serializePiProjectContextSection(retainedContextFiles);
100
100
  return systemPrompt.slice(0, start) + replacementSection + systemPrompt.slice(start + originalSection.length);
101
101
  }
102
- export function resolveCursorFacingSystemPrompt(systemPrompt, model, systemPromptOptions, settingSourcesRaw, agentDir, runtime = "local") {
103
- if (runtime === "cloud" || !systemPromptOptions)
102
+ export function resolveCursorFacingSystemPrompt(systemPrompt, model, systemPromptOptions, settingSourcesRaw, agentDir) {
103
+ if (!systemPromptOptions)
104
104
  return systemPrompt;
105
105
  const contextFiles = systemPromptOptions.contextFiles ?? [];
106
106
  const settingSources = settingSourcesRaw === undefined