`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.
@mosaicstack/mosaic
CLI package for the Mosaic self-hosted AI agent platform.
Usage
mosaic wizard # First-run setup wizard
mosaic gateway install # Install the gateway daemon
mosaic config show # View current configuration
mosaic config hooks list # Manage Claude hooks
Headless / CI Installation
Set MOSAIC_ASSUME_YES=1 (or ensure stdin is not a TTY) to skip all interactive prompts. The following environment variables control the install:
Gateway configuration (mosaic gateway install)
| Variable | Default | Required |
|---|---|---|
MOSAIC_STORAGE_TIER |
local |
No |
MOSAIC_GATEWAY_PORT |
14242 |
No |
MOSAIC_DATABASE_URL |
(none) | Yes if tier=team |
MOSAIC_VALKEY_URL |
(none) | Yes if tier=team |
MOSAIC_ANTHROPIC_API_KEY |
(none) | No |
MOSAIC_CORS_ORIGIN |
http://localhost:3000 |
No |
Admin user bootstrap
| Variable | Default | Required |
|---|---|---|
MOSAIC_ADMIN_NAME |
(none) | Yes (headless) |
MOSAIC_ADMIN_EMAIL |
(none) | Yes (headless) |
MOSAIC_ADMIN_PASSWORD |
(none) | Yes (headless) |
MOSAIC_ADMIN_PASSWORD must be at least 8 characters. In headless mode a missing or too-short password causes a non-zero exit.
Example: Docker / CI install
export MOSAIC_ASSUME_YES=1
export MOSAIC_ADMIN_NAME="Admin"
export MOSAIC_ADMIN_EMAIL="[email protected]"
export MOSAIC_ADMIN_PASSWORD="securepass123"
mosaic gateway install
Runtime launchers
mosaic claude # Launch Claude Code with Mosaic injection
mosaic yolo claude # …with --dangerously-skip-permissions
mosaic codex | opencode | pi
mosaic claudex (EXPERIMENTAL)
Runs GPT models inside the Claude Code harness by pointing Claude Code at a
local claude-code-proxy that
translates the Anthropic Messages API to a ChatGPT-subscription (Codex OAuth)
backend. This is not Anthropic Claude — model behavior, tool use, and output
quality may differ. Intended for evaluation, not production delivery.
mosaic claudex # launch (prompts through the proxy readiness gate)
mosaic yolo claudex # …with --dangerously-skip-permissions
mosaic claudex --print "hello" # trailing args are forwarded to Claude Code
Prerequisite: the claude-code-proxy binary must be installed and
authenticated (claude-code-proxy codex auth …). mosaic claudex runs a
preflight that verifies the binary, the OAuth state (triggering a device re-auth
if needed), and a trusted local listener before launching; it fails closed
if the proxy cannot be brought up with a verified identity.
Isolation (never touches your real Claude state). claudex always launches
against an isolated CLAUDE_CONFIG_DIR (default ~/.config/mosaic/claudex/home).
The ambient CLAUDE_CONFIG_DIR is deliberately ignored, and a guard proves the
resolved dir can never be — or live under — the real ~/.claude. A claudex
session therefore cannot mutate your normal Claude Code config.
No token leakage. claudex never reads the proxy's credential file. Claude
Code is handed only ANTHROPIC_AUTH_TOKEN=unused pointed at the loopback proxy;
the entire credential-bearing env family (ANTHROPIC_*, AWS_*, GOOGLE_CLOUD_*,
GOOGLE_APPLICATION_CREDENTIALS, *_TOKEN, *_KEY, *_SECRET, …) is stripped
from the composed environment. The Bedrock/Vertex routing switches
(CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX, and the _SKIP_*_AUTH
pair) are force-removed regardless of value — otherwise their mere presence
would route Claude Code to the real Anthropic API via AWS/GCP and bypass the
proxy. The proxy holds the real OAuth credential.
Model tiers (override via env).
| Tier | Env var | Default |
|---|---|---|
| primary (opus/sonnet) | ANTHROPIC_MODEL |
gpt-5.6-sol |
| small/fast (haiku) | ANTHROPIC_SMALL_FAST_MODEL |
gpt-5.6-luna |
Operator-provided values win over the defaults. Additional overrides:
MOSAIC_CLAUDEX_CONFIG_DIR (isolated config dir), ANTHROPIC_BASE_URL (proxy
endpoint).
Hooks management
After running mosaic wizard, Claude hooks are installed in ~/.claude/hooks-config.json.
mosaic config hooks list # Show all hooks and enabled/disabled status
mosaic config hooks disable PostToolUse # Disable a hook (reversible)
mosaic config hooks enable PostToolUse # Re-enable a disabled hook
Set CLAUDE_HOME to override the default ~/.claude directory.