Skip to content

feat: add verified local cursor harness and runtime integration#714

Open
abojja9 wants to merge 7 commits into
kunchenguid:mainfrom
abojja9:fm/cursor-adapter-refresh-h4
Open

feat: add verified local cursor harness and runtime integration#714
abojja9 wants to merge 7 commits into
kunchenguid:mainfrom
abojja9:fm/cursor-adapter-refresh-h4

Conversation

@abojja9

@abojja9 abojja9 commented Jul 18, 2026

Copy link
Copy Markdown

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:

  1. shared global-hook installation is atomic under concurrent spawns (mktemp+chmod+rename plus a bounded lock), and
  2. the shared hook artifacts are deterministically removed after the final Cursor task's token is gone, with every uncertain path skipping cleanup safely.

Design elements adopted from overlapping Cursor PRs, with credit: end-anchored busy signature (#491, @cybercat-yanik), --approve-mcps at worker launch (#446, @dilipgv), harness-env-marker test hygiene (#474, @valenzmanu), and never matching the generic agent binary (#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

  • Adds verified local cursor harness support across Firstmate runtime flow, including spawn/supervision wiring, user-level Cursor hook management via new bin/fm-cursor-lib.sh, and turn-end guard integration for Cursor-backed tasks.
  • Hardens liveness and bootstrap behavior for Cursor sessions by trusting dead verdicts only on tmux-verified process signals and otherwise downgrading to inconclusive, reducing false teardown/recovery actions on non-tmux backends.
  • Expands documentation and test coverage for Cursor adapter behavior, including new Cursor harness E2E coverage plus updates to session-start, supervision, tmux/backend, and pretool-check guidance to reflect fail-open hook handling and current runtime behavior.

Risk Assessment

✅ Low: Captain, the diff from bc1a21b2ccfcd500ae29181f82b28b6cf1075bfb to 9d36b167a51aabbeb07ba4ae3e964e5a1582b436 appears 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.

  • Outcome: ⚠️ 1 error across 4 runs (1h37m57s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

⚠️ **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: Stabilize flaky watcher lock restart test timing
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"

🔧 Fix: Stabilize watcher restart test by accepting healthy timeout
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"

🔧 Fix: Stabilize watcher restart test timeout exit handling
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** - 1 warning
  • ⚠️ linter found issues (exit code 127)

🔧 Fix: lint blocked by missing shellcheck binary
1 warning still open:

  • ⚠️ linter found issues (exit code 127)

🔧 Fix: Captain, lint blocked by missing shellcheck binary
1 warning still open:

  • ⚠️ linter found issues (exit code 127)

🔧 Fix: Captain, lint blocked by missing shellcheck binary
1 warning still open:

  • ⚠️ linter found issues (exit code 127)
✅ **Push** - passed

✅ No issues found.

@kunchenguid

kunchenguid commented Jul 19, 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#714 at 858ed44f.

shawnpetros and others added 6 commits July 19, 2026 14:35
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
abojja9 force-pushed the fm/cursor-adapter-refresh-h4 branch from 858ed44 to 20029e2 Compare July 19, 2026 09:05
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.

3 participants