Skip to content
11 changes: 11 additions & 0 deletions .agents/skills/harness-adapters/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,17 @@ The extension reports `session_start` readiness, acknowledges the initial instru
Firstmate waits for the first `turn_start` acknowledgement before reporting a successful spawn.
OMP workers keep their sessions under the task temp root so recovery can resume the exact conversation and ordinary cleanup can remove the session files with the rest of the task temp.

**Native orchestration opt-in.** OMP activates its built-in multi-agent orchestration mode when the exact lowercase keyword `orchestrate` appears in the initial user message; `magicKeywords.enabled` and `magicKeywords.orchestrate` (both default true) then append a hidden `orchestrate-notice` system instruction that directs the worker to decompose, dispatch `task` subagents, integrate, and verify.
The matcher is a Unicode word-boundary scan of the message that starts the turn, case-sensitive, with fenced code, inline code spans, comments, and balanced tags masked out: `orchestrate`, `orchestrate,` and `path:orchestrate` fire; `Orchestrate`, `orchestration`, `orchestrate.ts`, `path/orchestrate`, `foo::orchestrate`, `orchestrate()`, and backtick-quoted forms do not.
The OMP launch message is an encoded instruction to read the original brief at its absolute path (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: <body>` as the positional argument). File reads mid-session are tool results and are never scanned for keywords.
`bin/fm-brief.sh --orchestrate` records the opt-in for an ordinary ship task as a generated YAML front-matter marker (`---\norchestration: enabled\n---`) at the very top of the brief. `bin/fm-spawn.sh` reads only that front-matter, so task prose, acceptance criteria, quoted examples, or code blocks that happen to contain the same line cannot spoof the opt-in.
For an opted-in OMP launch, `bin/fm-spawn.sh` passes a single message: the standalone `orchestrate` keyword followed by an instruction to read the original brief at its absolute path before doing any work. For an ordinary (non-opted) OMP launch it passes only the instruction to read the original brief. The full original task text is read from the brief file in a tool result, which is never scanned for keywords.
Marked briefs refuse raw launch commands before endpoint creation, so the verified OMP launch template cannot be bypassed and silently lose the opt-in keyword.
Any other harness or task kind is refused before launch.
Nested `task` subagents stay inside the task worktree as implementation helpers owned by the crewmate; they do not become independent Firstmate workers and do not gain merge or production authority, so Firstmate's registered-crewmate supervision, production/merge authority, receipt contract, and No-Mistakes branch custody are unchanged.
Use the opt-in only for tasks with genuinely independent workstreams inside the same worktree: ordinary and sequential tasks launch unchanged, `orchestrate` and `workflowz` are never combined, and the keyword is never added by default or forced onto trivial work.
The activation boundary was verified on OMP 18.1.14 (2026-09-10); `docs/verification/runtime-backends.md` owns the live commands and bounded output.

[The tmux backend guide](../../../docs/tmux-backend.md#current-behavior-and-safety) owns OMP's launch identity, supported canonical paths, composer geometry, submission, and recovery behavior.
[The Herdr backend guide](../../../docs/herdr-backend.md#composer-and-injection-safety) owns OMP's native identity, composer, busy steering, normal exit, and blocked-injection behavior on Herdr.
OMP is verified only on tmux and Herdr; the backend applicability rationale and inspection evidence live in [runtime-backends verification](../../../docs/verification/runtime-backends.md#omp-applicability-outside-tmux-and-herdr).
Expand Down
34 changes: 31 additions & 3 deletions bin/fm-brief.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# placeholder with the task description, concrete outcomes, and context, and may adjust other sections
# when the task genuinely deviates (e.g. working an existing external PR instead
# of shipping a new one).
# Usage: fm-brief.sh <task-id> <repo-name> --mode <no-mistakes|direct-PR|local-only> [--herdr-lab]
# Usage: fm-brief.sh <task-id> <repo-name> --mode <no-mistakes|direct-PR|local-only> [--herdr-lab] [--orchestrate]
# fm-brief.sh <task-id> <repo-name> --scout [--herdr-lab]
# fm-brief.sh <task-id> --secondmate {<project>...|--no-projects}
# fm-brief.sh --render-ship-delivery <task-id> <no-mistakes|direct-PR|local-only>
Expand All @@ -17,6 +17,11 @@
# tells the main firstmate when to route work there; routine churn stays in its own home;
# captain-relevant escalations and marked from-firstmate replies append to this
# home's status file.
# --orchestrate opts an ordinary ship task into native OMP orchestration: it
# records the `orchestration: enabled` marker as front-matter at the top of the
# brief and lets bin/fm-spawn.sh carry the exact lowercase `orchestrate` keyword
# as a separate OMP launch message before the unchanged encoded brief. It is
# refused on scout and secondmate briefs, which are not ship tasks.
# --no-projects writes a project-less charter for a domain whose subject is the
# firstmate repo itself (its home is a firstmate worktree, its crews take pooled
# worktrees of the same repo). It is mutually exclusive with a project list, and
Expand Down Expand Up @@ -186,6 +191,7 @@ fi
KIND=ship
HERDR_LAB=0
NO_PROJECTS=0
ORCHESTRATE=0
MODE=
MODE_SET=0
POS=()
Expand All @@ -206,6 +212,7 @@ for a in "$@"; do
--scout) KIND=scout ;;
--secondmate) KIND=secondmate ;;
--herdr-lab) HERDR_LAB=1 ;;
--orchestrate) ORCHESTRATE=1 ;;
--no-projects) NO_PROJECTS=1 ;;
--mode) want_value=mode ;;
--mode=*) MODE=${a#--mode=}; MODE_SET=1 ;;
Expand Down Expand Up @@ -243,6 +250,11 @@ if [ "$KIND" = secondmate ] && [ "$HERDR_LAB" -eq 1 ]; then
exit 1
fi

if [ "$ORCHESTRATE" -eq 1 ] && [ "$KIND" != ship ]; then
echo "error: --orchestrate applies only to ship briefs; a scout delivers a report and a secondmate is not a delivery task" >&2
exit 1
fi

if [ "$NO_PROJECTS" -eq 1 ] && [ "$KIND" != secondmate ]; then
echo "error: --no-projects applies only to --secondmate charters" >&2
exit 1
Expand Down Expand Up @@ -492,16 +504,32 @@ case "$MODE" in
esac
DOD=$(render_ship_delivery "$ID" "$MODE")

ORCHESTRATION_FRONTMATTER=""
ORCHESTRATION_SECTION=""
if [ "$ORCHESTRATE" -eq 1 ]; then
IFS= read -r -d '' ORCHESTRATION_FRONTMATTER <<'EOF' || true
---
orchestration: enabled
---

EOF
IFS= read -r -d '' ORCHESTRATION_SECTION <<'EOF' || true
# Orchestration
This task may use native `task` subagents for independent workstreams; you remain accountable for integrating and verifying their output.

EOF
fi

IFS= read -r -d '' SHIP_BRIEF <<EOF || true
You are a crewmate: an autonomous worker agent managed by firstmate. Work on your own; do not wait for a human.
${ORCHESTRATION_FRONTMATTER:+$ORCHESTRATION_FRONTMATTER}You are a crewmate: an autonomous worker agent managed by firstmate. Work on your own; do not wait for a human.

# Task
{TASK}

# Acceptance criteria
- AC1: {ACCEPTANCE CRITERION}

$HERDR_SECTION
${ORCHESTRATION_SECTION:+$ORCHESTRATION_SECTION}$HERDR_SECTION

# Setup
You are in a disposable git worktree of $REPO, at a detached HEAD on a clean default branch.
Expand Down
39 changes: 37 additions & 2 deletions bin/fm-spawn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
# __OMPRESUMEFLAG__ empty for a fresh OMP launch or the exact retained secondmate session file
# __OMPPRIMARY__ absolute path to .omp/extensions/fm-primary-omp.ts in an OMP secondmate home
# __OMPMAXTIME__ OMP-only `--max-time=<duration>` fragment from config/omp-max-time
# __OMPMESSAGE__ OMP-only initial positional message: the encoded launch brief, or the `orchestrate` keyword plus the brief path when the brief opts in
# __PITURNEND__ absolute path to .pi/extensions/fm-primary-turnend-guard.ts in a pi secondmate home
# __PIWATCH__ absolute path to .pi/extensions/fm-primary-pi-watch.ts in a pi secondmate home
# __HERMESBIN__ absolute resolved Hermes executable (PATH first, then $HOME/.local/bin/hermes)
Expand Down Expand Up @@ -1322,9 +1323,9 @@ launch_template() {
if [ "$kind" = secondmate ]; then
# The explicit path is the exact same tracked file native project discovery sees.
# OMP 17.1.8's discoverExtensionPaths path-resolves and deduplicates before loading, so this guarantees the integration without registering it twice.
printf '%s' '__OMPENV____OMPBIN__ --session-dir __OMPSESSIONDIR__ __OMPRESUMEFLAG__--auto-approve __OMPMAXTIME____MODELFLAG____EFFORTFLAG____PREWALKFLAG__-e __OMPPRIMARY__ "$(__OPINPUT__ encode launch-brief < __BRIEF__)"'
printf '%s' '__OMPENV____OMPBIN__ --session-dir __OMPSESSIONDIR__ __OMPRESUMEFLAG__--auto-approve __OMPMAXTIME____MODELFLAG____EFFORTFLAG____PREWALKFLAG__-e __OMPPRIMARY__ __OMPMESSAGE__'
else
printf '%s' '__OMPENV____OMPBIN__ --session-dir __OMPSESSIONDIR__ --auto-approve __OMPMAXTIME____MODELFLAG____EFFORTFLAG____PREWALKFLAG__-e __OMPEXT__ "$(__OPINPUT__ encode launch-brief < __BRIEF__)"'
printf '%s' '__OMPENV____OMPBIN__ --session-dir __OMPSESSIONDIR__ --auto-approve __OMPMAXTIME____MODELFLAG____EFFORTFLAG____PREWALKFLAG__-e __OMPEXT__ __OMPMESSAGE__'
fi
;;
# grok (Grok Build TUI): a positional prompt starts the supervised interactive
Expand Down Expand Up @@ -2833,6 +2834,27 @@ else
fi
[ -f "$BRIEF" ] || { echo "error: no brief at $BRIEF" >&2; exit 1; }

# Orchestration opt-in is explicit task data, never a keyword scan of prose:
# fm-brief.sh --orchestrate records a front-matter marker `orchestration: enabled`
# at the very top of the generated brief, and a ship task launched with
# harness=omp then carries the exact `orchestrate` keyword in its launch message
# while every other combination refuses before any endpoint exists.
# The marker is only honored when it is the literal first three lines of the
# brief, so ordinary task text, acceptance criteria, quoted examples, or code
# blocks that happen to contain the words cannot spoof the opt-in.
ORCHESTRATE_BRIEF=0
if [ "$(head -n 3 "$BRIEF" 2>/dev/null)" = $'---\norchestration: enabled\n---' ]; then
ORCHESTRATE_BRIEF=1
fi
if [ "$ORCHESTRATE_BRIEF" -eq 1 ]; then
[ "$KIND" = ship ] || { echo "error: orchestration applies only to ordinary ship tasks; the brief at $BRIEF records it but this spawn is kind=$KIND" >&2; exit 1; }
if [ "$RAW_LAUNCH" -eq 1 ]; then
echo "error: orchestration requires the verified OMP launch template; this spawn is a raw launch command for a marked brief at $BRIEF. Pass --harness omp and a project or worktree path, not a raw command" >&2
exit 1
fi
[ "$HARNESS" = omp ] || { echo "error: orchestration requires harness=omp; the brief at $BRIEF records it but this spawn resolved harness=$HARNESS" >&2; exit 1; }
fi

if [ "$HARNESS" = omp ] && [ "$KIND" = secondmate ]; then
validate_omp_prewalk_for_launch_dir "$PROJ_ABS"
omp_project_extension_preflight "$PROJ_ABS" || exit 1
Expand Down Expand Up @@ -4288,6 +4310,19 @@ HERMESRESUMEFLAG=
LAUNCH=${LAUNCH//__MODELFLAG__/$MODELFLAG}
LAUNCH=${LAUNCH//__EFFORTFLAG__/$EFFORTFLAG}
LAUNCH=${LAUNCH//__PREWALKFLAG__/$PREWALKFLAG}
if [ "$HARNESS" = omp ]; then
# shellcheck disable=SC2016
# Placeholders __BRIEF__ and __OPINPUT__ are substituted after shell-quoting;
# single quotes here keep the pane-side command literal. The launch message is
# a single task-bearing instruction to read the original brief before working;
# opted-in launches prepend the standalone `orchestrate` keyword.
if [ "$ORCHESTRATE_BRIEF" -eq 1 ]; then
OMP_MESSAGE='"$(printf '"'"'orchestrate\n\nRead the brief at %s and follow it exactly.'"'"' __BRIEF__ | __OPINPUT__ encode launch-brief)"'
else
OMP_MESSAGE='"$(printf '"'"'Read the brief at %s and follow it exactly.'"'"' __BRIEF__ | __OPINPUT__ encode launch-brief)"'
fi
LAUNCH=${LAUNCH//__OMPMESSAGE__/$OMP_MESSAGE}
fi
LAUNCH=${LAUNCH//__BRIEF__/$sq_brief}
LAUNCH=${LAUNCH//__TURNEND_SIGNAL__/$sq_turnend_signal}
LAUNCH=${LAUNCH//__STATE__/$sq_state}
Expand Down
25 changes: 25 additions & 0 deletions docs/verification/runtime-backends.md
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,31 @@ Raw-launch OMP refusals and direct non-OMP compatibility are covered by `tests/f
The secondmate integration checks reran on 2026-08-27 and prove that the exact Firstmate primary and fleet-hook extensions remain permitted in the persistent home without allowing modified or unrelated tracked extension code.
Live firing of the fleet hook's `tool_result`, `todo_reminder`, and `session.compacting` handlers is PENDING firstmate scratch OMP verification before merge; deterministic extension and spawn tests do not claim OMP event delivery.

### OMP native orchestration opt-in

The agent-runtime launch and activation contract is owned by the [harness-adapters skill](../../.agents/skills/harness-adapters/SKILL.md); this page records its verification evidence without restating that contract.

The activation boundary was verified on 2026-09-10 against OMP 18.1.14. The live proof used an isolated `FM_HOME`, a disposable project, a private tmux socket, and the `tests/fm-omp-worker-tmux-live-e2e.test.sh` fixture shape:

```sh
omp --version
FM_HOME="$fixture_home" bin/fm-brief.sh <id> <project> --mode local-only --orchestrate
FM_HOME="$fixture_home" FM_BACKEND=tmux bin/fm-spawn.sh <id> <project> \
--mode local-only --yolo off --harness omp --model openai-codex/gpt-5.6-luna --effort low
```

Observed bounded output:

```text
omp/18.1.14
spawned orch-live-worker harness=omp kind=ship mode=local-only yolo=off
status: done: ready in branch fm/orch-live-worker
session: orchestrate-notice injected; task toolCall dispatched CalcImplementation + GreetImplementation
subagent sessions: CalcImplementation.jsonl, GreetImplementation.jsonl
combined verification: python3 -m pytest tests/ 5 passed
```

The session file records one `orchestrate-notice` custom message, one `task` toolCall whose `tasks` array named two subagents (`CalcImplementation`, `GreetImplementation`), and the two corresponding `agent="task"` completion results. The worktree contains the committed `lib/calc.py` and `lib/greet.py` implementations, and the combined pytest suite passed.
The Herdr role matrix required each expected turn-end or routed-reply notification to reach the durable queue or the primary follow-up transcript before the fixture drained it.

The deterministic composer, tmux, and Herdr fixtures reran on 2026-08-26 and proved that the backend typed-submit primitive for an already-busy OMP target returns internal `queued-unconfirmed` only after Enter transport succeeds and the composer either clears or remains proven pending while native state is still working.
Expand Down
37 changes: 36 additions & 1 deletion tests/fm-brief.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,42 @@ yolo on a ship brief|brief-refused-b1 some-proj --mode direct-PR --yolo on|--yol
yolo=value form on a ship brief|brief-refused-b2 some-proj --mode direct-PR --yolo=off|--yolo is not a brief input
mode on a scout brief|brief-refused-b3 some-proj --scout --mode direct-PR|--mode applies only to ship briefs
mode on a secondmate charter|brief-refused-b4 --secondmate --no-projects --mode no-mistakes|--mode applies only to ship briefs
orchestrate on a scout brief|brief-refused-b5 some-proj --scout --orchestrate|--orchestrate applies only to ship briefs
orchestrate on a secondmate charter|brief-refused-b6 --secondmate --no-projects --orchestrate|--orchestrate applies only to ship briefs
ROWS
pass "fm-brief.sh: --yolo and scout/secondmate --mode are refused, never silently dropped"
pass "fm-brief.sh: --yolo, scout/secondmate --mode, and non-ship --orchestrate are refused, never silently dropped"
}

# The opt-in marker is explicit task data: a ship brief carries
# `orchestration: enabled` only when --orchestrate was passed, and the same
# scaffold without the flag stays byte-free of the marker.
test_orchestrate_opt_in_adds_marker_only_on_ship() {
local home brief out status
home="$TMP_ROOT/orchestrate-home"
mkdir -p "$home/data"

out=$(FM_HOME="$home" "$ROOT/bin/fm-brief.sh" brief-orch-c1 some-proj --mode direct-PR --orchestrate 2>&1)
status=$?
expect_code 0 "$status" "fm-brief.sh ship --orchestrate should exit 0"
assert_contains "$out" "replace {TASK} and every {ACCEPTANCE CRITERION}" \
"orchestrate scaffold success omitted required placeholder replacements"
brief="$home/data/brief-orch-c1/brief.md"
assert_present "$brief" "orchestrate brief was not scaffolded"
assert_grep "# Orchestration" "$brief" "orchestrate brief missing the Orchestration section"
[ "$(head -n 3 "$brief")" = $'---\norchestration: enabled\n---' ] \
|| fail "orchestrate brief did not record the front-matter orchestration marker"
# shellcheck disable=SC2016
assert_grep 'native `task` subagents' "$brief" \
"orchestrate brief missing the native subagent boundary statement"

FM_HOME="$home" "$ROOT/bin/fm-brief.sh" brief-plain-c2 some-proj --mode direct-PR >/dev/null 2>&1 \
|| fail "plain ship brief should scaffold"
brief="$home/data/brief-plain-c2/brief.md"
assert_no_grep "orchestration: enabled" "$brief" "plain ship brief leaked the orchestration marker"
assert_no_grep "# Orchestration" "$brief" "plain ship brief leaked the Orchestration section"
assert_no_grep "subagents" "$brief" "plain ship brief leaked the orchestration subagent statement"

pass "fm-brief.sh: --orchestrate adds the ship marker only when opted in"
}

test_faster_paths_use_configured_authority_without_stacked_review() {
Expand Down Expand Up @@ -860,6 +894,7 @@ test_ship_modes_generate_clean_briefs
test_ship_mode_is_required_and_closed_set
test_ship_mode_is_explicit_not_registry
test_delivery_flags_are_refused_where_they_do_not_apply
test_orchestrate_opt_in_adds_marker_only_on_ship
test_faster_paths_use_configured_authority_without_stacked_review
test_no_mistakes_dod_wording
test_ship_project_memory_wording
Expand Down
Loading
Loading