From a2665fc38a657e8833fa5bc4b5ebed2e5d0b8a7b Mon Sep 17 00:00:00 2001 From: kunchenguid Date: Fri, 10 Jul 2026 14:21:44 -0700 Subject: [PATCH 1/4] docs: consolidate universal backend contracts into configuration.md Slice 2 of the documentation redundancy cleanup wave (firstmate scope). docs/configuration.md is now the declared single owner of three universal contracts, each with an explicit ownership sentence: - the universal toolchain list (Toolchain), now also carrying the per-tool purpose clauses that previously lived only in the tmux guide; - the task-selector vocabulary (Runtime backend); - the tasks-axi compatibility definition (Backlog backend). The five backend guides' prerequisites replace their verbatim universal-requirements parentheticals (5 full copies) with a pointer plus only backend-specific items; zellij/cmux selector restatements and architecture.md's partial copy become pointers or are dropped; CONTRIBUTING's compatibility sentence becomes a pointer; two near-verbatim orca-bootstrap restatements (configuration.md Runtime backend, orca guide) collapse into the Toolchain owner copy. Backend-specific setup, behavior, target-string shapes, and every empirical verification record are untouched. AGENTS.md untouched (slice 3). --- CONTRIBUTING.md | 3 +-- docs/architecture.md | 2 +- docs/cmux-backend.md | 4 ++-- docs/configuration.md | 9 ++++++--- docs/herdr-backend.md | 2 +- docs/orca-backend.md | 3 +-- docs/tmux-backend.md | 7 +------ docs/zellij-backend.md | 4 ++-- 8 files changed, 15 insertions(+), 19 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index abbad1d6649..a97eaeaef40 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,8 +37,7 @@ See the [no-mistakes quick start](https://kunchenguid.github.io/no-mistakes/star - Only shared material is tracked: `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.tasks.toml`, `.github/workflows/`, `bin/`, `.agents/skills/`, and `skills/`. `.agents/skills/` holds agent-loaded skills that assume a live firstmate home and carry `metadata.internal: true` so installers such as [skills.sh](https://skills.sh) hide them from discovery; `skills/` holds standalone, installer-facing public skills with no firstmate dependency (see the README's "Two-tier skill layout"). Everything personal to one captain's fleet (`.env`, `data/`, `state/`, `config/`, `projects/`, `.no-mistakes/`) is gitignored; never commit it. - The root `.tasks.toml` is tracked `tasks-axi` config for `data/backlog.md`; compatible `tasks-axi` is the default backend for routine backlog mutations. - Compatible means version 0.1.1 or newer, `tasks-axi update --help` exposing `--archive-body`, and `tasks-axi mv --help` exposing `[...]` for atomic multi-ID moves. + The root `.tasks.toml` is tracked `tasks-axi` config for `data/backlog.md`; compatible `tasks-axi` is the default backend for routine backlog mutations, with the compatibility definition owned by [`docs/configuration.md`](docs/configuration.md) ("Backlog backend"). A local `config/backlog-backend=manual` opt-out forces firstmate's routine backlog updates to hand-editing and stays gitignored; validated secondmate handoffs still delegate through `tasks-axi mv`. A local `config/backend` file explicitly overrides runtime auto-detection for new task endpoints and stays gitignored; spawn-supported values are `tmux` plus experimental `herdr`, `zellij`, `orca`, and `cmux`, while `codex-app` is documented only in `docs/codex-app-backend.md`. It does not make `data/` tracked. diff --git a/docs/architecture.md b/docs/architecture.md index eeb814e4bd2..7832b030b39 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -71,7 +71,7 @@ The deeper session-start agent-process liveness probe is separate from that busy Herdr is experimental and can be selected explicitly or by runtime auto-detection: treehouse remains the worktree provider for it exactly as it is for tmux (herdr is a session provider only), and its full verification - the container shape decision, created-vs-adopted default-tab prune safety, restored-layout husk respawn idempotency, verified CLI facts, ANSI-preserved ghost/placeholder classification through the shared extractor, a verified small-`--lines` capture bug and its workaround, and known gaps - is recorded in `docs/herdr-backend.md`. Herdr's container shape is workspace-per-home plus tab-per-task: the primary home uses workspace label `firstmate`, secondmate homes use `2ndmate-`, and recovery/list-live scopes to the current `FM_HOME`'s workspace. Zellij is experimental and selected only explicitly: treehouse remains its worktree provider too, and its full verification - the resolved "gaps to verify" list from the original design report, the unconditional-exit-0 CLI quirk and its mitigation, the focus-steal-on-new-tab finding, the home-scoped tab-title collision fix, and known gaps - is recorded in `docs/zellij-backend.md`. -Zellij's container shape is simpler than herdr's: one shared `firstmate` session, one tab per task, with no per-home workspace split; visible tab titles are scoped by the active home label plus a short hash of the resolved `FM_ROOT` path while task selectors can use exact ids or stable `fm-` labels. +Zellij's container shape is simpler than herdr's: one shared `firstmate` session, one tab per task, with no per-home workspace split; visible tab titles are scoped by the active home label plus a short hash of the resolved `FM_ROOT` path. Orca is experimental and selected only explicitly: Orca owns both worktree and terminal lifecycle, records `orca_worktree_id=` and `terminal=`, and removes worktrees through `orca worktree rm` only after the usual firstmate teardown checks pass. Its current behavior and limitations are recorded in `docs/orca-backend.md`. cmux is experimental, GUI-first, macOS-only, and can be selected explicitly or by runtime auto-detection from its primary `CMUX_WORKSPACE_ID` marker plus documented fallback signals: treehouse remains its worktree provider (cmux is a session provider only, like herdr/zellij), and its full verification - the socket access setup requirement with Automation mode recommended, the read-screen-fails-on-a-fresh-surface finding, the close-surface-refuses-on-the-last-surface finding, the source-verified runtime marker and fallback behavior, and known gaps - is recorded in `docs/cmux-backend.md`. cmux's container shape is one workspace per task with one surface, no per-home container split; workspace titles are scoped by the active home label plus a short hash of the resolved `FM_ROOT` path, and `--secondmate` spawns are refused, mirroring Orca. diff --git a/docs/cmux-backend.md b/docs/cmux-backend.md index bd2c0eb375c..baf30f5fa5e 100644 --- a/docs/cmux-backend.md +++ b/docs/cmux-backend.md @@ -17,7 +17,7 @@ Prerequisites: - The cmux app itself, installed from [cmux.com](https://cmux.com) or `brew install --cask cmux`, version 0.64.17 or newer. - `jq`, required to parse cmux's JSON output: `brew install jq` (or your platform's package manager). -- The same universal requirements as tmux (a verified crew harness, git with GitHub auth, node, treehouse, no-mistakes, gh-axi, chrome-devtools-axi, lavish-axi, tasks-axi 0.1.1 or newer with `update --archive-body` and atomic multi-ID `mv` from 0.2.2, and quota-axi); treehouse still provides the worktree, cmux only provides the session. +- The universal firstmate prerequisites - a verified crew harness plus the required toolchain, owned by [`docs/configuration.md`](configuration.md) ("Harness support", "Toolchain"); treehouse still provides the worktree, cmux only provides the session. - The cmux CLI binary is not guaranteed to be on `PATH` after a plain app install (see "CLI is not on PATH by default" below) - the adapter falls back to the well-known bundle path automatically, so this is not a blocker, just something to be aware of if you want to run `cmux` yourself from a shell. **One-time socket access setup (required, not optional):** cmux's control socket defaults to `automation.socketControlMode: "cmuxOnly"`, which rejects any CLI process not spawned inside cmux itself - firstmate always drives cmux from an external shell, so this must be changed before `backend=cmux` can work at all. @@ -55,7 +55,7 @@ A cmux spawn refuses loudly, with an actionable message pointing back to this do No first-run provisioning beyond the socket-access setup above and having `jq` installed; firstmate creates the workspace it needs on first spawn, launching the app itself (`open -a cmux`) if it is not already running. Watching and attaching: firstmate uses one workspace per task in whatever cmux window is currently open. -Callers can use exact task ids or stable `fm-` labels, while the actual cmux workspace title is home-scoped as `fm--`, for example `fm-firstmate-<8hex>-cmux-e2e-t1` in the primary home or `fm-2ndmate--<8hex>-cmux-e2e-t1` in a secondmate home. +Task selectors resolve through the shared contract owned by [`docs/configuration.md`](configuration.md) ("Runtime backend"), while the actual cmux workspace title is home-scoped as `fm--`, for example `fm-firstmate-<8hex>-cmux-e2e-t1` in the primary home or `fm-2ndmate--<8hex>-cmux-e2e-t1` in a secondmate home. You do not need to bring the window forward for routine supervision: from an active firstmate session, `bin/fm-peek.sh ` reads a task's surface without focusing it, and `FM_HOME= bin/fm-send.sh ""` steers it unless `FM_HOME` is already set to the active firstmate home - workspace/surface/pane creation all default `focus` to `false`, so an unattended spawn never steals your view. Verify it works by spawning a trivial task with `--backend cmux` and confirming the task's meta records `backend=cmux` plus `cmux_workspace_id=` and `cmux_surface_id=`. diff --git a/docs/configuration.md b/docs/configuration.md index df4ee46c9c5..14c92f74164 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -15,6 +15,7 @@ It moves in-scope `## Queued` items only and refuses `## In flight` and historic Handoff item bodies must use at least two leading spaces, and the helper refuses a selected item with a single-space or tab-indented continuation rather than risk orphaning it. Because bootstrap requires `tasks-axi` on `PATH` on every profile, that delegation works fleet-wide, and the `config/backlog-backend=manual` knob governs firstmate's own hand-editing of its backlog, not this validated helper. Compatible means the shared bootstrap probe accepts `tasks-axi --version` as 0.1.1 or newer, `tasks-axi update --help` exposes `--archive-body`, and `tasks-axi mv --help` exposes `[...]` for the atomic multi-ID move introduced in 0.2.2 and required by handoff delegation. +That sentence is the single owner of the tasks-axi compatibility definition; every other document points here instead of restating the version gates. Bootstrap requires compatible `tasks-axi` on every profile; see "Toolchain" below for missing-tool reporting and `TASKS_AXI: available` behavior. Set the local, gitignored `config/backlog-backend` file to `manual` to force manual backlog editing and suppress `TASKS_AXI: available`, not missing-tool reporting. Absent or `tasks-axi` selects the default tasks-axi backend. @@ -39,7 +40,6 @@ A herdr spawn additionally version-gates against the installed `herdr` binary's A zellij spawn additionally version-gates against the installed `zellij` binary's version and requires `jq`, refusing loudly when either is missing or the version is older than 0.44. A cmux spawn additionally version-gates against the installed `cmux` binary's version, requires `jq`, and requires the control socket to be reachable and accessible (see [`docs/cmux-backend.md`](cmux-backend.md) "Setup" for the one-time socket-access configuration this needs; Automation mode is the recommended socket control mode, with Password mode supported via `config/cmux-socket-password`), refusing loudly and non-retryably on a `cmuxOnly`/unauthenticated socket. A backend spawn refusal from a missing dependency, version gate, or unauthenticated socket is terminal for that selected backend; firstmate surfaces it as a blocker instead of silently retrying another backend. -When bootstrap resolves `backend=orca` from `FM_BACKEND` or `config/backend`, it checks for `orca`, keeps the universal `node` requirement, and skips the tmux/treehouse tool pair because Orca owns both the worktree and terminal lifecycle. Task meta records `backend=` only for a non-default backend; an absent `backend=` means `tmux`, preserving existing default-path meta files. A herdr task additionally records `herdr_session=`, `herdr_workspace_id=`, `herdr_tab_id=`, and `herdr_pane_id=`. A zellij task additionally records `zellij_session=`, `zellij_tab_id=`, and `zellij_pane_id=`. @@ -50,13 +50,14 @@ A selector containing `:` is passed through as an explicit backend endpoint esca Otherwise an exact task id matching `state/.meta` wins before the legacy `fm-` label fallback, so task ids that themselves start with `fm-` route to their own metadata instead of being stripped. A metadata-routed selector returns the recorded backend target (`terminal=` for Orca, otherwise `window=`), and matching explicit targets can still recover the recorded backend when metadata contains the same endpoint. Only metadata-routed task selectors carry secondmate-marker and Codex-harness context; explicit endpoint escape hatches do not. +These five sentences are the single owner of the task-selector vocabulary; backend guides and other documents point here instead of restating the resolution order. `fm-teardown.sh ` takes a task id directly and uses the same recorded backend target fields after loading `state/.meta`. Herdr workspaces are derived from `FM_HOME`: the primary home uses `firstmate`, and a secondmate home marked by `.fm-secondmate-home` uses `2ndmate-`. Spawn, list-live, and recovery paths read that label from the active home, so a secondmate's own crewmates stay inside that secondmate home's herdr space. For normal herdr operations, `HERDR_SESSION` selects the named session, but destructive test cleanup must not rely on `HERDR_SESSION` alone. Use the explicit guarded cleanup path described in [`docs/herdr-backend.md`](herdr-backend.md) instead of `herdr server stop`. For normal zellij operations, `FM_ZELLIJ_SESSION` selects the named session and defaults to `firstmate`. -Zellij has no per-home workspace split: primary and secondmate tasks share that one session, task selectors can be exact ids or stable `fm-` labels, and visible tab titles are scoped by the active `FM_HOME` readable label plus a short hash of the resolved `FM_ROOT` path as `fm--`. +Zellij has no per-home workspace split: primary and secondmate tasks share that one session, and visible tab titles are scoped by the active `FM_HOME` readable label plus a short hash of the resolved `FM_ROOT` path as `fm--`. Use the guarded cleanup path described in [`docs/zellij-backend.md`](zellij-backend.md) instead of `kill-all-sessions` or `delete-all-sessions`. cmux has no session layer at all - one workspace per task, in whatever cmux window is open - and its socket password (when configured) is read from local, gitignored `config/cmux-socket-password` under the effective config directory, never committed. The caller-facing label remains `fm-`, but the actual cmux workspace title is scoped by the active `FM_HOME` readable label plus a short hash of the resolved `FM_ROOT` path as `fm--`. @@ -167,7 +168,9 @@ Secondmate homes inherit this file from the primary, so a secondmate's own crewm ## Toolchain -On session start the first mate detects what its required toolchain is missing or too old (tmux, node, gh, treehouse with durable lease support, no-mistakes v1.31.2 or newer, gh-axi, chrome-devtools-axi, lavish-axi, tasks-axi 0.1.1 or newer with `update --archive-body` and atomic multi-ID `mv` from 0.2.2, and quota-axi), lists it with the exact install commands, and installs only after you say go. +On session start the first mate detects what its required toolchain is missing or too old (tmux, node, gh, treehouse with durable lease support, no-mistakes v1.31.2 or newer, gh-axi, chrome-devtools-axi, lavish-axi, compatible tasks-axi per "Backlog backend" above, and quota-axi), lists it with the exact install commands, and installs only after you say go. +This section is the single owner of that universal toolchain list; backend guides' prerequisites point here and add only their backend-specific tools. +In that list, treehouse pools clean task worktrees, no-mistakes runs the validation pipeline, gh-axi, chrome-devtools-axi, and lavish-axi cover GitHub, browser, and rich-review operations, and tasks-axi plus quota-axi back backlog mutations and quota-balanced dispatch. When bootstrap resolves `backend=orca` from `FM_BACKEND` or `config/backend`, it requires `orca`, keeps the universal `node` requirement, and skips `tmux` and `treehouse`. When `config/crew-dispatch.json` exists, bootstrap also requires `jq` for dispatch profile validation. When X mode is opted in, bootstrap also requires `curl` and `jq` before arming the relay poll shim. diff --git a/docs/herdr-backend.md b/docs/herdr-backend.md index 97d205f8b3d..479e14f43f1 100644 --- a/docs/herdr-backend.md +++ b/docs/herdr-backend.md @@ -20,7 +20,7 @@ Prerequisites: - `herdr` itself, protocol 14 or newer (installed 0.7.1 verified) - see [herdr.dev](https://herdr.dev) for install instructions. - `jq`, required to parse herdr's JSON output: `brew install jq` (or your platform's package manager). -- The same universal requirements as tmux (a verified crew harness, git with GitHub auth, node, treehouse, no-mistakes, gh-axi, chrome-devtools-axi, lavish-axi, tasks-axi 0.1.1 or newer with `update --archive-body` and atomic multi-ID `mv` from 0.2.2, and quota-axi); treehouse still provides the worktree, herdr only provides the session. +- The universal firstmate prerequisites - a verified crew harness plus the required toolchain, owned by [`docs/configuration.md`](configuration.md) ("Harness support", "Toolchain"); treehouse still provides the worktree, herdr only provides the session. Select herdr by putting `herdr` in a local `config/backend` file - the durable way to pick it - or by exporting `FM_BACKEND=herdr` when you launch your harness for a one-off session; telling the first mate in chat to use herdr also works. It can also be auto-detected: when firstmate itself is running natively inside herdr (`HERDR_ENV=1`) and no explicit backend is set, firstmate auto-selects herdr and prints a one-time opt-out notice; running inside tmux nested in herdr always resolves to tmux instead. diff --git a/docs/orca-backend.md b/docs/orca-backend.md index 7cf25adace2..725eca7d5b7 100644 --- a/docs/orca-backend.md +++ b/docs/orca-backend.md @@ -14,11 +14,10 @@ Prerequisites: - The Orca app installed at `/Applications/Orca.app`, and **running**. - The `orca` CLI: `brew install orca`. - `node`, used by firstmate's adapter to parse Orca's JSON output and to gate spawns on runtime readiness. -- `git` with GitHub auth, `no-mistakes`, `gh-axi`, `chrome-devtools-axi`, `lavish-axi`, `tasks-axi` 0.1.1 or newer with `update --archive-body` and atomic multi-ID `mv` from 0.2.2, and `quota-axi` - the same universal requirements as tmux, minus `tmux` and `treehouse` (Orca replaces both). +- The universal firstmate prerequisites minus `tmux` and `treehouse` (Orca replaces both) - a verified crew harness plus the required toolchain, owned by [`docs/configuration.md`](configuration.md) ("Harness support", "Toolchain"). Select Orca by putting `orca` in a local `config/backend` file - the durable way to pick it - or by exporting `FM_BACKEND=orca` when you launch your harness for a one-off session; telling the first mate in chat to use Orca also works. It is never auto-detected. -When bootstrap resolves Orca from `FM_BACKEND=orca` or `config/backend=orca`, it checks for `orca`, keeps the universal `node` requirement, and skips `tmux` and `treehouse`. First run: before spawn mutates any repo or worktree state, firstmate runs `orca status --json` and requires the app to report `reachable=true` and `state="ready"` - start the Orca app and wait for it to finish loading before spawning. Spawn fails closed if the runtime is not ready. diff --git a/docs/tmux-backend.md b/docs/tmux-backend.md index 94e6e1d6ebb..544781e39e6 100644 --- a/docs/tmux-backend.md +++ b/docs/tmux-backend.md @@ -12,12 +12,7 @@ Pick tmux unless you have a specific reason to try an experimental backend (herd ## Prerequisites - tmux itself: `brew install tmux` (or your platform's package manager). -- A verified crew harness: `claude`, `codex`, `opencode`, `pi`, or `grok`. -- `git` with GitHub auth (`gh auth login`). -- `node`, required by firstmate's universal toolchain. -- `treehouse` for pooling clean worktrees; `no-mistakes` for the validation pipeline; `gh-axi`, `chrome-devtools-axi`, and `lavish-axi` for GitHub, browser, and rich-review operations; `tasks-axi` 0.1.1 or newer with `update --archive-body` and atomic multi-ID `mv` from 0.2.2, plus `quota-axi` for bootstrap-managed backlog and dispatch support. - -The first mate detects missing tools at session start and offers to install them after you approve. +- The universal firstmate prerequisites: a verified crew harness plus the required toolchain, detected at session start and installed only after you approve; [`docs/configuration.md`](configuration.md) owns both lists ("Harness support", "Toolchain"). ## Selecting it diff --git a/docs/zellij-backend.md b/docs/zellij-backend.md index 8bec7e02a25..5f80574c51f 100644 --- a/docs/zellij-backend.md +++ b/docs/zellij-backend.md @@ -15,7 +15,7 @@ Prerequisites: - `zellij` itself, version 0.44 or newer (installed 0.44.0 verified) - see [zellij.dev](https://zellij.dev) for install instructions. - `jq`, required to parse zellij's JSON output: `brew install jq` (or your platform's package manager). -- The same universal requirements as tmux (a verified crew harness, git with GitHub auth, node, treehouse, no-mistakes, gh-axi, chrome-devtools-axi, lavish-axi, tasks-axi 0.1.1 or newer with `update --archive-body` and atomic multi-ID `mv` from 0.2.2, and quota-axi); treehouse still provides the worktree, zellij only provides the session. +- The universal firstmate prerequisites - a verified crew harness plus the required toolchain, owned by [`docs/configuration.md`](configuration.md) ("Harness support", "Toolchain"); treehouse still provides the worktree, zellij only provides the session. Select zellij by putting `zellij` in a local `config/backend` file - the durable way to pick it - or by exporting `FM_BACKEND=zellij` when you launch your harness for a one-off session; telling the first mate in chat to use zellij also works. Unlike tmux and herdr, zellij is **never** auto-detected - it always requires an explicit choice. @@ -57,7 +57,7 @@ No empirical evidence surfaced during verification that forces a different conta Because every task in every firstmate home - primary or secondmate - shares this ONE session's tab bar with no per-home container split, and zellij enforces no tab-name uniqueness at all (verified: two tabs can share a name), two firstmate homes whose task ids happen to collide could send/peek/close each other's tabs. This is the exact gap a captain-directed no-mistakes review gate caught for the cmux backend (`docs/cmux-backend.md` "Task container shape") - cmux's fix was ported here for the identical reason, sharing its tag-derivation code (`bin/fm-backend-hometag-lib.sh`). -The caller-facing task label stays `fm-` in meta and briefs, while `fm-send.sh` and `fm-peek.sh` also accept exact task ids before the legacy `fm-` selector fallback. +The caller-facing task label stays `fm-` in meta and briefs; task-selector resolution is the shared contract owned by [`docs/configuration.md`](configuration.md) ("Runtime backend"). The actual zellij tab title a NEW task's tab is created with is home-scoped: `fm--`. `` is `firstmate` for the primary home, or `2ndmate-` when `$FM_HOME/.fm-secondmate-home` contains a secondmate id, plus a short stable hash of the resolved `FM_ROOT` path - the same identity scheme as cmux's home label (`docs/cmux-backend.md` "Task container shape"), so e.g. `fm-firstmate-a1b2c3d4-fix-login-k3` or `fm-2ndmate-sm1-9f8e7d6c-fix-login-k3`. The path hash means even two independent PRIMARY installations on one machine (each with no `.fm-secondmate-home` marker, so both would otherwise resolve to the same `firstmate` prefix) still get distinct tags. From 799542086d9149ea37530da3a41da21bc4cbd517 Mon Sep 17 00:00:00 2001 From: kunchenguid Date: Fri, 10 Jul 2026 14:28:57 -0700 Subject: [PATCH 2/4] docs: include git and GitHub auth in the toolchain owner list The review flagged that the new universal-toolchain owner omitted git and GitHub authentication while every backend guide now defers its prerequisites here; bootstrap's NEEDS_GH_AUTH check makes them real universal requirements. --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 14c92f74164..a1d93a3eb17 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -168,7 +168,7 @@ Secondmate homes inherit this file from the primary, so a secondmate's own crewm ## Toolchain -On session start the first mate detects what its required toolchain is missing or too old (tmux, node, gh, treehouse with durable lease support, no-mistakes v1.31.2 or newer, gh-axi, chrome-devtools-axi, lavish-axi, compatible tasks-axi per "Backlog backend" above, and quota-axi), lists it with the exact install commands, and installs only after you say go. +On session start the first mate detects what its required toolchain is missing or too old (tmux, node, git, gh with GitHub auth via `gh auth login`, treehouse with durable lease support, no-mistakes v1.31.2 or newer, gh-axi, chrome-devtools-axi, lavish-axi, compatible tasks-axi per "Backlog backend" above, and quota-axi), lists it with the exact install commands, and installs only after you say go. This section is the single owner of that universal toolchain list; backend guides' prerequisites point here and add only their backend-specific tools. In that list, treehouse pools clean task worktrees, no-mistakes runs the validation pipeline, gh-axi, chrome-devtools-axi, and lavish-axi cover GitHub, browser, and rich-review operations, and tasks-axi plus quota-axi back backlog mutations and quota-balanced dispatch. When bootstrap resolves `backend=orca` from `FM_BACKEND` or `config/backend`, it requires `orca`, keeps the universal `node` requirement, and skips `tmux` and `treehouse`. From 962c6957e08f1614be76706e6fa8c05bc9a3a48d Mon Sep 17 00:00:00 2001 From: kunchenguid Date: Fri, 10 Jul 2026 15:43:25 -0700 Subject: [PATCH 3/4] no-mistakes(review): Detect Git in bootstrap toolchain --- bin/fm-bootstrap.sh | 6 +++--- tests/fm-bootstrap.test.sh | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/bin/fm-bootstrap.sh b/bin/fm-bootstrap.sh index c60cf8e6a6e..7a2b2a9f925 100755 --- a/bin/fm-bootstrap.sh +++ b/bin/fm-bootstrap.sh @@ -311,7 +311,7 @@ secondmate_liveness_sweep() { install_cmd() { case "$1" in - tmux|node|gh|curl|jq|orca) echo "brew install $1 # or the platform's package manager" ;; + tmux|node|git|gh|curl|jq|orca) echo "brew install $1 # or the platform's package manager" ;; treehouse) echo "curl -fsSL https://kunchenguid.github.io/treehouse/install.sh | sh" ;; no-mistakes) echo "curl -fsSL https://raw.githubusercontent.com/kunchenguid/no-mistakes/main/docs/install.sh | sh" ;; gh-axi|chrome-devtools-axi|lavish-axi) echo "npm install -g $1 && $1 setup hooks" ;; @@ -322,8 +322,8 @@ install_cmd() { BACKEND=$(fm_backend_name) case "$BACKEND" in - orca) TOOLS="orca node gh no-mistakes gh-axi chrome-devtools-axi lavish-axi tasks-axi quota-axi" ;; - *) TOOLS="tmux node gh treehouse no-mistakes gh-axi chrome-devtools-axi lavish-axi tasks-axi quota-axi" ;; + orca) TOOLS="orca node git gh no-mistakes gh-axi chrome-devtools-axi lavish-axi tasks-axi quota-axi" ;; + *) TOOLS="tmux node git gh treehouse no-mistakes gh-axi chrome-devtools-axi lavish-axi tasks-axi quota-axi" ;; esac NO_MISTAKES_MIN_MAJOR=1 NO_MISTAKES_MIN_MINOR=31 diff --git a/tests/fm-bootstrap.test.sh b/tests/fm-bootstrap.test.sh index 4a540740b0b..f16314e9555 100755 --- a/tests/fm-bootstrap.test.sh +++ b/tests/fm-bootstrap.test.sh @@ -301,6 +301,32 @@ ROWS pass "bootstrap enforces no-mistakes minimum version" } +test_git_is_required_with_supported_install_instruction() { + local case_dir fakebin bash_env out expected + case_dir="$TMP_ROOT/git-required" + mkdir -p "$case_dir/home/config" + printf '%s\n' manual > "$case_dir/home/config/backlog-backend" + fakebin=$(make_fake_toolchain "$case_dir") + bash_env="$case_dir/no-git.bash" + cat > "$bash_env" <<'SH' +command() { + if [ "${1:-}" = -v ] && [ "${2:-}" = git ]; then + return 1 + fi + builtin command "$@" +} +git() { + return 127 +} +SH + + out=$(PATH="$fakebin:$BASE_PATH" BASH_ENV="$bash_env" FM_HOME="$case_dir/home" FM_ROOT_OVERRIDE="$case_dir/home" \ + FM_FAKE_TREEHOUSE_LEASE_HELP=1 "$ROOT/bin/fm-bootstrap.sh") + expected="MISSING: git (install: brew install git # or the platform's package manager)" + [ "$out" = "$expected" ] || fail "missing git should report the supported install instruction, got: $out" + pass "bootstrap requires git with an install instruction" +} + test_orca_backend_gates_orca_tool_only_when_selected() { local case_dir fakebin out missing_orca missing_orca="MISSING: orca (install: brew install orca # or the platform's package manager)" @@ -468,6 +494,7 @@ ROWS test_bootstrap_reporting test_no_mistakes_min_version +test_git_is_required_with_supported_install_instruction test_orca_backend_gates_orca_tool_only_when_selected test_fleet_sync_timeout_scales_with_origin_backed_project_count test_fleet_sync_timeout_floor_preserves_small_fleets From d48dd7418c9b12ea9be004283f3a624dd4160681 Mon Sep 17 00:00:00 2001 From: kunchenguid Date: Fri, 10 Jul 2026 16:11:18 -0700 Subject: [PATCH 4/4] no-mistakes(document): Clarify GitHub CLI and centralize selector documentation --- README.md | 2 +- docs/herdr-backend.md | 5 ++--- docs/zellij-backend.md | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7f2e5d04f40..9e0aedf72e0 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Full detail on every feature lives in [docs/architecture.md](docs/architecture.m ### Requirements - A verified agent harness: Claude Code, Grok, Pi, Codex, or OpenCode. -- Git with GitHub auth (`gh auth login`). +- Git and the GitHub CLI, authenticated through `gh auth login`. - tmux, for the reference session backend. The first mate detects and offers to install everything else. diff --git a/docs/herdr-backend.md b/docs/herdr-backend.md index 479e14f43f1..9816a94ef2f 100644 --- a/docs/herdr-backend.md +++ b/docs/herdr-backend.md @@ -163,9 +163,8 @@ A workspace whose label this adapter did not derive (see "Label derivation" abov A herdr task's `window=` meta field holds `:`, for example `default:w1:p2`. The pane id itself contains a colon, so the adapter splits on the FIRST colon only, never on every colon. This mirrors tmux's `session:window` target shape closely enough that `fm_backend_resolve_selector` (in `bin/fm-backend.sh`) needed no backend-specific logic at all - it already just returns a task's recorded `window=` value verbatim. -Operational commands should prefer the exact task id or stable `fm-` label, both of which resolve through this home's metadata. -Exact task ids win first, so ids beginning with `fm-` are not stripped as legacy labels. -An explicit herdr target also works when it exactly matches recorded metadata, but ad hoc bare-name lookup with no metadata remains the legacy tmux live-window fallback for non-`fm-` names. +Task-selector resolution is the shared contract owned by [`docs/configuration.md`](configuration.md) ("Runtime backend"). +For a bare unknown non-`fm-` name, Herdr retains the legacy tmux live-window fallback. Herdr tasks additionally record: diff --git a/docs/zellij-backend.md b/docs/zellij-backend.md index 5f80574c51f..b2464c0e47e 100644 --- a/docs/zellij-backend.md +++ b/docs/zellij-backend.md @@ -78,7 +78,7 @@ This is accepted, exactly as it is for cmux: a task's own recorded worktree path A zellij task's `window=` meta field holds `:`, for example `firstmate:7`. The pane id is a bare non-negative integer with no embedded colon (simpler than herdr's own pane-id shape, which itself contains a colon), so splitting on the first colon is trivially correct. This mirrors tmux's `session:window` and herdr's `session:pane` target shapes closely enough that `fm_backend_resolve_selector` (`bin/fm-backend.sh`) needed no zellij-specific logic at all. -When a caller reaches a zellij endpoint through firstmate metadata (an exact task id, a legacy `fm-` selector, or a meta scan), it also supplies the expected caller-facing tab label `fm-` to the zellij adapter, which internally checks it against the home-scoped title (falling back to the unambiguous-untagged legacy match described above). +When the shared selector contract routes a zellij caller through firstmate metadata, it also supplies the expected caller-facing tab label `fm-` to the zellij adapter, which internally checks it against the home-scoped title (falling back to the unambiguous-untagged legacy match described above). That label check prevents a stale numeric pane id from being trusted after an external session deletion/recreation, or from being trusted for a different firstmate home's same-named tab; explicit raw `session:pane` targets remain a pane-existence-only escape hatch because there is no metadata label to verify. Zellij tasks additionally record: