---
name: cursor-cli-runtime
description: Internal helper contract for calling the cursor-companion runtime from Claude Code
user-invocable: false
---

# Cursor runtime

Primary helper:

- `node "${CLAUDE_PLUGIN_ROOT}/scripts/cursor-companion.mjs" <subcommand> [flags]`

Subcommand surface:

- `task [--write] [--model <id>] [--effort <effort>] [--resume <session-id>|--resume-last|--fresh] [--background] [--cwd <dir>] [--json] [--] [prompt]`
- `review [--scope <auto|working-tree|branch>] [--base <ref>] [--focus <text>] [--model <id>] [--effort <effort>] [--cwd <dir>] [--background] [--json]`
- `status [job-id] [--all] [--cwd <dir>] [--json]`
- `result <job-id> [--wait] [--cwd <dir>] [--json]`
- `cancel <job-id> [--cwd <dir>] [--json]`
- `history [--all] [--limit <n>] [--cwd <dir>] [--json]`
- `models [--refresh] [--json]`
- `setup [--json]`
- `record-acceptance --job-id <id> --acceptance <accepted|rejected|unverified> [--reason <text>] [--failure-kind <kind>] [--source <collector|main-loop|stats>] [--accept-failed-transport] [--json]`
- `transport-create` and `transport-discard --raw-args-token <token>`
- `task-worker` and `review-worker` are internal background workers that the helper never invokes directly.

Execution rules:

- Slash commands stage their complete raw arguments through `transport-create`, one Read of the allocated empty file, Write to that same file, and a fixed `--raw-args-token` invocation. The token transport applies to task, review, status, history, result, cancel, and setup. Raw request bytes never enter Bash, shell arguments, environment variables, redirections, substitutions, encoded literals, or heredocs. A transport is private, bounded, validated, and consumed once. Never delete, rename, recreate, or change the permissions of the transport file; use `transport-discard` when Read or Write fails or when the allocated file is not empty.
- Place every task option before the prompt, and put `--` before a prompt that begins with an option shaped token. The prompt text may also arrive on stdin.
- The companion resolves the CLI as `cursor-agent`, never as the bare `agent` name, because other CLIs install an `agent` executable earlier on PATH. `CURSOR_AGENT_BIN` overrides the path. Every job records the build as `cursorVersion` and the resolved executable as `cursorBuildPath`.
- The tested interval is `[2026.10.01, 2026.11.01)` by build date. A build older than the floor fails preflight as `setup`; a build at or past the ceiling runs and `/cursor:setup` reports it as newer than the tested interval. The CLI updates itself on a timer, so every managed run passes `--disable-auto-update`, and a build change between jobs is visible through the recorded build identity.
- The brief reaches the CLI on stdin and never appears in process arguments. Every run passes `--sandbox enabled`, `--disable-project-configs`, `--single-turn`, and an explicit `--allowed-tools` list. The companion never passes `--force`, `--yolo`, `--auto-review`, `--approve-mcps`, `--worktree`, `--plugin-dir`, or `--add-dir`. Headless approvals use Cursor's always deny decision provider, so any action outside the allowlist and sandbox is rejected rather than prompted.
- Consult is the default mode, `--write` selects write mode, and `review` is always read only. Consult and review run with `--mode ask` and the tools `read_tool_call`, `grep_tool_call`, `glob_tool_call`, and `ls_tool_call`. Write mode adds `edit_tool_call`, `delete_tool_call`, `shell_tool_call`, `update_todos_tool_call`, and `read_todos_tool_call`. Web search and fetch, MCP, subagent and agent creation, background shell input, semantic search, computer use, image generation, pull request management, and every other tool stay outside every allowlist. The allowlist travels to Cursor's backend as request metadata, so the companion also enforces it locally: a `tool_call` event naming a tool outside the mode's allowlist terminates the process group and fails the job as `policy`.
- Consult and review use a `workspace_readonly` sandbox policy and write uses `workspace_readwrite`; both bound reads to the workspace and deny network access. In write mode an edit and a shell write inside the workspace succeed without approval, while a shell write outside the workspace, a read outside the workspace, and outbound network access are refused. A write package therefore runs inside the workspace named by `--cwd`, which for a `burst` package is an orchestrator owned worktree. Write mode also exposes the language runtime installation root as read only, and for a linked worktree the repository's Git common directory as read only and the worktree's own Git directory as read write. A run never proceeds without the sandbox; an unavailable sandbox helper fails the run as `sandbox`.
- Every run executes with `HOME` set to a private home at `<data>/runs/<job-id>/home` that holds only the keychain link, a generated `.cursor/cli-config.json` and `.cursor/sandbox.json`, and read only empty plugin and skill directories. This removes Claude Code, Codex, Grok, and Cursor user configuration from the session, because Cursor otherwise imports those from fixed locations under the home directory. Credentials are the macOS keychain items reached through a symbolic link, and no credential file is copied or read. On Linux authentication requires `CURSOR_API_KEY` in the companion environment, which is passed through unchanged.
- Project scoped sources still load: `AGENTS.md`, `CLAUDE.md`, `.cursor/rules`, and skill and agent definitions under the workspace. Project hooks still execute outside the sandbox: the companion detects a non empty `hooks` object in `.cursor/hooks.json`, `.claude/settings.json`, and `.claude/settings.local.json` before launch and renders a `warning:` line naming them. Account level Cursor user rules reach every session. Prompts, workspace content read by tools, and results pass through Cursor's backend to the serving model vendor under the account's privacy mode, so never delegate secrets or credentials to this lane.
- Fusion routed dispatches always carry `--model` and `--effort` from the routing table. A direct user call may leave them unset and falls back to the model selected in the user's own `~/.cursor/cli-config.json`. `models` prints the account catalog parsed from `cursor-agent models`, cached for one hour, and `--refresh` reads the CLI again.
- Catalog identifiers are flattened variants that encode effort and speed, such as `muse-spark-1.3-xhigh`, `grok-4.7-high-fast`, `composer-2.5`, and `composer-2.5-fast`. A requested model resolves in order: a value containing `[` passes through unchanged; an exact catalog identifier is used as is when the effort is `default` or already encoded in it; otherwise the companion tries `<model>-<effort>` (with `xhigh` also tried as `extra-high`) and, for a model ending in `-fast`, `<base>-<effort>-fast`; a model with no effort variants resolves to its exact identifier and records `effortApplied: false`. A request that matches no catalog identifier fails before job creation as `input` and lists the available variants. `auto` and `default` are refused as `input`, because Auto routes to a model that no event reports.
- The `system/init` event reports only a display name, which can differ from the catalog's display name for the same variant, so it is recorded as `observedModel` and a mismatch is not drift. `billingPool` is `first-party` for `composer-*` identifiers and `api` for every other model, and it names the subscription pool that a quota failure exhausts.
- The stream must open with a `system` init event and close with one `result` event. Malformed lines, a missing init event, or a zero exit without a result event fail the job as `protocol`. Usage is recorded exactly as reported (`inputTokens` excluding cache, `outputTokens`, `cacheReadTokens`, and `cacheWriteTokens`) and is marked unreported when the result event omits it. Cost is never reported.
- The CLI starts in its own process group and may spawn a helper that outlives it, so the companion terminates the whole group once the CLI has exited or the job has otherwise ended. After the `result` event it waits up to `CURSOR_COMPANION_EXIT_GRACE_MS` (default 15000) for the CLI to exit, then sends `SIGTERM` to the group and `SIGKILL` after five more seconds, and records a `late_close` warning while keeping the outcome `done`. The run timeout is `CURSOR_COMPANION_TIMEOUT_MS` (default 540000), sized so a foreground wrapper finishes inside the ten minute tool limit. `CURSOR_COMPANION_WAIT_TIMEOUT_MS` and `CURSOR_COMPANION_WAIT_POLL_MS` bound `result --wait`, and `CURSOR_COMPANION_PIDLESS_RUNNING_GRACE_MS` sets the pidless grace as in the Grok companion. Cancellation, died detection, and process identity verification follow the shared companion contract.
- Ordinary delegations use one foreground helper call with timeout `600000`. Only an explicit incoming user `--background` detaches a task or review into an internal worker and creates a manual receipt; the helper prints the job id plus `/cursor:status` and `/cursor:result` hints. Never add `--background` because a task appears large or slow, and never use Bash background mode. `result --wait` blocks while a job is running, and when its bounded wait budget elapses first it returns output ending in `state: running`.
- A user asking to resume maps to the companion's `--resume <session-id>` or `--resume-last`; the two resume forms and `--fresh` are alternatives. Never invent a session id; only ids recorded by finished tasks are resumable. Cursor stores a chat under the private home of the job that created it, so a resume copies the parent job's chat directory into the new job's home before launch, and it accepts only a terminal job of the same workspace and mode. `--resume-last` selects the newest eligible job and, when the current Claude session id is available, only jobs launched by that session. `--fresh` ignores continuity. The private home of a terminal job is retained with its job record and pruned with the job history.
- `history` exposes a safe metadata projection with resumable session ids. It defaults to the current workspace, `--all` includes every recorded workspace, and `--limit` caps the number of jobs shown.
- `--cwd` selects the workspace for task, review, status, history, result, and cancel. Status, result, and cancel search all recorded workspaces by job id when `--cwd` is omitted. A bad working directory, or an implicit task or review working directory below its Git repository root, fails before a job record is created. Worktree isolation means creating a real Git worktree before launch and supplying that path as the actual `--cwd`.
- Review collects the working tree diff or a branch range, interpolates it into `${CLAUDE_PLUGIN_ROOT}/prompts/review.md`, and runs a review mode job. The reply must contain one JSON object with `verdict` (`approve` or `request_changes`), `summary`, and `findings` (each with `severity`, `file`, `line`, `title`, and `body`). The companion extracts the first JSON object from the result text and validates it, and a missing or invalid object fails the review as `error` instead of falling back to prose.
- Typed failure kinds are `missing_cli`, `setup`, `auth`, `quota`, `rate_limited`, `network`, `sandbox`, `policy`, `protocol`, `timeout`, `process`, `cancelled`, `died`, `input`, `resource`, and `error`. Quota and rate limit failures carry the job's `billingPool`, so the circuit breaker opens only the pool that failed; authentication, missing CLI, setup, sandbox, protocol, and policy failures are engine wide.
- Outcomes end with the shared footer block: `cursor-session: <session-id>` when a resumable session exists, then `job:`, `sandbox:`, `delivery:`, `semantic:`, any adapter `warning:` lines, `state:`, and `failure:` for error and cancelled outcomes.
- Job records live at `<data>/state/<workspace>/jobs/<id>.json`, where `<data>` is `CURSOR_COMPANION_DATA` or `~/.claude/plugins/data/cursor-claude-code-fusion`. They carry `engine: "cursor"` plus `cursorVersion`, `cursorBuildPath`, `sessionId`, `requestId`, `requestedModel`, `resolvedModel`, `observedModel`, `requestedEffort`, `effortApplied`, `billingPool`, `mode`, `role`, `usage`, `homeDir`, and `warnings`.
- `scripts/session-end-hook.mjs` runs at Claude Code SessionEnd, performs verified cleanup of this session's running jobs, and removes unused raw transports.
- Return the helper output exactly as received, whether the Bash tool reports it from stdout or stderr.
- If the Bash call fails or Cursor cannot be invoked, surface the failure instead of hiding it; the cursor-rescue agent returns exactly one `cursor unavailable: <reason>` line for the orchestrator's circuit breaker.
