Skip to content

fix(cursor-agent): enable headless CLI dispatch end-to-end (-p --trust --approve-mcps --force + Windows .cmd shim resolution)#2631

Open
One-TheOnly wants to merge 3 commits into
github:mainfrom
One-TheOnly:fix/cursor-agent-cli-dispatch
Open

fix(cursor-agent): enable headless CLI dispatch end-to-end (-p --trust --approve-mcps --force + Windows .cmd shim resolution)#2631
One-TheOnly wants to merge 3 commits into
github:mainfrom
One-TheOnly:fix/cursor-agent-cli-dispatch

Conversation

@One-TheOnly
Copy link
Copy Markdown

@One-TheOnly One-TheOnly commented May 19, 2026

Summary

Enable specify workflow run to dispatch the cursor-agent CLI headlessly end-to-end on Windows, matching the way it already dispatches claude / codex / gemini. Existing in-IDE skill flow (via .cursor/skills/speckit-*/SKILL.md) is preserved exactly — this PR only adds the CLI dispatch path on top.

Fixes #2629.

Problem

Before this PR, specify workflow run speckit --input integration=cursor-agent ... fails immediately with:

Cannot dispatch command 'speckit.specify': integration 'cursor-agent' CLI not found or not installed.
Install the CLI tool or check 'specify integration list'.

even when cursor-agent is installed and healthy (cursor-agent --version returns 2026.05.16-0338208).

Three separate gaps each independently block the headless path; this PR fixes all three.

Three commits, three gaps

1) 1c55988 fix(cursor-agent): enable CLI dispatch via -p --trust headless mode

CursorAgentIntegration had requires_cli: False and did not override build_exec_args, so SkillsIntegration.build_exec_args returned None, the dispatcher in workflows/steps/command/__init__.py::_try_dispatch returned None, and the misleading CLI-missing error was surfaced. The CLI is actually fully headless-capable:

  • -p / --print — print mode, "Has access to all tools, including write and shell"
  • --output-format text | json | stream-json
  • --model <name>
  • --trust — "Trust the current workspace without prompting (only works with --print/headless mode)"

Without --trust, the CLI exits non-zero with ⚠ Workspace Trust Required.

This commit:

  • config["requires_cli"]: FalseTrue
  • config["install_url"]: Nonehttps://docs.cursor.com/en/cli/overview
  • Override build_exec_args to emit [self.key, "-p", "--trust", prompt, …].

2) 454d3d0 fix(integrations): resolve .cmd/.bat shims before subprocess.run

After commit (1), the dispatcher still failed on Windows with FileNotFoundError [WinError 2]. Root cause:

  • shutil.which("cursor-agent") returns cursor-agent.CMD (honoring PATHEXT).
  • subprocess.run(["cursor-agent", ...]) calls CreateProcess, which does not consult PATHEXT, so the bare command name fails to launch.

The same bug affects every .cmd/.bat-wrapped CLI on Windows (verified for codex as well; only .exe CLIs like claude were unaffected).

Fix in IntegrationBase.dispatch_command: resolve exec_args[0] via shutil.which before subprocess.run. No-op on POSIX (no PATHEXT to consult); transparent fix on Windows.

3) 595bcab fix(cursor-agent): inject --approve-mcps --force for headless MCP/tool access

After commits (1)+(2), subprocess.run succeeds and cursor-agent starts, but the first MCP call (e.g. to read a DingTalk PRD) fails with The tool call was rejected. I can't retrieve the document name without permission to call the tool. Two more flags are needed:

  • --approve-mcps — without it, every MCP server stays not loaded (needs approval) and tool calls are silently dropped.
  • --force — without it, the agent halts on the first tool-call approval prompt; the workflow returns a misleading non-zero exit. With it, cursor-agent matches the implicit "trusted environment" semantics that claude -p and codex --exec already have by default — the right semantics for an unattended specify workflow run.

Final argv after all three commits:

args = [self.key, "-p", "--trust", "--approve-mcps", "--force", prompt]
if model: args.extend(["--model", model])
if output_json: args.extend(["--output-format", "json"])

End-to-end verification (real DingTalk PRD, just a URL as input)

Repro on Windows 10 + cursor-agent 2026.05.16-0338208:

cd D:\Code\MBM\MBM-Backend     # real Maven multi-module Java project
specify workflow run speckit `
  --input "spec=https://alidocs.dingtalk.com/i/nodes/<dingtalk-prd-node>" `
  --input "integration=cursor-agent" `
  --input "scope=full"

Two independent runs (df8c4b9b, 388d3c15) both reach the review-spec gate:

specify step:
  dispatched=true, exit_code=0, status=completed, duration ~156s / ~147s

agent behaviour (autonomously, from a URL-only spec input):
  - calls dingtalk-doc MCP get_document_content to fetch the PRD
  - reads project constitution + existing specs/ layout
  - decides specs/ subpath itself (e.g. specs/tooling/mold-assembly/202605/<feature>/)
  - produces spec.md (31.5 KB) + checklists/requirements.md
  - updates .specify/feature.json and specs/menu-dictionary.md
  - marks 3 [NEEDS CLARIFICATION] items for Gate 1 review

next step (review-spec gate):
  (gate started; status would be `paused` on a normal completion)

(Both runs above were eventually cancelled by Ctrl+C while the gate step was just starting, which surfaced an [Errno 22] Invalid argument from the interrupted subprocess.run. That was an artifact of my cancellation, not a gate-step bug — review-spec is a gate step and its designed terminal status is paused. Independent of this PR either way.)

Backward compatibility

  • In-IDE skill flow (.cursor/skills/speckit-*/SKILL.md, --skills default) — unchanged.
  • multi_install_safe, context_file, registrar_config, options() — unchanged.
  • POSIX behaviour — shutil.which lookup is a no-op for already-absolute exec_args[0], and the --approve-mcps --force flags exist on Linux/macOS cursor-agent identically.
  • catalog.json, workflow.yml, templates — untouched.
  • Other integrations (claude, codex, gemini) — their build_exec_args paths are not touched; the only shared change is base.py::dispatch_command adding the shutil.which shim resolution, which only takes effect when shutil.which returns a different path than the input (i.e. .cmd/.bat shim case on Windows).

Testing

$ uv run python -m pytest tests/integrations/test_integration_cursor_agent.py -v
============================= 43 passed in 3.72s ==============================

$ uv run python -m pytest -q
========== 12 failed, 2867 passed, 109 skipped in 372.85s (0:06:12) ===========
  • 43 cursor-agent integration tests pass (34 pre-existing + 9 new across all three commits).
  • New tests pin:
    • requires_cli is True and install_url points at cursor.com
    • Exact argv layout [cursor-agent, -p, --trust, --approve-mcps, --force, …] (default + text-output + with-model variants)
    • All four mandatory headless flags are always present together
    • Hyphenated skill invocation (/speckit-plan not /speckit.plan)
    • .cmd shim resolution: subprocess receives full cursor-agent.CMD path, not bare cursor-agent
    • Passthrough when shutil.which returns None
  • Existing tests/test_workflows.py::TestCommandStep::test_dispatch_with_mock_cli and test_dispatch_failure_returns_failed_status updated to patch shutil.which at the base.py layer (was previously only patching the dispatcher layer, which made the test environment-sensitive — passed on CI with no claude on PATH, failed locally with claude installed).
  • Full repo: 2867 passed, 0 regressions from this PR. The 12 remaining pre-existing failures are unrelated Windows symlink privilege issues (WinError 1314) requiring elevated runner — not introduced or affected by this PR.

Out of scope (deliberately)

  • The misleading "CLI not found or not installed. Install the CLI tool." error message itself (it conflates 5 distinct dispatch failure modes into one). Worth a separate PR to split per-failure-mode messages — happy to do that as a follow-up if maintainers want.
  • Adding cursor-agent to bundled speckit workflow's requires.integrations.any list (currently ["copilot", "claude", "gemini"]). Not strictly required — specify workflow run does not enforce that list strictly today — but worth a follow-up so specify workflow info speckit is consistent with the actual support matrix.
  • docs/reference/integrations.md page for cursor-agent (none exists today; happy to add if wanted).
  • Adding a speckit.git.feature step to speckit workflow.yml (current workflow doesn't auto-create feature branches; that's by design but worth surfacing as an opt-in for teams that want branch-per-feature).

Restores the ability for ``specify workflow run`` to dispatch the
cursor-agent CLI, complementing the existing in-IDE skill flow.
Without this fix, ``specify workflow run speckit --input
integration=cursor-agent ...`` fails with a misleading
``CLI not found or not installed`` error even when the CLI is
installed (since cursor-agent had ``requires_cli=False`` and an
unset ``build_exec_args``).

The cursor-agent CLI (>= 2026.05.16) supports headless execution
via ``-p`` (print mode with full tool access including write/shell)
and ``--trust`` (bypass Workspace Trust prompt). Without ``--trust``
the CLI exits non-zero in non-TTY contexts (verified locally).

Changes to ``src/specify_cli/integrations/cursor_agent/__init__.py``:

* ``config.requires_cli``: ``False`` -> ``True``
* ``config.install_url``: ``None`` -> Cursor CLI docs URL
* Override ``build_exec_args()`` to emit
  ``[cursor-agent, -p, --trust, <prompt>, ...]``
  with optional ``--model`` and ``--output-format json`` flags,
  mirroring the shape used by ``claude``/``codex``/``gemini``.

Tests:

* 34 existing cursor-agent tests still pass.
* 6 new tests in ``TestCursorAgentCliDispatch`` pin
  ``requires_cli``, ``install_url``, and the exact argv shape
  (default, text-output, with-model, and the hyphenated skill
  invocation form ``/speckit-<name>``).
* Full repo: 1085 / 1085 passed, no regressions.

Fixes github#2629

Co-authored-by: Cursor <cursoragent@cursor.com>
刘一 and others added 2 commits May 19, 2026 15:28
On Windows, ``shutil.which`` honors ``PATHEXT`` and locates wrappers
like ``cursor-agent.cmd`` and ``codex.cmd``, but Python's
``subprocess.run`` calls ``CreateProcess`` which does **not** consult
``PATHEXT`` and therefore fails with ``WinError 2`` on a bare argv
like ``[cursor-agent, ...]``.

Resolve ``exec_args[0]`` via ``shutil.which`` in
``IntegrationBase.dispatch_command`` so ``.cmd``/``.bat`` shims work
transparently. On POSIX this is a no-op for absolute paths and a
harmless lookup otherwise.

Verified locally on Windows 10 + cursor-agent 2026.05.16:
without this fix, ``specify workflow run speckit --input
integration=cursor-agent`` fails with ``FileNotFoundError`` even
after the cursor-agent integration starts producing valid exec
args (per the prior commit on this branch).

Tests:

* New: 2 cursor-agent tests pin the shim-resolution + passthrough
  behavior (``test_dispatch_command_resolves_cmd_shim_for_subprocess``
  and ``test_dispatch_command_passthrough_when_shutil_which_finds_nothing``).
* Updated: ``tests/test_workflows.py::TestCommandStep::test_dispatch_with_mock_cli``
  was mocking ``shutil.which`` only at the ``command`` step level
  and not at the ``base`` level, which made it environment-sensitive
  (fails locally when the real ``claude`` CLI is on PATH).  Added the
  matching base-level patch and updated the argv-assertion to reflect
  the resolved path. ``test_dispatch_failure_returns_failed_status``
  gets the same patch for consistency.
* Full repo: 2867 passed, 0 regression from this PR. The 12 remaining
  pre-existing failures are unrelated Windows ``symlink`` privilege
  failures (``WinError 1314``) on a non-admin Windows runner.

Co-authored-by: Cursor <cursoragent@cursor.com>
…l access

The previous commit (1c55988) wired up ``-p --trust`` so the CLI launches
in headless mode without the Workspace Trust prompt, but that alone is
not enough to let ``specify workflow run`` drive a real speckit feature
end-to-end with cursor-agent on Windows. Two more flags are required:

* ``--approve-mcps``: without it, every MCP server configured in
  ``.cursor/mcp.json`` stays ``not loaded (needs approval)``, and any
  tool call against them is silently dropped. We hit this immediately
  trying to read a DingTalk PRD from a remote MCP server during the
  ``/speckit-specify`` step.
* ``--force``: without it, the agent halts on the first tool-call
  approval prompt (the tool call gets rejected and the workflow exits
  non-zero with a misleading message). With ``--force`` cursor-agent
  matches the implicit "trusted environment" semantics that ``claude -p``
  and ``codex --exec`` already have by default -- which is the right
  semantics for an unattended ``specify workflow run`` invocation.

Verified end-to-end on Windows 10 + cursor-agent 2026.05.16-0338208:

* ``cursor-agent -p --trust --approve-mcps --force --output-format text``
  + a ``/speckit-specify`` prompt that included a DingTalk URL produced
  a full spec.md (31.5 KB) plus checklists/requirements.md in ~10.7 min,
  reading the source PRD through the ``dingtalk-doc`` remote MCP server,
  deciding the ``specs/`` subpath itself, and updating
  ``.specify/feature.json`` and ``specs/menu-dictionary.md`` along the
  way -- no human-in-the-loop, no source PRD ever touched the filesystem.
* Without ``--approve-mcps`` the same prompt errors with the tool call
  rejected message; without ``--force`` the agent stops at the first
  non-MCP tool call.

Tests:

* ``test_build_exec_args_*`` updated to pin the new four-flag prefix.
* New ``test_build_exec_args_contains_mandatory_headless_flags`` asserts
  the four flags are always present together.
* ``test_dispatch_command_resolves_cmd_shim_for_subprocess`` updated to
  match the new argv layout.
* All 43 cursor-agent tests pass; no other tests touched.

Co-authored-by: Cursor <cursoragent@cursor.com>
@One-TheOnly One-TheOnly changed the title fix(cursor-agent): enable CLI dispatch via -p --trust headless mode fix(cursor-agent): enable headless CLI dispatch end-to-end (-p --trust --approve-mcps --force + Windows .cmd shim resolution) May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Enable CLI dispatch for cursor-agent integration so 'specify workflow run' can drive Cursor headlessly

1 participant