Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
84a550e
feat: import and harden Agent Fleet
ruby-dlee Jul 18, 2026
89e2c59
no-mistakes(review): Harden Agent Fleet trust and recovery
ruby-dlee Jul 18, 2026
b7b0df5
no-mistakes(review): Harden Agent Fleet routing and trust boundaries
ruby-dlee Jul 18, 2026
bcfee06
no-mistakes(test): Captain, fix Agent Fleet lint parity assertion
ruby-dlee Jul 18, 2026
a681a0e
no-mistakes(document): Correct Agent Fleet documentation ownership an…
ruby-dlee Jul 18, 2026
9a5b8fe
no-mistakes(document): Correct Agent Fleet runtime documentation
ruby-dlee Jul 18, 2026
ce3baf9
no-mistakes: apply CI fixes
ruby-dlee Jul 18, 2026
b5dfcf5
fix(agent-fleet): skip TOON preflight for launches
ruby-dlee Jul 18, 2026
58cde83
test(report-stack): refresh relocated manifests
ruby-dlee Jul 18, 2026
97b7dc1
Harden Agent Fleet identity isolation
ruby-dlee Jul 18, 2026
a381c52
Require fresh public routeability proofs
ruby-dlee Jul 18, 2026
96e88ad
feat: add crash-safe Bridge cutover control plane
ruby-dlee Jul 18, 2026
aca31a2
Harden Bridge worker isolation and recovery
ruby-dlee Jul 18, 2026
db78c57
Harden managed Bridge launch freshness
ruby-dlee Jul 18, 2026
f363753
Harden Bridge session and Herdr lifecycle gates
ruby-dlee Jul 18, 2026
7a5513a
Recover interrupted Herdr artifact publication
ruby-dlee Jul 18, 2026
8b5a11d
Recover all attributed Herdr cleanup phases
ruby-dlee Jul 18, 2026
c62efc6
feat(agent-fleet): add safe credential login transactions
ruby-dlee Jul 18, 2026
01dfac8
fix(agent-fleet): make credential recovery restart-safe
ruby-dlee Jul 18, 2026
813c00d
fix(agent-fleet): fence credential recovery transactions
ruby-dlee Jul 18, 2026
ff0ae75
fix(agent-fleet): close recovery routing races
ruby-dlee Jul 18, 2026
d07f708
fix(agent-fleet): make credential rollback no-replace
ruby-dlee Jul 18, 2026
51f6c5a
fix(agent-fleet): bind rollback cleanup ownership
ruby-dlee Jul 18, 2026
e31fff3
fix(agent-fleet): make credential recovery generation-safe
ruby-dlee Jul 18, 2026
a7df75a
fix(agent-fleet): close credential recovery races
ruby-dlee Jul 18, 2026
7f54966
fix(agent-fleet): bind rollback copy sources
ruby-dlee Jul 18, 2026
bcd5ae0
fix(agent-fleet): preserve exact Quota account contract
ruby-dlee Jul 18, 2026
d4f1d24
fix(agent-fleet): pin sealed Quota release
ruby-dlee Jul 18, 2026
5c475c3
fix: close sealed cutover proof and recovery gaps
ruby-dlee Jul 18, 2026
fd2e995
fix: harden sealed cutover recovery
ruby-dlee Jul 18, 2026
aacd439
fix: make cutover recovery generation-safe
ruby-dlee Jul 18, 2026
4c5b9bb
fix: bind recovery to durable generations
ruby-dlee Jul 18, 2026
5538600
fix: converge identity cleanup restarts
ruby-dlee Jul 18, 2026
ece9297
docs: normalize cutover Markdown
ruby-dlee Jul 18, 2026
660104f
test: assert canonical desktop anchor home
ruby-dlee Jul 18, 2026
fcb230e
no-mistakes(review): Captain: Harden bridge cutover recovery and prov…
ruby-dlee Jul 18, 2026
6803949
no-mistakes(test): Fix routing and Herdr test fixtures
ruby-dlee Jul 18, 2026
d821056
no-mistakes(document): Refresh Bridge cutover documentation
ruby-dlee Jul 18, 2026
18f14fa
no-mistakes(document): Refresh Bridge liveness documentation
ruby-dlee Jul 18, 2026
4098db5
no-mistakes(lint): Document intentional deferred shell expansions for…
ruby-dlee Jul 18, 2026
0553c98
fix: make Bridge CI checks platform-safe
ruby-dlee Jul 18, 2026
2ddaa6b
fix: retain proof staging inode through publish
ruby-dlee Jul 18, 2026
d62988c
test: report managed rollback metadata drift
ruby-dlee Jul 18, 2026
bbd6609
test: expose managed rollback cleanup failure
ruby-dlee Jul 19, 2026
84a39dd
test: expose failed rollback control calls
ruby-dlee Jul 19, 2026
12ef9b6
fix: report rollback release status
ruby-dlee Jul 19, 2026
827b62d
test: trace rollback release inputs
ruby-dlee Jul 19, 2026
06d3698
fix: preserve successful bounded control status
ruby-dlee Jul 19, 2026
71c6957
fix: preserve routed control success status
ruby-dlee Jul 19, 2026
675ed57
test: expose Herdr recertification failure
ruby-dlee Jul 19, 2026
722e35b
test: age metadata lock grace authority
ruby-dlee Jul 19, 2026
9c9c9c5
test: stabilize Herdr lifecycle process probes
ruby-dlee Jul 19, 2026
f7aa56a
test: stabilize concurrent Herdr process probes
ruby-dlee Jul 19, 2026
4360ec1
fix: retain Herdr lock owner PID across probes
ruby-dlee Jul 19, 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
4 changes: 2 additions & 2 deletions .agents/skills/bootstrap-diagnostics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ The inline rules in `AGENTS.md` section 3 still bind: detect, then consent, then
- `FLEET_SYNC: <repo>: STUCK: on <state>, N commits behind <base> - needs attention` - the clone is dirty, on a non-default branch, detached with unique commits, or diverged, so the sync left it untouched (never forcing or discarding); it will keep falling behind until you look.
A loud STUCK, especially a growing N across bootstraps, means that clone needs hands-on attention; dispatch a crewmate or resolve it before it strands work.
- `SECONDMATE_SYNC: secondmate <id>: skipped: <reason>` - the local-HEAD secondmate sync left a live secondmate home on its existing checkout because the home was dirty, diverged, unsafe, on the wrong branch, missing the primary target commit, or otherwise not fast-forwardable, or because inheritable-config propagation failed; bootstrap continued, but inspect the reason because the secondmate's tracked instructions or inherited settings may be stale after a primary update.
- `SECONDMATE_LIVENESS: secondmate <id>: already-live|respawned|skipped: <reason>|respawn failed: <reason>` - the session-start liveness sweep checked a live secondmate's recorded endpoint for a real agent process.
Treat `already-live` and `respawned` as handled; investigate `skipped` or `respawn failed` because that secondmate is not guaranteed live.
- `SECONDMATE_LIVENESS: secondmate <id>: <outcome>` - the session-start liveness sweep checked a live secondmate's recorded endpoint for a real agent process.
Treat `already-live`, `respawned`, and `rollback reconciled and respawned` as handled; investigate `skipped` or `respawn failed`, and load `secondmate-provisioning` for any `respawn deferred` outcome because its "Recovery" section owns the required routing decision.
- `TASKS_AXI: available` - a default-backend capability fact, not a problem; record it silently and use `AGENTS.md` section 10 for backlog mutations.
It prints only when `config/backlog-backend` is absent or set to `tasks-axi` and the shared compatibility probe passes (`docs/configuration.md` "Backlog backend").
If the backend is not opted out and `tasks-axi` is missing or incompatible, bootstrap reports the `MISSING: tasks-axi` line but firstmate still hand-edits routine backlog updates and never blocks work.
Expand Down
7 changes: 5 additions & 2 deletions .agents/skills/secondmate-provisioning/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,15 @@ bin/fm-spawn.sh <id> --resume-account

This path requires the recorded Agent Fleet SessionStart mapping and uses `lease recover` rather than new-task quota selection.
If exact native resume is unavailable, recover the same task under a fresh Claude or Codex profile with `bin/fm-spawn.sh <id> --continue-account` after re-verifying the endpoint is dead; `bin/fm-account-continuation.sh` owns the provider-neutral packet and fail-closed state checks.
For unmanaged `kind=secondmate` meta with no window, treat the secondmate as a dead persistent direct report and respawn it with:
For unmanaged `kind=secondmate` metadata with a missing or confidently dead endpoint, bootstrap deliberately defers recovery rather than silently changing its routing state.
Surface the required routing decision; to preserve the unmanaged generation after an explicit operator decision, respawn it with:

```sh
bin/fm-spawn.sh <id> --secondmate
bin/fm-spawn.sh <id> --secondmate --no-account-routing
```

If the operator instead intends to convert the generation to managed routing, use an explicit `--account-pool` or `--account-profile` under the normal enforced-routing contract.

Use the recorded `home=` in meta.
If meta is missing but `data/secondmates.md` still registers the secondmate, respawn from the registry entry and its persistent on-disk home.
Respawn re-resolves the secondmate harness from current config, uses the same guarded pre-launch sync, and re-propagates inheritable config, so recovered secondmates converge to the primary firstmate version and local dispatch, crew-harness, backlog-backend, and account-routing settings whenever their home can be cleanly fast-forwarded.
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/updatefirstmate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ metadata:
# updatefirstmate

Self-update firstmate in place.
Firstmate is its own repo, behind the same no-mistakes gate as any project, so new tracked material (`AGENTS.md`, `bin/`, `.agents/skills/`, and public `skills/`) reaches `main` and then sits there until each running firstmate pulls it.
Firstmate is its own repo behind the same no-mistakes gate as any project, so shared tracked material reaches `main` and then waits for each running firstmate to pull it; `AGENTS.md` section 12 owns that material's self-update boundary.
Only `AGENTS.md`, `bin/`, and `.agents/skills/` are a running firstmate instruction surface; public `skills/` is installer-facing and is not loaded by firstmate.
This skill performs that pull for the running main firstmate and every secondmate, without disturbing any in-flight work.

Expand Down
30 changes: 26 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ jobs:
tests:
name: Behavior tests
runs-on: ubuntu-latest
# The complete suite now takes roughly 16 minutes on ubuntu-latest. Keep a
# bounded cap that accommodates healthy growth while still failing loudly
# on a genuinely hung watcher or tmux test.
timeout-minutes: 30
# The pre-cutover suite reached 25m35s, and the exhaustive Bridge crash
# matrix adds bounded work. Keep enough margin without masking a real hang.
timeout-minutes: 45
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install pinned ShellCheck
run: |
set -eu
Expand All @@ -59,6 +61,26 @@ jobs:
"$test_script"
done

agent-fleet:
name: Agent Fleet package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install pinned uv
run: python -m pip install uv==0.9.10
- name: Verify locked package
working-directory: tools/agent-fleet
run: |
set -eu
uv sync --locked
uv run --locked ruff check .
uv run --locked pytest
uv run --locked python -m compileall -q src
uv build --out-dir "$RUNNER_TEMP/agent-fleet-dist"

invariants:
name: Repo invariants
runs-on: ubuntu-latest
Expand Down
20 changes: 11 additions & 9 deletions .no-mistakes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ disable_project_settings: true
# commands.lint, the gate's lint step never ran the deterministic
# `shellcheck bin/*.sh bin/backends/*.sh tests/*.sh` that CI runs, so info-level
# ShellCheck findings (e.g. SC2015) were not surfaced locally before CI rejected
# them. commands.lint delegates to bin/fm-lint.sh, the single owner of the lint
# definition that .github/workflows/ci.yml also invokes, so local can never
# diverge from CI again (parity asserted by tests/fm-lint.test.sh).
# The test command mirrors .github/workflows/ci.yml: iterate every
# tests/*.test.sh, run each, and fail the step if any one exits non-zero (an
# agent-driven test step has crashed the daemon). The e2e tests need tmux on
# PATH, which the firstmate environment provides.
# them. commands.lint delegates the shell definition to bin/fm-lint.sh and runs
# the locked Agent Fleet ruff check that .github/workflows/ci.yml also invokes.
# The shell definition stays single-owned, so local and CI cannot diverge
# (parity asserted by tests/fm-lint.test.sh).
# The test command mirrors the source checks in .github/workflows/ci.yml:
# iterate every tests/*.test.sh, including the Python 3.11 Bridge cutover runner,
# then run Agent Fleet's locked pytest and compileall checks, and fail if any
# check exits non-zero. The e2e tests need tmux on PATH, which the firstmate
# environment provides.
commands:
lint: 'bin/fm-lint.sh'
test: 'command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"'
lint: 'bin/fm-lint.sh && uv run --directory tools/agent-fleet --locked ruff check .'
test: 'command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; uv run --directory tools/agent-fleet --locked pytest || rc=1; uv run --directory tools/agent-fleet --locked python -m compileall -q src || rc=1; exit "$rc"'

# Keep test evidence out of this repo; it stays in a temp dir instead.
test:
Expand Down
9 changes: 5 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Hard rules, in priority order:

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/`.
Shared, tracked material means `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.tasks.toml`, `.github/workflows/`, `bin/`, `.agents/skills/`, public `skills/`, and provider-neutral components under `tools/`.
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.
Expand Down Expand Up @@ -73,6 +73,7 @@ README.md public overview and development notes
.claude/skills symlink to .agents/skills for claude compatibility
skills/ standalone public installer-facing skills, committed; not loaded by firstmate
bin/ helper scripts, committed; read each script's header before first use
tools/ independently versioned provider-neutral components, committed; Agent Fleet lives under tools/agent-fleet
.env optional X-mode pairing token; LOCAL, gitignored; presence-gates section 14
config/crew-harness crewmate harness override; LOCAL, gitignored; absent or "default" = same as firstmate. Inherited as the literal file: a concrete primary adapter value also controls a secondmate home's own crewmates (section 4)
config/crew-dispatch.json optional crewmate dispatch profiles; LOCAL, gitignored; firstmate-maintained but human-editable natural-language rules that choose a per-task harness/model/effort profile (section 4). Inherited by secondmate homes
Expand Down Expand Up @@ -132,7 +133,7 @@ It composes today's `fm-lock.sh`, `fm-bootstrap.sh`, and `fm-wake-drain.sh` - ca
2. **Bootstrap** - detect-only diagnostics (tool/version problems, GitHub auth, the worktree-tangle check, harness override, dispatch-profile validation, backlog-backend status) always run and always print.
When the lock could not be acquired, the worktree-tangle check uses read-only advisory wording without a checkout repair command.
The five MUTATING sweeps - report-retention ownership, fleet sync, the local secondmate fast-forward sweep, the secondmate liveness sweep, and X-mode artifact writes - run only when this session actually holds the lock from step 1.
The secondmate liveness sweep deterministically guarantees every registered secondmate is actually running: it probes each live secondmate's endpoint for a real agent process (not just pane presence) and respawns only on a confident dead reading, reported as `SECONDMATE_LIVENESS:` lines (`bin/fm-bootstrap.sh`; `bin/fm-backend.sh`'s `fm_backend_agent_alive`).
The secondmate liveness sweep probes each live secondmate's endpoint for a real agent process, reports handled or deferred outcomes as `SECONDMATE_LIVENESS:` lines, and leaves any required routing decision to `secondmate-provisioning` (`bin/fm-bootstrap.sh`; `bin/fm-backend.sh`'s `fm_backend_agent_alive`).
3. **Wake queue** - when locked, drains the durable wake queue and prints the records prominently as this turn's first work queue, exactly as `bin/fm-wake-drain.sh` did before; a lapsed watcher chain still surfaces here via the same guard banner.
When the lock could not be acquired, the queue is left untouched because another session owns it, and the guard's tangle/watcher-liveness alarms still print in read-only advisory mode without drain, supervision repair, or checkout repair commands.
4. **Context digest** - the full contents of `data/projects.md`, `data/secondmates.md`, `data/captain.md`, and `data/learnings.md`, each clearly delimited.
Expand Down Expand Up @@ -253,7 +254,7 @@ Reconcile reality with your records before doing anything else, working from the
6. For meta with no window, or an endpoint the digest reported dead, reconcile by kind.
If meta records `account_profile=`, first try the exact sticky session with `bin/fm-spawn.sh <id> --resume-account`; when that session/profile is unavailable, use `--continue-account` for the task-owned provider-neutral handoff after re-verifying live and repository state, with `bin/fm-account-continuation.sh` owning the fail-closed packet contract.
For ordinary crewmates, check the recorded backend metadata first; use `treehouse status` for treehouse-backed tasks, and the recorded `orca_worktree_id=`/`terminal=` for Orca tasks.
For an unmanaged `kind=secondmate`, load `secondmate-provisioning`, treat it as a dead persistent direct report, and respawn it from recorded meta or the registry entry.
For an unmanaged `kind=secondmate`, load `secondmate-provisioning`; its "Recovery" section owns the explicit routing decision and respawn procedure.
7. Do not reconstruct a secondmate's whole tree from the main home.
The main firstmate reconciles only direct reports.
Each secondmate is a firstmate in its own home, so it reconciles only work that is already its own and then idles; it never creates new work during recovery.
Expand Down Expand Up @@ -763,7 +764,7 @@ Adjust the other sections only when the task genuinely deviates from the standar

## 12. Self-update

firstmate is its own repo behind the no-mistakes gate, so improvements to `AGENTS.md`, `bin/`, `.agents/skills/`, and public `skills/` reach `main` and then wait for each running firstmate to pull them.
firstmate is its own repo behind the no-mistakes gate, so improvements to `AGENTS.md`, `bin/`, `.agents/skills/`, public `skills/`, and `tools/` reach `main` and then wait for each running firstmate to pull them.
Only `AGENTS.md`, `bin/`, and `.agents/skills/` are a running firstmate instruction surface; public `skills/` is tracked for installers and is not loaded by firstmate.
When the captain invokes `/updatefirstmate` or asks to update firstmate, load the `/updatefirstmate` skill.
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/`.
Expand Down
9 changes: 6 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ See the [no-mistakes quick start](https://kunchenguid.github.io/no-mistakes/star

- This repo is a template for running a firstmate orchestrator agent.
`AGENTS.md` is the agent's main job description and names when to load bundled firstmate skills; `CLAUDE.md` is a symlink to it, and `.claude/skills` is a symlink to `.agents/skills`.
- Only shared material is tracked: `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.tasks.toml`, `.github/workflows/`, `bin/`, `.agents/skills/`, and `skills/`.
- Only shared material is tracked: `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.tasks.toml`, `.github/workflows/`, `bin/`, `.agents/skills/`, `skills/`, and provider-neutral components under `tools/`.
`.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, with the compatibility definition owned by [`docs/configuration.md`](docs/configuration.md) ("Backlog backend").
Expand All @@ -54,15 +54,15 @@ See the [no-mistakes quick start](https://kunchenguid.github.io/no-mistakes/star

## Development

Tracked changes to firstmate itself - `AGENTS.md`, `README.md`, `CONTRIBUTING.md`, `.tasks.toml`, `.github/workflows/`, `bin/`, `.agents/skills/`, and `skills/` - ship through the `no-mistakes` pipeline on a feature branch and require an explicit merge approval.
Changes to the shared tracked material listed under "Repo conventions" ship through the `no-mistakes` pipeline on a feature branch and require an explicit merge approval.
Before making any such change, load the agent-only `firstmate-coding-guidelines` skill (`.agents/skills/firstmate-coding-guidelines/SKILL.md`).
It has the knowledge-placement rules that keep `AGENTS.md` from regrowing after each diet pass.
There is no reliable way for `bin/fm-brief.sh`'s scaffold to detect that a task's repo is firstmate itself, so firstmate adds this skill's load line to firstmate-repo briefs by hand.
A crewmate picking up such a brief should load the skill even if the brief predates this instruction.
When supervising live crewmates, keep firstmate's own long validation or build commands in the background so watcher wakes can still be handled.
Crewmate validation follows the installed no-mistakes version's SKILL.md and live `axi` help instead of duplicating gate mechanics in firstmate docs.
Firstmate's wrapper still matters: `ask-user` findings route to the captain through firstmate, and crewmates avoid `--yes` because it silently resolves captain-owned decisions without escalation.
Local `.no-mistakes/` state and test evidence stay out of this repo; `.no-mistakes.yaml` keeps evidence in a temp directory and pins the gate's lint and test commands to the same `bin/fm-lint.sh` and bash behavior suite as CI, so the pre-push gate runs the exact checks CI enforces.
Local `.no-mistakes/` state and test evidence stay out of this repo; `.no-mistakes.yaml` keeps evidence in a temp directory and pins the gate's shell and Agent Fleet source checks to their matching CI commands.
That is firstmate-specific; do not commit `.no-mistakes/evidence/` here even when another no-mistakes-managed target project keeps committed PR evidence.

Check and test the toolbelt before pushing:
Expand All @@ -76,6 +76,9 @@ for test_script in tests/*.test.sh; do bash "$test_script"; done # behavior te
tmp=$(mktemp -d) && printf 'done: smoke\n' > "$tmp/smoke.status" && FM_STATE_OVERRIDE="$tmp" FM_SIGNAL_GRACE=1 FM_POLL=1 FM_HEARTBEAT=999999 bin/fm-watch-arm.sh # watcher re-arm smoke test (prints arm status, then an actionable signal)
```

Agent Fleet is independently packaged under `tools/agent-fleet` and requires Python 3.11 or newer plus `uv`.
Run the complete locked verification in [`tools/agent-fleet/RELEASING.md`](tools/agent-fleet/RELEASING.md) before pushing; that document also owns versioning, tagging, and clean-install verification.

Discover tests by listing `tests/*.test.sh`: each is a self-contained bash script named `<subject>.test.sh`, and its header comment describes what it covers, so run one directly to focus on a subject.
Tests that need a real optional backend, an explicit opt-in, or an ambient toolchain capability (real herdr/zellij/cmux smoke tests, the live Pi regression, the Pi TypeScript-extension checks when node cannot import `.ts` modules directly) skip themselves and print the tool or environment gate needed to enable them, so the run-all loop above is always safe.

Expand Down
Loading