feat: add verified local cursor harness and runtime integration#714
Open
abojja9 wants to merge 7 commits into
Open
feat: add verified local cursor harness and runtime integration#714abojja9 wants to merge 7 commits into
abojja9 wants to merge 7 commits into
Conversation
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#714 at |
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>
…idence - Re-verify the adapter live on Cursor Agent 2026.07.16-899851b: hook execution is server-gated per account (no project, user, Claude-compat, or plugin hooks execute for an ungated account), the busy signature is now an end-anchored 'ctrl+c to stop' footer, /quit exits cleanly, and liveness argv evidence still holds on both the macOS comm and node paths. Docs record both dated readings. - Add bin/fm-cursor-lib.sh as the single owner of the shared user-level turn-end hook artifacts: atomic mktemp+mv hook install, bounded mkdir lock serializing concurrent spawns and teardowns, and deterministic last-token cleanup that removes the hook script, Firstmate's own hooks.json stop entry, and the empty registry after the final Cursor task while never rewriting a malformed hooks.json. - Register the shared session-start nudge on Cursor's bundle-confirmed sessionStart hook event, documented fail-open like Grok's. - Launch workers with --approve-mcps so MCP trust prompts cannot wedge an unattended worker; extend busy regexes, dispatch tests, nudge registration tests, and cursor lib contract tests.
Only tmux's argv0-based pane classifier is verified to read a live node-wrapped cursor-agent; herdr's native agent registry is unverified for cursor-agent, so a non-tmux cursor dead reading downgrades to inconclusive instead of authorizing a respawn over a possibly-live agent. Covered by a faked-herdr sweep regression test.
fm-teardown.sh now sources bin/fm-cursor-lib.sh for Cursor turn-end auth cleanup, and fm-gotmp.test.sh's fake roots enumerate every lib teardown sources, so the missing symlink made teardown exit non-zero under set -eu. Mirrors how fm-pr-lib.sh was added to the same fixtures.
abojja9
force-pushed
the
fm/cursor-adapter-refresh-h4
branch
from
July 19, 2026 09:05
858ed44 to
20029e2
Compare
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.
Attribution: refresh of PR #609
This PR refreshes #609 by @shawnpetros onto current
main.PR 609's two implementation commits are cherry-picked with their original authorship preserved.
A new branch was necessary because PR 609's head lives on the contributor's fork (which we are not authorized to push to), the branch has a merge conflict with the current base, and the refresh required substantive reconciliation with contracts that landed after its base (native session-start nudges #687, silent bootstrap confirmations, secondmate vocabulary #685).
It resolves PR 609's two open review concerns via the new
bin/fm-cursor-lib.sh:Design elements adopted from overlapping Cursor PRs, with credit: end-anchored busy signature (#491, @cybercat-yanik),
--approve-mcpsat worker launch (#446, @dilipgv), harness-env-marker test hygiene (#474, @valenzmanu), and never matching the genericagentbinary (#400, @vitalNohj).New live evidence was collected on the pinned current Cursor Agent 2026.07.16-899851b (2026-07-18); notably, hook execution proved to be server-gated per account, so every Cursor hook integration is documented and engineered strictly fail-open. Details in
docs/turnend-guard.md.Intent
Refresh PR 609 (shawnpetros) onto current main: verified local Cursor Agent CLI (cursor-agent) harness for Firstmate workers/primaries/secondmates. PR 609's commits are cherry-picked with authorship preserved; new branch because the fork PR is conflicted and we lack push rights there. Resolves PR 609's two review concerns via new bin/fm-cursor-lib.sh: atomic (mktemp+mv) locked install of the shared user-level turn-end hook, and deterministic last-task cleanup of hook script + hooks.json entry + token registry; uncertain paths (lock timeout, malformed hooks.json) deliberately skip ALL shared cleanup, never rewrite user config; token removal deliberately precedes cleanup. Live evidence on Cursor Agent 2026.07.16-899851b (2026-07-18): hook execution is server-gated per account (none fire for this account; PR 609's 2026-07-14 evidence had them firing), so ALL Cursor hook integrations (turn-end guard, seatbelts, sessionStart nudge, worker fallback) are deliberately fail-open with watcher staleness supervision as the working mechanism. Busy signature is now end-anchored 'ctrl+c to stop' (plus legacy 'Running N tokens'); deliberately not tightened further. Workers launch cursor-agent --force --approve-mcps --workspace with task plugin; deliberately no standalone effort flag (Cursor has none). Cursor dead liveness verdicts trusted only on tmux's verified argv0 classifier; other backends downgrade to inconclusive. Detection stays ancestry-based; CURSOR_AGENT env deliberately unused (inherited-env ambiguity). Expected baseline test failures NOT to fix (captain's explicit direction, reproduce on clean main): fm-brief 'persistent domain supervisor' assertion (broken by #685) and fm-cd-pretool-check unguarded shellcheck on hosts without shellcheck. Environment-dependent e2e failures on this host (afk-inject timing flake, real-herdr pane_input_pending, treehouse-pool-contention spawn timeouts) are host conditions, not regressions - all passed in a clean local full-suite run of this code. Push goes through the abojja9/firstmate fork; PR targets kunchenguid/firstmate. Scope is local cursor-agent only.
What Changed
cursorharness support across Firstmate runtime flow, including spawn/supervision wiring, user-level Cursor hook management via newbin/fm-cursor-lib.sh, and turn-end guard integration for Cursor-backed tasks.Risk Assessment
✅ Low: Captain, the diff from
bc1a21b2ccfcd500ae29181f82b28b6cf1075bfbto9d36b167a51aabbeb07ba4ae3e964e5a1582b436appears cohesive and defensive, with no substantiated correctness, security, or reliability regressions identified in the changed paths during this review pass.Testing
Completed 1 recorded test check.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
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: Stabilize flaky watcher lock restart test timing
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"🔧 Fix: Stabilize watcher restart test by accepting healthy timeout
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"🔧 Fix: Stabilize watcher restart test timeout exit handling
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.
🔧 Fix: lint blocked by missing shellcheck binary
1 warning still open:
🔧 Fix: Captain, lint blocked by missing shellcheck binary
1 warning still open:
🔧 Fix: Captain, lint blocked by missing shellcheck binary
1 warning still open:
✅ **Push** - passed
✅ No issues found.