feat: add verified local Cursor harness support#609
Open
shawnpetros wants to merge 3 commits into
Open
Conversation
shawnpetros
marked this pull request as ready for review
July 15, 2026 17:01
4 tasks
Author
|
The no-mistakes gate and CI are green on this. The only thing left is the fork-PR workflows sitting in action_required: they need a maintainer to approve-and-run so the required checks complete. Could you approve the workflow runs when you get a minute? Thanks. |
shawnpetros
force-pushed
the
fm/cursor-harness-c11
branch
from
July 16, 2026 02:44
9b77ef9 to
9411716
Compare
Support local Cursor primary sessions and workers with empirically verified hooks, lifecycle detection, supervision, and focused regression coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
shawnpetros
force-pushed
the
fm/cursor-harness-c11
branch
from
July 16, 2026 11:12
9411716 to
24cf32a
Compare
Owner
|
Automated reminder: thanks for the PR! This branch currently has a merge conflict with the base branch. When you get a chance, please rebase onto (or merge) the latest base branch, resolve the conflict, and push. After that, checks will re-run and the PR will get looked at again. Noted for firstmate#609 at |
5 tasks
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
Add verified local Cursor harness support to firstmate (PR #609, branch fm/cursor-harness-c11). Firstmate can now run local Cursor sessions as both a primary and a worker through the existing adapter and backend contracts: the adapter detects cursor-agent specifically, launches workers with the verified local CLI flags, adds project hooks for primary supervision, and uses a token-scoped fallback for worker turn-end signals because Cursor Agent 2026.07.09 does not execute plugin stop hooks yet. Live process, TUI, interrupt, resume, and hook evidence is recorded in the existing docs. Scope is deliberately local-only: no Cursor Cloud, web dashboard, My Machines, ACP, SDK, or API-backed runtime support. The implementation is complete and was already validated by a prior task: current origin/main (e063ca5) was merged into the branch (merge commit f629515) resolving two conflicts to keep Cursor dispatch alongside upstream Pi max-effort support; the full 72-script behavior suite passed 71/1 with the single failure (tests/fm-watch-checkpoint.test.sh) reproducing identically on origin/main, so it is a pre-existing flake, not a Cursor regression; canonical lint (bin/fm-lint.sh, ShellCheck 0.11.0) passed. This run exists to put the legitimate no-mistakes gate signature on the existing PR 609 so its 'PR must be raised via no-mistakes' check passes. The known upstream checkpoint-test flake and the AFK lifecycle timing flake are pre-existing on main and deliberate non-goals here.
What Changed
fm-spawn.shand the harness adapter now detectcursor-agentand dispatch it as both a primary and a worker: workers launch with the verified local CLI flags, primaries get project-level.cursor/hooks.jsonsupervision hooks, and tmux backend, bootstrap, lock, and teardown paths handle the new harness.bin/fm-turnend-guard-cursor.shplus a merged~/.cursor/hooks.jsonstop entry); teardown removes the per-task auth token while the fail-open shared hook persists by design.tests/fm-cursor-harness.test.sh, spawn dispatch, supervision instructions, pretool checks).Risk Assessment
✅ Low: Purely additive harness adapter that follows the repo's established per-harness patterns, with careful token-scoped/fail-open design for the one global side effect, thorough new tests, live verification evidence in docs, and a correct merge resolution against upstream Pi support; no correctness, security, or intent-conformance defects found.
Testing
Completed 1 recorded test check.
The recorded error is the full 72-script behavior suite exiting 1 on two known cases, both re-verified during the gate's fix round with no code changes needed:
tests/fm-watch-checkpoint.test.sh("watch lock pid survived quiet checkpoint timeout") fails identically on currentorigin/main(e063ca5); it is pre-existing upstream and out of scope for this PR.tests/fm-afk-inject-e2e.test.shScenario C failed once on the initial run and passed on the gate's rerun (its herdr variant passed in both runs); it is the documented AFK-injection timing flake, not a Cursor regression.All other 70 test scripts passed in both runs.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
bin/fm-spawn.sh:956- The shared user-level fallback hook ~/.cursor/hooks/fm-turn-end.sh is rewritten in place withcat >on every cursor spawn, leaving a small truncate-while-exec window against a concurrently stopping cursor session. Content is identical across rewrites and the hook is fail-open, and this mirrors the existing grok idiom (bin/fm-spawn.sh:1039), so impact is a rare missed turn-end signal the watcher's staleness path already tolerates. A mktemp+mv write (as already done for hooks.json two lines below) would eliminate the window if ever hardened.bin/fm-teardown.sh:176- Teardown removes only the per-task auth token (remove_cursor_turnend_auth) and plugin dir; the user-level ~/.cursor/hooks/fm-turn-end.sh script and its merged stop entry in ~/.cursor/hooks.json persist indefinitely after the last cursor task ends. This is documented as the deliberate additive design (the hook no-ops without a registered token) and matches the grok global-hook pattern, but it is permanent global config growth outside firstmate's own tree.command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"🔧 Fix: confirm both test failures pre-existing flakes, no changes
1 error still open:
command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.