Files
stack/docs/fleet/FLEET-LAUNCH.md
T

104 lines
6.1 KiB
Markdown

# Fleet Launch Runbook
The local fleet roster is the sole writable desired-state authority for membership and launch policy.
Generated environment files are rebuildable projections, not an operator-editable command surface.
## Launch chain
| Layer | Responsibility |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Roster | `fleet/roster.yaml` supplies the agent name, class, supported runtime, model, reasoning, tool policy, workdir, and tmux socket. |
| Projection writer | Renders deterministic fleet/agents/<name>.env.generated from the roster. |
| Optional local data | Reads a strict, data-only fleet/agents/<name>.env.local; it cannot shadow generated keys. |
| systemd | Starts the launcher with env -i and fixed bootstrap data. It does not preload either environment file. |
| session launcher | Validates generated and local data before it queries, creates, or stops an exact tmux session. |
| runtime launch | Derives the fixed mosaic yolo <runtime> argument array from validated roster data, then seeds the runtime contract. |
The launcher never `source`s or `eval`s an environment file and never accepts an environment-supplied
command. `MOSAIC_AGENT_COMMAND`, command/channel overrides, unknown keys, generated-key shadowing,
secret-like key names, duplicate keys, comments, quoted/export syntax, and unsafe values are rejected.
## Generated and local files
<name>.env.generated is complete, deterministic, and written only by Mosaic. Its ordered keys are:
```dotenv
MOSAIC_AGENT_NAME=<roster name>
MOSAIC_AGENT_CLASS=<roster class>
MOSAIC_AGENT_RUNTIME=<roster runtime>
MOSAIC_AGENT_MODEL=<roster model hint>
MOSAIC_AGENT_REASONING=<roster reasoning>
MOSAIC_AGENT_TOOL_POLICY=<roster tool policy>
MOSAIC_AGENT_WORKDIR=<absolute roster work directory>
MOSAIC_TMUX_SOCKET=<roster socket or empty>
```
The generated launch contract supports `claude`, `codex`, `opencode`, and `pi`. mosaic fleet add
rejects another runtime before it writes the roster or modifies generated, local, or quarantine state.
The legacy dogfood stub remains an observability-only canary on its separate `mosaic-factory` socket;
it has no generated-launch adapter and cannot be added through this path.
<name>.env.local is optional and may contain only non-secret machine data:
- `MOSAIC_RUNTIME_BIN`
- `MOSAIC_HEARTBEAT_RUN_DIR`
- `MOSAIC_HEARTBEAT_INTERVAL`
- `MOSAIC_CLAUDE_JSON`
- `CLAUDE_CONFIG_DIR`
Paths must be safe absolute paths and the heartbeat interval must be a positive integer. Projection,
local, and quarantine files must be private regular files; the managed directories must be real,
private, non-symlink paths. Violations fail closed before tmux interaction.
## Legacy input and diagnostics
A legacy <name>.env is input only during projection generation. Roster-owned keys are regenerated;
valid allowed local data can move to `.env.local`; invalid legacy input is privately retained at
<name>.env.quarantine. Neither legacy nor quarantine files are launch authority.
Diagnostics expose only rule code, key name, and a SHA-256 content hash. They do not reveal command
text, credentials, or other values.
## Pane executable preflight
The fleet install, install-systemd, and doctor commands plus the session launcher use
**pane-runtime-path.sh** as the single pane-PATH implementation. Install inspects every distinct
roster runtime and effective MOSAIC_RUNTIME_BIN pair before creating holder identity, tool,
projection, or unit files. Doctor reports the same checks as JSON.
A resolved command is not automatically executable. The helper reads a script shebang, unwraps the
common “/usr/bin/env node” and “/usr/bin/env -S node …” forms, then resolves the declared command
against the pane PATH. When Node is the declared interpreter, the helper runs the side-effect-free
“node --version” probe. It does not run “mosaic --version”, whose startup update check can write cache
state. Native binaries have no PATH-resolved shebang dependency and retain their normal executable
check. Failures name the executable or runtime, requesting roster rows, searched pane PATH,
dependency, and runtime install command.
Supported runtime install commands are:
- **Claude:** curl -fsSL https://claude.ai/install.sh | bash
- **Codex:** npm install -g @openai/codex
- **OpenCode:** npm install -g opencode-ai
- **Pi:** npm install -g @earendil-works/pi-coding-agent
## Launch and stop behavior
The launcher obtains the agent's socket only from the validated generated projection. It creates or
checks the exact =<agent-name> tmux target; it never uses an ambient socket or fuzzy session match.
The same strict parser runs before exact-stop behavior. A fresh native Pi heartbeat remains authoritative;
the shell sidecar only provides fallback state when the native marker is stale or absent.
mosaic agent comms-block <exact-member> can inspect that exact roster member's resolved Fleet-Comms
block. It is a read-only inspection tool and fails loudly for an unknown exact member or missing roster.
On Linux, the installed roster, TOOLS contract, and executable helper are opened through a held
descriptor chain rooted at `/`; every managed path component uses no-follow traversal, and content plus
execute validation stay bound to the same opened file. Systems without Linux `/proc/self/fd` support
fail closed rather than falling back to pathname revalidation.
## Current M2 boundary
FCM-M2-001 supplies generated/local parsing, validation, projection, quarantine, and launch-boundary
evidence only. It does not authorize roster CRUD expansion, reconciliation, lifecycle changes, remote
or connector mutation, site canaries, or migration. M3 must establish the local reconcile/lifecycle
path; M4 separately provides migration preview, canary, and rollback gates.