Shipmoor plugs into Cursor on the same three levels it does for Claude: the CLI is the scan engine, Agent Skills tell the agent to scan and triage, and the Agent Harness closes the loop, re-scanning on each edit and gating before the agent finishes. Since 0.5.1, Cursor is a first-class native adapter: the harness writes a real .cursor/hooks.json backed by Cursor’s own lifecycle hooks, at parity with the Claude Stop hook. This page covers the supported single-repo install first, then a clearly-labeled advanced pattern for multi-root workspaces.
The native single-repo adapter is the primary, supported path. Multi-root is an advanced setup you assemble yourself because of a Cursor limitation described below.
Prerequisites
Same as the Claude Code page:
- CLI
shipmoor version≥0.5.1. The harness is bundled into the binary; you invoke it asshipmoor harness <cmd>. - Entitlements.
shipmoor capabilitiesshould showagent_harnessenabled (the IC plan). Check identity withshipmoor whoami; sign in withshipmoor login. - git in the repo:
scan --changedneeds a repo to diff. - Cursor recent enough to ship the
.cursor/hooks.jsonlifecycle-hook surface.
shipmoor version
shipmoor capabilities
shipmoor whoami
Install the skills
Install the five skills into Cursor’s rule surface:
shipmoor skills install cursor
This writes .cursor/rules/shipmoor.md, an always-applied managed rule (re-running the install overwrites it byte-for-byte). It teaches the agent the five Shipmoor behaviors:
| Skill | What it makes the agent do |
|---|---|
shipmoor-review | Run scan --changed, triage, explain blockers, gate before “done”. |
shipmoor-agent-guard | Inspect manifests first; never invent imports or APIs; no placeholder logic. |
shipmoor-intent-contract | Provide the change’s intent and check the result against it (Claim Check). |
shipmoor-fix | Repair only introduced findings, re-scan until the gate passes, report the delta. |
shipmoor-pr-preflight | Diff-scoped “am I ready to open this PR?” with a copyable PR note. |
Skills make the agent want to scan; the harness makes the scan happen and gates the result. Run both. See Agent Skills for the full surface.
Advisory code review with Cursor
Cursor is also a built-in reviewer for Shipmoor Code Review, the advisory AI review that sits next to the deterministic scan above:
shipmoor review --agent cursor --from main --to HEAD
This drives your own cursor-agent CLI in read-only mode (--mode ask, no file edits) over the change and reports advisory findings. It is Pro (cli_pro), it never gates the build, and your source never leaves the machine. Override the underlying command with SHIPMOOR_REVIEW_CURSOR_CMD. See Bring your own agent for the wire contract and the claude, codex, and cursor presets.
Install the harness (single repo)
When you open a single repo as its own Cursor workspace, the native adapter is the whole setup:
shipmoor harness install cursor
This writes a real .cursor/hooks.json with two managed entries beside any hooks you already have (yours are never touched). The shape:
{
"version": 1,
"// shipmoor:harness": {
"note": "Managed by shipmoor-harness (Cursor adapter). Uninstall removes these entries."
},
"hooks": {
"afterFileEdit": {
"command": "shipmoor harness hook cursor after-file-edit"
},
"stop": {
"command": "shipmoor harness hook cursor stop"
}
}
}
The top-level "version": 1 is required for Cursor to load the hooks. The sibling "// shipmoor:harness" key records provenance so shipmoor harness uninstall cursor removes exactly what was added and a reinstall stays byte-idempotent.
What each hook does
afterFileEditruns after the agent edits a file. Cursor gives this event no channel back to the agent, so the handler only records: it runs onescan --changedpass and refreshes.shipmoor/last-watch.json. The skills/adapter rule then tells the agent to read that report; Shipmoor surfaces the report rather than pushing it back inline.stopruns when the agent tries to finish. This is the gating event. It scans the repo’s Git changes; infeedbackorblockmode, on routable findings it returns{"followup_message": "..."}, which Cursor auto-submits as the next user turn so the agent keeps fixing. Infeedbackmode the loop is bounded bymax_feedback_cycles(Cursor passes itsloop_count, and Cursor independently enforces its ownloop_limit); inblockmode a breach always gates, the direct analogue of the Claude Stop hook returning a non-zero exit every time.
Soft fallback
If you decline native hooks, install the rules-only fallback:
shipmoor harness install cursor --soft
This writes only .cursor/rules/shipmoor-harness.md, a fully managed adapter rule, no native hooks. The agent gets feedback through that rule instead, off a last-watch.json report. The --soft install never touches .cursor/rules/shipmoor.md (the skills file); they are separate surfaces. Installing one harness mode migrates away from the other; uninstall removes both.
Choose a mode and verify
Start in feedback so blockers loop back to the agent without hard-failing:
shipmoor harness mode feedback
shipmoor harness status
| Mode | Behavior |
|---|---|
observe | Reports only; never changes the outcome (safest start). |
feedback | Loops blockers back to the agent, bounded by max_feedback_cycles (the default). |
block | Non-zero verdict on a gate breach (firmest; pair with CI). |
Why one-shot scans, not a daemon? Native Cursor hooks running a one-shot (
shipmoor harness scanorshipmoor scan --changed) are deterministic and tied to the agent lifecycle, the same shape as the Claude Stop hook, with no long-lived process to babysit. Through 0.5.1 a detachedwatchdaemon was not reliably keep-alive-able for hook use, so the one-shot supersedes it for the loop.
Advanced: multi-root workspaces
This section is an advanced, self-assembled pattern. If you open one repo as its own workspace, use the native adapter above and skip this.
The catch. Cursor executes only the workspace-root .cursor/hooks.json. It does not discover nested per-repo hooks.json the way it discovers nested rules. So a per-repo shipmoor harness install cursor run inside a subfolder writes <repo>/.cursor/hooks.json that never fires from a multi-root root.
The pattern. Keep one root-level, self-extending hook set that fans out to every opted-in repo, with each hook calling the CLI one-shot. A compact root .cursor/hooks.json:
{
"version": 1,
"hooks": {
"afterFileEdit": [
{ "command": ".cursor/hooks/shipmoor-scan-edit.sh", "timeout": 30 }
],
"stop": [
{ "command": ".cursor/hooks/shipmoor-gate.sh", "timeout": 90, "loop_limit": 3 }
]
}
}
Two small scripts back it, both one-shot:
shipmoor-scan-edit.sh(afterFileEdit): reads the edited file, maps it to its opted-in repo, and refreshes that repo’s<repo>/.shipmoor/last-watch.json. Pure side effect:afterFileEdithas no channel back to the agent, so the adapter rule surfaces the report.shipmoor-gate.sh(stop): for each opted-in repo, runsshipmoor scan --changed --fail-on high; if blocking findings exist, it prints{"followup_message": "..."}so the agent keeps fixing. Theloop_limitbounds the loop.
Opt a repo into the loop:
cd <repo>
shipmoor init # writes .shipmoor.yaml
shipmoor harness install cursor --soft # writes .cursor/rules/shipmoor-harness.md (the opt-in marker)
shipmoor harness mode feedback
--soft is deliberate here: the root-level hooks do the enforcement, and the adapter rule file doubles as the opt-in marker the root scripts look for. Ensure <repo>/.gitignore contains .shipmoor/ so local reports are never committed. The root hooks act on any immediate subdir that has both .shipmoor.yaml and .cursor/rules/shipmoor-harness.md; adding a repo is just the setup above, with no hook edits.
Troubleshooting
| Symptom | Likely cause / fix |
|---|---|
| Agent finishes despite issues | Repo is in observe mode (shipmoor harness mode feedback), or the repo isn’t opted into the loop. |
| Gate never fires | Missing <repo>/.shipmoor.yaml, or the marker rule .cursor/rules/shipmoor-harness.md is absent. Re-run the opt-in steps. |
| A correct import is flagged | Declare it in the manifest (requirements.txt / pyproject.toml / package.json), or waive it narrowly in .shipmoor.yaml if it’s a vendored package the scanner can’t resolve. |
A scan in an && chain killed the rest of the line | The scan exited 1 by design at a blocker; append a guard (|| true) so it doesn’t abort the line. |
Next
- Cursor’s counterpart: Claude Code: the native Stop/PostToolUse hook setup.
- Agent support: which agents are native vs. rules-only, and why.
- Install and modes: the full install surface and
observe/feedback/block.