From 87c473d7662b28a2f06384d3b7732505310b9f40 Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 18:59:21 +0800 Subject: [PATCH 1/8] feat(omp): add --orchestrate opt-in for ship briefs - fm-brief.sh --orchestrate records orchestration: enabled marker - fm-spawn.sh detects marker and refuses non-ship/non-omp before endpoint creation - OMP launch message now carries explicit orchestrate keyword + brief pointer - Documented in .agents/skills/harness-adapters/SKILL.md and runtime-backends.md - Tests cover opt-in, default behavior, and incompatible-harness refusal --- .agents/skills/harness-adapters/SKILL.md | 9 ++++++ bin/fm-brief.sh | 26 +++++++++++++++-- bin/fm-spawn.sh | 31 ++++++++++++++++++-- docs/verification/runtime-backends.md | 29 +++++++++++++++++++ tests/fm-brief.test.sh | 37 +++++++++++++++++++++++- tests/fm-omp-harness.test.sh | 21 ++++++++++++++ 6 files changed, 148 insertions(+), 5 deletions(-) diff --git a/.agents/skills/harness-adapters/SKILL.md b/.agents/skills/harness-adapters/SKILL.md index 19e41c83462..8c15ec7f9fc 100644 --- a/.agents/skills/harness-adapters/SKILL.md +++ b/.agents/skills/harness-adapters/SKILL.md @@ -328,6 +328,15 @@ 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 default OMP launch message is the encoded full brief (`fm-operational-input.sh encode launch-brief` reads the brief body on stdin and emits `⁣FIRSTMATE_OP: v1 launch-brief: ` as the positional argument), so standalone `orchestrate` in a brief's own prose reaches the matcher even without the opt-in - brief authors must write `orchestration` or backtick `orchestrate` to discuss the mode without triggering it; file reads mid-session are tool results and are never scanned. +`bin/fm-brief.sh --orchestrate` records the opt-in for an ordinary ship task as the non-matching marker `orchestration: enabled`; `bin/fm-spawn.sh` then launches the OMP worker with an initial message containing the standalone keyword plus the brief pointer, so activation is an explicit firstmate-authored signal rather than ambiguous brief prose. +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). diff --git a/bin/fm-brief.sh b/bin/fm-brief.sh index cff2117691d..61674555774 100755 --- a/bin/fm-brief.sh +++ b/bin/fm-brief.sh @@ -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 --mode [--herdr-lab] +# Usage: fm-brief.sh --mode [--herdr-lab] [--orchestrate] # fm-brief.sh --scout [--herdr-lab] # fm-brief.sh --secondmate {...|--no-projects} # fm-brief.sh --render-ship-delivery @@ -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 validated `orchestration: enabled` marker in the brief and lets +# bin/fm-spawn.sh carry the exact lowercase `orchestrate` keyword in the OMP +# launch message. 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 @@ -186,6 +191,7 @@ fi KIND=ship HERDR_LAB=0 NO_PROJECTS=0 +ORCHESTRATE=0 MODE= MODE_SET=0 POS=() @@ -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 ;; @@ -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 @@ -492,6 +504,16 @@ case "$MODE" in esac DOD=$(render_ship_delivery "$ID" "$MODE") +ORCHESTRATION_SECTION="" +if [ "$ORCHESTRATE" -eq 1 ]; then + IFS= read -r -d '' ORCHESTRATION_SECTION <<'EOF' || true +# Orchestration +orchestration: enabled +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 <` 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) @@ -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 @@ -2833,6 +2834,20 @@ 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 `orchestration: enabled` in the 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. +ORCHESTRATE_BRIEF=0 +if grep -Fqx 'orchestration: enabled' "$BRIEF" 2>/dev/null; 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; } + [ "$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 @@ -4288,6 +4303,18 @@ HERMESRESUMEFLAG= LAUNCH=${LAUNCH//__MODELFLAG__/$MODELFLAG} LAUNCH=${LAUNCH//__EFFORTFLAG__/$EFFORTFLAG} LAUNCH=${LAUNCH//__PREWALKFLAG__/$PREWALKFLAG} +if [ "$HARNESS" = omp ]; then + if [ "$ORCHESTRATE_BRIEF" -eq 1 ]; then + # shellcheck disable=SC2016 + # Placeholders __BRIEF__ and __OPINPUT__ are substituted after shell-quoting; + # single quotes here keep the pane-side command literal. + OMP_MESSAGE='"$(printf '"'"'orchestrate\n\nRead the brief at %s and follow it exactly.'"'"' __BRIEF__ | __OPINPUT__ encode launch-brief)"' + else + # shellcheck disable=SC2016 + OMP_MESSAGE='"$(__OPINPUT__ encode launch-brief < __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} diff --git a/docs/verification/runtime-backends.md b/docs/verification/runtime-backends.md index e8e8c03fbca..e56ceb4f8ab 100644 --- a/docs/verification/runtime-backends.md +++ b/docs/verification/runtime-backends.md @@ -381,6 +381,35 @@ 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 + +OMP native orchestration is activated when the exact lowercase keyword `orchestrate` appears in the initial user message. The matcher is a Unicode word-boundary scan 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. A keyword read later from a file does not activate orchestration because tool results are never scanned. The `orchestrate-notice` system prompt is then injected into the session. + +The default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: `), so standalone `orchestrate` in a brief's own prose reaches the matcher even without the opt-in; the `orchestration: enabled` marker deliberately uses the non-matching noun, and brief authors should write `orchestration` or backtick `orchestrate` to discuss the mode without triggering it. + +`fm-brief.sh --orchestrate` records the opt-in for an ordinary ship task by writing `orchestration: enabled` in the brief. `fm-spawn.sh` detects that marker and, only when the resolved harness is `omp`, constructs an OMP-specific initial message containing the standalone keyword plus a pointer to the brief. Any other harness or task kind is refused before any endpoint exists. Nested `task` subagents stay inside the task worktree as implementation helpers; firstmate continues to own outer-task isolation, supervision, delivery, merge authority, receipts, and No-Mistakes branch custody. The `orchestrate` and `workflowz` keywords must not be combined, and the keyword is never added by default. + +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 --mode local-only --orchestrate +FM_HOME="$fixture_home" FM_BACKEND=tmux bin/fm-spawn.sh \ + --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. diff --git a/tests/fm-brief.test.sh b/tests/fm-brief.test.sh index 504cc6249a7..9f147c1cf67 100755 --- a/tests/fm-brief.test.sh +++ b/tests/fm-brief.test.sh @@ -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" + grep -qx "orchestration: enabled" "$brief" \ + || fail "orchestrate brief did not record the machine-readable 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() { @@ -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 diff --git a/tests/fm-omp-harness.test.sh b/tests/fm-omp-harness.test.sh index a73168f2a85..93a3a58e834 100755 --- a/tests/fm-omp-harness.test.sh +++ b/tests/fm-omp-harness.test.sh @@ -408,6 +408,26 @@ test_capability_probe_never_falls_back_when_omp_is_missing() { pass "selected OMP refuses instead of falling back to another harness" } +# An orchestrate opt-in is brief-level data, not a spawn flag. It must fail before +# any endpoint exists if the selected harness is not OMP, so the keyword can never +# be forced onto a different runtime. +test_orchestrate_marker_refuses_non_omp_harness() { + local home proj id out status + home="$TMP_ROOT/orchestrate-refuse-home" + mkdir -p "$home/data" "$home/state" "$home/config" "$home/projects" + proj="$home/project" + fm_git_init_commit "$proj" || fail "could not create project for orchestrate refusal" + id=brief-orch-refuse + out=$(FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" "$(basename "$proj")" --mode direct-PR --orchestrate 2>&1) + status=$? + expect_code 0 "$status" "orchestrate ship brief should scaffold" + out=$(FM_HOME="$home" "$ROOT/bin/fm-spawn.sh" "$id" "$proj" --mode direct-PR --yolo off --harness claude --backend tmux 2>&1) + status=$? + expect_code 1 "$status" "orchestration marker with a non-omp harness should refuse" + assert_contains "$out" "orchestration requires harness=omp" "non-omp harness refusal did not explain the required harness" + pass "fm-spawn: orchestration marker refuses non-omp harnesses" +} + test_launch_boundary_marker_preserves_exact_omp_identity test_standalone_worker_uses_bound_identity test_standalone_primary_survives_executable_replacement @@ -420,3 +440,4 @@ test_capability_probe_rejects_non_bun_entrypoint test_capability_probe_reports_every_missing_requirement test_capability_probe_scopes_exact_max_time_to_bounded_launches test_capability_probe_never_falls_back_when_omp_is_missing +test_orchestrate_marker_refuses_non_omp_harness From e39a07fb3c4e99b50be1154527006923fe1a02be Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 19:39:18 +0800 Subject: [PATCH 2/8] no-mistakes(review): Scoped orchestration marker parsing and added regression coverage --- bin/fm-spawn.sh | 7 ++++++- tests/fm-omp-harness.test.sh | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index 55e008443a2..6b8b6f43619 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -2840,7 +2840,12 @@ fi # in its launch message while every other combination refuses before any endpoint # exists. ORCHESTRATE_BRIEF=0 -if grep -Fqx 'orchestration: enabled' "$BRIEF" 2>/dev/null; then +if awk ' + $0 == "# Orchestration" { section = 1; next } + section && $0 ~ /^#/ { section = 0 } + section && $0 == "orchestration: enabled" { found = 1 } + END { exit(found ? 0 : 1) } +' "$BRIEF" 2>/dev/null; then ORCHESTRATE_BRIEF=1 fi if [ "$ORCHESTRATE_BRIEF" -eq 1 ]; then diff --git a/tests/fm-omp-harness.test.sh b/tests/fm-omp-harness.test.sh index 93a3a58e834..d59c3bb51fb 100755 --- a/tests/fm-omp-harness.test.sh +++ b/tests/fm-omp-harness.test.sh @@ -428,6 +428,27 @@ test_orchestrate_marker_refuses_non_omp_harness() { pass "fm-spawn: orchestration marker refuses non-omp harnesses" } +test_task_text_marker_does_not_opt_in() { + local home proj brief out status + home="$TMP_ROOT/task-text-marker-home" + mkdir -p "$home/data" "$home/state" "$home/config" "$home/projects" + proj="$home/project" + fm_git_init_commit "$proj" || fail "could not create project for task marker regression" + out=$(FM_HOME="$home" "$ROOT/bin/fm-brief.sh" brief-task-marker some-proj --mode direct-PR 2>&1) + status=$? + expect_code 0 "$status" "plain ship brief should scaffold for task marker regression" + brief="$home/data/brief-task-marker/brief.md" + sed -i '/^# Task$/a orchestration: enabled' "$brief" + sed -i 's/{TASK}/Complete the requested work/; s/{ACCEPTANCE CRITERION}/The task completes successfully/' "$brief" + out=$(FM_HOME="$home" "$ROOT/bin/fm-spawn.sh" brief-task-marker "$proj" --mode direct-PR --yolo off --harness claude --backend tmux 2>&1) + status=$? + case "$out" in + *"orchestration requires harness=omp"*) fail "task prose marker was misclassified as orchestration opt-in" ;; + esac + [ "$status" -ne 0 ] || fail "task marker regression unexpectedly launched a worker" + pass "fm-spawn: task prose marker does not opt into orchestration" +} + test_launch_boundary_marker_preserves_exact_omp_identity test_standalone_worker_uses_bound_identity test_standalone_primary_survives_executable_replacement @@ -441,3 +462,4 @@ test_capability_probe_reports_every_missing_requirement test_capability_probe_scopes_exact_max_time_to_bounded_launches test_capability_probe_never_falls_back_when_omp_is_missing test_orchestrate_marker_refuses_non_omp_harness +test_task_text_marker_does_not_opt_in From f821be53a7ec70a1d645f04f56f37cf0632ef983 Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 19:47:36 +0800 Subject: [PATCH 3/8] no-mistakes(review): Prevented accidental OMP orchestration from ordinary brief prose --- bin/fm-spawn.sh | 2 +- docs/verification/runtime-backends.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index 6b8b6f43619..96346bd2c97 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -4316,7 +4316,7 @@ if [ "$HARNESS" = omp ]; then OMP_MESSAGE='"$(printf '"'"'orchestrate\n\nRead the brief at %s and follow it exactly.'"'"' __BRIEF__ | __OPINPUT__ encode launch-brief)"' else # shellcheck disable=SC2016 - OMP_MESSAGE='"$(__OPINPUT__ encode launch-brief < __BRIEF__)"' + OMP_MESSAGE='"$(__OPINPUT__ encode launch-brief < __BRIEF__ | sed -E '\''s/(^|[^[:alnum:]_])orchestrate([^[:alnum:]_]|$)/\1\2/g'\'')"' fi LAUNCH=${LAUNCH//__OMPMESSAGE__/$OMP_MESSAGE} fi diff --git a/docs/verification/runtime-backends.md b/docs/verification/runtime-backends.md index e56ceb4f8ab..c9cbec4fa8f 100644 --- a/docs/verification/runtime-backends.md +++ b/docs/verification/runtime-backends.md @@ -385,7 +385,7 @@ Live firing of the fleet hook's `tool_result`, `todo_reminder`, and `session.com OMP native orchestration is activated when the exact lowercase keyword `orchestrate` appears in the initial user message. The matcher is a Unicode word-boundary scan 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. A keyword read later from a file does not activate orchestration because tool results are never scanned. The `orchestrate-notice` system prompt is then injected into the session. -The default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: `), so standalone `orchestrate` in a brief's own prose reaches the matcher even without the opt-in; the `orchestration: enabled` marker deliberately uses the non-matching noun, and brief authors should write `orchestration` or backtick `orchestrate` to discuss the mode without triggering it. +The default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: `). Before delivery, standalone `orchestrate` in an ordinary brief is wrapped in an inline HTML comment so brief prose cannot activate native orchestration accidentally; the `orchestration: enabled` marker deliberately uses the non-matching noun. `fm-brief.sh --orchestrate` records the opt-in for an ordinary ship task by writing `orchestration: enabled` in the brief. `fm-spawn.sh` detects that marker and, only when the resolved harness is `omp`, constructs an OMP-specific initial message containing the standalone keyword plus a pointer to the brief. Any other harness or task kind is refused before any endpoint exists. Nested `task` subagents stay inside the task worktree as implementation helpers; firstmate continues to own outer-task isolation, supervision, delivery, merge authority, receipts, and No-Mistakes branch custody. The `orchestrate` and `workflowz` keywords must not be combined, and the keyword is never added by default. From f7155cccd9fea73a5ea84084c76de6acb3ccd7d9 Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 21:45:07 +0800 Subject: [PATCH 4/8] fix(omp): front-matter orchestration marker and separate orchestrate launch message - bin/fm-brief.sh --orchestrate now writes a generated YAML front-matter marker (---\norchestration: enabled\n---) at the top of the brief, not a line scannable through task prose. - bin/fm-spawn.sh reads only the first three lines to detect the opt-in, so ordinary task/AC text, quoted examples, and code blocks cannot spoof it. - Opted-in OMP launches pass two positional messages: the standalone lowercase 'orchestrate' keyword, followed by the unchanged encoded brief. - Non-opted launches pass only the unchanged encoded brief; no sed rewriting or HTML-comment corruption. - Update tests and docs to match the front-matter and two-message design. - Live proof on OMP 18.1.14 confirms orchestrate-notice injection, multiple task subagents, and combined pytest verification. --- .agents/skills/harness-adapters/SKILL.md | 5 ++-- bin/fm-brief.sh | 18 ++++++++----- bin/fm-spawn.sh | 32 ++++++++++++------------ docs/verification/runtime-backends.md | 6 +++-- tests/fm-brief.test.sh | 4 +-- tests/fm-omp-harness.test.sh | 2 +- 6 files changed, 38 insertions(+), 29 deletions(-) diff --git a/.agents/skills/harness-adapters/SKILL.md b/.agents/skills/harness-adapters/SKILL.md index 8c15ec7f9fc..be8c4e15be8 100644 --- a/.agents/skills/harness-adapters/SKILL.md +++ b/.agents/skills/harness-adapters/SKILL.md @@ -330,8 +330,9 @@ OMP workers keep their sessions under the task temp root so recovery can resume **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 default OMP launch message is the encoded full brief (`fm-operational-input.sh encode launch-brief` reads the brief body on stdin and emits `⁣FIRSTMATE_OP: v1 launch-brief: ` as the positional argument), so standalone `orchestrate` in a brief's own prose reaches the matcher even without the opt-in - brief authors must write `orchestration` or backtick `orchestrate` to discuss the mode without triggering it; file reads mid-session are tool results and are never scanned. -`bin/fm-brief.sh --orchestrate` records the opt-in for an ordinary ship task as the non-matching marker `orchestration: enabled`; `bin/fm-spawn.sh` then launches the OMP worker with an initial message containing the standalone keyword plus the brief pointer, so activation is an explicit firstmate-authored signal rather than ambiguous brief prose. +The default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: ` 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 two positional user messages: the standalone `orchestrate` keyword, followed by the unchanged encoded brief. For an ordinary (non-opted) OMP launch it passes only the unchanged encoded brief. 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. diff --git a/bin/fm-brief.sh b/bin/fm-brief.sh index 61674555774..ddc46bc0491 100755 --- a/bin/fm-brief.sh +++ b/bin/fm-brief.sh @@ -18,10 +18,10 @@ # 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 validated `orchestration: enabled` marker in the brief and lets -# bin/fm-spawn.sh carry the exact lowercase `orchestrate` keyword in the OMP -# launch message. It is refused on scout and secondmate briefs, which are not -# ship tasks. +# 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 @@ -504,18 +504,24 @@ 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 -orchestration: enabled 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 <&2; exit 1; } # Orchestration opt-in is explicit task data, never a keyword scan of prose: -# fm-brief.sh --orchestrate records `orchestration: enabled` in the 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. +# 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 awk ' - $0 == "# Orchestration" { section = 1; next } - section && $0 ~ /^#/ { section = 0 } - section && $0 == "orchestration: enabled" { found = 1 } - END { exit(found ? 0 : 1) } -' "$BRIEF" 2>/dev/null; then +if [ "$(head -n 3 "$BRIEF" 2>/dev/null)" = $'---\norchestration: enabled\n---' ]; then ORCHESTRATE_BRIEF=1 fi if [ "$ORCHESTRATE_BRIEF" -eq 1 ]; then @@ -4309,14 +4307,16 @@ 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 encoded brief is + # passed as a separate positional argument so the full original task text is + # delivered unchanged. Opt-in adds the standalone `orchestrate` keyword as its + # own message before the brief. if [ "$ORCHESTRATE_BRIEF" -eq 1 ]; then - # shellcheck disable=SC2016 - # Placeholders __BRIEF__ and __OPINPUT__ are substituted after shell-quoting; - # single quotes here keep the pane-side command literal. - OMP_MESSAGE='"$(printf '"'"'orchestrate\n\nRead the brief at %s and follow it exactly.'"'"' __BRIEF__ | __OPINPUT__ encode launch-brief)"' + OMP_MESSAGE='"orchestrate" "$(__OPINPUT__ encode launch-brief < __BRIEF__)"' else - # shellcheck disable=SC2016 - OMP_MESSAGE='"$(__OPINPUT__ encode launch-brief < __BRIEF__ | sed -E '\''s/(^|[^[:alnum:]_])orchestrate([^[:alnum:]_]|$)/\1\2/g'\'')"' + OMP_MESSAGE='"$(__OPINPUT__ encode launch-brief < __BRIEF__)"' fi LAUNCH=${LAUNCH//__OMPMESSAGE__/$OMP_MESSAGE} fi diff --git a/docs/verification/runtime-backends.md b/docs/verification/runtime-backends.md index c9cbec4fa8f..08e91935cb9 100644 --- a/docs/verification/runtime-backends.md +++ b/docs/verification/runtime-backends.md @@ -385,9 +385,11 @@ Live firing of the fleet hook's `tool_result`, `todo_reminder`, and `session.com OMP native orchestration is activated when the exact lowercase keyword `orchestrate` appears in the initial user message. The matcher is a Unicode word-boundary scan 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. A keyword read later from a file does not activate orchestration because tool results are never scanned. The `orchestrate-notice` system prompt is then injected into the session. -The default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: `). Before delivery, standalone `orchestrate` in an ordinary brief is wrapped in an inline HTML comment so brief prose cannot activate native orchestration accidentally; the `orchestration: enabled` marker deliberately uses the non-matching noun. +The default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: `). File reads mid-session are tool results and are never scanned for keywords. -`fm-brief.sh --orchestrate` records the opt-in for an ordinary ship task by writing `orchestration: enabled` in the brief. `fm-spawn.sh` detects that marker and, only when the resolved harness is `omp`, constructs an OMP-specific initial message containing the standalone keyword plus a pointer to the brief. Any other harness or task kind is refused before any endpoint exists. Nested `task` subagents stay inside the task worktree as implementation helpers; firstmate continues to own outer-task isolation, supervision, delivery, merge authority, receipts, and No-Mistakes branch custody. The `orchestrate` and `workflowz` keywords must not be combined, and the keyword is never added by default. +`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. `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, `fm-spawn.sh` passes two positional user messages: the standalone `orchestrate` keyword, followed by the unchanged encoded brief. For an ordinary (non-opted) OMP launch it passes only the unchanged encoded brief. Any other harness or task kind is refused before any endpoint exists. Nested `task` subagents stay inside the task worktree as implementation helpers; firstmate continues to own outer-task isolation, supervision, delivery, merge authority, receipts, and No-Mistakes branch custody. The `orchestrate` and `workflowz` keywords must not be combined, and the keyword is never added by default. 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: diff --git a/tests/fm-brief.test.sh b/tests/fm-brief.test.sh index 9f147c1cf67..141d2a3bb09 100755 --- a/tests/fm-brief.test.sh +++ b/tests/fm-brief.test.sh @@ -334,8 +334,8 @@ test_orchestrate_opt_in_adds_marker_only_on_ship() { 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" - grep -qx "orchestration: enabled" "$brief" \ - || fail "orchestrate brief did not record the machine-readable orchestration marker" + [ "$(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" diff --git a/tests/fm-omp-harness.test.sh b/tests/fm-omp-harness.test.sh index d59c3bb51fb..bc3a6f335c3 100755 --- a/tests/fm-omp-harness.test.sh +++ b/tests/fm-omp-harness.test.sh @@ -417,7 +417,7 @@ test_orchestrate_marker_refuses_non_omp_harness() { mkdir -p "$home/data" "$home/state" "$home/config" "$home/projects" proj="$home/project" fm_git_init_commit "$proj" || fail "could not create project for orchestrate refusal" - id=brief-orch-refuse + id="brief-orch-refuse" out=$(FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" "$(basename "$proj")" --mode direct-PR --orchestrate 2>&1) status=$? expect_code 0 "$status" "orchestrate ship brief should scaffold" From 118c59801dfb15efdb926d45f8fc064d40c05e10 Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 22:19:03 +0800 Subject: [PATCH 5/8] fix(omp): single task-bearing launch message with optional orchestrate keyword - Replaces the two-positional-message launch with a single encoded message. - Non-opted launches: 'Read the brief at and follow it exactly.' - Opted-in launches: 'orchestrate\n\nRead the brief at and follow it exactly.' - The original task text stays in the brief file, read via a tool result (never keyword-scanned). - Keeps the generated front-matter marker so task prose cannot spoof opt-in. - Live proof on OMP 18.1.14: orchestrate-notice injected, two task subagents, 5 pytest passes. --- .agents/skills/harness-adapters/SKILL.md | 4 ++-- bin/fm-spawn.sh | 11 +++++------ docs/verification/runtime-backends.md | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.agents/skills/harness-adapters/SKILL.md b/.agents/skills/harness-adapters/SKILL.md index be8c4e15be8..5a6e9f4a285 100644 --- a/.agents/skills/harness-adapters/SKILL.md +++ b/.agents/skills/harness-adapters/SKILL.md @@ -330,9 +330,9 @@ OMP workers keep their sessions under the task temp root so recovery can resume **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 default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: ` as the positional argument). File reads mid-session are tool results and are never scanned for keywords. +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: ` 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 two positional user messages: the standalone `orchestrate` keyword, followed by the unchanged encoded brief. For an ordinary (non-opted) OMP launch it passes only the unchanged encoded brief. +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. 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. diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index 45463d85d01..0b91fbe47f1 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -4309,14 +4309,13 @@ 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 encoded brief is - # passed as a separate positional argument so the full original task text is - # delivered unchanged. Opt-in adds the standalone `orchestrate` keyword as its - # own message before the brief. + # 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='"orchestrate" "$(__OPINPUT__ encode launch-brief < __BRIEF__)"' + OMP_MESSAGE='"$(printf '"'"'orchestrate\n\nRead the brief at %s and follow it exactly.'"'"' __BRIEF__ | __OPINPUT__ encode launch-brief)"' else - OMP_MESSAGE='"$(__OPINPUT__ encode launch-brief < __BRIEF__)"' + OMP_MESSAGE='"$(printf '"'"'Read the brief at %s and follow it exactly.'"'"' __BRIEF__ | __OPINPUT__ encode launch-brief)"' fi LAUNCH=${LAUNCH//__OMPMESSAGE__/$OMP_MESSAGE} fi diff --git a/docs/verification/runtime-backends.md b/docs/verification/runtime-backends.md index 08e91935cb9..2b8dd6e0795 100644 --- a/docs/verification/runtime-backends.md +++ b/docs/verification/runtime-backends.md @@ -385,11 +385,11 @@ Live firing of the fleet hook's `tool_result`, `todo_reminder`, and `session.com OMP native orchestration is activated when the exact lowercase keyword `orchestrate` appears in the initial user message. The matcher is a Unicode word-boundary scan 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. A keyword read later from a file does not activate orchestration because tool results are never scanned. The `orchestrate-notice` system prompt is then injected into the session. -The default OMP launch message is the encoded full brief body (`fm-operational-input.sh encode launch-brief` emits `⁣FIRSTMATE_OP: v1 launch-brief: `). File reads mid-session are tool results and are never scanned for keywords. +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: ` as the positional argument). File reads mid-session are tool results and are never scanned for keywords. `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. `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, `fm-spawn.sh` passes two positional user messages: the standalone `orchestrate` keyword, followed by the unchanged encoded brief. For an ordinary (non-opted) OMP launch it passes only the unchanged encoded brief. Any other harness or task kind is refused before any endpoint exists. Nested `task` subagents stay inside the task worktree as implementation helpers; firstmate continues to own outer-task isolation, supervision, delivery, merge authority, receipts, and No-Mistakes branch custody. The `orchestrate` and `workflowz` keywords must not be combined, and the keyword is never added by default. +For an opted-in OMP launch, `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. Any other harness or task kind is refused before any endpoint exists. Nested `task` subagents stay inside the task worktree as implementation helpers; firstmate continues to own outer-task isolation, supervision, delivery, merge authority, receipts, and No-Mistakes branch custody. The `orchestrate` and `workflowz` keywords must not be combined, and the keyword is never added by default. 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: From 9749aba869aac82dd00f17d03a4b20a33b86acde Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 22:39:05 +0800 Subject: [PATCH 6/8] no-mistakes(document): Consolidated OMP orchestration documentation ownership --- docs/verification/runtime-backends.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/verification/runtime-backends.md b/docs/verification/runtime-backends.md index 2b8dd6e0795..2f20a539eb9 100644 --- a/docs/verification/runtime-backends.md +++ b/docs/verification/runtime-backends.md @@ -383,13 +383,7 @@ Live firing of the fleet hook's `tool_result`, `todo_reminder`, and `session.com ### OMP native orchestration opt-in -OMP native orchestration is activated when the exact lowercase keyword `orchestrate` appears in the initial user message. The matcher is a Unicode word-boundary scan 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. A keyword read later from a file does not activate orchestration because tool results are never scanned. The `orchestrate-notice` system prompt is then injected into the session. - -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: ` as the positional argument). File reads mid-session are tool results and are never scanned for keywords. - -`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. `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, `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. Any other harness or task kind is refused before any endpoint exists. Nested `task` subagents stay inside the task worktree as implementation helpers; firstmate continues to own outer-task isolation, supervision, delivery, merge authority, receipts, and No-Mistakes branch custody. The `orchestrate` and `workflowz` keywords must not be combined, and the keyword is never added by default. +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: From 5d52705b19fbf1fb0cbd20335ac2295d5764655d Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 23:25:00 +0800 Subject: [PATCH 7/8] fix(omp): refuse orchestrated briefs on raw launch commands - Reject marked briefs when RAW_LAUNCH=1, before the harness check, so a raw command cannot bypass the verified OMP launch template and silently drop the orchestrate keyword. - Add negative regression test that verifies a raw 'cat /dev/null' launch for a marked brief is refused with the verified-template message. - Non-opted raw launches and non-raw verified OMP launches are unchanged. --- bin/fm-spawn.sh | 4 ++++ tests/fm-omp-harness.test.sh | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index 0b91fbe47f1..dab51c3d1ea 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -2848,6 +2848,10 @@ if [ "$(head -n 3 "$BRIEF" 2>/dev/null)" = $'---\norchestration: enabled\n---' ] 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 diff --git a/tests/fm-omp-harness.test.sh b/tests/fm-omp-harness.test.sh index bc3a6f335c3..d2e94fb56cb 100755 --- a/tests/fm-omp-harness.test.sh +++ b/tests/fm-omp-harness.test.sh @@ -428,6 +428,26 @@ test_orchestrate_marker_refuses_non_omp_harness() { pass "fm-spawn: orchestration marker refuses non-omp harnesses" } +# An orchestrate opt-in is brief-level data. The verified OMP template is the only +# launch path that injects the exact `orchestrate` keyword; a raw launch command +# bypasses that template and must refuse a marked brief before endpoint creation. +test_orchestrate_marker_refuses_raw_launch_command() { + local home proj id out status + home="$TMP_ROOT/orchestrate-raw-refuse-home" + mkdir -p "$home/data" "$home/state" "$home/config" "$home/projects" + proj="$home/project" + fm_git_init_commit "$proj" || fail "could not create project for raw launch refusal" + id="brief-orch-raw" + out=$(FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" "$(basename "$proj")" --mode direct-PR --orchestrate 2>&1) + status=$? + expect_code 0 "$status" "orchestrate ship brief should scaffold" + out=$(FM_HOME="$home" "$ROOT/bin/fm-spawn.sh" "$id" "$proj" "cat /dev/null" --mode direct-PR --yolo off --backend tmux 2>&1) + status=$? + expect_code 1 "$status" "orchestration marker with a raw launch command should refuse" + assert_contains "$out" "orchestration requires the verified OMP launch template" "raw launch refusal did not explain the required template" + pass "fm-spawn: orchestration marker refuses raw launch commands" +} + test_task_text_marker_does_not_opt_in() { local home proj brief out status home="$TMP_ROOT/task-text-marker-home" @@ -462,4 +482,5 @@ test_capability_probe_reports_every_missing_requirement test_capability_probe_scopes_exact_max_time_to_bounded_launches test_capability_probe_never_falls_back_when_omp_is_missing test_orchestrate_marker_refuses_non_omp_harness +test_orchestrate_marker_refuses_raw_launch_command test_task_text_marker_does_not_opt_in From c0969214a4e83ce06f1ebb756208965efe827a3a Mon Sep 17 00:00:00 2001 From: dnth Date: Thu, 10 Sep 2026 23:36:00 +0800 Subject: [PATCH 8/8] no-mistakes(document): Documented marked-brief raw-launch refusal --- .agents/skills/harness-adapters/SKILL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.agents/skills/harness-adapters/SKILL.md b/.agents/skills/harness-adapters/SKILL.md index 5a6e9f4a285..866b92e76e3 100644 --- a/.agents/skills/harness-adapters/SKILL.md +++ b/.agents/skills/harness-adapters/SKILL.md @@ -333,6 +333,7 @@ The matcher is a Unicode word-boundary scan of the message that starts the turn, 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: ` 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.