Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ You talk to a single agent - the first mate - and it runs the crew for you: spaw
There is no app to install; the whole orchestrator is an `AGENTS.md` file that any terminal coding agent can follow.

- **One liaison** — you never talk to a worker agent. The first mate dispatches, supervises, escalates only real decisions, and reports when PRs are ready.
- **A visible crew** — every crewmate lives in a tmux window in your session. Watch any of them work, or type into their window to intervene; the first mate reconciles.
- **A visible crew** — every crewmate lives in a tmux window. Watch any of them work, or type into their window to intervene; the first mate reconciles.
- **Guarded by construction** — the first mate is read-only over your projects; crewmates work in disposable [treehouse](https://github.com/kunchenguid/treehouse) worktrees and ship through the [no-mistakes](https://github.com/kunchenguid/no-mistakes) validation pipeline. Nothing lands without a PR you merge.

This is not an agent harness. This is not a skill. This is not a CLI.

This is.. a directory that turns any agent into your firstmate, and you the captain.

## Quick Start

```sh
Expand All @@ -59,8 +63,9 @@ $ claude # launch your agent harness here; AGENTS.md takes over
**Prerequisites** (the first mate detects everything else and offers to install it):

```sh
# 1. an agent harness - claude code is the verified one today
# 1. a verified agent harness - claude, codex, opencode, or pi
# 2. git + GitHub auth
# 3. tmux - the crew lives in tmux windows (firstmate offers to install it if missing)
gh auth login
```

Expand All @@ -74,6 +79,9 @@ cd firstmate && claude
That is the whole install.
On first launch the first mate detects what its toolchain is missing (tmux, treehouse, no-mistakes, gh-axi, chrome-devtools-axi, lavish-axi), lists it with the exact install commands, and installs only after you say go.

**Run it inside tmux for the best experience.**
firstmate works from any terminal - outside tmux, crewmates land in a detached `firstmate` session you can attach to - but launching your harness from inside tmux puts every crewmate window in your own session, one per task, where you can watch the crew work in real time or type into any window to intervene.

## How It Works

```
Expand Down Expand Up @@ -104,32 +112,38 @@ On first launch the first mate detects what its toolchain is missing (tmux, tree
- **Event-driven supervision** — a zero-token bash watcher (`bin/fm-watch.sh`) sleeps on the fleet and wakes the first mate only when a crewmate reports, stalls, or a PR merges. An idle crew costs you nothing.
- **Worktrees, not branches in your checkout** — crewmates never touch your clone; treehouse pools clean worktrees so parallel tasks on one repo cannot collide.
- **Validation is non-negotiable** — every project gets `no-mistakes init`; every task ends with its pipeline. Human-judgment findings escalate to you through the first mate.
- **Restart-proof** — all state lives in tmux, status files, and committed markdown. Kill the first mate session anytime; the next one reconciles and carries on.
- **Restart-proof** — all state lives in tmux, status files, and local markdown under `data/`. Kill the first mate session anytime; the next one reconciles and carries on.

## The bin/ toolbelt

The first mate drives these; you rarely need to, but they work by hand too.

| Script | Description |
| ---------------- | --------------------------------------------------------------------------- |
| `fm-spawn.sh` | Window → treehouse worktree → agent launched with its brief |
| `fm-watch.sh` | Block until a crewmate needs attention; exits with one reason line |
| `fm-send.sh` | Send one literal line (or `--key Escape`) to a crewmate window |
| `fm-peek.sh` | Print a bounded tail of a crewmate pane |
| `fm-teardown.sh` | Return the worktree and kill the window; refuses if work is not on a remote |
| Script | Description |
| ----------------- | ---------------------------------------------------------------------------- |
| `fm-bootstrap.sh` | Detect missing toolchain pieces; install them only after consent |
| `fm-brief.sh` | Scaffold a crewmate brief with the standard contract filled in |
| `fm-spawn.sh` | Window → treehouse worktree → agent launched with its brief |
| `fm-watch.sh` | Block until a crewmate needs attention; exits with one reason line |
| `fm-send.sh` | Send one literal line (or `--key Escape`) to a crewmate window |
| `fm-peek.sh` | Print a bounded tail of a crewmate pane |
| `fm-pr-check.sh` | Record a PR-ready task and arm the watcher's merge poll |
| `fm-teardown.sh` | Return the worktree and kill the window; refuses if work is not on a remote |
| `fm-harness.sh` | Detect the running harness; resolve the effective crewmate harness |
| `fm-lock.sh` | Single-firstmate session lock |

## Configuration

The orchestrator's behavior lives in `AGENTS.md` - edit it like any prompt.
Harness support is a table in section 4 (claude is verified; codex/opencode/pi are stubs awaiting empirical verification).
Harness support is a table in section 4: claude, codex, opencode, and pi are all empirically verified; new harnesses get verified through a supervised trial task before joining the table.

Watcher tuning via environment variables:
Watcher tuning via environment variables (defaults shown):

```sh
FM_POLL=15 # seconds between watcher cycles
FM_HEARTBEAT=600 # max seconds before a mandatory fleet review
FM_CHECK_EVERY=20 # cycles between slow checks (merged-PR polls)
FM_BUSY_REGEX='esc to interrupt' # busy-pane signatures, extend per harness
FM_POLL=15 # seconds between watcher cycles
FM_HEARTBEAT=600 # base seconds between fleet reviews; backs off exponentially while idle
FM_HEARTBEAT_MAX=7200 # heartbeat backoff cap
FM_CHECK_INTERVAL=300 # seconds between slow checks (merged-PR polls)
FM_BUSY_REGEX='esc (to )?interrupt|Working\.\.\.' # busy-pane signatures, extend per harness
```

## Development
Expand Down
2 changes: 1 addition & 1 deletion bin/fm-harness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ set -u
FM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

detect_own() {
# Layer 1: environment markers (claude VERIFIED; pi source-verified).
# Layer 1: environment markers for verified harnesses.
[ "${CLAUDECODE:-}" = "1" ] && { echo claude; return; }
[ "${PI_CODING_AGENT:-}" = "true" ] && { echo pi; return; }
# Layer 2: walk the parent chain and match the command name.
Expand Down
2 changes: 1 addition & 1 deletion bin/fm-spawn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# turn-end signal rides the launch command, e.g. codex -c notify=[...])
# __PIEXT__ absolute path to state/<task-id>.pi-ext.ts (pi turn-end extension,
# written by this script; outside the worktree to avoid pi's trust gate)
# Per-harness turn-end hook files are installed into the worktree automatically.
# Per-harness turn-end hooks are installed automatically; some live outside the worktree.
# On success prints: spawned <id> harness=<name> window=<session:window> worktree=<path>
set -eu

Expand Down
2 changes: 1 addition & 1 deletion bin/fm-watch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# signal: <file> a crewmate wrote a status line or a turn-end hook fired
# stale: <window> a crewmate pane stopped changing and shows no busy signature
# check: <script>: <out> a per-task check script (e.g. merged-PR poll) produced output
# heartbeat nothing happened for FM_HEARTBEAT seconds; review the fleet
# heartbeat fleet review due; starts at FM_HEARTBEAT and backs off to FM_HEARTBEAT_MAX
# Run as a background task. Restart it after handling each wake.
set -u

Expand Down