# Fleet Control-Plane CLI

The local desired-state surface is `mosaic fleet`. It is distinct from the gateway-backed `mosaic agent` catalog and from legacy compatibility commands that act on roster v1.

## Roster-v2 desired-state commands

| Command                                                    | Effect                                         | Generation | Output                     |
| ---------------------------------------------------------- | ---------------------------------------------- | ---------- | -------------------------- |
| `mosaic fleet get <name>`                                  | Read one authoritative agent                   | no         | One JSON object            |
| `mosaic fleet plan <create\|update\|delete> ...`           | Validate proposed CRUD and projections         | required   | One JSON object; no writes |
| `mosaic fleet create ... [--dry-run] [--persisted-start]`  | Add desired state; default enabled/stopped     | required   | One JSON object            |
| `mosaic fleet update <name> ... [--dry-run]`               | Replace mutable agent fields                   | required   | One JSON object            |
| `mosaic fleet delete <name> ... [--dry-run]`               | Remove roster member/generated projection      | required   | One JSON object            |
| `mosaic fleet apply ... [--dry-run]`                       | Plan or converge projections/lifecycle         | required   | One JSON object            |
| `mosaic fleet reconcile ... [--dry-run]`                   | Alias of the same convergence contract         | required   | One JSON object            |
| `mosaic fleet start\|stop\|restart [name] ... [--dry-run]` | Exact one-shot lifecycle action                | required   | One JSON object            |
| `mosaic fleet status [name]`                               | Observe desired/managed/runtime state          | no         | One JSON object            |
| `mosaic fleet verify`                                      | Strict observational drift/ownership gate      | no         | One JSON object            |
| `mosaic fleet doctor`                                      | Classify local drift and recovery context      | no         | One JSON object            |
| `mosaic fleet migrate-v1 preview ...`                      | Non-mutating field-complete migration evidence | no         | One JSON object            |

CRUD syntax and full payload shape are documented in [agent mutations](agent-mutations.md). Reconciliation syntax:

```text
mosaic fleet apply --expected-generation <n> [--dry-run]
mosaic fleet reconcile --expected-generation <n> [--dry-run]
mosaic fleet start [name] --expected-generation <n> [--dry-run]
mosaic fleet stop [name] --expected-generation <n> [--dry-run]
mosaic fleet restart [name] --expected-generation <n> [--dry-run]
mosaic fleet status [name]
mosaic fleet verify
mosaic fleet doctor
mosaic fleet migrate-v1 preview --source <path> --decisions <path> --observations <path>
```

`get` is the read/show operation for one v2 agent. Full roster parsing and semantic validation occur on every v2 mutation/reconcile path; there is no separate mutable “config store.” The executable JSON Schema and validated example provide offline structural evidence. The PRD requires an explicit programmatic `mosaic fleet validate` operation, but the current CLI does not expose one; do not substitute another command or claim that requirement is delivered. This remains an implementation gap for #758.

## JSON and exit behavior

Roster-v2 CRUD and reconciler precondition failures emit `{ "error": { "code": "..." } }` and exit non-zero. Migration preview has its own result envelope: a non-ready preview emits `{ "status": "blocked", "blockers": [...] }` and exits non-zero rather than using the CRUD/reconciler error object. Use both exit status and command-specific state fields. A partial reconciliation result distinguishes `authoritativeRoster`, `projections`, `lifecycle`, `recovery`, and optional `cleanup`; it never claims automatic rollback. `verify` exits non-zero for drift, ownership failure, or unmanaged sessions. Sensitive legacy values, credentials, and rejected command text are never printed.

## Compatibility and scope

Roster-v1 initialization, provisioning, profiles/personas, and historical `fleet add/remove` remain compatibility surfaces, not roster-v2 CRUD aliases. New v2 automation should use the table above. `migrate-v1 preview` writes nothing and has no cutover, canary, or rollback option.

`mosaic agent` is a separate catalog/transport surface; it does not own `<MOSAIC_HOME>/fleet/roster.yaml` desired state. Remote/SSH reconciliation, connector mutation, arbitrary commands/channels, secret references, and gateway convergence are rejected or outside scope.
