Skip to content

feat: add verified local Cursor harness support#609

Open
shawnpetros wants to merge 3 commits into
kunchenguid:mainfrom
shawnpetros:fm/cursor-harness-c11
Open

feat: add verified local Cursor harness support#609
shawnpetros wants to merge 3 commits into
kunchenguid:mainfrom
shawnpetros:fm/cursor-harness-c11

Conversation

@shawnpetros

@shawnpetros shawnpetros commented Jul 15, 2026

Copy link
Copy Markdown

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.sh and the harness adapter now detect cursor-agent and dispatch it as both a primary and a worker: workers launch with the verified local CLI flags, primaries get project-level .cursor/hooks.json supervision hooks, and tmux backend, bootstrap, lock, and teardown paths handle the new harness.
  • Because Cursor Agent 2026.07.09 does not execute plugin stop hooks, worker turn-end signaling falls back to a token-scoped user-level hook (bin/fm-turnend-guard-cursor.sh plus a merged ~/.cursor/hooks.json stop entry); teardown removes the per-task auth token while the fail-open shared hook persists by design.
  • Docs (supervision protocol, tmux backend, turnend guard, arm pretool check, harness inventories) add Cursor coverage with live-verified evidence, and new/extended tests cover the Cursor harness end to end (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.

  • Outcome: ⚠️ 1 error across 2 runs (51m47s)

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 current origin/main (e063ca5); it is pre-existing upstream and out of scope for this PR.
  • tests/fm-afk-inject-e2e.test.sh Scenario 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.

⚠️ **Review** - 2 infos
  • ℹ️ bin/fm-spawn.sh:956 - The shared user-level fallback hook ~/.cursor/hooks/fm-turn-end.sh is rewritten in place with cat > 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.
⚠️ **Test** - 1 error
  • 🚨 tests failed with exit code 1
  • 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:

  • 🚨 tests failed with exit code 1
  • 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.

@shawnpetros
shawnpetros marked this pull request as ready for review July 15, 2026 17:01
@shawnpetros shawnpetros changed the title feat: add verified local Cursor harness feat: add verified local Cursor harness support Jul 15, 2026
@shawnpetros

Copy link
Copy Markdown
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
shawnpetros force-pushed the fm/cursor-harness-c11 branch from 9b77ef9 to 9411716 Compare July 16, 2026 02:44
shawnpetros and others added 2 commits July 16, 2026 03:58
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
shawnpetros force-pushed the fm/cursor-harness-c11 branch from 9411716 to 24cf32a Compare July 16, 2026 11:12
@kunchenguid

kunchenguid commented Jul 16, 2026

Copy link
Copy Markdown
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 67f82e9f.

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