Skip to content

feat(omp): add Oh My Pi harness adapter - #529

Closed
LoneExile wants to merge 16 commits into
kunchenguid:mainfrom
LoneExile:feat/omp-harness-adapter
Closed

LoneExile wants to merge 16 commits into
kunchenguid:mainfrom
LoneExile:feat/omp-harness-adapter

Conversation

@LoneExile

@LoneExile LoneExile commented Jul 13, 2026 •

Copy link
Copy Markdown

Intent

Add Oh My Pi (omp) as a first-class firstmate harness adapter (primary or crew) alongside claude/codex/opencode/pi/grok, faithfully mirroring the verified pi adapter. Adds the omp backend to fm-harness.sh (detect OMPCODE before CLAUDECODE), an fm-spawn.sh launch template, a turnend-guard + watch extension under .omp/extensions mirroring .pi/extensions, an intent reader, lock detection via the bun interpreter, and the fixed harness allowlists (bootstrap, AGENTS.md verified list, spawn header). Ports the cd-guard seatbelt to OMP's turn_end event; omp behaves like pi for gate-instruction neutralization.
The omp crewmate launch is an interactive positional session wrapped in the agent-secrets prefix like every sibling adapter: omp --auto-approve <flags> -e <ext> "$(cat <brief>)" (ship/scout) / ... -e <turnend> -e <watch> ... (secondmate). There is no -p/--mode json/--no-session invocation.
Rebased onto latest upstream main through #658 (local agent secret injection); the omp launch template adopts the $agent_secrets_prefix wrapping exactly like pi so omp crewmates also receive 1Password secret injection.

What Changed

  • Add Oh My Pi (omp) as a first-class firstmate harness backend: fm-harness.sh detects OMPCODE ahead of CLAUDECODE, fm-spawn.sh grows an omp launch template (ship/scout and secondmate) wrapped in $agent_secrets_prefix, fm-lock.sh recognizes omp via its bun interpreter, fm-teardown.sh cleans state-resident omp extensions, and tmux/watch busy-state regexes gain omp indicators.
  • Add .omp/extensions/fm-primary-turnend-guard.ts and fm-primary-omp-watch.ts mirroring the .pi extensions, porting the cd-guard seatbelt onto OMP's turn_end event and writing the turn-end signal.
  • Register omp across the fixed harness allowlists (bootstrap, AGENTS.md verified list, spawn header, skill/architecture/configuration docs), add a docs/supervision-protocols/omp.md protocol page, and add live-e2e, extension-types, and ambient-OMPCODE-isolation test coverage.
  • Harden detect_own's bare-interpreter ancestry match: the args globs now mirror fm-lock.sh's (^|/| )name( |$) word boundary so the real launched form bun /…/omp --auto-approve … resolves (previously fell through to unknown); applied to both omp and pi, with tests/fm-harness-detect.test.sh covering it. Live-verified 2026-07-17 that a live omp reports comm=bun / pane_current_command=bun; docs/tmux-backend.md records that capture and its liveness-gap summary now names omp's bun alongside pi's node.

Risk Assessment

✅ Low: additive, well-bounded port that faithfully mirrors the already-verified pi adapter across every touched script, with matching unit tests, an opt-in live e2e, a detection regression test, and docs. No functional defects; the detection hardening is verified live and covered by a test.

Testing

  • ⏭️ Test - skipped

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 2 infos
  • ℹ️ bin/fm-spawn.sh:362 - User intent states fm-spawn's omp invocation uses -p --mode json --no-session, but the actual launch template uses an interactive positional session: omp --auto-approve __MODELFLAG____EFFORTFLAG__-e __OMPEXT__ &#34;$(cat __BRIEF__)&#34; (crewmate) / ... -e __OMPTURNEND__ -e __OMPWATCH__ ... (secondmate). No -p/--mode json/--no-session omp invocation exists anywhere in bin/. The interactive launch is almost certainly the correct choice — supervised crewmates run in a watched tmux pane and every sibling adapter (claude/pi/grok) launches interactively; a -p print-mode one-shot could not be supervised or steered. Surfacing so the author can confirm the intent text was just imprecise shorthand and no non-interactive path was dropped.
  • ℹ️ .agents/skills/firstmate-orca/SKILL.md:16 - This change added omp to the harness enumeration in docs/orca-backend.md but left the parallel list in .agents/skills/firstmate-orca/SKILL.md line 16 (claude, codex, opencode, pi, or grok) unchanged, so the orca skill doc now under-documents the supported harness set and could read as omp not being orca-compatible. Mechanical parity edit to match the sibling doc that was updated.
⏭️ **Test** - skipped

Step was skipped.

⚠️ **Document** - 1 info
  • ℹ️ docs/tmux-backend.md:106 - docs/tmux-backend.md secondmate-liveness 'Known gap' section names only pi as the interpreter-based harness the tmux agent-liveness classifier (fm_backend_tmux_agent_alive) cannot confidently classify. omp now runs under bun, and backends/tmux.sh was NOT changed by this branch (its deliberate-unknown interpreter set is still node/python/python3, and bun falls into the generic 'unknown' bucket), so an omp secondmate shares pi's inconclusive-liveness gap. The doc still accurately describes the unchanged code, so I left it untouched; but omp's arrival as a verified adapter makes the gap section incomplete. Out of scope here because a real fix touches liveness classification behavior, not just prose. Worth a follow-up to either wire omp/bun into the classifier or add omp alongside pi in the gap note.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch 2 times, most recently from 0f49ccb to f4e778f Compare July 13, 2026 17:18
@kunchenguid

kunchenguid commented Jul 14, 2026 •

Copy link
Copy Markdown
Owner

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#529 at f4e778f1.

@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch from f4e778f to a5a7923 Compare July 14, 2026 02:51
@kunchenguid kunchenguid removed the wheelhouse:pending-contributor-action Managed by Wheelhouse label Jul 14, 2026
@kunchenguid

kunchenguid commented Jul 14, 2026 •

Copy link
Copy Markdown
Owner

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#529 at a5a79238.

@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch 2 times, most recently from 9dbc1a1 to 3806c04 Compare July 15, 2026 03:54
@kunchenguid

kunchenguid commented Jul 15, 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#529 at 3806c049.

@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch from 3806c04 to 8a01b6b Compare July 15, 2026 13:06
@kunchenguid kunchenguid removed the wheelhouse:pending-contributor-action Managed by Wheelhouse label Jul 15, 2026
@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch from 8a01b6b to bdc0e16 Compare July 15, 2026 23:54
@kunchenguid

kunchenguid commented Jul 16, 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#529 at bdc0e161.

@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch from bdc0e16 to 0ff0b98 Compare July 16, 2026 04:17
@LoneExile

This comment was marked as resolved.

@LoneExile LoneExile closed this Jul 16, 2026
@LoneExile LoneExile reopened this Jul 16, 2026
@kunchenguid kunchenguid removed the wheelhouse:pending-contributor-action Managed by Wheelhouse label Jul 16, 2026
@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch from 5ddb00b to 163dd63 Compare July 16, 2026 13:52
@kunchenguid

kunchenguid commented Jul 17, 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#529 at 163dd639.

@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch from 163dd63 to a367435 Compare July 17, 2026 03:35
@kunchenguid kunchenguid removed the wheelhouse:pending-contributor-action Managed by Wheelhouse label Jul 17, 2026
Adds OMP (Oh My Pi) as a firstmate primary and crew harness. OMP is a Pi fork with a Pi-compatible extension API but was previously unusable: fm-harness.sh misdetected it as claude (OMP sets CLAUDECODE=1), and OMP auto-loads .omp/extensions/, never .pi/extensions/.

Rebased on upstream main, including kunchenguid#397 (fix(pi): restore primary watcher supervision lifecycle). The .omp/ supervisors are kept in lockstep with the kunchenguid#397 Pi supervisors: guardFollowupActive one-shot skip, void markLoaded, awaited follow-up delivery, stopArm() + a one-shot process.once("exit") cleanup, ctx.ui.notify command handler, and the fm_watch_arm_omp tool (label + text content + structured details) as the primary arm path with /fm-watch-arm-omp as the human fallback.

OMP adaptations from the Pi source:
- the turn-end guard listens for `turn_end` (OMP has no `agent_settled` event, which is Pi 0.80.5-only);
- the tool schema uses pi.zod.object({}) (OMP-canonical), not typebox, and omits promptSnippet/promptGuidelines (not in OMP's ToolDefinition);
- Promise.withResolvers + in/typeof narrowing + typed ChildProcess per this repo's TS lint.

Files: fm-harness.sh (detect OMPCODE before CLAUDECODE), .omp/extensions/* (turn-end guard + PreToolUse seatbelt, watcher bridge), fm-spawn.sh (omp launch template + model/effort flags + crew turn-end hook), fm-session-start.sh (extension-loaded check), fm-supervision-instructions.sh + docs/supervision-protocols/omp.md (supervision block), fm-watch.sh / fm-tmux-lib.sh (busy signature), tests/fm-omp-primary-types.test.sh (strict typecheck mirroring fm-pi-primary-types), plus docs + harness-adapters skill.

Verified: rebased clean; tsc --strict --noEmit clean against @oh-my-pi/pi-coding-agent types; shellcheck -x clean; fm-{supervision-instructions,session-start,turnend-guard,secondmate-harness,spawn-batch,spawn-dispatch-profile} tests pass. Live in a herdr pane: omp -p -e <exts> returned OMP_DONE_EXIT=0, bin/fm-harness.sh returned omp from the omp child, and both extension-loaded markers were written by the running extensions.

PENDING: the full multi-turn guarded-wake / re-arm loop and the exact busy signature / exit / interrupt keys still want a longer live co-primary session; the harness-adapters entry stays PENDING LIVE VERIFICATION until then.
Live run on 2026-07-10 (omp v16.3.15, herdr backend): a fresh omp became the first mate (root AGENTS.md loaded via agents-md), detection via bin/fm-harness.sh AND bin/fm-lock.sh resolved omp, both .omp/extensions/ loaded (markers written), the turn-end guard fired on a real multi-turn primary ("TURN WOULD END BLIND ... 2 task(s) in flight, no live watcher") and the primary re-armed the watcher instead of ending blind, and two omp crewmates (fm-webull-broker-w7, fm-finnhub-free-f3) ran autonomously under --auto-approve in treehouse worktrees and shipped two green PRs.

Promoted the PENDING LIVE VERIFICATION markers to VERIFIED across the harness-adapters skill (heading + guard/watcher + launch-profile row + a live validation record), docs/supervision-protocols/omp.md, docs/turnend-guard.md, and docs/arm-pretool-check.md.

Kept honest (not yet exercised): a seatbelt {block:true} deny of an arm anti-pattern, the tmux-backend busy signature (this run used herdr's native busy-state), and the exit/interrupt keys.
Adds tests/fm-omp-primary-live-e2e.test.sh, the OMP counterpart to fm-pi-primary-live-e2e.test.sh, so the VERIFIED omp adapter is backed by a repeatable regression like the author's pi/grok adapters (deviation from the verified-harness pattern, closed).

The test (opt-in, FM_OMP_LIVE_E2E=1) launches omp on a private tmux socket with the tracked .omp/extensions via -e, drives bash/read turns, triggers the turn-end guard, arms fm_watch_arm_omp, delivers a watcher wake, drains + re-arms, and asserts: one-or-more guard injections, no foreground bin/fm-watch-arm.sh arm, a live re-armed watcher pid, and a clean /quit (OMP_EXIT=0) that reaps both the watcher and arm children. Passes on omp v16.4.0.

OMP adaptations vs the pi e2e: no PI_OFFLINE stub model (drives a real model turn, hence opt-in); uses the default authed agent dir because a fresh PI_CODING_AGENT_DIR triggers omp's blocking first-run setup wizard; and it asserts >=1 guard injection (not exactly 1) because omp's guard listens for turn_end (no agent_settled), so it re-nags on each blind turn until armed - the run saw 3 injections before the model armed the watcher.

Reconciled the docs to this stronger, honest state: Exit (/quit) is now VERIFIED (clean exit + child cleanup), the guard 'once per run' claim is corrected to the per-turn re-nag, and the still-unexercised items are narrowed to a seatbelt {block:true} deny, the tmux busy-footer regex, and the interrupt (Escape) key.
LoneExile added 12 commits July 17, 2026 13:05
…nds kunchenguid#432)

omp (Oh My Pi) exports OMPCODE=1 (and CLAUDECODE=1) into child shells and
fm-harness.sh detect_own checks OMPCODE first, so running the suite from an
omp session leaks OMPCODE past the suites' harness pins - flipping detection
to omp and breaking cases that CI (no ambient marker) keeps green. Extends
kunchenguid#432's ambient-marker isolation to OMPCODE:

- fm-session-start: add OMPCODE to run_session_start's env -u neutralization.
- fm-secondmate-harness / fm-turnend-guard / fm-x-mode: drop ambient OMPCODE
  at the top so their CLAUDECODE=1 harness pins stay authoritative.

(fm-watcher-lock's ambient failure was a pre-existing flaky restart timeout,
status 124 - unrelated to omp, left untouched.)
commands.test iterates the full tests/*.test.sh suite to mirror ci.yml, which
runs with no ambient harness/backend markers. A contributor gating from inside
an omp/herdr session, though, leaks OMPCODE/CLAUDECODE/HERDR_ENV/TMUX into the
run: HERDR_ENV routes fm-bootstrap.sh into the EXPERIMENTAL herdr backend (a
deterministic FLEET_SYNC timeout-scaling failure) and OMPCODE/CLAUDECODE flip
detect_own harness detection. Strip those per test so the gate matches CI's
clean env regardless of the shell it runs from.
Upstream kunchenguid#483 (feat: guard primary shells from persistent cd commands)
refactored the Pi turnend-guard's runPretoolCheck into a generic
runChecker(script, command) and wired a cd-guard check before the
watcher-arm check. Port the same change to the OMP twin:

- .omp/extensions/fm-primary-turnend-guard.ts: replace runPretoolCheck
  with runChecker, run fm-cd-pretool-check.sh then fm-arm-pretool-check.sh
  in the tool_call handler (cd-guard deny short-circuits before the arm
  check, matching Pi's order). Wrappers inlined per the ts-no-tiny-functions
  lint rule (single-return, one call site each).
- docs/cd-guard.md: add OMP row to the harness wiring table.
- tests/fm-cd-pretool-check.test.sh: add test_omp_wiring parallel to
  test_pi_wiring, asserting the OMP extension runs both seatbelts.
Upstream kunchenguid#658 (agent secret injection) wraps every launch template with
$agent_secrets_prefix but its coverage loop omitted omp. The rebase
resolution added the prefix to the omp template (mirroring pi); extend the
test's baselines and both harness loops so the omp ship/secondmate launch
commands and their prefix wrapping are verified, not just eyeballed.
detect_own's bare-interpreter args globs (`*" omp "*|*/omp`, `*" pi "*|*/pi`)
only matched a trailing `/omp` or a space-delimited ` omp `, so the real
launched form `bun /…/omp --auto-approve …` (a live omp runs as bun with the
harness at a path-final component followed by flags) fell through to `unknown`,
diverging from fm-lock.sh's `(^|/| )name( |$)` word boundary. Align both globs
to that boundary. Detection is layered (OMPCODE=1 catches native omp first), so
this hardens the fallback rather than fixing an observed failure.

Verified live 2026-07-17: a live omp tmux pane reports pane_current_command=bun
with foreground child `bun /Users/…/.bun/bin/omp`. docs/tmux-backend.md records
that capture (removing the pending-verification caveat) and its liveness-gap
summary now names omp's generic `bun` alongside pi's `node`; `bun` still cannot
join the alive-glob without misclassifying unrelated bun processes.

Add tests/fm-harness-detect.test.sh covering the launched-form match and
guarding against false positives (omp workers, unrelated bun/node sessions).
@LoneExile
LoneExile force-pushed the feat/omp-harness-adapter branch from a7a00a7 to 28be797 Compare July 17, 2026 06:06
@kunchenguid

kunchenguid commented Jul 17, 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#529 at 28be797a.

@julius-retzer

Copy link
Copy Markdown

It would be nice to get this merged

@kunchenguid

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate: closing this as stale. It has been waiting on a contributor update for 14+ days with no author push or comment. Reopen if you want to pick it back up.

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