Skip to content

feat(agents): add Cursor Agent runtime support#545

Open
bowser-bot wants to merge 2 commits into
cline:mainfrom
bowser-bot:feat/cursor-agent-runtime-support
Open

feat(agents): add Cursor Agent runtime support#545
bowser-bot wants to merge 2 commits into
cline:mainfrom
bowser-bot:feat/cursor-agent-runtime-support

Conversation

@bowser-bot

@bowser-bot bowser-bot commented Jun 27, 2026

Copy link
Copy Markdown

Summary

  • add Cursor Agent as a first-class runtime agent, using cursor-agent as the canonical binary and agent as a fallback launch alias
  • wire Cursor detection, auto-selection, launch resolution, Settings/onboarding visibility, and home sidebar prompt injection
  • add a Cursor session adapter for --force, --continue, --plan, project-level .cursor/hooks.json task lifecycle hooks, and cleanup that restores pre-existing hook config
  • avoid auto-selecting Cursor from a generic agent binary; auto-selection requires canonical cursor-agent or explicit cursor selection

Fixes #544
Supersedes #253

Test plan

  • npm test -- test/runtime/config/runtime-config.test.ts test/runtime/terminal/agent-registry.test.ts test/runtime/terminal/agent-session-adapters.test.ts test/runtime/append-system-prompt.test.ts
  • npm --prefix web-ui run test -- src/components/runtime-settings-dialog.test.tsx src/hooks/use-startup-onboarding.test.tsx src/runtime/use-runtime-config.test.tsx src/runtime/use-runtime-project-config.test.tsx
  • npm run typecheck
  • npm --prefix web-ui run typecheck
  • npx @biomejs/biome check src/config/runtime-config.ts src/core/agent-catalog.ts src/core/api-contract.ts src/prompts/append-system-prompt.ts src/terminal/agent-registry.ts src/terminal/agent-session-adapters.ts test/runtime/append-system-prompt.test.ts test/runtime/config/runtime-config.test.ts test/runtime/terminal/agent-registry.test.ts test/runtime/terminal/agent-session-adapters.test.ts web-ui/src/components/runtime-settings-dialog.tsx web-ui/src/components/task-start-agent-onboarding-carousel.tsx
  • Pre-commit hook: npm run typecheck and npm run test:fast with inherited Kanban task runtime env cleared

Notes

Cursor's current CLI surface can expose both cursor-agent and agent. This PR uses cursor-agent as the clearer canonical command while accepting agent only as a fallback when Cursor is already selected.

Compared with #253, this PR is based on current main, keeps alias handling centralized in the runtime catalog, avoids generic agent auto-selection false positives, and wires Cursor task state transitions through .cursor/hooks.json.

@greptile-apps

greptile-apps Bot commented Jun 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR registers Cursor Agent as a first-class runtime in Kanban, wiring detection, auto-selection, session launch, onboarding UI, and home-sidebar prompt injection across the full stack.

  • Multi-binary detection: Adds cursor-agent as the canonical binary with agent as a fallback alias; getRuntimeAgentBinaryCandidates propagates this through detection, registry, and auto-selection, preferring cursor-agent when both are present.
  • Session adapter: cursorAdapter handles --plan / --force / --yolo / --continue flag lifecycle and merges home-sidebar system prompt content directly into the initial user prompt (since Cursor has no --append-system-prompt flag).
  • UI + onboarding: Inserts Cursor into settings display order, onboarding carousel, and Linear MCP guidance in the appended system prompt.

Confidence Score: 3/5

The binary detection and UI wiring are solid, but the cursor adapter omits the hook configuration step that every other adapter performs, leaving task state transitions unimplemented for Cursor sessions.

The cursor adapter propagates hook env vars but never writes a hook configuration file or passes hook flags to Cursor — unlike claude, codex, gemini, droid, kiro, and cline adapters which all register agent-side callbacks. Without it, tasks will not auto-transition from in_progress to review states. The Linear MCP guidance also hardcodes the agent alias in a runnable command, which breaks on installs where only cursor-agent is available.

src/terminal/agent-session-adapters.ts (cursorAdapter hook setup) and src/prompts/append-system-prompt.ts (Linear MCP binary reference) need attention before merging.

Important Files Changed

Filename Overview
src/terminal/agent-session-adapters.ts Adds cursorAdapter with plan/force/continue flag handling and hook env propagation, but unlike every other adapter, it writes no hook configuration file — meaning Cursor Agent has no registration to call Kanban webhooks on task completion.
src/prompts/append-system-prompt.ts Adds Cursor to the home-agent prompt list and provides Linear MCP guidance; the guidance hardcodes the agent alias binary rather than the canonical cursor-agent, which will cause a command-not-found failure on systems where only cursor-agent is installed.
src/core/agent-catalog.ts Adds Cursor catalog entry with cursor-agent as canonical binary and agent as alias; introduces getRuntimeAgentBinaryCandidates helper. The agent alias is generic but the design tradeoff is acknowledged in the PR.
src/core/api-contract.ts Adds cursor to runtimeAgentIdSchema enum — straightforward schema extension with no issues.
src/terminal/agent-registry.ts Updates detectInstalledCommands and resolveAgentCommand to use getRuntimeAgentBinaryCandidates, correctly preferring the first detected binary. Logic is clean and well-tested.
src/config/runtime-config.ts Adds cursor to auto-selection priority and normalizeAgentId; switches from single-binary to multi-candidate detection. Correct and consistent with catalog additions.
web-ui/src/components/runtime-settings-dialog.tsx Inserts cursor into SETTINGS_AGENT_ORDER list — trivial and correct.
web-ui/src/components/task-start-agent-onboarding-carousel.tsx Adds cursor to onboarding list with install description and install link label — straightforward UI extension.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant K as Kanban Runtime
    participant R as agent-registry
    participant C as agent-catalog
    participant A as cursorAdapter
    participant CUR as cursor-agent / agent

    K->>R: detectInstalledCommands()
    R->>C: RUNTIME_AGENT_CATALOG.flatMap(binary + aliases)
    note over R: checks cursor-agent, then agent
    R-->>K: detectedCommands[]

    K->>R: pickBestInstalledAgentIdFromDetected()
    note over R: cursor before codex in priority list
    R-->>K: cursor

    K->>R: resolveAgentCommand(config)
    R->>C: getRuntimeAgentBinaryCandidates(cursor)
    C-->>R: [cursor-agent, agent]
    R-->>K: "ResolvedAgentCommand binary=cursor-agent"

    K->>A: prepareAgentLaunch(input)
    A->>A: removeCursorPlanModeConflicts() if plan mode
    A->>A: push --plan / --force / --continue flags
    A->>A: resolveHookContext set KANBAN_HOOK env vars
    A->>A: mergeCursorPromptWithHomeSystemPrompt()
    A-->>K: PreparedAgentLaunch

    K->>CUR: spawn binary with args + env
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant K as Kanban Runtime
    participant R as agent-registry
    participant C as agent-catalog
    participant A as cursorAdapter
    participant CUR as cursor-agent / agent

    K->>R: detectInstalledCommands()
    R->>C: RUNTIME_AGENT_CATALOG.flatMap(binary + aliases)
    note over R: checks cursor-agent, then agent
    R-->>K: detectedCommands[]

    K->>R: pickBestInstalledAgentIdFromDetected()
    note over R: cursor before codex in priority list
    R-->>K: cursor

    K->>R: resolveAgentCommand(config)
    R->>C: getRuntimeAgentBinaryCandidates(cursor)
    C-->>R: [cursor-agent, agent]
    R-->>K: "ResolvedAgentCommand binary=cursor-agent"

    K->>A: prepareAgentLaunch(input)
    A->>A: removeCursorPlanModeConflicts() if plan mode
    A->>A: push --plan / --force / --continue flags
    A->>A: resolveHookContext set KANBAN_HOOK env vars
    A->>A: mergeCursorPromptWithHomeSystemPrompt()
    A-->>K: PreparedAgentLaunch

    K->>CUR: spawn binary with args + env
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
src/terminal/agent-session-adapters.ts:767-776
**Missing hook configuration file — task state transitions won't fire**

Every other adapter that supports hooks (claude, codex, gemini, opencode, droid, kiro, cline) writes a hook configuration file and passes it to the CLI, so the agent actually knows to call back into Kanban on `Stop`, `PreToolUse`, etc. The cursor adapter only sets `KANBAN_HOOK_TASK_ID`/`KANBAN_HOOK_WORKSPACE_ID` env vars, but never registers any hook command with Cursor Agent. Without a hook config, Cursor has no instruction to call the Kanban webhook, so tasks will stay stuck in `in_progress` indefinitely rather than transitioning to `awaiting_review`.

### Issue 2 of 3
src/prompts/append-system-prompt.ts:62-63
**Linear MCP guidance hardcodes the `agent` alias, which may not exist**

The detection layer preferentially uses `cursor-agent` as the canonical binary; `agent` is only a fallback alias. If a user's install exposes `cursor-agent` but not `agent` as a standalone command, Cursor Agent will try to run `agent mcp login linear` and get a "command not found" error. The guidance should mention both possible binaries so the instruction stays valid regardless of which binary was resolved.

```suggestion
		case "cursor":
			return "- If Linear MCP is not available in the current agent (Cursor Agent), suggest adding `linear` in `.cursor/mcp.json` or `~/.cursor/mcp.json`, then run: `cursor-agent mcp login linear` (or `agent mcp login linear` if `cursor-agent` is not available)";
```

### Issue 3 of 3
src/core/agent-catalog.ts:33-35
**Generic `agent` alias risks false-positive Cursor detection**

`agent` is an extremely common binary name used by unrelated tools (e.g., HashiCorp Vault Agent, New Relic Agent, AWS SSM Agent). Because `cursor` now sits ahead of `codex` in `AUTO_SELECT_AGENT_PRIORITY`, any system with a non-Cursor `agent` binary on PATH will have Cursor auto-selected over Codex, and `resolveAgentCommand` will return that unrelated binary as the Cursor binary. The PR notes this tradeoff, but it may be worth documenting a follow-up to narrow detection or at least adding a comment explaining the known risk.

Reviews (1): Last reviewed commit: "feat(agents): add Cursor Agent runtime s..." | Re-trigger Greptile

Comment on lines +767 to +776
const hooks = resolveHookContext(input);
if (hooks) {
Object.assign(
env,
createHookRuntimeEnv({
taskId: hooks.taskId,
workspaceId: hooks.workspaceId,
}),
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing hook configuration file — task state transitions won't fire

Every other adapter that supports hooks (claude, codex, gemini, opencode, droid, kiro, cline) writes a hook configuration file and passes it to the CLI, so the agent actually knows to call back into Kanban on Stop, PreToolUse, etc. The cursor adapter only sets KANBAN_HOOK_TASK_ID/KANBAN_HOOK_WORKSPACE_ID env vars, but never registers any hook command with Cursor Agent. Without a hook config, Cursor has no instruction to call the Kanban webhook, so tasks will stay stuck in in_progress indefinitely rather than transitioning to awaiting_review.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/terminal/agent-session-adapters.ts
Line: 767-776

Comment:
**Missing hook configuration file — task state transitions won't fire**

Every other adapter that supports hooks (claude, codex, gemini, opencode, droid, kiro, cline) writes a hook configuration file and passes it to the CLI, so the agent actually knows to call back into Kanban on `Stop`, `PreToolUse`, etc. The cursor adapter only sets `KANBAN_HOOK_TASK_ID`/`KANBAN_HOOK_WORKSPACE_ID` env vars, but never registers any hook command with Cursor Agent. Without a hook config, Cursor has no instruction to call the Kanban webhook, so tasks will stay stuck in `in_progress` indefinitely rather than transitioning to `awaiting_review`.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread src/prompts/append-system-prompt.ts Outdated
Comment on lines +62 to +63
case "cursor":
return "- If Linear MCP is not available in the current agent (Cursor Agent), suggest adding `linear` in `.cursor/mcp.json` or `~/.cursor/mcp.json`, then run: `agent mcp login linear`";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Linear MCP guidance hardcodes the agent alias, which may not exist

The detection layer preferentially uses cursor-agent as the canonical binary; agent is only a fallback alias. If a user's install exposes cursor-agent but not agent as a standalone command, Cursor Agent will try to run agent mcp login linear and get a "command not found" error. The guidance should mention both possible binaries so the instruction stays valid regardless of which binary was resolved.

Suggested change
case "cursor":
return "- If Linear MCP is not available in the current agent (Cursor Agent), suggest adding `linear` in `.cursor/mcp.json` or `~/.cursor/mcp.json`, then run: `agent mcp login linear`";
case "cursor":
return "- If Linear MCP is not available in the current agent (Cursor Agent), suggest adding `linear` in `.cursor/mcp.json` or `~/.cursor/mcp.json`, then run: `cursor-agent mcp login linear` (or `agent mcp login linear` if `cursor-agent` is not available)";
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/prompts/append-system-prompt.ts
Line: 62-63

Comment:
**Linear MCP guidance hardcodes the `agent` alias, which may not exist**

The detection layer preferentially uses `cursor-agent` as the canonical binary; `agent` is only a fallback alias. If a user's install exposes `cursor-agent` but not `agent` as a standalone command, Cursor Agent will try to run `agent mcp login linear` and get a "command not found" error. The guidance should mention both possible binaries so the instruction stays valid regardless of which binary was resolved.

```suggestion
		case "cursor":
			return "- If Linear MCP is not available in the current agent (Cursor Agent), suggest adding `linear` in `.cursor/mcp.json` or `~/.cursor/mcp.json`, then run: `cursor-agent mcp login linear` (or `agent mcp login linear` if `cursor-agent` is not available)";
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread src/core/agent-catalog.ts
Comment on lines +33 to +35
binary: "cursor-agent",
binaryAliases: ["agent"],
baseArgs: [],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Generic agent alias risks false-positive Cursor detection

agent is an extremely common binary name used by unrelated tools (e.g., HashiCorp Vault Agent, New Relic Agent, AWS SSM Agent). Because cursor now sits ahead of codex in AUTO_SELECT_AGENT_PRIORITY, any system with a non-Cursor agent binary on PATH will have Cursor auto-selected over Codex, and resolveAgentCommand will return that unrelated binary as the Cursor binary. The PR notes this tradeoff, but it may be worth documenting a follow-up to narrow detection or at least adding a comment explaining the known risk.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/core/agent-catalog.ts
Line: 33-35

Comment:
**Generic `agent` alias risks false-positive Cursor detection**

`agent` is an extremely common binary name used by unrelated tools (e.g., HashiCorp Vault Agent, New Relic Agent, AWS SSM Agent). Because `cursor` now sits ahead of `codex` in `AUTO_SELECT_AGENT_PRIORITY`, any system with a non-Cursor `agent` binary on PATH will have Cursor auto-selected over Codex, and `resolveAgentCommand` will return that unrelated binary as the Cursor binary. The PR notes this tradeoff, but it may be worth documenting a follow-up to narrow detection or at least adding a comment explaining the known risk.

How can I resolve this? If you propose a fix, please make it concise.

@bowser-bot

Copy link
Copy Markdown
Author

Addressed the Greptile review in commit ce77316:

  • Added project-level Cursor hook wiring via .cursor/hooks.json in the task worktree. The adapter now registers stop, beforeSubmitPrompt, shell/MCP/read/edit activity hooks, and restores any pre-existing hook file during session cleanup.
  • Updated Cursor Linear MCP guidance to prefer cursor-agent mcp login linear, with agent mcp login linear as the fallback.
  • Reduced the generic agent false-positive risk: Cursor auto-selection now requires the canonical cursor-agent binary or explicit cursor detection. The agent alias remains only as a launch fallback when Cursor is already selected.

Validation after the fixes:

  • npm test -- test/runtime/config/runtime-config.test.ts test/runtime/terminal/agent-registry.test.ts test/runtime/terminal/agent-session-adapters.test.ts test/runtime/append-system-prompt.test.ts
  • npm --prefix web-ui run test -- src/components/runtime-settings-dialog.test.tsx src/hooks/use-startup-onboarding.test.tsx src/runtime/use-runtime-config.test.tsx src/runtime/use-runtime-project-config.test.tsx
  • npm run typecheck
  • npm --prefix web-ui run typecheck
  • npx @biomejs/biome check ...
  • Pre-commit hook passed with npm run typecheck and npm run test:fast (53 files, 555 tests)

@bowser-bot

Copy link
Copy Markdown
Author

For reviewers comparing this with #253, the intended decision frame is:

The main design tradeoff left for maintainers is whether project-level .cursor/hooks.json injection is the right v1 integration strategy for Cursor. I think it is the closest match to Cursor CLI's current hook surface, and it avoids relying on plugin hook loading behavior.

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.

Add Cursor Agent CLI runtime support

1 participant