Skip to content
6 changes: 3 additions & 3 deletions .agents/skills/harness-adapters/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ The current tmux and Herdr adapters pass their captures and capability descripto
See `docs/herdr-backend.md` "Composer and injection safety" for Herdr's current boundary and `tests/fm-backend-herdr.test.sh` for regression coverage.

Startup dialog: the "Run Grok Build in a project directory?" project picker appears ONLY when grok is launched from a non-project directory (home, Desktop, Downloads, `/tmp`).
`fm-spawn` launches inside the treehouse worktree (a git repo root), so the picker never appears and grok treats the worktree as a trusted project automatically - no post-launch keystroke is needed.
`fm-spawn` launches inside the isolated task worktree (a Git repo root), so the picker never appears and grok treats the worktree as a trusted project automatically - no post-launch keystroke is needed.
Pin `[hints] project_picker_disabled = true` in `~/.grok/config.toml` if a non-project launch ever needs to skip it.

**TRUECOLOR placeholder styling: covered (task afk-herdr-false-pending, 2026-07-10).**
Expand All @@ -358,7 +358,7 @@ Its `Stop` command fires only when the current workspace holds a `.fm-grok-turne
`fm-spawn` writes that per-task pointer (`<worktree>/.fm-grok-turnend`, gitignored via git info/exclude like the other harnesses' worktree hook files) and a matching registry entry naming this task's `state/<id>.turn-ended`.
The hook reads `$GROK_WORKSPACE_ROOT`, which is always set for hooks and equals the worktree.
This keeps the hook outside the worktree, needs no trust grant, and writes only firstmate-owned files.
`fm-teardown` removes the worktree pointer before returning a pooled worktree.
`fm-teardown` removes the worktree pointer before cleaning up the task worktree.
Secondmate spawns skip the pointer (idle panes are healthy, no stale-pane detection for them).

**Primary-session guard fact (verified 2026-07-28, Grok 0.2.112 and 0.2.73).**
Expand Down Expand Up @@ -427,7 +427,7 @@ Herdr additionally draws the composer's rules with half-block glyphs, which the
FM_HARNESS_LIVENESS_DRIFT=1 bin/fm-test-run.sh tests/fm-harness-liveness-drift-live-e2e.test.sh
```

Firstmate acquires and enters the treehouse worktree before launching Cursor, then passes that same absolute path through `--workspace`.
Firstmate acquires and enters the isolated task worktree before launching Cursor, then passes that same absolute path through `--workspace`.
NEVER pass Cursor's own `-w/--worktree`: it allocates a SECOND worktree under `~/.cursor/worktrees` and would break firstmate's worktree-isolation contract.
The raw CLI accepts repeatable `--add-dir <path>` for deliberate multi-root workspaces; the adapter adds none, and the brief rides inline as the positional prompt, so the private brief directory needs no grant.

Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/stuck-crewmate-recovery/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Read the targeted current state with `bin/fm-crew-state.sh <id>` before deciding
A no-mistakes run matched to the crew's branch and current code remains authoritative when the endpoint is dead: handle a terminal or parked run through the normal lifecycle, and keep supervising an active run instead of creating a duplicate worker.

When no authoritative run accounts for the task, inspect only its recorded backend and worktree inventory.
Use `treehouse status` for treehouse-backed tmux, herdr, zellij, or cmux tasks, and use the recorded `orca_worktree_id=` and `terminal=` for Orca tasks.
Use `treehouse status` for the default Treehouse-backed tmux, Herdr, Zellij, or cmux tasks, inspect the exact recorded Git worktree directly when metadata says `worktree_provider=project-command`, and use the recorded `orca_worktree_id=` and `terminal=` for Orca tasks.
Do not sweep another home's endpoints or infer ownership from a matching window label.

Before relaunch, prove that no live agent still owns the recorded task and that the existing worktree remains available.
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ config/herdr-presentation-spaces optional "off" opt-out from, or "on" opt-in to
config/trace-context optional presence flag enabling default-off native W3C trace-context propagation to spawned agents; LOCAL, gitignored; inherited by secondmate homes; see docs/configuration.md "Trace context propagation" and docs/trace-context.md
config/cmux-socket-password optional cmux control-socket password; LOCAL, gitignored; read fresh on every cmux CLI call and passed through without ever overriding an operator's own ambient CMUX_SOCKET_PASSWORD when absent (docs/cmux-backend.md "Setup")
config/wedge-alarm optional away-mode wedge-alarm active-alert directives; LOCAL, gitignored; absent means auto (macOS Notification Center when available); see docs/wedge-alarm.md
config/worktree-acquire/<project-name> optional per-project fresh-worktree acquisition command replacing treehouse get for that project's tmux, herdr, zellij, and cmux ship/scout spawns; LOCAL, gitignored, and not inherited; absent means default Treehouse acquisition and return; see docs/configuration.md "Project worktree acquisition"
config/x-mode.env generated Relay watcher cadence; LOCAL, gitignored; source before arming watcher when present
data/ personal fleet records; LOCAL, gitignored as a whole
backlog.md task queue, dependencies, history
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Launching a supported harness inside it instantiates your first mate - and makes

- **One liaison** - you talk only to the first mate; it dispatches, supervises, escalates only real decisions, and reports plain outcomes.
- **A visible crew** - every crewmate works in its own tmux window, experimental herdr/zellij tab, cmux workspace, or Orca terminal you can watch or type into; the first mate reconciles.
- **Disposable worktrees** - each task runs in a clean [treehouse](https://github.com/kunchenguid/treehouse) git worktree, or an Orca-managed worktree when `backend=orca`, so parallel work on one repo never collides.
- **Disposable worktrees** - each task runs in a clean [Treehouse](https://github.com/kunchenguid/treehouse), [project-prepared](docs/configuration.md#project-worktree-acquisition), or Orca-managed Git worktree, so parallel work on one repo never collides.
- **Two task shapes** - ship tasks deliver authorized changes; scout tasks leave standalone investigation reports when the intake contract warrants separate research.
- **Explicit project modes** - each project ships via `no-mistakes`, `direct-PR`, or `local-only`, with an optional `+yolo` autonomy flag.
- **Optional secondmates** - opt in to persistent second mates that run from isolated firstmate homes with their own `FM_HOME`, state, projects, and session lock, either locally or as a whole home on an SSH-reachable host, with guarded updates and recovery that never turns an unavailable remote route into a local replacement.
Expand Down Expand Up @@ -150,7 +150,7 @@ Setup guides for tmux (the default) and every other supported backend (herdr, ze
│crewmate│ │crewmate│ │crewmate│ one autonomous agent each
└───┬────┘ └───┬────┘ └───┬────┘
▼ ▼ ▼
treehouse worktree, Orca worktree, or isolated secondmate home
Treehouse/project-prepared worktree, Orca worktree, or isolated secondmate home
├─ ship: project mode ► PR/local merge ► teardown
Expand Down
60 changes: 55 additions & 5 deletions bin/backends/herdr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2522,17 +2522,67 @@ fm_backend_herdr_target_ready() { # <target>
# would make fm-spawn.sh's worktree-discovery poll never see the pane "leave"
# the project directory, since `cwd` stays frozen at the original path forever.
# `.result.pane.foreground_cwd` tracks the ACTUALLY RUNNING foreground
# process's cwd instead, which is what changes when `treehouse get` enters its
# worktree subshell - confirmed live against a real treehouse acquisition.
fm_backend_herdr_current_path() { # <target>
# process's cwd instead, which is what changes when an acquisition command enters
# its worktree - confirmed live against a real Treehouse acquisition.
#
# That read answers "where is the live foreground process", which is only the
# question worth asking while an acquisition command is still holding a
# worktree subshell open. A trusted project-local acquisition command
# (docs/configuration.md "Project worktree acquisition") has the opposite
# shape: `<creator> <slug> && cd <path>/<slug>` runs its `cd` in the pane's OWN
# top-level shell and then EXITS, so by the time the acquisition reports
# completion there is no foreground process left to read and `cwd` is still
# frozen at pane-creation time. That provider therefore reads the shell's own
# cwd through the active marker probe below instead - the same workaround
# zellij and cmux already use for their frozen cwd fields.
fm_backend_herdr_current_path() { # <target> [worktree-provider]
if [ "${2:-}" = project-command ]; then
fm_backend_herdr_probe_current_path "$1"
return 0
fi
fm_backend_herdr_target_ready "$1" || return 0
fm_backend_herdr_cli "$FM_BACKEND_HERDR_SESSION" pane get "$FM_BACKEND_HERDR_PANE" 2>/dev/null \
| jq -r '.result.pane.foreground_cwd // empty' 2>/dev/null
}

# fm_backend_herdr_probe_current_path: the pane's own top-level shell cwd, or
# empty on any error, read by active probe rather than any pane field. Mirrors
# fm_backend_zellij_current_path / fm_backend_cmux_current_path verbatim in
# spirit: print `$PWD` between unique markers (atomically submitted, mirroring
# send_text_line), briefly settle, then capture and read only that marked
# block, joining wrapped path lines. Empty output means "no answer yet", which
# fm-spawn.sh's poll treats as not-settled, so a missed probe costs one more
# poll rather than a wrong worktree. Scoped to that worktree-discovery poll.
# It types into the pane, so fm-spawn.sh calls it for a project-command
# acquisition only AFTER that command's completion status is published - never
# while the operator's own command still owns the pane's foreground and stdin.
fm_backend_herdr_probe_current_path() { # <target>
local target=$1 out line marker_begin="__FM_HERDR_CWD_BEGIN__" marker_end="__FM_HERDR_CWD_END__" in_block=0 chunk="" last=""
fm_backend_herdr_target_ready "$target" || return 0
fm_backend_herdr_send_text_line "$target" "printf '%s\n' '$marker_begin'; pwd; printf '%s\n' '$marker_end'" || return 0
sleep 0.3
out=$(fm_backend_herdr_capture "$target" 200) || return 0
while IFS= read -r line; do
if [ "$line" = "$marker_begin" ]; then
in_block=1
chunk=""
continue
fi
if [ "$line" = "$marker_end" ]; then
case "$chunk" in /*) last=$chunk ;; esac
in_block=0
continue
fi
[ "$in_block" -eq 1 ] && chunk="$chunk$line"
done <<EOF
$out
EOF
printf '%s' "$last"
}

# fm_backend_herdr_send_text_line: send one line of TEXT then submit,
# ATOMICALLY - mirrors tmux's `send-keys -t T text Enter`. Used for the fixed
# spawn-time commands (treehouse get, the GOTMPDIR export). `pane run` types
# ATOMICALLY - mirrors tmux's `send-keys -t T text Enter`. Used for spawn-time
# acquisition and environment commands. `pane run` types
# the command and submits it in one call (verified).
fm_backend_herdr_send_text_line() { # <target> <text>
fm_backend_herdr_target_ready "$1" || return 1
Expand Down
12 changes: 6 additions & 6 deletions bin/backends/tmux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
# default (tmux, `backend=` absent) path stays byte-identical. Sourced only
# through bin/fm-backend.sh's fm_backend_source, never directly.
#
# Worktree acquisition (running `treehouse get` inside the pane, and polling
# its cwd) is unchanged by this extraction: P1 scopes only the session
# provider, not the worktree provider, so fm-spawn.sh still drives that part
# inline with these same send/current-path primitives.
# Worktree acquisition (running Treehouse or the trusted project-local command
# inside the pane, and polling its cwd) remains outside this adapter: P1 scopes
# only the session provider, so fm-spawn.sh drives that shared path inline with
# these same send/current-path primitives.
#
# The verified composer/busy-detection and verify-and-retry-submit primitives
# already live in bin/fm-tmux-lib.sh, shared with the away-mode daemon
Expand Down Expand Up @@ -106,8 +106,8 @@ fm_backend_tmux_current_path() { # <target>
}

# fm_backend_tmux_send_text_line: send one line of TEXT then Enter, with no
# composer verification - used for the fixed spawn-time commands
# (`treehouse get`, the GOTMPDIR export) that already ran this exact sequence
# composer verification - used for spawn-time acquisition and environment
# commands that already ran this exact sequence
# inline in fm-spawn.sh. Mirrors `tmux send-keys -t "$T" "<text>" Enter`.
fm_backend_tmux_send_text_line() { # <target> <text>
tmux send-keys -t "$1" "$2" Enter
Expand Down
3 changes: 1 addition & 2 deletions bin/backends/zellij.sh
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,7 @@ fm_backend_zellij_target_ready() { # <target> [expected-label]
}

# fm_backend_zellij_current_path: the live pane's cwd, or empty on any error.
# Mirrors tmux's pane_current_path poll used for worktree-path discovery after
# `treehouse get`.
# Mirrors tmux's pane_current_path poll used after worktree acquisition.
#
# Verified pitfall (docs/zellij-backend.md "Worktree-path discovery: pane_cwd
# does not track a subshell"): `list-panes --json`'s `pane_cwd` DOES reflect a
Expand Down
Loading