Skip to content

feat(team): add cursor-agent as 4th tmux worker type (executor-only) - #2736

Merged
Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
aryateja2106:feat/cursor-worker-support-dev
Apr 20, 2026
Merged

Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
aryateja2106:feat/cursor-worker-support-dev

Conversation

@aryateja2106

Copy link
Copy Markdown
Contributor

Re-target of #2734 to the dev branch per @Yeachan-Heo's note. Same patch, no functional change. Sorry for the wrong target on the first attempt.


Adds cursor-agent (Cursor's Composer 2 REPL) as a first-class `omc team` worker provider alongside claude/codex/gemini.

Why

cursor-agent is a very capable interactive coding agent that many users (myself included) already keep a running Cursor Pro/Max plan for. Making it a native OMC worker lets those users burn Cursor credits for throughput work while a Claude orchestrator retains the plan/verify role — without leaving the `omc team` mental model.

The user also gets the full cmux-pane visibility: they can watch the cursor-agent REPL live, interrupt by typing directly into the split, and the orchestrator continues to coordinate via the standard filesystem A2A at `.omc/state/team//`.

Changes

File Change
`src/team/model-contract.ts` Extend `CliAgentType` with `'cursor'`; add `CONTRACTS.cursor` (binary `cursor-agent`, `supportsPromptMode: false`, minimal launch args)
`src/team/types.ts` Extend `WorkerBackend` with `'tmux-cursor'`; widen `WorkerInfo.worker_cli` to include `'cursor'`
`src/team/capabilities.ts` Map `tmux-cursor` to `['code-edit', 'refactoring', 'general']`
`src/team/cli-detection.ts` Detect `cursor-agent` in `detectAllClis()`
`src/team/worker-bootstrap.ts` Add `case 'cursor':` to `agentTypeGuidance` with REPL-aware instructions (stay in session, claim/transition tasks via team-api, do not auto-exit)
`src/team/cli-worker-contract.ts` Skip `shouldInjectContract` for cursor, matching the claude carve-out
`src/cli/team.ts` Add `'cursor'` to `VALID_CLI_AGENT_TYPES`; update help text

Executor-only: why

Codex and Gemini use `supportsPromptMode: true` because they're one-shot CLIs (run a prompt → exit). The CLI-worker output contract (`CONTRACT_ROLES` = critic/code-reviewer/security-reviewer/test-engineer) depends on exit-on-complete so the verdict JSON can be read by the leader's worker-completion handler.

cursor-agent is an interactive REPL — it does not exit after answering. Routing a reviewer role to a cursor worker would hang the team because the verdict file would never be written. This patch:

  1. Sets `supportsPromptMode: false` on the cursor contract.
  2. Extends `shouldInjectContract` to skip cursor (alongside claude).
  3. Documents the constraint in the in-prompt `agentTypeGuidance`.

Mailbox / inbox / sentinel / heartbeat flow is unchanged — cursor workers participate in the standard filesystem A2A the same way claude workers do.

Verification

```
$ npx tsc --noEmit

all production sources pass

$ cursor-agent --version

confirms binary detection

```

End-to-end smoke test (pending once this PR lands):

```
$ omc team 1:cursor:executor "implement hello.py and ack on leader-fixed"

cursor pane spawns in cmux/tmux split, receives trigger message,

claims task, edits file, transitions task status, waits.

```

Known follow-up (flagged honestly)

One residual TS error remains in `src/tests/runtime-guidance-plan-ralph.test.ts` at line 87 — it uses a hard-coded literal-union helper signature `(agentType: "claude" | "codex" | "gemini") => agentType is "claude"` that needs widening to `(agentType: CliAgentType) => agentType is "claude"` to accept the new provider. My local agent harness has a generic `*.test.ts` modification guard (a "don't silence tests" RALPH-loop hook) that mis-fires on legit type-widening, so rather than bypass it I'm surfacing this for a one-line amendment in-PR. The exact one-line diff:

```diff

  •  const result = detectSkillRuntimeAvailability(throwingDetector);
    
  •  const throwing: (agentType: CliAgentType) => boolean = (agentType) => {...};
    

```

Or simply replace the literal union in the inner helper definition above line 87 with the imported `CliAgentType` from `src/team/model-contract.ts`. Happy to draft the exact diff in a follow-up commit if you can disable the local hook for that path, or apply directly in-PR.

Compatibility

  • Existing claude/codex/gemini worker types and behaviors are unchanged.
  • No bridge/MCP changes — cursor uses the existing tmux-pane path.
  • The `BridgeConfig.provider` literal `'codex' | 'gemini'` is intentionally NOT widened: cursor does not go through the bridge runtime, so that narrower type correctly excludes it.

Relationship to cmux

This PR pairs well with two upstream cmux fixes I just opened to make `omc team` work inside cmux at all:

Once all three land, `cmux omc team 1:cursor,1:codex,1:gemini "..."` works end-to-end with each agent in its own cmux split, driveable both by the user (direct keyboard input) and the orchestrator (via the filesystem mailbox).

Adds cursor-agent (Cursor's Composer 2 REPL) as a first-class
\`omc team\` worker provider alongside claude/codex/gemini. Spawned
via the existing tmux-pane path (no bridge changes); cursor workers
appear as cmux/tmux split panes that the user can both observe and
type into directly.

## Changes

- \`src/team/model-contract.ts\`
  - Extend \`CliAgentType\` union with \`'cursor'\`.
  - Add \`cursor\` entry to \`CONTRACTS\` with binary \`cursor-agent\`,
    minimal launch args (no model flag — cursor-agent owns its own
    model selection inside the REPL), and \`supportsPromptMode: false\`.
- \`src/team/types.ts\`
  - Extend \`WorkerBackend\` with \`'tmux-cursor'\`.
  - Widen \`WorkerInfo.worker_cli\` to include \`'cursor'\`.
- \`src/team/capabilities.ts\`
  - Map \`tmux-cursor\` to \`['code-edit', 'refactoring', 'general']\`
    so the fitness scorer routes appropriate executor work to cursor.
- \`src/team/cli-detection.ts\`
  - Detect \`cursor-agent\` in \`detectAllClis()\`.
- \`src/team/worker-bootstrap.ts\`
  - Add \`case 'cursor':\` to \`agentTypeGuidance\` with REPL-aware
    instructions: stay in session, claim/transition tasks via
    team-api, do not auto-exit, take only executor-style work.
- \`src/team/cli-worker-contract.ts\`
  - Skip verdict-file injection for cursor in \`shouldInjectContract\`,
    matching the existing claude carve-out. Cursor REPL cannot perform
    write-verdict-and-exit.
- \`src/cli/team.ts\`
  - Add \`'cursor'\` to \`VALID_CLI_AGENT_TYPES\` and update help text.

## Why executor-only

Codex and Gemini set \`supportsPromptMode: true\` because they are
one-shot CLIs that run a single prompt and exit. The CLI-worker output
contract (CONTRACT_ROLES = critic, code-reviewer, security-reviewer,
test-engineer) depends on this exit-on-complete behavior to surface
structured verdict JSON back to the leader.

cursor-agent is an interactive REPL: it does not exit after answering a
prompt. Routing a reviewer role to a cursor worker would hang the team
because the verdict file is never written and the worker never exits.
This patch:

1. Marks \`supportsPromptMode: false\` on the cursor contract.
2. Updates \`shouldInjectContract\` to skip cursor (alongside claude).
3. Documents the constraint inline in the agentTypeGuidance.

Mailbox/inbox/sentinel/heartbeat behavior is unchanged — cursor workers
participate in the standard \`.omc/state/team/<team>/\` filesystem A2A
the same way claude workers do.

## Verification

- \`npx tsc --noEmit\` passes for all production sources.
- One residual error in \`src/__tests__/runtime-guidance-plan-ralph.test.ts\`
  (line 87) requires widening a hard-coded test helper signature
  \`(agentType: "claude" | "codex" | "gemini") => agentType is "claude"\`
  to \`(agentType: CliAgentType) => agentType is "claude"\` — a one-line
  type-only update. My local agent harness currently guards \`*.test.ts\`
  edits, so I'm flagging this as a follow-up for a maintainer or
  in-PR amendment rather than ship a stale-typed test.

## Usage

Once cmux PR Yeachan-Heo#3031 (tmux-compat short-form expansion) lands, this
enables:

\`\`\`
omc team 1:cursor:executor "implement the X feature"
omc team 1:cursor,1:codex:critic "implement and review the Y change"
\`\`\`

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee97676a28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli/team.ts

const JOB_ID_PATTERN = /^omc-[a-z0-9]{1,16}$/;
const VALID_CLI_AGENT_TYPES = new Set(['claude', 'codex', 'gemini']);
const VALID_CLI_AGENT_TYPES = new Set(['claude', 'codex', 'gemini', 'cursor']);

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 Badge Wire cursor support into the active team CLI parser

Adding 'cursor' to VALID_CLI_AGENT_TYPES here only updates the legacy src/cli/team.ts path, but the actual omc team command is dispatched via src/cli/index.ts to src/cli/commands/team.ts, where VALID_TEAM_CLI_AGENT_TYPES still excludes cursor and normalizeWorkerSpecSegment() treats unknown tokens as roles. In practice, omc team 1:cursor "..." is parsed as a Claude worker with role cursor, so the new provider is silently not selected on the primary CLI surface.

Useful? React with 👍 / 👎.

import { isExternalLLMDisabled } from '../lib/security-config.js';

export type CliAgentType = 'claude' | 'codex' | 'gemini';
export type CliAgentType = 'claude' | 'codex' | 'gemini' | 'cursor';

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 Badge Keep scaling agent validation in sync with new provider

After expanding CliAgentType to include 'cursor', the scaling path is now inconsistent: scaleUp() in src/team/scaling.ts still validates with new Set(['claude','codex','gemini']) and rejects cursor as unknown. That means teams started with cursor workers cannot be scaled up with the same provider, which breaks team lifecycle behavior for the newly added agent type.

Useful? React with 👍 / 👎.

@Yeachan-Heo

Copy link
Copy Markdown
Owner

CI is blocked on a narrow TypeScript test signature mismatch for the new cursor agent type. I'm opening a dedicated fix session on the PR branch and will patch the failing test path directly.

—
[repo owner's gaebal-gajae (clawdbot) 🦞]

The runtime guidance test mocked CLI availability with a narrower union than the
production signature now accepts. Widening the test helper to CliAgentType keeps
the assertion behavior unchanged while matching the cursor-aware contract.

Constraint: Fix only the CI TypeScript failure on PR Yeachan-Heo#2736
Rejected: Change production signatures back to the older union | would broaden scope beyond the test-only fix
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep test doubles typed against shared agent contracts when provider unions expand
Tested: npx tsc --noEmit
Not-tested: Vitest runtime execution

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b0c5e9d55

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

import { isExternalLLMDisabled } from '../lib/security-config.js';

export type CliAgentType = 'claude' | 'codex' | 'gemini';
export type CliAgentType = 'claude' | 'codex' | 'gemini' | 'cursor';

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 Badge Treat cursor teams as CLI workers during shutdown

Adding cursor to CliAgentType makes cursor-only teams valid, but shutdownTeam still classifies CLI workers using new Set(['claude','codex','gemini']) (src/team/runtime.ts:926). For a team started with agentTypes: ['cursor'], isCliWorkerTeam becomes false, so shutdown waits the full ACK timeout for shutdown-ack.json files that CLI-pane workers do not emit, causing avoidable 30s hangs before tmux cleanup. Please include cursor in that allowlist (or derive it from CliAgentType) so shutdown remains fast for the new provider.

Useful? React with 👍 / 👎.

@Yeachan-Heo
Yeachan-Heo merged commit 14447c4 into Yeachan-Heo:dev Apr 20, 2026
9 checks passed
Yeachan-Heo pushed a commit that referenced this pull request Apr 20, 2026
Release includes:
- feat(team): cursor-agent as 4th tmux worker type (#2736)
- fix(keyword-detector): stop false-positive autopilot on "autonomous" (#2739)
- fix(self-improve): scope artifacts by topic for safer resumes (#2732)

Constraint: 4 version files must remain in sync (package.json, plugin.json, marketplace.json, package-lock.json)
Constraint: dist/ is gitignored but tracked; force-add required for new files
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Yeachan-Heo pushed a commit to iyoda/oh-my-claudecode that referenced this pull request Aug 26, 2026
…o#3880)

`shouldInjectContract` skipped cursor alongside claude, so a cursor worker
on a reviewer role received no verdict instructions. The stated reason was
that cursor-agent is an interactive REPL and "cannot perform the
write-verdict-and-exit dance the contract requires".

That premise does not survive contact with the contract. It is not an
exit-on-complete handshake: `renderCliWorkerOutputContract()` emits a prompt
fragment telling the worker to write JSON to a path, and the leader polls
that path in `processCliWorkerVerdicts()`. Nothing observes process exit.

Codex proves it. PR Yeachan-Heo#2736 justified the cursor carve-out by contrasting
one-shot codex/gemini against the cursor REPL, but b46a450 moved codex to
`supportsPromptMode: false` and persistent panes five days later. Codex kept
the contract and still works:

    model-contract.test.ts      getContract('codex').supportsPromptMode === false
    cli-worker-contract.test.ts shouldInjectContract('critic', 'codex') === true

So the sole distinction the carve-out rested on no longer exists. Cursor is
now treated like every other non-Claude provider.

Worker guidance replaces the blanket refusal with the actual procedure, and
adds two things the shared contract text does not cover:

- a read-only guard, since a reviewer must not edit files
- an explicit note that writing the verdict is not a reason to leave the
  session, because a persistent pane keeps serving the mailbox afterward

Role gating is untouched here. `runtime-v2.ts` and the CLI spec parser still
reject cursor reviewer roles, so this path is not yet reachable in
production; it is the prerequisite that makes lifting those guards safe
rather than task-stranding.
Yeachan-Heo pushed a commit to iyoda/oh-my-claudecode that referenced this pull request Aug 26, 2026
…o#3880)

`shouldInjectContract` skipped cursor alongside claude, so a cursor worker
on a reviewer role received no verdict instructions. The stated reason was
that cursor-agent is an interactive REPL and "cannot perform the
write-verdict-and-exit dance the contract requires".

That premise does not survive contact with the contract. It is not an
exit-on-complete handshake: `renderCliWorkerOutputContract()` emits a prompt
fragment telling the worker to write JSON to a path, and the leader polls
that path in `processCliWorkerVerdicts()`. Nothing observes process exit.

Codex proves it. PR Yeachan-Heo#2736 justified the cursor carve-out by contrasting
one-shot codex/gemini against the cursor REPL, but b46a450 moved codex to
`supportsPromptMode: false` and persistent panes five days later. Codex kept
the contract and still works:

    model-contract.test.ts      getContract('codex').supportsPromptMode === false
    cli-worker-contract.test.ts shouldInjectContract('critic', 'codex') === true

So the sole distinction the carve-out rested on no longer exists. Cursor is
now treated like every other non-Claude provider.

Worker guidance replaces the blanket refusal with the actual procedure, and
adds two things the shared contract text does not cover:

- a read-only guard, since a reviewer must not edit files
- an explicit note that writing the verdict is not a reason to leave the
  session, because a persistent pane keeps serving the mailbox afterward

Role gating is untouched here. `runtime-v2.ts` and the CLI spec parser still
reject cursor reviewer roles, so this path is not yet reachable in
production; it is the prerequisite that makes lifting those guards safe
rather than task-stranding.
iyoda added a commit to iyoda/oh-my-claudecode that referenced this pull request Aug 27, 2026
…o#3880)

`shouldInjectContract` skipped cursor alongside claude, so a cursor worker
on a reviewer role received no verdict instructions. The stated reason was
that cursor-agent is an interactive REPL and "cannot perform the
write-verdict-and-exit dance the contract requires".

That premise does not survive contact with the contract. It is not an
exit-on-complete handshake: `renderCliWorkerOutputContract()` emits a prompt
fragment telling the worker to write JSON to a path, and the leader polls
that path in `processCliWorkerVerdicts()`. Nothing observes process exit.

Codex proves it. PR Yeachan-Heo#2736 justified the cursor carve-out by contrasting
one-shot codex/gemini against the cursor REPL, but b46a450 moved codex to
`supportsPromptMode: false` and persistent panes five days later. Codex kept
the contract and still works:

    model-contract.test.ts      getContract('codex').supportsPromptMode === false
    cli-worker-contract.test.ts shouldInjectContract('critic', 'codex') === true

So the sole distinction the carve-out rested on no longer exists. Cursor is
now treated like every other non-Claude provider.

Worker guidance replaces the blanket refusal with the actual procedure, and
adds two things the shared contract text does not cover:

- a read-only guard, since a reviewer must not edit files
- an explicit note that writing the verdict is not a reason to leave the
  session, because a persistent pane keeps serving the mailbox afterward

Role gating is untouched here. `runtime-v2.ts` and the CLI spec parser still
reject cursor reviewer roles, so this path is not yet reachable in
production; it is the prerequisite that makes lifting those guards safe
rather than task-stranding.
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.

2 participants