Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8dc638b
fix(spawn): isolate docker-compose project names per worktree
Jul 5, 2026
d3e11be
no-mistakes(test): waiting for background test run to complete
Jul 5, 2026
82ee294
no-mistakes(test): fix(tests): make herdr fake CLI counter race-safe …
Jul 5, 2026
6cb74a0
no-mistakes(document): docs: document per-worktree docker-compose pro…
Jul 5, 2026
8bc3bee
no-mistakes(document): docs already fully synced; added missing docke…
Jul 5, 2026
b9e0056
no-mistakes(lint): Fix unused $out variable flagged by shellcheck in …
Jul 5, 2026
cbffac9
feat(spawn): auto-compact claude crewmates around 200k tokens
Jul 10, 2026
01862e0
no-mistakes(test): fix environment-fragile test failures (jq, git, ha…
Jul 10, 2026
4b6e23d
feat(spawn): raise claude auto-compact window to 300000
Jul 11, 2026
9b378f7
fix(teardown): recognize work fast-forwarded into local main as landed
Jul 11, 2026
e214229
test(teardown): drop stale git-2.38 skip gate for content-in-default …
Jul 11, 2026
b85d4f5
feat(dispatch): add model/effort tiers and mechanical quality guardrails
Jul 9, 2026
b6420ad
no-mistakes(review): scope risk-tripwire brief scan, narrow bin path,…
Jul 9, 2026
f080d24
no-mistakes(review): harden risk-tripwire scans and mechanically wire…
Jul 9, 2026
c61300d
no-mistakes(review): make risk-tripwire grep portable, give tier-guar…
Jul 9, 2026
34fe271
no-mistakes(review): set exec bit on new tests, fix ultracode marker doc
Jul 10, 2026
dcea866
no-mistakes(test): fix jq/git-version and test-env portability in fai…
Jul 10, 2026
357cc64
no-mistakes(document): sync docs with new resource-tiering guardrail …
Jul 10, 2026
c96e944
no-mistakes(review): exclude herdr-lab brief block from risk-tripwire…
Jul 10, 2026
b649c24
no-mistakes(review): clean up orphan .ultracode state marker on teardown
Jul 10, 2026
7b02cf7
no-mistakes(review): stop tiering guardrails passing silently when di…
Jul 10, 2026
cb8851d
no-mistakes(review): pass ultracode through dispatch, tighten tiering…
Jul 10, 2026
0e7e0ba
no-mistakes(test): skip handoff tests on incompatible tasks-axi; fix …
Jul 10, 2026
2395610
no-mistakes: apply CI fixes
Jul 10, 2026
a0ff04d
fix(teardown): check both origin and local ref for landed content
Jul 11, 2026
89276e6
feat: auto-sync live NAS deployments after a landed ship task
Jul 12, 2026
b42b5ea
no-mistakes(review): docs: document fm-nas-deploy-sync.sh script and …
Jul 12, 2026
fd75451
no-mistakes(review): Sandbox teardown tests' NAS deploy sync lookup file
Jul 12, 2026
2183f00
no-mistakes(review): Aggregate pm2 cluster status and stub NAS sync i…
Jul 12, 2026
3c35024
no-mistakes(review): Bound NAS deploy sync git/fs calls with a timeout
Jul 12, 2026
89ca07f
no-mistakes(review): Guard NAS sync fetch race, document timeout knob…
Jul 12, 2026
c2abe66
no-mistakes(test): placeholder - awaiting background test run completion
Jul 12, 2026
2ba86a0
no-mistakes(document): Synced AGENTS.md and docs/architecture.md/cmux…
Jul 12, 2026
66d264d
feat: surface failed critical systemd services at bootstrap
Jul 13, 2026
df5d421
keep firstmate repo in sync with upstream template
Jul 14, 2026
7742067
clarify /updatefirstmate converges to the fork, not the upstream temp…
Jul 14, 2026
74962fc
fix: scope fm-merge-local.sh auto-push to firstmate's own repo
Jul 15, 2026
52fd50e
no-mistakes(review): will report after background lint completes
Jul 16, 2026
017dbcb
no-mistakes(document): Synced docs for fm-teardown --force NAS-sync s…
Jul 16, 2026
e5b2d4a
no-mistakes: apply CI fixes
Jul 16, 2026
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
11 changes: 10 additions & 1 deletion .agents/skills/bootstrap-diagnostics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: bootstrap-diagnostics
description: >-
Agent-only handling playbook for session-start bootstrap diagnostics.
Use whenever the session-start digest's bootstrap section prints any diagnostic or capability line - MISSING, MISSING_MANUAL, BACKEND_INVALID, NEEDS_GH_AUTH, TANGLE, CREW_HARNESS_OVERRIDE, CREW_DISPATCH, FLEET_SYNC, SECONDMATE_SYNC, SECONDMATE_LIVENESS, TASKS_AXI, NUDGE_SECONDMATES, or FMX - or when a standalone bin/fm-bootstrap.sh run prints one.
Use whenever the session-start digest's bootstrap section prints any diagnostic or capability line - MISSING, MISSING_MANUAL, BACKEND_INVALID, NEEDS_GH_AUTH, TANGLE, CREW_HARNESS_OVERRIDE, CREW_DISPATCH, FLEET_SYNC, SECONDMATE_SYNC, SECONDMATE_LIVENESS, TASKS_AXI, NUDGE_SECONDMATES, FMX, SERVICE_FAILED, or UPSTREAM_DRIFT - or when a standalone bin/fm-bootstrap.sh run prints one.
A silent bootstrap section means all good and needs no skill load.
user-invocable: false
metadata:
Expand Down Expand Up @@ -47,3 +47,12 @@ The inline rules in `AGENTS.md` section 3 still bind: detect, then consent, then
A secondmate that was skipped, already current, or whose advance changed no instructions is not listed and must not be disturbed.
- `FMX: X mode on ...` / `FMX: X mode off ...` - bootstrap confirmed or removed the local X-mode poll artifacts (`docs/configuration.md` "X mode (.env)").
Only when a running watcher needs the cadence transition applied immediately, restart the home-scoped watcher through the emitted harness supervision protocol; bootstrap deliberately never restarts the watcher itself.
- `SERVICE_FAILED: <unit> - failed since <timestamp>` - a systemd unit named in the optional local `config/critical-services` file is in the failed state; a pure read-only detection (`systemctl is-failed`, no root), so a read-only session still surfaces it.
Report it to the captain in plain language; never restart the unit yourself - a unit that failed may be unsafe to restart without knowing why.
An absent or empty config file, a host without `systemctl`, or no failed unit all print nothing.
- `UPSTREAM_DRIFT: local main is <ahead> ahead / <behind> behind upstream/main, last reconciled <days>d ago (<date>)` - the always-on FYI variant: firstmate's OWN repo tracking how far it has drifted from its read-only upstream template (`kunchenguid/firstmate`, the `upstream` remote after the remote swap).
It prints every session; record it silently like any capability fact and take no action while the wording stays FYI.
It only reports - the network fetch that refreshes the ref runs in the locked fleet-sync sweep, and reconciling upstream is never a bootstrap side effect.
- `UPSTREAM_DRIFT: this repo's upstream sync needs attention - ...` - the escalated variant (local main more than ~30 commits behind `upstream/main`, or the merge-base older than 10 days).
Surface it to the captain in plain outcome language and, on their go-ahead, dispatch a deliberately-reviewed firstmate-repo reconciliation ship task - fetch `upstream`, merge it into local `main`, resolve conflicts, and land local-only (`AGENTS.md` section 1) - the same shape that reconciled the divergence before.
Never automate the merge; keeping the gap small also keeps the pipeline's opportunistic upstream PR's diff clean (`AGENTS.md` section 1).
7 changes: 7 additions & 0 deletions .agents/skills/harness-adapters/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ Its broader dark-TRUECOLOR placeholder handling and dark-theme tradeoff are docu
That styled capture is internal to the boolean detector only.
`fm-peek` and every other human or LLM-facing capture path stays plain `tmux capture-pane` with no escape codes.

**Auto-compaction fact (verified 2026-07-09, Claude Code 2.1.206; shipped constant raised to 300000 2026-07-11).**
`bin/fm-spawn.sh` launches every claude crewmate and secondmate with `CLAUDE_CODE_AUTO_COMPACT_WINDOW=300000`, scoped the same way as `CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false` above, so these separately-launched processes auto-compact around 300k tokens the way the primary already does via its own `.claude/settings.local.json` (which they never inherit).
The var is read once at process startup and is capped at the model's real context window, so it can only lower the effective trigger, never raise it past the real ceiling: `min(300000, window)` is `300000` once `window` exceeds it, but a no-op (stays at `window`) below that.
This is not a universal guarantee for every possible future model choice - a differently-configured account/model capped at the plain ~200k window would see no change - but it is true for the window tier crew actually runs on today: `--model sonnet` on this account, the standard crewmate spawn, resolves to the ~1M-context beta, well above 300000.
Verified live in a tmux pane at the original 200000 value (the mechanism is unchanged, only the shipped constant moved to 300000): `claude --model sonnet` on this account resolves to a ~967k-token auto-compact window with no override (`/context` reported `Auto-compact window: 967k tokens`, i.e. the 1M-context beta, not the 200k a plain Sonnet window would imply); relaunched with `CLAUDE_CODE_AUTO_COMPACT_WINDOW=200000` set, `/context` reported `39.5k/200k tokens (20%)` and `Auto-compact window: 200k tokens` - the window pinned to the override as expected.
This is why the primary's own two-var form (`CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000` + `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=20`) is not copied here: that pair assumes a 1M window, and would silently cap a smaller-window model/account combination to a far more aggressive trigger.

**Primary-session guard fact (verified 2026-07-04, Claude Code 2.1.201; preserved 2026-07-08, Claude Code 2.1.204).**
This is separate from the per-task crewmate turn-end hook above (that one just `touch`es a marker file in a task's own `.claude/settings.local.json`).
The firstmate PRIMARY's own `.claude/settings.json` registers `bin/fm-turnend-guard.sh` as a Stop hook, and exiting with status 2 plus stderr reliably forces the model to continue.
Expand Down
3 changes: 3 additions & 0 deletions .agents/skills/updatefirstmate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ It never forces, never creates a merge commit, never stashes, and advances a tar
A tracked-files fast-forward leaves the gitignored operational dirs (data/, state/, config/, projects/, .no-mistakes/) untouched, so a secondmate's in-flight work is never disrupted.
This touches only the firstmate repo and its own worktrees, never anything under `projects/`.

Post-swap, this pull follows `origin`, which is the captain's fork, so `/updatefirstmate` converges the whole fleet onto that fork and does nothing on the primary checkout, which is itself the source every fork tracks.
It deliberately never reaches for the read-only `upstream` template: folding template improvements into local `main` is a separate, reviewed reconciliation ship task, the one the `UPSTREAM_DRIFT:` bootstrap diagnostic surfaces, and it never rides in on a self-update.

## What it does

1. **Run the updater:**
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ config/backend
config/x-mode.env
config/cmux-socket-password
config/wedge-alarm
config/critical-services
47 changes: 35 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,19 @@ Hard rules, in priority order:
5. **Report outcomes faithfully.**
If work failed, say so plainly with the evidence.

You may maintain this repo's private operational state directly.
Shared tracked material is `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.tasks.toml`, `.github/workflows/`, `bin/`, `.agents/skills/`, and public `skills/`.
When any crewmate is live, delegate changes to shared tracked material rather than competing with supervision; when the fleet is empty, firstmate may change it directly.
This repo is a shared template, while `.env`, `data/`, `state/`, `config/`, `projects/`, and `.no-mistakes/` are captain-private and gitignored.
Ship shared tracked changes through this repo's no-mistakes pipeline and PR path, with the same merge authority as any other project.
Never add an agent name as a commit co-author.
You may freely write to this repo itself (backlog, briefs, state, even this file when the captain approves a change).
Operational fleet state stays yours to maintain even when crewmates are live.
Shared, tracked material means `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.tasks.toml`, `.github/workflows/`, `bin/`, `.agents/skills/`, and public `skills/`.
When one or more crewmates are in flight, delegate changes to shared, tracked material to a crewmate through the normal scout or ship machinery instead of hand-editing them yourself.
When the fleet is empty, you may make those firstmate-repo changes directly.
Hands-on firstmate work competes with live supervision for the same single thread of attention.
This repo is a shared template, not the captain's personal project.
The tracking principle: shared, tracked material is tracked under git; anything personal to this captain's fleet (.env, data/, state/, config/, projects/, .no-mistakes/) is not.
Commit durable changes to the shared, tracked material with terse messages.
This repo is itself behind the no-mistakes gate: ship shared, tracked material through the pipeline - branch, commit, run the pipeline, PR - and the captain's merge rule applies here exactly as it does to projects.
This repo's own upstream (`kunchenguid/firstmate`, the `upstream` remote after the remote swap) is read-only to this fleet with no merge rights, ever, so firstmate-repo ship tasks land local-only: branch, commit, firstmate reviews the diff, the captain approves, and firstmate fast-forwards local `main`.
The pipeline still auto-opens a PR against that upstream, but it is a non-blocking, purely opportunistic contribution back - never a merge gate here and never waited on - and its diff stays clean only while the `UPSTREAM_DRIFT:` gap (section 3) is small, since a large gap makes the PR carry a lot of unrelated local-only history.
Never add an agent name as co-author.

## 2. Layout and state

Expand All @@ -50,10 +57,6 @@ Never add an agent name as a commit co-author.
Each secondmate has a persistent isolated `FM_HOME`, including its own state, backlog, projects, and session lock.
`bin/fm-send.sh` fails closed unless `FM_HOME` is explicit, so a steer cannot silently resolve against another home.

Tracked files hold shared instructions and tooling; `data/` holds durable private fleet records; `state/` holds volatile runtime records and append-only status events; `config/` holds local operating choices; and `projects/` contains clones that are read-only to firstmate.
A `state/<id>.status` line is a wake event, not current-state truth; `bin/fm-crew-state.sh` owns current-state reconciliation.
Treat `data/captain.md` as the canonical portable record of captain preferences and `data/learnings.md` as curated fleet-local knowledge, regardless of harness memory.

## 3. Session start (run once at every session start)

Run `bin/fm-session-start.sh` exactly once at session start.
Expand Down Expand Up @@ -89,6 +92,12 @@ Do not add model-specific versions of that policy.
Dispatch only on a backend that `fm-spawn` validates as spawn-capable.
A missing dependency, authentication failure, unsupported backend, or version refusal is a blocker; never silently retry on another backend.

Before naming a specific non-default model in a dispatch rule, verify that model end-to-end on a trivial supervised task, exactly as for a new harness adapter; never copy an unverified model into a live `config/crew-dispatch.json`.

A dispatch profile's `ultracode: true` means the matched task must get a genuinely independent second pass on its finished diff before PR-ready, launched as its own separately dispatched task rather than a sub-task the implementing crewmate spawns itself; `bin/fm-ultracode-guard.sh` tracks this mechanically (`flag` right after spawn, `check`/`reviewed` at the PR-ready gate in section 7's Validate step).
As a second, structurally independent check, run `bin/fm-risk-tripwire.sh <id>` before spawn and again at Validate time against the actual diff; a hit floors the model/effort to `opus`/`xhigh` with ultracode `independent-review` regardless of which rule matched, and is never silently downgraded afterward.
On a hit, also run `bin/fm-ultracode-guard.sh flag <id> independent-review` so the independent-review requirement is tracked mechanically even when the matched rule did not set ultracode.

## 5. Recovery

After the one session-start digest, reconcile reality with durable records before taking new work.
Expand Down Expand Up @@ -206,6 +215,15 @@ Running, fixing, or CI states remain working; parked approval or fix-review stat
A worker hand-editing, committing, aborting, or restarting during an active validation run duplicates pipeline ownership; steer it back to the gate response flow.
The worker reports the PR when CI first becomes green rather than waiting for merge monitoring to finish.

**Escalation triggers (mechanical, never rest on self-report alone).**
For a task assigned the trivial tier (Haiku/low), run `bin/fm-tier-guard.sh <id>` during Validate, or whenever a heartbeat review touches it, to check whether its diff or elapsed time has outgrown that tier's envelope; any tier also escalates once its diff crosses the script's general heavy-scale ceiling.
A report escalates the task to at least Sonnet/high in place, without losing its branch or context, mirroring `bin/fm-promote.sh`'s in-place promotion.
A crewmate's own report - it cannot find root cause, a "confirmed" fix touches a shared path, or it raised a tradeoff buried in seemingly mechanical work - is a second, non-mechanical trigger with the same effect.
Either way, escalate the model/effort in place and never silently de-escalate for the rest of that task's life.

**Ultracode confirmation.**
Before advancing an ultracode-flagged task to PR-ready, run `bin/fm-ultracode-guard.sh check <id>`; it refuses until a genuinely separate task - dispatched independently, never a sub-task the flagged crewmate spawned itself - has reviewed the finished diff and its findings were addressed, recorded with `bin/fm-ultracode-guard.sh reviewed <id> <reviewer-task-id>`.

### PR ready, landing, and teardown

For a ready PR, use `bin/fm-pr-check.sh` to record the PR and authoritative head and to arm merge monitoring.
Expand All @@ -215,6 +233,9 @@ A captain instruction to merge is explicit authority; `yolo` is the only standin
Tear down a ship task only after landing is confirmed.
A teardown refusal for uncommitted or unlanded work is a stop-and-investigate result, never an obstacle to bypass.
Never force teardown without explicit discard authority.
`bin/fm-teardown.sh`'s header owns the full landed-work definition; a known benign case is an external-PR task whose squash merge leaves the branch commits reachable only on the contributor's fork - add the fork as a remote and fetch, then retry, never reach for `--force`.
After a successful PR-based teardown it also best-effort syncs that project's clone via `bin/fm-fleet-sync.sh`, and any non-scout, non-secondmate, non-forced teardown best-effort syncs and restarts that project's live NAS deployment, if one is recorded in `data/nas-deployments.md`, through `bin/fm-nas-deploy-sync.sh`; a project with no recorded deployment is a silent no-op.
A forced teardown (`--force`) skips this sync, since `--force` carries no landed-work guarantee.
After successful teardown, record completion, retain only the configured recent Done history, and re-evaluate queued work whose blockers and time gates have cleared.

A secondmate is persistent and an empty queue is healthy.
Expand Down Expand Up @@ -347,13 +368,15 @@ The scaffold is a safety contract, not a suggestion.
Firstmate's shared instruction surface reaches running homes only after it lands on the default branch and those homes fast-forward.
Only `AGENTS.md`, `bin/`, and `.agents/skills/` are loaded by a running firstmate; public `skills/` is an installer-facing surface.
When the captain invokes `/updatefirstmate` or asks to update firstmate, load the `/updatefirstmate` skill.
It performs guarded fast-forward updates of firstmate and registered secondmate homes, refreshes instructions, and never touches anything under `projects/`.
It performs only fast-forward self-updates of firstmate and registered secondmate homes, re-reads `AGENTS.md` when needed, nudges updated live secondmates, and never touches anything under `projects/`.
Post-swap, `origin` is the captain's fork, so `/updatefirstmate` only ever converges the fleet onto that fork and is a no-op on the primary checkout, which is itself the fleet's source of truth.
It never pulls the read-only `upstream` template; folding upstream-template improvements into local `main` is the separate reviewed reconciliation task the `UPSTREAM_DRIFT:` bootstrap line surfaces (section 3), never a self-update.

## 13. Agent-only reference skills

These skills are not captain-invocable; load them only at their precise triggers.

- `bootstrap-diagnostics` - load whenever the session-start digest's bootstrap section prints any diagnostic or capability line (`MISSING:`, `MISSING_MANUAL:`, `BACKEND_INVALID:`, `NEEDS_GH_AUTH`, `TANGLE:`, `CREW_HARNESS_OVERRIDE:`, `CREW_DISPATCH:`, `FLEET_SYNC:`, `SECONDMATE_SYNC:`, `SECONDMATE_LIVENESS:`, `TASKS_AXI:`, `NUDGE_SECONDMATES:`, or `FMX:`); silence needs no load.
- `bootstrap-diagnostics` - load whenever the session-start digest's bootstrap section prints any diagnostic or capability line (`MISSING:`, `MISSING_MANUAL:`, `BACKEND_INVALID:`, `NEEDS_GH_AUTH`, `TANGLE:`, `CREW_HARNESS_OVERRIDE:`, `CREW_DISPATCH:`, `FLEET_SYNC:`, `SECONDMATE_SYNC:`, `SECONDMATE_LIVENESS:`, `TASKS_AXI:`, `NUDGE_SECONDMATES:`, `FMX:`, `SERVICE_FAILED:`, or `UPSTREAM_DRIFT:`); silence needs no load.
- `diagnostic-reasoning` - load before scoping a reported bug and before acting on a diagnostic report.
- `harness-adapters` - load before spawning or recovering a crewmate or secondmate, handling a trust dialog, sending a harness-specific skill invocation, interrupting or exiting an agent, resuming an exited agent, or verifying a new harness adapter.
- `firstmate-orca` - load before switching to Orca, spawning or supervising Orca-backed work, smoke-testing Orca backend behavior, debugging Orca task state, or reconciling Orca-backed task metadata.
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Dependency bots are exempt so their automation keeps working, but regular contri

See the [no-mistakes quick start](https://kunchenguid.github.io/no-mistakes/start-here/quick-start/) for the full first-run walkthrough.

Note: a firstmate maintainer's own working copy uses the inverted remote layout - there `origin` is the maintainer's fork and `upstream` is this parent repo - so if you are ever reading such a copy's git config rather than your own fresh clone, expect `origin` and `upstream` swapped from the step 1 layout above.

## Repo conventions

- This repo is a template for running a firstmate orchestrator agent.
Expand Down
11 changes: 9 additions & 2 deletions bin/backends/cmux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,15 @@ fm_backend_cmux_parse_target() { # <target>
# (fm_backend_zellij_pane_exists) rather than the design sketch's original
# read-screen-based suggestion.
fm_backend_cmux_surface_exists() { # <workspace_id> <surface_id>
local wsid=$1 sfid=$2
fm_backend_cmux_cli list-panes --workspace "$wsid" --json --id-format uuids 2>/dev/null \
local wsid=$1 sfid=$2 out
# Capture the list-panes call and gate on its OWN exit/output before piping to
# jq: an absent target makes list-panes fail with no output, and `jq -e` on
# empty input exits 0 on jq 1.6 (only 1.7+ reports the no-result exit 4), so
# relying on the pipe's trailing jq status alone would false-positive the
# surface as present on older jq. A failed or empty list-panes means no surface.
out=$(fm_backend_cmux_cli list-panes --workspace "$wsid" --json --id-format uuids 2>/dev/null) || return 1
[ -n "$out" ] || return 1
printf '%s' "$out" \
| jq -e --arg s "$sfid" '[.panes[]? | select(.surface_ids // [] | index($s))] | length > 0' >/dev/null 2>&1
}

Expand Down
Loading
Loading