Harness integration
What each supported harness needs, which files wire it in, how it stays supervised, and which harnesses can serve as primary, crewmate, secondmate or scout.
firstmate is vendor-agnostic. .agents/skills/harness-adapters/ routes every harness-specific fact, with per-vendor references under references/harness/. It carries one non-negotiable rule: never dispatch on an unverified adapter. If detection returns unknown, the first mate asks you.
Support matrix#
| Harness | Primary | Crewmate | Secondmate | Scout |
|---|---|---|---|---|
Claude Code (claude) |
✓ co-primary | ✓ | ✓ | ✓ |
Grok (grok) |
✓ co-primary | ✓ | ✓ | ✓ |
Pi (pi, pi-signed) |
✓ co-primary | ✓ | ✓ | ✓ |
Oh My Pi (omp) |
✓ | ✓ | ✓ | ✓ |
Codex (codex) |
✓ | ✓ | ✓ | ✓ |
OpenCode (opencode) |
✓ | ✓ | ✓ | ✓ |
Cursor Agent CLI (cursor) |
✓ | ✓ | ✓ | ✓ |
Kimi (kimi) |
— | ✓ | ✓ | ✓ |
| Gemini, Muse, Rovo, AGY, Devin | — | ✓ | — | ✓ |
The last row has no primary supervision protocol, so it can't host a secondmate. Kimi is refused on cmux and Orca. Source: docs/configuration.md "Harness support".
Claude Code#
- Wiring:
.claude/settings.jsonregisters these hooks:SessionStart→bin/fm-sessionstart-run.shPreToolUseseatbelts:fm-arm-pretool-check.sh,fm-cd-pretool-check.sh,fm-subagent-pretool-check.shUserPromptSubmit→fm-host-mirror.shStop→fm-turnend-guard.sh --claude, thenfm-claude-stop-autoarm.sh(asyncRewake: true, 28800s timeout)
- How it stays supervised: on every Stop, the autoarm checks that this is the primary checkout and that it holds
state/.lock. It arms the watcher through a single-flight epoch ledger. On an actionable wake it exits 2 with a rewake banner, which Claude delivers as Stop-hook feedback. - Model instruction: drain wakes with
bin/fm-wake-drain.shand never re-arm by hand. - Workers:
config/claude-permission-modesetsbypass(default) orauto.bin/fm-claude-trust.shpre-registers workspace trust per worktree. /calmneedsCLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1.- All Claude hooks no-op when
GROK_AGENTorGROK_HOOK_EVENTshows that Grok is really driving.
Subscription terms
Kun on running Claude Code under firstmate: "you are still just running the real claude code as-is. zero TOS implication" (2026-08-10 thread). He uses Claude Code for Claude models and Pi for everything else.
Pi / pi-signed#
- Wiring: tracked
.pi/extensions/*.tsauto-load after you approve project trust once per clone:fm-primary-pi-watch.ts— watcher bridge; exposes thefm_watch_arm_pitoolfm-branch-supervision.ts— the in-process supervision branchfm-primary-turnend-guard.tsfm-calm.ts
- Fallback if the extensions didn't load: restart
piwith the extension paths passed via-e. - Supervision branch: a second AgentSession in the same process. It absorbs routine wakes and heartbeats and hands outcomes to main. It is on by default once the fleet lock is held. It is Pi-only; it does not run on omp.
/supervision-modelpins the branch to a cheaper model and effort.FM_PI_HARNESS=pi-signed pi-signedfor the signed wrapper.
omp (Oh My Pi)#
- Wiring:
.omp/extensions/holdsfm-primary-omp-watch.tsand the turn-end guard. No trust gate. Startompwith the checkout as cwd. Don't also pass-e, or they load twice. - Guard: a blocking
session_stophook compels a continuation, bounded to one per turn bystop_hook_active. This is the strongest guard of any harness. - omp needs both extensions trusted; with only one, it fails loudly.
Grok#
- Wiring: there is no extension. The model arms the watcher itself through Grok's
run_terminal_commandwithbackground: true. Grok injects a synthetictask_completedmessage when the arm finishes, and that is the wake. - A
.grok/hooks/Stop-hook backstop exists but is not the normal path. - Launch with
grok --trustonce per clone, or run/hooks-trust. Headlessgrok -pis unsupported as primary. - Version trap: Grok 1.0.0 hook processes carry
GROK_HOOK_EVENT/GROK_SESSION_IDbut notGROK_AGENT. A guard keyed only on the old marker let Claude's auto-arm run synchronously under Grok, and the turn never ended. The docs warn: do not widen the guard toGROK_SESSION_ID, which leaks into child Claude sessions.
Cursor Agent CLI#
- Wiring:
.cursor/hooks.jsonstop→bin/fm-turnend-guard-cursor.sh. - Cursor's stop hook is synchronous, and exit 2 is a silent no-op, so the hook parks: it runs one watcher cycle as its own child and returns a
followup_messageon an actionable wake. It is bounded by Cursor'sloop_limitand byFM_CURSOR_TURNEND_LOOP_CEILING(180). - Must launch with
--trust, or no project hooks load. Must be interactive:cursor-agent -phas no stop hook.
OpenCode#
- Wiring:
.opencode/plugins/fm-primary-watch-arm.jslistens forsession.idle, spawnsfm-watch-arm.sh --restart, and delivers wakes withclient.session.promptAsync.fm-primary-pretool-check.jsis the seatbelt. - TUI only.
opencode runis unsupported as primary.
Codex#
- There is no background mechanism ("Codex cannot reason while a foreground tool call is running"). The model loops
bin/fm-watch-checkpoint.sh --seconds ${FM_CODEX_WATCH_CHECKPOINT:-180}. It exits 124 when quiet. .codex/hooks.jsonholds the seatbelt and Stop guard.- Skills are invoked with
$instead of/:$afk,$bearings. - Codex Desktop threads are a companion workflow (
firstmate-codexappskill), not a runtime backend. A thread counts as supervised only once its status-file write is verified.
Kimi#
Kimi has no project-level hooks. A captain-approved global config region in ~/.kimi-code/config.toml (bin/fm-kimi-turnend-hook.sh) gives crew wakes. It is not usable as a primary.
Supervision host (non-Pi primaries)#
The supervision host runs the supervision-branch contract on a headless engine beside your primary (bin/fm-supervision-host.sh). It is on by default for Claude, so no file is needed there. Cursor, OpenCode, omp, Grok and Codex need config/supervision-host. A file saying off disables it on any harness. Each harness's existing arm owner runs the host in place of the raw watcher.
| Away | Attended | |
|---|---|---|
| Claude, Cursor | ✓ | ✓ (via the fm-host-mirror.sh dialog mirror) |
| OpenCode, omp, Grok, Codex | ✓ | pass-through |
Kun's harness split#
for video generation and real time info, i use grok build. image generation uses codex - this is because of harness capability. for claude models i use claude code - because their TOS does not allow any other harness. everything else is pi. — @kunchenguid, 2026-08-05 thread