# @deepseek-ai/dsh-subagent-cursor English | [中文](README.zh.md) This package registers the fixed `cursor` subagent provider. Each accepted run starts the official `cursor-agent` CLI in non-interactive print mode in the delegating Session's workspace, submits one self-contained text task, reads the CLI's `stream-json` event stream, and returns only the final answer through the shared [`dsh-subagent`](../subagent/README.md) result contract. ## Start and ownership `start(request)` accepts only a non-empty sequence of text blocks and derives the child cwd from the parent Session. It resolves `cursor-agent` through [`dsh-subprocess`](../../subprocess/subprocess/README.md), spawns the fixed command, and publishes the run only after the CLI's `system`/`init` event announces its own chat id — the point at which the CLI has started and resolved its credentials and model. A failure or cancellation before that announcement terminates the managed process tree, waits for it to exit, and rejects `start()`. The task crosses the boundary as a positional command-line argument, because that is the only prompt channel print mode offers: the CLI documents no `--` end-of-options separator and reads no prompt from stdin. Two consequences are enforced rather than papered over. A task whose first character is `-` is rejected at admission, since the CLI would parse it as an option. A resolved Windows `.cmd` or `.bat` shim is rejected as well, because only `cmd.exe` can run it and its command tail would reparse model-authored text as shell syntax; PATHEXT resolution prefers the `cursor-agent.exe` that the native Windows installer provides. Stdin is closed immediately after spawn, so a prompt the CLI still tries to read fails fast instead of stalling an unattended child on an answer nobody can give. The published `run.result` waits for the authoritative terminal `result` event and accepts only `subtype: "success"` with `is_error: false` and a nonblank `result`. Every other terminal event, malformed stdout line, stream failure, or end of stream without a result maps to `error`; print mode carries no machine-readable failure taxonomy, so the provider produces neither `max-tokens` nor `refusal`. `user`, `tool_call`, and event kinds a newer CLI adds contribute nothing to this contract. Print mode has no reply channel, so there is no protocol interrupt: cancellation is the run's abort signal, which the subprocess seam turns into its termination escalation while the result settles immediately as `aborted` with the last non-empty assistant message collected so far. `dispose()` is idempotent: it detaches the event stream, invokes the shared process-tree termination escalation, and waits for whole-tree exit. Result failure and independent teardown failure remain separate. ## Capabilities and context The provider advertises no optional start-time capabilities and reports `inheritsParentContext: false`. Cursor receives the standalone text task and the parent Session cwd, but not the parent conversation, persona, tool filter, depth policy, or structured-output contract. The CLI's own chat id and model stay private to the run and are never persisted in the parent Session. ## Configuration | Key | Default | Meaning | |---|---|---| | `env` | `{}` | Explicit child environment layered over the subprocess seam's credential-scrubbed parent environment. | | `disposeGraceMs` | `3000` | Positive finite grace in milliseconds, no greater than [`MAX_TIMER_DELAY_MS`](../../util/timeout/README.md), between the shared process-tree owner's termination tiers; disposal then waits for whole-tree exit. | | `force` | `false` | Pass `--force`, letting the child apply file changes and run commands. Cursor's own print-mode default only PROPOSES changes, so a delegation expected to edit the workspace needs this on. | | `trust` | `false` | Pass `--trust`, letting the child act in the workspace without Cursor's interactive trust prompt an unattended child cannot answer. | Production resolves `cursor-agent` from the subprocess execution world's credential-scrubbed `PATH`, with explicit `env` entries applied, and uses the host's native Cursor configuration and authentication. The plugin does not install the CLI, select a model, create a Cursor home, log in, or probe a version. Credential-shaped ambient variables are removed by the subprocess seam, so a `CURSOR_API_KEY` intended for the child must be supplied in `env`; it is never passed as `--api-key`, where a process listing would expose it. Ordinary ambient values such as `PATH` and `HOME` remain available unless overridden. The `dsh-base` host plane mounts this provider, and the `code`, `cordis`, and `standard` Agent Presets carry an enabled `subagent_cursor` tool row; the `economy` preset keeps it `disabled: true` because an economy composition should not reach for external paid agents by default. Loading the provider starts no Cursor process until a tool call. Its `one-shot` policy keeps omitted or `false` `run_in_background` calls in the foreground, while explicit `true` returns a parent-owned Job id for `job_output` or `job_kill`. The standalone composition below shows the complete explicit capability. A Profile based on `@deepseek-ai/dsh-base` keeps its existing Job rows and provider row and enables only the preset tool row instead of mounting duplicates. ```yaml - id: subagent-cursor name: '@deepseek-ai/dsh-subagent-cursor' config: force: true trust: true env: CURSOR_API_KEY: !!js process.env.CURSOR_API_KEY - id: jobs name: '@deepseek-ai/dsh-jobs-local' - id: tool-jobs name: '@deepseek-ai/dsh-tool-jobs' - id: tool-subagent-cursor name: '@deepseek-ai/dsh-tool-subagent' config: provider: cursor toolName: subagent_cursor backgroundMode: one-shot maxDepth: provider-managed ``` ## Product compatibility and evidence The provider reads only the print-mode events this one-shot contract needs: `system`/`init` to publish, `assistant` to snapshot partial output, and `result` to settle. Deployments supply `cursor-agent` on `PATH`; the CLI is not an npm dependency of this package, so unit evidence drives the real event stream through the subprocess seam rather than a pinned binary. The CLI also speaks the Agent Client Protocol as `cursor-agent acp`, which the generic [`dsh-subagent-acp`](../subagent-acp/README.md) provider can drive with configuration alone. That path exists for a deployment that wants ACP's permission auto-answer policy or a long-lived remote session; this package exists for the one-shot delegation contract, its own `subagent_cursor` tool row, and print mode's simpler failure surface. ## Model Experience ### Child request #### What the model sees The Cursor child receives the concatenated text task as one positional prompt in a fresh print-mode run. Its workspace is the parent Session cwd, and its model, system instructions, tools, and authentication come from the native Cursor installation and configuration. #### Token effect The child pays for an independent Cursor context and turn. Child tokens do not enter the parent's context. #### KV Cache effect Independent of the parent request cache. Reuse depends only on Cursor's own model, instructions, tools, and per-run request. ### Parent scheduling and results, indirectly #### What the model sees Through `dsh-tool-subagent`, a foreground call gives the parent the terminal Cursor answer or the consumer's exact error for a non-completed result. A background call first returns a Job id; the generic job controls later deliver a completion notice, expose the final answer and status through `job_output`, and let `job_kill` request cancellation. Cursor's intermediate messages, tool activity, stderr, workspace diffs, usage, and product ids are not copied into the parent Session. #### Token effect Foreground input grows by the retained final answer or error. Background input also includes the start acknowledgement, completion notice, and any `job_output`, `job_kill`, or later status results; child tokens still do not enter the parent context. This provider adds no parent tool schema by itself. #### KV Cache effect Append-only: foreground adds one result after the reusable parent prefix, while background appends the Job acknowledgement, notice, and later control or collection results. Background scheduling can add a notice-driven turn, but none of these messages rewrites the earlier prefix. ## Known Limitations and Deferred Work - **One fresh process and run per delegation** — there is no continuation, `--resume`, pooling, progress stream, or product-session persistence, even though the CLI itself supports resuming a chat by id. - **The task cannot begin with `-`** — print mode takes the prompt positionally and documents no `--` separator, so such a task is rejected at admission instead of being mis-parsed as an option. - **Windows needs the native executable** — a resolved `.cmd` or `.bat` shim is rejected rather than run through `cmd.exe`, whose command tail would reparse the task text. - **Host-managed product installation and account state** — a missing `cursor-agent`, configuration error, or authentication failure is surfaced as a startup or run error; the plugin provides no installer, login flow, or runtime version gate. - **No graduated approval path** — `force` and `trust` are whole-run deployment switches; there is no per-call policy, allowlist, or human approval channel through this package. - **No failure taxonomy** — print mode reports only a terminal subtype and error marker, so a context-window ending is indistinguishable from any other failure and never maps to `max-tokens`. - **Product payload is final text only** — intermediate messages, tool traffic, usage, stderr, and workspace diffs remain product-local; generic Job ids, notices, and status come from the shared job runtime. - **No optional shared capabilities** — output schemas, child personas, tool filtering, and harness depth enforcement are rejected by the shared service for this provider. - **No wall-clock timeout or side-effect rollback** — the caller cancels long work, and files or external systems changed before cancellation are not restored.