Skip to content

Add Cursor as a third agent under the CodingAgent protocol (#417)#418

Merged
dgershman merged 4 commits into
mainfrom
feature/crow-417-cursor-agent
Jun 4, 2026
Merged

Add Cursor as a third agent under the CodingAgent protocol (#417)#418
dgershman merged 4 commits into
mainfrom
feature/crow-417-cursor-agent

Conversation

@dgershman
Copy link
Copy Markdown
Collaborator

Summary

Lands Cursor as a third agent on the CodingAgent protocol established by PR #197. Mirrors Packages/CrowCodex/'s package shape, but the HookConfigWriter / StateSignalSource implementations are closer to Packages/CrowClaude/'s — Cursor's hook engine is a superset of Claude Code's, not a no-op like Codex's per-session writer.

  • New Packages/CrowCursor/ with CursorAgent, CursorHookConfigWriter, CursorSignalSource, CursorScaffolder, CursorLauncher
  • AgentKind.cursor added to CrowCore
  • AppDelegate registers CursorAgent gated on findBinary() and installs ~/.cursor/hooks.json ($CURSOR_CONFIG_DIR aware) on launch
  • The camelCase ↔ PascalCase event-name mapping is collapsed into the writer (Cursor preToolUse key → --event PreToolUse arg), letting CursorSignalSource share Claude/Codex's canonical vocabulary verbatim
  • supportsRemoteControl = true — Cursor's stop.followup_message enables auto-continue and the RemoteControlBadge
  • CursorScaffolder reuses Resources/AGENTS.md.template; co-existence with CodexScaffolder is idempotent (byte-identical writes, same ## Known Issues / Corrections marker preservation)

No CLI changes — crow hook-event --agent and crow new-session --agent already accept arbitrary agent kinds from #197. No UI changes — CreateSessionView auto-grows from AgentRegistry.shared.allAgents().

Things deferred to follow-ups (called out in the ticket as "empirical")

  • Does `agent -p` headless mode actually fire `~/.cursor/hooks.json`? If not, the follow-up parses `--output-format stream-json` as an alternate signal-source input. The `afterAgentResponse → Notification` mapping in the writer is a safety net until then.
  • Real `agent` binary exit codes for failure paths — drives `.error` transitions.
  • Whether `.cursorrules` surfaces a warning when only `AGENTS.md` is present.

No `crow cursor-notify` subcommand — Cursor's hook engine fires `crow hook-event --agent cursor` directly. The Codex `notify` analog was a Tier-2 fallback for Codex's missing hook-engine pieces; Cursor doesn't need it.

Test plan

  • `arch -arm64 swift build` at repo root succeeds.
  • `arch -arm64 swift test` at repo root passes (152 tests).
  • `arch -arm64 swift test` in `Packages/CrowCursor` passes (25 tests).
  • `arch -arm64 swift test` in `Packages/CrowCodex` still passes (27 tests).
  • `arch -arm64 swift test` in `Packages/CrowClaude` still passes (37 tests).
  • `arch -arm64 swift test` in `Packages/CrowCore` still passes (205 tests).
  • Manual: launch app without `agent` installed — picker stays disabled with two agents; no `~/.cursor/` files written.
  • Manual: launch app with `agent` installed — picker enables and shows all three agents; `~/.cursor/hooks.json` written at first launch with the 6 event keys.
  • Manual: create a Cursor session — terminal launches `agent`; sidebar icon shows `cursorarrow.rays`; detail header shows "Agent: Cursor"; `RemoteControlBadge` renders.
  • Manual: submit a prompt to Cursor — sidebar transitions `.idle → .working` on `preToolUse`/`beforeSubmitPrompt`, `.working → .done` on `stop` (or `afterAgentResponse` in headless fallback).
  • Manual: `crow send` to a Cursor session works (verifies `supportsRemoteControl = true`).
  • Manual: existing Claude session in parallel behaves identically.
  • Manual: Manager session still hardcoded to `.claudeCode`.
  • Manual: Cursor session reads Crow's `.claude/skills/*` slash commands.
  • Manual: `AGENTS.md` written by `CursorScaffolder` doesn't clobber an existing one written by `CodexScaffolder` — preserves `## Known Issues / Corrections` section.

Closes #417

🤖 Generated with Claude Code

Lands Cursor as a third agent on the existing CodingAgent protocol from
PR #197. Mirrors CrowCodex's package shape but the hook layer (writer +
signal source) more closely mirrors CrowClaude — Cursor's hook engine is
a superset of Claude Code's, not a no-op like Codex's per-session writer.

* Add AgentKind.cursor
* New package Packages/CrowCursor with CursorAgent, CursorHookConfigWriter,
  CursorSignalSource, CursorScaffolder, CursorLauncher
* CursorHookConfigWriter collapses the camelCase ↔ PascalCase event-name
  mapping into the writer (Cursor camelCase JSON key → Crow-canonical
  PascalCase --event arg), letting CursorSignalSource share Claude/Codex's
  event vocabulary verbatim
* CursorAgent.supportsRemoteControl = true (enables RemoteControlBadge and
  crow send — Cursor's stop.followup_message gives us auto-continue)
* CursorScaffolder reuses Resources/AGENTS.md.template; co-existence with
  CodexScaffolder is idempotent (byte-identical writes, same Known Issues
  marker preservation)
* AppDelegate registers CursorAgent gated on findBinary() and installs
  ~/.cursor/hooks.json (or $CURSOR_CONFIG_DIR) on launch when present
* 25 new tests covering protocol members, autoLaunchCommand for work and
  review sessions, hook event mapping, idempotency, user-key preservation,
  scaffolder roundtrip, full StateSignalSource transition table

No CLI changes needed — crow hook-event --agent and crow new-session
--agent already accept arbitrary agent kinds. CreateSessionView auto-grows
from AgentRegistry.shared.allAgents(), so the picker picks up the third
entry for free.

Closes #417

🐦‍⬛ Generated with Claude Code, orchestrated by Crow

Co-Authored-By: Claude <noreply@anthropic.com>
Crow-Session: 968C71B6-8487-41C2-A841-E982DC017A5F
@dgershman dgershman requested a review from dhilgaertner as a code owner June 3, 2026 23:12
@dgershman dgershman added the crow:merge Crow auto-merge on green label Jun 3, 2026
Copy link
Copy Markdown
Contributor

@dhilgaertner dhilgaertner left a comment

Choose a reason for hiding this comment

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

Code & Security Review

Solid, well-scoped addition. CrowCursor mirrors CrowCodex/CrowClaude faithfully, the dynamic AgentRegistry keeps the picker auto-growing (no UI/CLI changes needed), and the 25 package tests pass locally (swift test --package-path Packages/CrowCursor). One should-fix robustness issue around the chosen launch token, plus a few minor notes.

Note: I could not run the full-app swift build/swift test — the root build needs Frameworks/GhosttyKit.xcframework, which isn't present in this review checkout (error: local binary target 'GhosttyKit' ... does not contain a binary artifact). I verified the CrowCursor package in isolation instead and trust the PR's full-suite results.

Critical Issues

None.

Security Review

Strengths:

  • installGlobalConfig builds hooks.json from a trusted resolved crowPath (ClaudeHookConfigWriter.findCrowBinary()) and hardcoded event names — no untrusted interpolation.
  • CursorLauncher single-quote-escapes the worktree path and prompt-file path; the temp prompt file is written 0o600.
  • No secrets, no injection surface, no auth/crypto concerns.

Concerns:

  • None blocking.

Code Quality

Yellow — launchCommandToken = \"agent\" collides as a substring (CursorAgent.swift:17, consumed at AppDelegate.swift:1840 via command.contains(agent.launchCommandToken)).
prepareAgentLaunchText decides a command "launches the agent" by substring-matching the token. \"claude\"/\"codex\" rarely appear incidentally, but \"agent\" is a common English word. For a Cursor session, any crow send text containing \"agent\" (e.g. a prompt like "refactor the agent registry") is treated as an agent launch and flips terminalReadiness[…] = .agentLaunched.
Practical impact today is small (the OTEL prefix is Claude-only and Cursor's writeHookConfig is a no-op, so the forwarded text is never mutated), but list-terminals exposes readiness to CLI callers like setup.sh (AppDelegate.swift:1437-1448) specifically so they can "verify the agent actually started." A user who crow sends text containing \"agent\" before the bare-agent launch would report .agentLaunched falsely. Recommend anchoring the match (prefix/word-boundary) rather than a bare contains — small fix, removes the footgun the generic token introduces.

Green — supportsRemoteControl = true justification is aspirational (CursorAgent.swift:6-7,66). The comment attributes remote control to stop.followup_message in hooks.json, but generateHooks (CursorHookConfigWriter.swift:66) never writes a followup_message — only command hooks. Crow's actual remote control is crow send into the TUI (SessionService.swift:535, agent-agnostic), so the badge and behavior are correct; only the stated mechanism is inaccurate. Worth aligning the comment with reality (the PR body already flags the headless/empirical unknowns).

Green — scaffolder fallback isn't byte-identical to Codex (CursorScaffolder.swift:54-64 vs CodexScaffolder.swift:44-54). The PR claims byte-identical co-existence. That holds when Resources/AGENTS.md.template is found (the normal path — both reuse it). In the fallback path the two emit different headers ("Cursor Workspace Context" vs "Codex Workspace Context") to the same AGENTS.md. With both agents registered each launch has Codex write then Cursor overwrite — deterministic (Cursor wins, since its block runs after Codex's in AppDelegate), so no real fight, but the "byte-identical" framing only strictly holds when the bundled template exists.

Green — findBinary() path-list vs dependency-check PATH mismatch (CursorAgent.swift:26-48). Registration checks 3 hardcoded paths while the launch-dependency check uses ShellEnvironment.hasCommand(\"agent\") (PATH). A user with agent installed elsewhere won't get Cursor registered yet won't be warned. This mirrors OpenAICodexAgent exactly, so it's a pre-existing accepted pattern — noting only for parity.

Summary Table

Color Meaning Verdict effect
Red Must fix Request changes
Yellow Should fix Request changes
Green Consider Approve allowed

Recommendation: Request Changes — driven by [0 Red, 1 Yellow, 3 Green] findings. The Yellow (anchor the \"agent\" token match) is the only one that needs to land; the Greens are consider-only and fine to fold in or defer.


🐦‍⬛ Reviewed by Crow via Claude Code

…fixes

* Yellow: replace bare command.contains(token) in prepareAgentLaunchText
  with commandLaunchesToken — a shell-word-boundary check anchored at
  start-of-string or after `;`, `&&`, `||`, `|`. Cursor's `agent` token
  collides with English prose; this prevents `crow send "refactor the
  agent registry"` from falsely flipping terminalReadiness = .agentLaunched
  and contaminating list-terminals readiness reporting.
* Green: fix CursorAgent doc comment — remove the aspirational claim that
  remote control rides on `stop.followup_message` in hooks.json. The
  hook writer only emits command hooks; actual remote control is `crow
  send` typing into the TUI (agent-agnostic, in SessionService).
* Green: soften the CursorScaffolder co-existence claim — byte-identical
  only holds when the bundled template is present; the in-source fallback
  strings differ between Codex and Cursor. Document the fallback ordering
  (Cursor wins, runs after Codex in AppDelegate) so the behavior is
  predictable rather than implied.
* Green deferred: findBinary path-list vs ShellEnvironment.hasCommand
  PATH mismatch is a pre-existing accepted pattern (mirrors OpenAICodexAgent
  exactly per the reviewer's own note); deferred for cross-agent consistency.

Adds 13 new tests in Tests/CrowTests/CommandLaunchesTokenTests.swift
covering the Cursor footgun (prose like "agent registry", "--agent flag"),
all known auto-launch shapes (bare, env-prefixed, cd-prefixed for each of
the three agents), and edge cases (empty command, token at end-of-string,
semicolon separator).

Test run: 165 root + 25 CrowCursor + 27 CrowCodex + 37 CrowClaude + 205
CrowCore — all green.

🐦‍⬛ Generated with Claude Code, orchestrated by Crow

Co-Authored-By: Claude <noreply@anthropic.com>
Crow-Session: 968C71B6-8487-41C2-A841-E982DC017A5F
@dgershman
Copy link
Copy Markdown
Collaborator Author

Thanks for the review. Pushed cca3697 addressing the Yellow plus the two actionable Greens:

Yellow — anchored token match. Replaced command.contains(agent.launchCommandToken) in prepareAgentLaunchText with a new commandLaunchesToken helper that does shell-word-boundary matching: token must be at start-of-string or after a shell command separator (;, &&, ||, |, with optional whitespace) and bounded by whitespace, end-of-string, or a quote. Now crow send "refactor the agent registry" and "the --agent flag does X" both correctly stay at .notLaunched. 13 new tests at Tests/CrowTests/CommandLaunchesTokenTests.swift cover the Cursor footgun, all known auto-launch shapes (bare / env-prefixed / cd-prefixed for each of the three agents), and edge cases.

Green #1supportsRemoteControl comment. Fixed. The comment now says remote control rides on crow send typing into the TUI (agent-agnostic, in SessionService) instead of attributing it to a stop.followup_message we never actually write.

Green #2 — scaffolder co-existence framing. Softened the doc comment on CursorScaffolder — byte-identical co-existence only holds when the bundled template is present (the normal path). The in-source fallback strings differ between Codex and Cursor, and with both agents registered Cursor's block runs after Codex's in AppDelegate.launchMainApp, so Cursor wins deterministically. The user-edited ## Known Issues / Corrections section is preserved either way.

Green #3findBinary() PATH mismatch. Deferring per your own note ("mirrors OpenAICodexAgent exactly, so it's a pre-existing accepted pattern — noting only for parity"). A unified path/PATH discovery story is a sensible follow-up across all three agents but feels out of scope for this PR.

Re-requesting review.

🐦‍⬛ Replied with Claude Code via Crow

@dgershman dgershman requested a review from dhilgaertner June 3, 2026 23:28
Copy link
Copy Markdown
Contributor

@dhilgaertner dhilgaertner left a comment

Choose a reason for hiding this comment

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

Code & Security Review

Solid, well-documented package that faithfully mirrors the CrowCodex shape under the CodingAgent protocol. Tests are thorough (25 in CrowCursor, plus the new CommandLaunchesTokenTests), the scaffolder co-existence reasoning is sound, and the camelCase↔PascalCase event collapse into the writer is a clean way to let CursorSignalSource reuse the canonical vocabulary. The commandLaunchesToken anchoring is genuinely needed (crow send prose flows through this gate via the crow send RPC at AppDelegate.swift:1522).

But that same anchoring change regresses the Claude launch path, which is why this is request-changes.

Critical Issues

🔴 commandLaunchesToken breaks hook-config + OTEL injection for Claude managed sessions (regression).

AppDelegate.swift:1840 swapped command.contains(token) for the new anchored commandLaunchesToken. The left boundary only accepts start-of-string or a shell separator [;&|] — it does not accept a path separator /. But by the time a Claude command reaches prepareAgentLaunchText on the standard deferred-launch path (#408), the bare claude token has already been rewritten to an absolute path by resolveClaudeInCommand (AppDelegate.swift:1331, called in new-terminal), e.g. /opt/homebrew/bin/claude --rc …. The resolved command is stored in pendingLaunchCommands (AppDelegate.swift:1379) and later handed to prepareAgentLaunchText by SessionService.pasteDeferredLaunch (SessionService.swift:409).

Empirically:

commandLaunchesToken("/opt/homebrew/bin/claude --rc …", "claude")  -> false   # was true with .contains
commandLaunchesToken("claude --rc",                      "claude")  -> true

claude in /…/bin/claude is preceded by /, which matches neither ^ nor [;&|], so the guard returns (command, false) early — skipping agent.hookConfigWriter.writeHookConfig(...) (the per-worktree .claude/settings.local.json) and the OTEL telemetry env injection at AppDelegate.swift:1843 / 1855-1864.

Impact for a brand-new managed Claude work session (the common path — pasteDeferredLaunch is where new managed terminals paste per #408): hooks are not written for the fresh worktree, so Claude's hook events don't route back to the session and the sidebar activity-state machine (idle/working/done) breaks; OTEL telemetry stops being exported. The other two writeHookConfig call sites (SessionService.swift:279 adopt, :492 launchAgent) only cover restart/recovery, not first launch, and no write happens at worktree creation — so a fresh session has no fallback. The regression only manifests when claude is actually installed at a standard candidate path (SessionService.swift:1819), i.e. the real-user case; if it's not found, resolveClaudeInCommand leaves the token bare and the regex matches — which is likely why the existing suite didn't catch it. (Codex/Cursor are unaffected: their tokens aren't path-rewritten, and their writers are no-ops with no OTEL.)

Suggested fix: add the path separator to the left boundary so a path-prefixed binary still matches while space-preceded prose stays rejected:

let pattern = "(?:^|[;&|]\\s*|/)\(escaped)(?=\\s|$|[\"'])"

"refactor the agent registry" (space-preceded) still correctly returns false. Please add a CommandLaunchesTokenTests case for the absolute-path shape (/opt/homebrew/bin/claude --rc, /usr/local/bin/agent) to lock this in.

Security Review

Strengths:

  • CursorLauncher.launchCommand writes the prompt temp file 0o600 and shell-escapes both the worktree path and prompt path via single-quote wrapping; the $(cat …) substitution is double-quoted, so no word-splitting/injection (CursorLauncher.swift:350-362).
  • installGlobalConfig merges rather than clobbers — user-authored hook entries for events outside eventMapping are preserved (CursorHookConfigWriter.swift:256-278); covered by installGlobalConfigPreservesUserEntries.
  • Hook commands carry no session-derived interpolation — cwd-based resolution server-side, no --session injection surface.

Concerns: none beyond the critical issue above.

Code Quality

  • 🟢 AppDelegate.swift:1096 adds agent to the runtime-dependency probe list. Since agent is a generic name, every machine without Cursor now surfaces it in the missing-tools warning — consistent with how codex/glab/code are already listed, so acceptable, but worth a glance.
  • 🟢 CursorScaffolder fallback string ("Cursor Workspace Context") differs from Codex's, so when the bundled template is absent the two scaffolders rewrite AGENTS.md on each launch (Codex then Cursor). Idempotent and the user ## Known Issues / Corrections section is preserved, so harmless — already acknowledged in the doc comment.
  • 🟢 CursorLauncher / launchCommand are not yet wired into the auto-launch path (MVP launches bare agent); fine as documented, just dead-until-follow-up.

Summary Table

Color Meaning Verdict effect
Red Must fix Request changes
Yellow Should fix Request changes
Green Consider Approve allowed

Recommendation: Request Changes — driven by [1 Red, 0 Yellow, 3 Green] findings. The Cursor package itself is in good shape; the blocker is the collateral regression the shared commandLaunchesToken change introduces on the Claude path.

Note: full swift build couldn't run here (the vendored GhosttyKit.xcframework binary artifact is absent in this checkout); swift test in Packages/CrowCursor passes all 25 tests.

🐦‍⬛ Reviewed by Crow via Claude Code

dgershman and others added 2 commits June 3, 2026 20:42
cca3697's anchored regex rejected /opt/homebrew/bin/claude because `/`
wasn't a recognized left boundary. resolveClaudeInCommand rewrites the
bare `claude` token to an absolute path before pasteDeferredLaunch hands
the command to prepareAgentLaunchText (the standard #408 path for
brand-new managed Claude sessions), so the guard returned (command, false)
early and silently skipped both writeHookConfig (per-worktree
.claude/settings.local.json) and the OTEL env injection. Hooks didn't
route back to the session, sidebar idle/working/done state broke, and
telemetry stopped exporting.

Adds `/` to the left-boundary alternation:
  (?:^|[;&|]\s*|/)<token>(?=\s|$|["'])

The right boundary stays at \s|$|["'], so incidental path substrings
like /tmp/agent_log still reject (token followed by `_`, not a boundary
char). Codex and Cursor weren't impacted — their tokens aren't path-
resolved, and their writers are no-ops with no OTEL — which is why the
existing suite didn't catch it.

Adds 5 tests covering:
- /opt/homebrew/bin/claude --rc --name 'foo'
- /usr/local/bin/claude --rc
- /opt/homebrew/bin/agent (Cursor)
- env-prefixed path-resolved Claude (the full pasteDeferredLaunch shape)
- /tmp/agent_log negative case (confirms `/` doesn't open the door to
  incidental path substrings)

🐦‍⬛ Generated with Claude Code, orchestrated by Crow

Co-Authored-By: Claude <noreply@anthropic.com>
Crow-Session: 968C71B6-8487-41C2-A841-E982DC017A5F
@dgershman
Copy link
Copy Markdown
Collaborator Author

Good catch — the anchored regex broke Claude's deferred-launch path. Fixed in 759bb4d.

The bug. resolveClaudeInCommand rewrites bare claude/opt/homebrew/bin/claude before the command reaches prepareAgentLaunchText via pasteDeferredLaunch (the standard #408 path for brand-new managed sessions). My regex's left boundary (?:^|[;&|]\s*) rejected the path-prefixed token because / is neither start-of-string nor a shell separator, so the guard returned early and silently skipped both writeHookConfig (per-worktree .claude/settings.local.json) and the OTEL env injection. Cursor/Codex weren't impacted because their tokens aren't path-resolved and their writers are no-ops with no OTEL — which is exactly why my original test suite didn't catch it.

The fix. Took your suggested boundary verbatim:

let pattern = "(?:^|[;&|]\\s*|/)\(escaped)(?=\\s|$|[\"'])"

The right boundary stays at \s|$|["'], so an incidental path substring like /tmp/agent_log still rejects (token followed by _, not a boundary char). Added 5 new tests at CommandLaunchesTokenTests.swift:

  • /opt/homebrew/bin/claude --rc --name 'foo' → match
  • /usr/local/bin/claude --rc → match
  • /opt/homebrew/bin/agent → match
  • env-prefixed + path-resolved Claude (the full deferred-launch shape) → match
  • tail -f /tmp/agent_log (path with token as substring) → reject

All 170 root tests + 25 CrowCursor tests still green. Rebased onto the auto-merge from main (d370968) before pushing.

Re-requesting review.

🐦‍⬛ Replied with Claude Code via Crow

@dgershman dgershman requested a review from dhilgaertner June 4, 2026 00:55
Copy link
Copy Markdown
Contributor

@dhilgaertner dhilgaertner left a comment

Choose a reason for hiding this comment

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

Code & Security Review

Lands Cursor as a third CodingAgent conformer. The change is tightly scoped, faithfully mirrors the established Codex/Claude patterns, and is well-tested. Verified locally: CrowCursor package builds and all 25 package tests pass; the new commandLaunchesToken regex validated independently against all 18 documented cases (18/18 pass), including the path-resolved-binary regression fixed in 759bb4d. (The full-app swift build couldn't run here due to a missing local GhosttyKit.xcframework artifact — an environment issue, not a code problem.)

Critical Issues

None.

Security Review

Strengths:

  • CursorLauncher.launchCommand shell-escapes both the worktree path and the prompt-file path via single-quote wrapping (shellEscape), and writes the prompt temp file 0o600. No injection surface from session data.
  • installGlobalConfig builds hooks.json via JSONSerialization (no string concatenation of untrusted data into JSON) and merges conservatively — user-authored entries for events outside eventMapping survive, matching CodexHookConfigWriter exactly.
  • No secrets handled; Cursor reads CURSOR_API_KEY from the inherited shell, nothing logged.

Concerns:

  • None blocking.

Code Quality

  • commandLaunchesToken is the one piece of non-trivial new logic and it's the right fix: anchoring agent at start / shell-separator / / boundary prevents the .contains("agent") footgun on crow send prose. Anchor + the regression-driven / left boundary are both covered by tests.
  • AppDelegate Cursor block (registration + scaffold + global-config install) is a line-for-line mirror of the Codex block, gated on AgentRegistry.shared.agent(for: .cursor) and ordered deterministically after Codex's scaffold so the shared AGENTS.md write is idempotent.
  • Per-session HookConfigWriter methods are documented no-ops (Cursor is global-only) — consistent with Codex.

Green (consider — non-blocking)

  • Residual agent false-positive surface. The anchor still matches agent after / or a shell separator, so crow send prose like tail /var/agent or build | agent to a Cursor session could flip terminalReadiness = .agentLaunched. Impact is minimal (Cursor's writeHookConfig is a no-op and no text mutation occurs for non-Claude agents — only a wrong readiness flag), and the / boundary is genuinely required for path-resolved binaries. Acceptable tradeoff; flagging only for awareness.
  • Binary-detection mechanisms differ. findBinary() checks 3 hardcoded paths while the launch-time dependency check uses PATH (hasCommand("agent")), so the two can disagree. Pre-existing pattern shared with Codex — not introduced here.
  • .job sessions return nil from autoLaunchCommand (work-only guard). Identical to Codex; the inline comment only mentions review sessions, so a one-word mention of job sessions would round out the doc. Cosmetic.
  • Empirical unknowns (headless agent -p firing ~/.cursor/hooks.json, real exit codes) are explicitly deferred per the ticket, with afterAgentResponse → Notification as a documented safety net.

Summary Table

Color Meaning Verdict effect
Red Must fix Request changes
Yellow Should fix Request changes
Green Consider Approve allowed

Recommendation: Approve — driven by [0 Red, 0 Yellow, 4 Green] findings. Clean, well-tested, and faithful to the existing multi-agent architecture.

🐦‍⬛ Reviewed by Crow via Claude Code

@dgershman dgershman merged commit da02b48 into main Jun 4, 2026
2 checks passed
@dgershman dgershman deleted the feature/crow-417-cursor-agent branch June 4, 2026 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crow:merge Crow auto-merge on green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Cursor as a third agent under the CodingAgent protocol (mirrors PR #197 Phase C)

2 participants