Cursor SDK: local agent's shell ignores local.cwd and runs in the host process's cwd

Where does the bug appear (feature/product)?

Cursor SDK

Describe the Bug

A local agent created with Agent.create({ model, local: { cwd: workspace } }) runs its Shell tool in the host Node process’s process.cwd(), not in local.cwd, whenever the model does not pass working_directory on the shell call. File tools and the transcript folder correctly use local.cwd; only the shell’s default directory is wrong.

The SDK also sends processWorkingDirectory: process.cwd() to the model in the request environment (next to workspacePaths), so the model is told about the host directory as well.

Whether a run is affected therefore depends on the model: GPT-5.6 Sol, Grok 4.7 and Claude Sonnet 5.5 usually pass working_directory themselves; Claude Opus 5.5 usually does not on its first shell call.

Impact for us: we run many concurrent local agents from one server process (each with its own local.cwd checkout, so process.chdir per agent is not an option). A Claude Opus 5.5 plan run read the server’s own git checkout instead of its task workspace, planned against the wrong repository, and asked us to “re-provision” a workspace that was correct. An implement run in the same position could commit or push in the host directory.

Steps to Reproduce

  1. Create two directories, each with a MARKER.txt: workspace/MARKER.txt = MARKER-WORKSPACE, decoy/MARKER.txt = MARKER-DECOY-HOST-CWD.
  2. In a Node script, process.chdir(decoy).
  3. const agent = await Agent.create({ apiKey, model: { id }, local: { cwd: workspace } }).
  4. agent.send("Using your shell tool, run exactly pwd; cat MARKER.txt without passing any working directory and without cd-ing anywhere first. Reply with only the output."), then run.wait().
  5. The reply shows the decoy path and MARKER-DECOY-HOST-CWD.

Results (SDK 1.0.31 and 1.0.32, macOS):

  • Forced (no working_directory): gpt-5.6-sol, composer-2.5, claude-sonnet-5-5, claude-opus-5-5 → ALL ran in the host cwd.
  • Natural prompt (“show the current directory and MARKER.txt”): gpt-5.6-sol 3/3 workspace, claude-sonnet-5-5 3/3 workspace, claude-opus-5-5 ran in the host cwd first in 3/3 (1.0.31) and 2/3 (1.0.32), then re-ran with working_directory after noticing.

In the real incident the host directory was a plausible git repository, so Opus never noticed.

The probe script is ~100 lines; happy to share it.

Expected Behavior

The Shell tool’s default working directory is local.cwd (the agent’s workspace) regardless of model, and the host process’s process.cwd() is neither used as a fallback nor reported to the model as processWorkingDirectory when local.cwd is set.

Operating System

MacOS

Version Information

@cursor/sdk 1.0.31 and 1.0.32 (latest), local runtime
Node.js v26.8.1
macOS 26.6.2 (Apple Silicon)

For AI issues: which model did you use?

Most visible with claude-opus-5-5; the default-cwd fault reproduces with gpt-5.6-sol, composer-2.5, claude-sonnet-5-5 and claude-opus-5-5

Additional Information

Where we looked in the bundle (dist/esm, 1.0.31 357.js / 1.0.32 34.js): the request environment is built with workspacePaths: <local.cwd> and processWorkingDirectory: process.cwd().

In the incident transcript (agent-transcripts under the workspace’s project folder) the model’s Shell calls carried only command/description, no working_directory, and returned the host checkout’s files. Earlier GPT-5.6 Sol / Grok 4.7 runs in the same kind of workspace passed working_directory on most shell calls and were correct; the few that did not also ran in the host directory.

Workarounds on our side: starting the host process in an empty directory, and stating the absolute workspace path in the prompt. Neither removes the underlying fault for concurrent agents with different local.cwd values.

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey @amontesinos, thanks for the report and the repro steps.

I was able to confirm this. The local runtime starts its shell in the host process’s working directory instead of local.cwd, so any shell call that doesn’t pass a working directory lands in the host directory. That’s why it shows up mostly with models that skip that argument. This is a known issue, and I’ve added your report.

Until a fix ships, the most reliable workaround for concurrent agents is to run each agent in its own Node child process started with cwd set to that agent’s workspace (for example child_process.fork(script, { cwd: workspace })). Each shell then inherits the right directory. Starting the host in an empty directory, like you’re already doing, also prevents it from ever running against a real repo.