The Agent Harness installs per project: from your repo root, one command wires the scan→feedback loop into the agent(s) you use, and one config key decides how intrusive that loop is. The harness ships inside the shipmoor binary (bundled since 0.5.0) and is invoked as the shipmoor harness subcommand; there is no separate install. This page covers prerequisites, the install surface, reading status, and choosing a mode.
Prerequisites
Before you install, confirm four things:
| Check | Command | What you want to see |
|---|---|---|
| CLI version | shipmoor --version | 0.5.1 or newer |
| Harness entitlement | shipmoor capabilities | agent_harness enabled (the IC plan) |
| Signed in | shipmoor whoami | a non-empty identity; run shipmoor login if it’s empty |
| Git repo | git status | the harness scopes scans to your change-set, so it expects a git repo |
If you use the script-based watch fallback or any hook path, also make sure python3 is on your PATH.
The harness is a client of the CLI: it shells out to
shipmoor scanand readsshipmoor capabilities --json. It never checks a license itself, so its entitlement state is exactly whatever the CLI reports.
Install
shipmoor harness install claude # or aider | codex | cursor | all
aider: wrote .aider.conf.yml
claude: wrote .claude/settings.json
codex: wrote AGENTS.md
cursor: wrote .cursor/hooks.json
The agent_harness entitlement is checked once, up front. Each adapter writes a single marker-wrapped managed block into the agent’s own config, and every install is byte-idempotent: re-running changes nothing, your own config in the same files is preserved, and shipmoor harness uninstall <agent> removes only the managed block, restoring the file’s prior shape (and deleting a file that held nothing but our block). A pre-existing, unmarked Shipmoor footprint is reported as a conflict rather than overwritten.
| Adapter | File it manages |
|---|---|
claude | .claude/settings.json (top-level hooks; never touches CLAUDE.md) |
aider | .aider.conf.yml (a managed lint-cmd block) |
codex | AGENTS.md (a guidance block; run via the codex wrapper) |
cursor | .cursor/hooks.json, or .cursor/rules/shipmoor-harness.md with --soft |
Flags
| Flag | Effect |
|---|---|
--soft | Write a rules/guidance-only fallback instead of native hooks. Mainly for cursor, for setups that decline hooks; the harness owns the fallback file outright and migrates between the two forms. |
--replace-existing | Overwrite a pre-existing Aider lint-cmd. Without it, a user-defined lint-cmd is reported as a conflict; with it, status records a lint_cmd_replaced warning. |
If Agent Skills are installed in the same repo, the two coexist by the marker contract: distinct managed blocks, each owned by its own installer. See the per-agent pages for wiring detail: with Claude Code, with Cursor, and the full agent support matrix.
Status
shipmoor harness status is informational and always exits 0. It reports the CLI path and version, your capabilities, the active mode, which adapters are installed and the files they manage, the watch state, the entitlement_state, and any warnings.
shipmoor harness status
# CLI: /…/shipmoor (v0.5.1)
# Caps: agent_harness, intent_scan, repair_guidance
# State: ic_active
# Mode: block
# Adapters:
# · claude (.claude/settings.json)
# · aider … · codex … · cursor (soft)
# Watch: no report yet (run `shipmoor harness watch`)
For scripting, add --json to get the versioned shipmoor.harness.status.v1 envelope:
shipmoor harness status --json
{
"version": "1",
"cli": {
"path": "/Users/you/.shipmoor/bin/shipmoor",
"version": "0.5.1",
"found": true
},
"capabilities": {
"agent_harness": true,
"intent_scan": true,
"repair_guidance": true
},
"mode": "block",
"max_feedback_cycles": 3,
"adapters": [
{ "name": "aider", "installed": false, "version": null, "files": [], "soft": false },
{ "name": "claude", "installed": true, "version": "0.1.0", "files": [".claude/settings.json"], "soft": false },
{ "name": "codex", "installed": false, "version": null, "files": [], "soft": false },
{ "name": "cursor", "installed": false, "version": null, "files": [], "soft": true }
],
"watch": {
"last_report": false,
"exit_code": null,
"findings_total": null,
"report_path": ".shipmoor/last-watch.json"
},
"entitlement_state": "ic_active",
"warnings": []
}
If status shows Caps: none or a locked entitlement_state, install will refuse with the upgrade message; sign in or upgrade first (shipmoor login). The warnings array is where the harness surfaces non-fatal issues, including lint_cmd_replaced and the mode_block_without_intent warning described below.
Modes
The mode decides what findings do to the agent loop. Set it with:
shipmoor harness mode feedback # observe | feedback | block
| Mode | What it does | When to use it |
|---|---|---|
observe | Record and report only; never interrupt the agent. | The safest start. |
feedback | Route concise findings back into the agent’s context so it can self-correct, bounded by max_feedback_cycles (default 3). | Once you trust the loop. |
block | Exit non-zero on a gate breach. | The firmest; pair it with CI. |
feedback and block both lean on the bounded loop: re-prompts are capped by max_feedback_cycles, and whatever findings remain at the cap surface to you instead of spinning forever. See the self-correction loop for what that looks like in a live session.
block needs intent_scan
block requires the intent_scan entitlement. Without it, block degrades cleanly to feedback (so the agent still gets findings) unless you pass --force-structural, which lets block fire on structural findings only:
shipmoor harness mode block --force-structural
When block is set without intent_scan, status reports a mode_block_without_intent warning so the degrade is never silent.
Even in
block, intent advisories stay advisory by default. The harness only lets the intent gate fail a build under an un-degradedblock; the deterministic structural scan is what decides a structural gate. This mirrors the rest of Shipmoor: deterministic evidence blocks, an LLM opinion can only advise.
Config (.shipmoor.yaml)
mode and install edit only the harness: block of .shipmoor.yaml, by targeted line surgery; every other key, comment, and blank line in the file is preserved. The block:
harness:
mode: feedback # observe | feedback | block
max_feedback_cycles: 3 # caps re-prompts so a loop never spins (default 3)
watch:
debounce_ms: 750 # watch debounce window in ms (default 750)
You can edit this file directly or let the mode/install commands write it for you; both stay inside the CLI’s YAML subset.
Recommended path
Roll the loop in gradually:
- Start in
observe. It catches changes that did not earn their claim and records them, without ever interrupting the agent, so you can see what the harness would flag before it acts on anything. - Move to
feedbackonce you trust the findings. Now the agent gets concise findings back and self-corrects within the cap. - Use
blockin CI. The firmest gate belongs where a non-zero exit stops a merge, not in the middle of a local dev session.
Next
- The self-correction loop: what
feedbackandblocklook like in a real session. - With Claude Code: installing and running the loop inside Claude Code.
- With Cursor: native hooks and the
--softrules fallback.