feat: add cursor-agent (Composer 2.5) as a verified crew harness - #9
Merged
Conversation
Onboard cursor-agent as a directly-driven crew harness (grok/kimi Shape A: interactive pane plus native beforeSubmitPrompt/stop user hooks), slotting into the existing adapter machinery with no cursor-special path. - fm-harness.sh: cursor process-ancestry detection. - fm-spawn.sh: launch template (--force --trust --model, no effort flag, no trailing command so the pane reports cursor-agent), pre-pane hook install, busy-gen arming, the per-task registry entry and worktree pointer, and a per-worktree .cursor/cli.json that neutralizes commit/PR agent attribution without editing the shared global cli-config.json. - fm-cursor-turnend-hook.sh (new): idempotent, foreign-preserving install of the firstmate-owned ~/.cursor/hooks.json entries plus a guarded hook that writes cursor-hook busy/idle events and dedupes the stop interrupt double-fire by generation_id. - fm-busy-lib.sh: cursor-hook semantic source and the open fm_busy_cursor_verified gate. - fm-composer-lib.sh and fm-tmux-lib.sh: the dim cursor composer glyph (U+2192). - bin/backends/tmux.sh and fm-session-lock-lib.sh: cursor-agent liveness and identity. - fm-teardown.sh: cursor pointer, registry entry, stop-dedupe dir, state token, and cli.json cleanup. - harness-adapters/SKILL.md, docs/verification/runtime-backends.md, AGENTS.md: verified cursor facts and the verified-adapter list. Tests: new tests/fm-cursor-harness.test.sh plus cursor cases in the composer, busy-wiring, and tmux-liveness suites.
Quidge
added a commit
that referenced
this pull request
Aug 5, 2026
…sor for crew-dispatch (#10) * fix(cursor): repair non-functional attribution neutralization and register cursor for crew-dispatch The freshly-landed cursor-agent adapter (PR #9) crashed at launch and could not be routed via crew-dispatch. Two cursor-scoped, additive/corrective fixes: Defect 1 (fatal): fm-spawn wrote a project .cursor/cli.json carrying `{"version":1,"attribution":{...}}`. cursor-agent validates that project config against a strict schema that accepts only `permissions`, so it rejected `version`/`attribution` with "Unrecognized key(s)" and dropped the pane to a bash prompt; the worker never started (the `attribution` block is only valid in the GLOBAL ~/.cursor/cli-config.json, which cursor rewrites at runtime and shares across workers). There is no CLI flag or env var to disable attribution. Replace it with a per-task git commit-msg hook that strips cursor's `Co-authored-by: Cursor <cursoragent@cursor.com>` trailer, reached only by the cursor worker through an env-injected core.hooksPath (git resolves a linked worktree's hooks from the shared common dir, so a per-worktree hooks dir would not fire). The hook lives under state/, touches no cursor config, never races a concurrent worker, preserves human co-authors, and is removed at teardown. Defect 2 (minor): add cursor to the crew-dispatch verified-harness set in fm-bootstrap so a config/crew-dispatch.json routing work to cursor validates clean, and treat cursor like opencode/kimi in effort validation (it has no effort flag). Scoped to crewmate/scout-facing lists only; the remote-secondmate lists and secondmate-liveness gate correctly continue to omit cursor, which was verified only as a local crewmate. Tests: rework the cursor-harness attribution tests to cover the commit-msg hook (trailer stripped, human co-authors and clean messages preserved) and the core.hooksPath env wiring, and to assert the crash-inducing .cursor/cli.json is no longer written; add crew-dispatch cases for cursor. Docs: correct the attribution mechanism in harness-adapters and record the live crash/fix proof. * no-mistakes: apply CI fixes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Integrate cursor-agent (Cursor Composer 2.5, non-fast) as a verified firstmate crew harness using Shape A: an interactive tmux-pane worker driven directly like the grok/kimi adapters (NOT ACP), with turn lifecycle from cursor's native beforeSubmitPrompt and stop user hooks. This is standard harness onboarding that slots into the existing adapter machinery; there is deliberately NO cursor-special dispatch or supervision path, and the change is additive with no behavior change for any existing harness.
Change sites and the deliberate decisions behind them (so review can tell intent from mistakes):
Deliberately OUT OF SCOPE (firstmate owns these after merge; do not flag as missing): config/crew-dispatch.json routing (that file is LOCAL and gitignored), and the downstream supervised cursor test-drive. Known limitation: the LIVE trailer-free-commit proof needs an interactive cursor worker a crewmate cannot launch in its own pane, so it is captured in that downstream test-drive; the neutralization mechanism itself is implemented and unit-tested.
Tests added mirror the grok/kimi adapters: new tests/fm-cursor-harness.test.sh (launch template, hook guard, busy lifecycle, stop double-fire dedupe, teardown, attribution cli.json, detection, session lock) plus cursor cases in tests/fm-composer-lib.test.sh, tests/fm-composer-ghost.test.sh, tests/fm-busy-adapter-wiring.test.sh, and tests/fm-tmux-agent-liveness.test.sh.
What Changed
cursor-agent(Cursor Composer 2.5, non-fast) as an interactive tmux-pane crew harness driven like the grok/kimi adapters: added detection bycursor-agentprocess ancestry infm-harness.sh, acursor-agent --force --trust --model <m> "<brief>"launch template infm-spawn.shwith cursor added to the spawn accept-lists,--modellist, session-lock identity lists, and the tmux/backend alive-sets.fm-cursor-turnend-hook.shidempotently installs firstmate-ownedbeforeSubmitPrompt(busy) andstop(idle) entries into the shared~/.cursor/hooks.json(preserving other keys, refusing malformed/symlinked files), guarded per task byworkspace_roots[]token matching and deduping the double stop-fire bygeneration_id;fm-busy-lib.shgains the cursor-hook busy source behind an openedfm_busy_cursor_verifiedgate, andfm-composer-lib.sh/fm-tmux-lib.shclassify cursor's dim U+2192 prompt glyph as idle-empty..cursor/cli.jsonoverride;fm-teardown.shremoves the cursor pointer, registry entry, stop-dedupe dir, state token, andcli.json. Documented the verified facts in the harness-adapters skill,runtime-backends.md,configuration.md, andAGENTS.md, and addedtests/fm-cursor-harness.test.shplus cursor cases across the composer, ghost, busy-wiring, and liveness test suites.Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ **Rebase** - passed
✅ **Review** - completed
✅ **Document** - passed
✅ **Lint** - passed
✅ **Push** - passed