Repository navigation
feat(team): add cursor-agent as 4th tmux worker type (executor-only) - #2736
Conversation
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"
\`\`\`
There was a problem hiding this comment.
💡 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".
|
|
||
| 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']); |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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 👍 / 👎.
|
CI is blocked on a narrow TypeScript test signature mismatch for the new — |
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
There was a problem hiding this comment.
💡 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'; |
There was a problem hiding this comment.
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 👍 / 👎.
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>
…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.
…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.
…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.
Re-target of #2734 to the
devbranch 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
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:
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
```
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
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).