grep -ci tmux on tools/install.sh and on tools/_scripts/mosaic-doctor at origin/next returns 0 for both. The fleet runs entirely inside tmux, the installer never installs it, and the audit script never mentions it.
What that costs an operator
Measured on mosaic-sbx-dev — Debian, greenfield, framework installed, no tmux:
[mosaic-doctor] warnings=11
Eleven warnings, and not one of them is the reason no seat can launch on that box. The host installs a fleet, starts a fleet, and runs nothing. mosaic fleet ps is the first and only signal, and by then the operator is debugging systemd.
The fix
A check_fleet_transport in each of the two places, reading the roster's own transport: field rather than assuming tmux.
The installer warns; it does not hard-fail. tmux is required by the fleet, not by mosaic. Plenty of hosts install this to run mosaic claude and will never scaffold a roster; failing their install over a binary they do not need would be wrong. The warning names exactly what it blocks and says the rest is unaffected. It runs in --check mode as well as normal mode — "what is the state of this host" is precisely what --check is asked.
Why two implementations, and how they are kept honest
The installer has to be able to answer this before the framework's own scripts are guaranteed to be on disk, so it cannot call the doctor's copy. Two implementations of one rule is exactly the shape that drifts.
packages/mosaic/framework/tools/_scripts/test-fleet-transport-check.sh drives both, in one file, from one table of cases — and it extracts the functions from the shipped scripts by awk rather than carrying a copy. A test with its own copy of the logic is a test that keeps passing after the shipped copy changes, which is the failure mode this whole area keeps producing. If either script is reshaped so the extraction stops matching, the harness fails loudly instead of silently measuring an empty string.
The absent-transport cases run on a PATH containing only sed head tr awk, and the harness refuses to run at all if tmux turns out to be resolvable there — a green that measured nothing is the thing being guarded against.
Wiring, and the guard that caught me
The harness is registered in test:framework-shell. It is one line of package.json, and it matters: with the file on disk and unwired, check-test-enumeration.sh (#1017) fails it as UNENUMERATED. That guard is correct and it did its job here. A check nothing runs is not a check.
Evidence
Red — against origin/next:
FAIL: could not extract 'fleet_declared_transport' from .../mosaic-doctor
rc=1
plus grep -ci tmux = 0 on both shipped files.
Green, on real hosts, all four branches:
host
state
result
dev
no tmux, no roster
[WARN] Fleet transport 'tmux' is not installed — 'mosaic fleet' cannot run seats here. Install it (e.g. sudo apt-get install -y tmux) before 'mosaic fleet init'.
dev
no tmux, v2 roster
[WARN] … this host has a roster and no seat can launch. Install it …, then 'mosaic fleet start'.
dev
install.sh --check
⚠ Fleet transport 'tmux' is not installed. + "mosaic fleet start reports success and no seat comes up"
canary
tmux present, v2 roster
[OK] Fleet transport available: tmux under --verbose; silent by default (pass() is verbose-gated); installer silent
Both boxes were restored to their prior scripts afterward.
Harness runs green on node:24-alpine (busybox sed/awk), the CI base image — checked before adding it to CI rather than after.
Gates:bash -n ×3 · pnpm typecheck 45/45 · fleet specs 342 passed · enumeration guard OK (population 52, enumerated 33) · its self-test OK · prettier --check clean on package.json.
Where this sits in the chain
Upstream of both open fixes. A correct fix for #1237/#1243 or #1241/#1244 still leaves a greenfield host with install rc=0, start rc=0, and no live seat — because tmux is not there. This is the link that says so out loud.
Still downstream and unowned after this: no agent runtime (claude/pi/codex/opencode) is installed by anything, which #1244's launcher check will now report as code=missing-binary instead of a silent success.
Notes for the reviewer
Two places worth arguing with me about: warn-vs-fail in the installer, and running the check in --check mode. Both are deliberate and both are in the comments.
pass() in mosaic-doctor only prints under --verbose; the harness stubs it unconditionally on purpose, because what is under test is which severity the check chose, not whether default verbosity shows it. That is stated in the harness.
Closes #1240.
## The bug in one line
`grep -ci tmux` on `tools/install.sh` and on `tools/_scripts/mosaic-doctor` at `origin/next` returns **0** for both. The fleet runs entirely inside tmux, the installer never installs it, and the audit script never mentions it.
## What that costs an operator
Measured on `mosaic-sbx-dev` — Debian, greenfield, framework installed, no tmux:
```
[mosaic-doctor] warnings=11
```
Eleven warnings, and not one of them is the reason no seat can launch on that box. The host installs a fleet, starts a fleet, and runs nothing. `mosaic fleet ps` is the first and only signal, and by then the operator is debugging systemd.
## The fix
A `check_fleet_transport` in each of the two places, reading the roster's own `transport:` field rather than assuming tmux.
**The installer warns; it does not hard-fail.** tmux is required by the *fleet*, not by *mosaic*. Plenty of hosts install this to run `mosaic claude` and will never scaffold a roster; failing their install over a binary they do not need would be wrong. The warning names exactly what it blocks and says the rest is unaffected. It runs in `--check` mode as well as normal mode — "what is the state of this host" is precisely what `--check` is asked.
## Why two implementations, and how they are kept honest
The installer has to be able to answer this **before the framework's own scripts are guaranteed to be on disk**, so it cannot call the doctor's copy. Two implementations of one rule is exactly the shape that drifts.
`packages/mosaic/framework/tools/_scripts/test-fleet-transport-check.sh` drives **both**, in one file, from one table of cases — and it **extracts the functions from the shipped scripts by awk rather than carrying a copy**. A test with its own copy of the logic is a test that keeps passing after the shipped copy changes, which is the failure mode this whole area keeps producing. If either script is reshaped so the extraction stops matching, the harness fails loudly instead of silently measuring an empty string.
The absent-transport cases run on a PATH containing only `sed head tr awk`, and the harness refuses to run at all if tmux turns out to be resolvable there — a green that measured nothing is the thing being guarded against.
## Wiring, and the guard that caught me
The harness is registered in `test:framework-shell`. It is one line of `package.json`, and it matters: with the file on disk and unwired, `check-test-enumeration.sh` (#1017) fails it as `UNENUMERATED`. That guard is correct and it did its job here. A check nothing runs is not a check.
## Evidence
**Red** — against `origin/next`:
```
FAIL: could not extract 'fleet_declared_transport' from .../mosaic-doctor
rc=1
```
plus `grep -ci tmux` = 0 on both shipped files.
**Green, on real hosts, all four branches:**
| host | state | result |
|---|---|---|
| dev | no tmux, no roster | `[WARN] Fleet transport 'tmux' is not installed — 'mosaic fleet' cannot run seats here. Install it (e.g. sudo apt-get install -y tmux) before 'mosaic fleet init'.` |
| dev | no tmux, v2 roster | `[WARN] … this host has a roster and no seat can launch. Install it …, then 'mosaic fleet start'.` |
| dev | `install.sh --check` | `⚠ Fleet transport 'tmux' is not installed.` + "mosaic fleet start reports success and no seat comes up" |
| canary | tmux present, v2 roster | `[OK] Fleet transport available: tmux` under `--verbose`; silent by default (`pass()` is verbose-gated); installer silent |
Both boxes were restored to their prior scripts afterward.
**Harness runs green on `node:24-alpine`** (busybox `sed`/`awk`), the CI base image — checked before adding it to CI rather than after.
**Gates:** `bash -n` ×3 · `pnpm typecheck` 45/45 · fleet specs 342 passed · enumeration guard OK (population 52, enumerated 33) · its self-test OK · `prettier --check` clean on `package.json`.
## Where this sits in the chain
Upstream of both open fixes. **A correct fix for #1237/#1243 or #1241/#1244 still leaves a greenfield host with `install` rc=0, `start` rc=0, and no live seat** — because tmux is not there. This is the link that says so out loud.
Still downstream and unowned after this: no agent runtime (`claude`/`pi`/`codex`/`opencode`) is installed by anything, which #1244's launcher check will now report as `code=missing-binary` instead of a silent success.
## Notes for the reviewer
- Two places worth arguing with me about: warn-vs-fail in the installer, and running the check in `--check` mode. Both are deliberate and both are in the comments.
- `pass()` in `mosaic-doctor` only prints under `--verbose`; the harness stubs it unconditionally on purpose, because what is under test is which severity the check *chose*, not whether default verbosity shows it. That is stated in the harness.
`mosaic fleet --help` reads "Manage the local Mosaic tmux fleet" and every
roster the CLI scaffolds sets `transport: tmux`, but neither `tools/install.sh`
nor `tools/_scripts/mosaic-doctor` contained the string "tmux" at all. A
greenfield host therefore came out of the installer able to install a fleet,
start a fleet, and run no seat, with `mosaic fleet ps` as the operator's first
and only signal.
Measured on mosaic-sbx-dev (Debian, no tmux, framework installed): `mosaic-doctor`
reported 11 warnings and not one of them named the reason no seat could launch.
The installer gets a warning, not a `require_cmd` hard failure: tmux is required
by the fleet, not by mosaic. Hosts that install this to run `mosaic claude` and
never scaffold a roster are common, and failing their install over a binary they
do not need would be wrong. The check runs in `--check` mode too — "what is the
state of this host" is the question `--check` is asked.
Both checks read the roster's own `transport:` rather than assuming tmux, so a
host declaring something else is pointed at the binary it actually needs instead
of at the wrong package.
The two implementations are deliberately parallel and each carries a comment
pointing at the other. They are separate because the installer must answer this
before the framework's own scripts are guaranteed to be on disk. One harness
drives BOTH from the shipped text — the functions are extracted from the scripts
by awk rather than copied — so the pair cannot drift silently, and the test
cannot keep passing after the shipped copy changes.
The harness is wired into `test:framework-shell`. Without that it would have
tripped the #1017 enumeration guard as UNENUMERATED, which is the guard doing
its job: a check nothing runs is not a check.
Evidence:
- red: the harness fails against origin/next ("could not extract
fleet_declared_transport"); `grep -ci tmux` on both files at origin/next = 0.
- green on real hosts, all four branches:
- dev (no tmux, no roster) -> WARN naming tmux, points at `mosaic fleet init`
- dev (no tmux, v2 roster) -> WARN naming the roster, points at `mosaic fleet start`
- dev installer --check -> WARN saying start "reports success and no seat comes up"
- canary (tmux present) -> `[OK] Fleet transport available: tmux` under --verbose,
silent by default (pass() is verbose-gated), installer silent
- harness green on node:24-alpine/busybox, the CI base image.
- `bash -n` x3, `pnpm typecheck` 45/45, fleet specs 342 passed,
enumeration guard OK, its self-test OK, prettier clean.
Refs #1240. Upstream of #1237/#1243 and #1241/#1244: a correct fix for either of
those still leaves this host with no live seat.
Confirmed working on a genuinely greenfield box. The installer emitted the transport warning on a VM with no tmux — naming the package, stating that fleet start would otherwise report success with no seat up, and giving the apt command. With tmux installed the warning is silent and --verbose shows [OK] Fleet transport available: tmux.
Independently corroborated downstream: fleet start on that same box failed with refusing unmanaged Mosaic tmux server on socket mosaic-fleet: tmux binary is unavailable (exit 64) — exactly the failure the warning predicts. Full table in the comment on #1244.
Confirmed working on a genuinely greenfield box. The installer emitted the transport warning on a VM with no tmux — naming the package, stating that `fleet start` would otherwise report success with no seat up, and giving the apt command. With tmux installed the warning is silent and `--verbose` shows `[OK] Fleet transport available: tmux`.
Independently corroborated downstream: `fleet start` on that same box failed with `refusing unmanaged Mosaic tmux server on socket mosaic-fleet: tmux binary is unavailable` (exit 64) — exactly the failure the warning predicts. Full table in the comment on #1244.
This and #1244 should land together.
⚠️ Pre-merge gate: both install.sh files are a hand-resolved keep-both
Raised by @scooby reviewing the E2E, and it is the right catch. Recording it here so it cannot be
lost between now and the merge.
The risk.#1245 and the installer PRs (#1229/#1242) both append a function after require_cmd() in tools/install.sh, and the shared trailing } closes whichever side wins.
Git raises this conflict again when the PRs are merged one at a time. My greenfield E2E validated my resolution. If whoever merges resolves it differently, the install.sh that ships is not
the install.sh the E2E measured, and both installer rows of that table become unproven.
Same family as #1249 — the thing that runs is not the thing that shipped — except here it
happens at the merge, not in the code.
The resolution that was measured. Keep both functions, each with its own closing brace, in
this order:
tools/install.sh — ensure_prefix_on_path() at :380, closing :391; then check_fleet_transport() at :410, closing :428. Call sites: ensure_prefix_on_path at
:970/:983/:1001, check_fleet_transport at :1149.
packages/mosaic/framework/install.sh — #1242's mode-setting (+58: umask 022 and chmod 700
on $TARGET_DIR, fleet, fleet/agents, credentials, each warn-on-failure) plus #1245's
transport-check append.
Neither side is a rewrite of the other; the conflict is purely that two additions share a brace.
The check — one command, exact values. After the five land on next:
git diff origin/next origin/e2e-compose -- '*install.sh' # must be empty
If those match, the entire E2E table transfers to next unchanged. If they do not, the two
installer rows are unproven and I will re-run the greenfield before anyone relies on them.
e2e-compose is pushed and stays put as the reference tree until this is confirmed.
## ⚠️ Pre-merge gate: both `install.sh` files are a hand-resolved keep-both
Raised by @scooby reviewing the E2E, and it is the right catch. Recording it here so it cannot be
lost between now and the merge.
**The risk.** #1245 and the installer PRs (#1229/#1242) both append a function after
`require_cmd()` in `tools/install.sh`, and the shared trailing `}` closes whichever side wins.
Git raises this conflict again when the PRs are merged one at a time. My greenfield E2E validated
**my** resolution. If whoever merges resolves it differently, the `install.sh` that ships is not
the `install.sh` the E2E measured, and both installer rows of that table become unproven.
Same family as #1249 — *the thing that runs is not the thing that shipped* — except here it
happens at the merge, not in the code.
**The resolution that was measured.** Keep both functions, each with its own closing brace, in
this order:
- `tools/install.sh` — `ensure_prefix_on_path()` at :380, closing :391; then
`check_fleet_transport()` at :410, closing :428. Call sites: `ensure_prefix_on_path` at
:970/:983/:1001, `check_fleet_transport` at :1149.
- `packages/mosaic/framework/install.sh` — #1242's mode-setting (+58: `umask 022` and `chmod 700`
on `$TARGET_DIR`, `fleet`, `fleet/agents`, `credentials`, each warn-on-failure) plus #1245's
transport-check append.
Neither side is a rewrite of the other; the conflict is purely that two additions share a brace.
**The check — one command, exact values.** After the five land on `next`:
```
git fetch origin
git rev-parse origin/next:tools/install.sh origin/next:packages/mosaic/framework/install.sh
```
Must print exactly:
```
5d28f773c63e8e71f55f65f9c41221c5e16571e6 # tools/install.sh
1578c33bc0207203d2093d5120f1cafec8610292 # packages/mosaic/framework/install.sh
```
Equivalently, and easier to eyeball:
```
git diff origin/next origin/e2e-compose -- '*install.sh' # must be empty
```
**If those match, the entire E2E table transfers to `next` unchanged.** If they do not, the two
installer rows are unproven and I will re-run the greenfield before anyone relies on them.
`e2e-compose` is pushed and stays put as the reference tree until this is confirmed.
Resolves conflicts from #1229 (tools/install.sh node provisioning) and #1252
(package.json test:framework-shell). tools/install.sh resolved to the reviewed
composite blob 5d28f773; package.json resolved as a union so both #1252's four
suites and #1245's transport-check suite run (48 links).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #1240.
The bug in one line
grep -ci tmuxontools/install.shand ontools/_scripts/mosaic-doctoratorigin/nextreturns 0 for both. The fleet runs entirely inside tmux, the installer never installs it, and the audit script never mentions it.What that costs an operator
Measured on
mosaic-sbx-dev— Debian, greenfield, framework installed, no tmux:Eleven warnings, and not one of them is the reason no seat can launch on that box. The host installs a fleet, starts a fleet, and runs nothing.
mosaic fleet psis the first and only signal, and by then the operator is debugging systemd.The fix
A
check_fleet_transportin each of the two places, reading the roster's owntransport:field rather than assuming tmux.The installer warns; it does not hard-fail. tmux is required by the fleet, not by mosaic. Plenty of hosts install this to run
mosaic claudeand will never scaffold a roster; failing their install over a binary they do not need would be wrong. The warning names exactly what it blocks and says the rest is unaffected. It runs in--checkmode as well as normal mode — "what is the state of this host" is precisely what--checkis asked.Why two implementations, and how they are kept honest
The installer has to be able to answer this before the framework's own scripts are guaranteed to be on disk, so it cannot call the doctor's copy. Two implementations of one rule is exactly the shape that drifts.
packages/mosaic/framework/tools/_scripts/test-fleet-transport-check.shdrives both, in one file, from one table of cases — and it extracts the functions from the shipped scripts by awk rather than carrying a copy. A test with its own copy of the logic is a test that keeps passing after the shipped copy changes, which is the failure mode this whole area keeps producing. If either script is reshaped so the extraction stops matching, the harness fails loudly instead of silently measuring an empty string.The absent-transport cases run on a PATH containing only
sed head tr awk, and the harness refuses to run at all if tmux turns out to be resolvable there — a green that measured nothing is the thing being guarded against.Wiring, and the guard that caught me
The harness is registered in
test:framework-shell. It is one line ofpackage.json, and it matters: with the file on disk and unwired,check-test-enumeration.sh(#1017) fails it asUNENUMERATED. That guard is correct and it did its job here. A check nothing runs is not a check.Evidence
Red — against
origin/next:plus
grep -ci tmux= 0 on both shipped files.Green, on real hosts, all four branches:
[WARN] Fleet transport 'tmux' is not installed — 'mosaic fleet' cannot run seats here. Install it (e.g. sudo apt-get install -y tmux) before 'mosaic fleet init'.[WARN] … this host has a roster and no seat can launch. Install it …, then 'mosaic fleet start'.install.sh --check⚠ Fleet transport 'tmux' is not installed.+ "mosaic fleet start reports success and no seat comes up"[OK] Fleet transport available: tmuxunder--verbose; silent by default (pass()is verbose-gated); installer silentBoth boxes were restored to their prior scripts afterward.
Harness runs green on
node:24-alpine(busyboxsed/awk), the CI base image — checked before adding it to CI rather than after.Gates:
bash -n×3 ·pnpm typecheck45/45 · fleet specs 342 passed · enumeration guard OK (population 52, enumerated 33) · its self-test OK ·prettier --checkclean onpackage.json.Where this sits in the chain
Upstream of both open fixes. A correct fix for #1237/#1243 or #1241/#1244 still leaves a greenfield host with
installrc=0,startrc=0, and no live seat — because tmux is not there. This is the link that says so out loud.Still downstream and unowned after this: no agent runtime (
claude/pi/codex/opencode) is installed by anything, which #1244's launcher check will now report ascode=missing-binaryinstead of a silent success.Notes for the reviewer
--checkmode. Both are deliberate and both are in the comments.pass()inmosaic-doctoronly prints under--verbose; the harness stubs it unconditionally on purpose, because what is under test is which severity the check chose, not whether default verbosity shows it. That is stated in the harness.Confirmed working on a genuinely greenfield box. The installer emitted the transport warning on a VM with no tmux — naming the package, stating that
fleet startwould otherwise report success with no seat up, and giving the apt command. With tmux installed the warning is silent and--verboseshows[OK] Fleet transport available: tmux.Independently corroborated downstream:
fleet starton that same box failed withrefusing unmanaged Mosaic tmux server on socket mosaic-fleet: tmux binary is unavailable(exit 64) — exactly the failure the warning predicts. Full table in the comment on #1244.This and #1244 should land together.
⚠️ Pre-merge gate: both
install.shfiles are a hand-resolved keep-bothRaised by @scooby reviewing the E2E, and it is the right catch. Recording it here so it cannot be
lost between now and the merge.
The risk. #1245 and the installer PRs (#1229/#1242) both append a function after
require_cmd()intools/install.sh, and the shared trailing}closes whichever side wins.Git raises this conflict again when the PRs are merged one at a time. My greenfield E2E validated
my resolution. If whoever merges resolves it differently, the
install.shthat ships is notthe
install.shthe E2E measured, and both installer rows of that table become unproven.Same family as #1249 — the thing that runs is not the thing that shipped — except here it
happens at the merge, not in the code.
The resolution that was measured. Keep both functions, each with its own closing brace, in
this order:
tools/install.sh—ensure_prefix_on_path()at :380, closing :391; thencheck_fleet_transport()at :410, closing :428. Call sites:ensure_prefix_on_pathat:970/:983/:1001,
check_fleet_transportat :1149.packages/mosaic/framework/install.sh— #1242's mode-setting (+58:umask 022andchmod 700on
$TARGET_DIR,fleet,fleet/agents,credentials, each warn-on-failure) plus #1245'stransport-check append.
Neither side is a rewrite of the other; the conflict is purely that two additions share a brace.
The check — one command, exact values. After the five land on
next:Must print exactly:
Equivalently, and easier to eyeball:
If those match, the entire E2E table transfers to
nextunchanged. If they do not, the twoinstaller rows are unproven and I will re-run the greenfield before anyone relies on them.
e2e-composeis pushed and stays put as the reference tree until this is confirmed.fred referenced this pull request2026-08-16 18:13:24 +00:00