Files
stack/packages/mosaic/framework/fleet
topher 7e9e013f92
ci/woodpecker/pr/ci Pipeline was canceled
fleet: split-home-safe mosaic launcher (T110, P5-RM-009 stack side)
Ships fleet/bin/mosaic in the framework so the T106 shipped-first launcher
contract survives split-home layouts. The shipped npm mosaic resolves from the
passwd real home instead of $HOME: under a seat home (HOME=seat dir) the
operator's npm prefix is still found, so 'HOME=<seat-home> fleet/bin/mosaic
--version' returns the shipped version. The $HOME/.npm-global candidate is
consulted only when the passwd lookup fails, and then every path component
must be a non-symlink (secure descriptor traversal; a planted descriptor is
refused without execution).

T106 behavior preserved verbatim: worktree builds are MOSAIC_CLI_WORKTREE
opt-in only, health-checked, shipped fallback on doubt; MOSAIC_FLEET_CLI_OFF
forces pure pass-through; no runnable candidate exits 127 with the documented
stderr line; stale worktree candidates never regain default precedence
(without the opt-in env the worktree path is never read).

Manifest: fleet/bin/** added to the [framework] section so the updater and
installer both own the subtree (manifest-parity 17/17 green). Hermetic suite
test-mosaic-launcher.sh covers the split-home positive, typed failure,
stale-worktree non-precedence, opt-in healthy/unhealthy, OFF pass-through, and
descriptor-refusal arms. Marker T110-DISPATCH-TOPHER-1N2O.
2026-08-29 19:14:28 -05:00
..

Mosaic Fleet Rosters

The local fleet canary uses a product-owned roster schema with site-owned roster files. Product examples live here; active local rosters should live outside the package, normally at:

~/.config/mosaic/fleet/roster.yaml

The default tmux socket is mosaic-fleet so fleet commands do not touch the default tmux server. The roster is the desired-state authority; generated environment files are rebuildable projections, never a second source of configuration.

Brain-home split (fleet state vs framework templates)

When a mosaic-brain clone is present, fleet state resolves from the brain home while framework templates and dispatch state stay in the config home (three-tree model, canon docs/STRUCTURE-CANON.md §2):

Path Without brain (legacy) With brain
fleet/agents/<seat>.env.* ~/.config/mosaic/fleet/agents/ ~/.mosaic/fleet/agents/
fleet/roles.local/ (overrides) ~/.config/mosaic/fleet/roles.local/ ~/.mosaic/fleet/roles.local/
fleet/profiles/ (working copies) ~/.config/mosaic/fleet/profiles/ ~/.mosaic/fleet/profiles/
fleet/roster.yaml, fleet/roles/ (baseline), fleet/run/, fleet/services/ ~/.config/mosaic/fleet/… unchanged (config home)

Activation (packages/mosaic/src/fleet/brain-home.ts, mirrored in tools/fleet/start-agent-session.sh):

  1. MOSAIC_BRAIN_HOME env var — explicit, always wins.
  2. Canonical ~/.mosaic — adopted only when MOSAIC_HOME is the default ~/.config/mosaic AND ~/.mosaic/fleet/agents exists. Custom --mosaic-home values (tests, sandboxes, canaries) never adopt, keeping them hermetic.
  3. Otherwise the config home (legacy single-tree behavior).

Seat env dirs under a brain are subject to the same privacy boundary (0700 dirs, 0600 files); .env.generated files are structure-valuable and tracked in the brain repo, hand-maintained .env/.env.local stay ignored and private.

Examples

  • examples/minimal.yaml starts one local canary slot.
  • examples/local-canary.yaml starts a small generic dogfood fleet.
  • examples/operator-interaction.yaml is an example Pi operator-interaction service; replace its example agent name before provisioning.

Operator interaction service

services/operator-interaction.yaml pins the Pi runtime, GPT-5.6 Sol model, high reasoning, and the operator-interaction tool policy. The agent identity is provisioning data: choose a roster name, generate its per-agent environment file, then start the matching generic systemd instance. The service fails before launch if the configured identity does not match the instance or any pinned policy field drifts.

The installed tools/fleet/print-interaction-effective-policy.sh prints only the resolved name, runtime, model, reasoning, and tool policy. It never reads or prints credential variables.

Generated agent environment boundary

mosaic fleet install writes a private deterministic projection at ~/.config/mosaic/fleet/agents/<agent>.env.generated. It may relocate only approved local machine data to <agent>.env.local; generated keys, arbitrary commands, secret-like keys, duplicate keys, unknown keys, and unsafe permissions fail before a tmux session is created. Legacy .env input is regenerated, relocated, or quarantined and is not a launch authority.

See docs/fleet/reference/generated-env-boundary.md for allowed local keys and the USC downstream interface evidence.

Initialize a roster:

mosaic fleet init --profile minimal --write
mosaic fleet install-systemd
mosaic fleet start
mosaic fleet verify