test(fleet): close documentation code grammar

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jarvis
2026-07-17 18:39:05 -05:00
parent 862dbd5204
commit bfa08e9651
36 changed files with 966 additions and 1022 deletions

View File

@@ -4,17 +4,17 @@ FCM-M2-002 provides local roster-v2 create, get, update, delete, and plan operat
## CLI contract
The commands operate only on the canonical `<mosaic-home>/fleet/roster.yaml` v2 authority and print one JSON object to stdout. `--agent` is a JSON object with the roster agent fields expressed as `className`, `toolPolicy`, `workingDirectory`, `persistentPersona`, `resetBetweenTasks`, and `launch: { "yolo": boolean }`.
The commands operate only on the canonical <mosaic-home>/fleet/roster.yaml v2 authority and print one JSON object to stdout. `--agent` is a JSON object with the roster agent fields expressed as `className`, `toolPolicy`, `workingDirectory`, `persistentPersona`, `resetBetweenTasks`, and launch: { "yolo": boolean }.
```sh
```fleet-synopsis
mosaic fleet get <name>
mosaic fleet plan <create|update|delete> [name] --expected-generation <n> [--agent '<json>'] [--persisted-start]
mosaic fleet plan <create|update|delete> [<name>] --expected-generation <n> [--agent '<json>'] [--persisted-start]
mosaic fleet create --expected-generation <n> --agent '<json>' [--dry-run] [--persisted-start]
mosaic fleet update <name> --expected-generation <n> --agent '<json>' [--dry-run]
mosaic fleet delete <name> --expected-generation <n> [--dry-run]
```
`get` returns the authoritative generation and the selected agent. `plan create` derives its name from `--agent`; `plan update <name>` and `plan delete <name>` require the target name. `--agent` accepts only the documented roster-v2 request fields and `launch.yolo`; unknown keys such as commands, channels, or secret references are rejected. Rejection diagnostics return only the stable `invalid-request` code and never echo a rejected value. `plan` and `--dry-run` validate the complete proposed roster and projections but write neither the roster nor projections. `--persisted-start` is available only for a create request: it records `desired_state: running`, but does not start a process. Without it, create records `enabled: true` and `desired_state: stopped`. Handled failures return JSON with `error.code` and exit non-zero; unclassified validation/projection failures use the redacted `mutation-failed` code.
`get` returns the authoritative generation and the selected agent. plan create derives its name from `--agent`; plan update <name> and plan delete <name> require the target name. `--agent` accepts only the documented roster-v2 request fields and `launch.yolo`; unknown keys such as commands, channels, or secret references are rejected. Rejection diagnostics return only the stable `invalid-request` code and never echo a rejected value. `plan` and `--dry-run` validate the complete proposed roster and projections but write neither the roster nor projections. `--persisted-start` is available only for a create request: it records desired_state: running, but does not start a process. Without it, create records enabled: true and desired_state: stopped. Handled failures return JSON with `error.code` and exit non-zero; unclassified validation/projection failures use the redacted `mutation-failed` code.
## Generation, validation, and idempotency
@@ -22,7 +22,7 @@ Each create, update, or delete request includes `expectedGeneration`. A request
`planFleetAgentMutation` is deterministic and side-effect free. `executeFleetAgentMutation` validates the complete proposed roster through the existing structural and shared persona resolver, prepares generated/local/quarantine projections, and writes the roster authority atomically before applying derived projections. Equivalent create retries and delete requests for an already-absent agent are idempotent no-ops.
Delete removes only the exact `<name>.env.generated` projection for the removed roster entry. Operator-owned `<name>.env.local`, legacy `<name>.env`, quarantine records, and unrelated projections remain untouched. An already-absent generated projection is treated as stale derived state, not as a failed mutation.
Delete removes only the exact <name>.env.generated projection for the removed roster entry. Operator-owned <name>.env.local, legacy <name>.env, quarantine records, and unrelated projections remain untouched. An already-absent generated projection is treated as stale derived state, not as a failed mutation.
## Result and recovery
@@ -40,4 +40,4 @@ Mutation results are JSON-safe objects with `applied`, `authoritativeRoster`, `p
}
```
Dry-runs and idempotent no-ops report `authoritativeRoster: "unchanged"` and `projections: "not-applied"`; a complete mutation reports `"committed"` and `"complete"`. Recovery output identifies the authoritative roster path and regeneration action only. It never contains generated/local/quarantine values, credentials, or command text. A recovery result exits non-zero because the authoritative roster was persisted but derived projections require regeneration. Regenerate projections from the roster before attempting another mutation.
Dry-runs and idempotent no-ops report authoritativeRoster: "unchanged" and projections: "not-applied"; a complete mutation reports "committed" and "complete". Recovery output identifies the authoritative roster path and regeneration action only. It never contains generated/local/quarantine values, credentials, or command text. A recovery result exits non-zero because the authoritative roster was persisted but derived projections require regeneration. Regenerate projections from the roster before attempting another mutation.

View File

@@ -1,46 +1,46 @@
# 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.
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 |
| 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]
```fleet-synopsis
mosaic fleet apply --expected-generation <n>
mosaic fleet reconcile --expected-generation <n>
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.
`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.
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.
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.
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.

View File

@@ -8,14 +8,14 @@ a second roster or a command configuration surface.
## Paths and ownership
For agent `<name>` under `<MOSAIC_HOME>/fleet/agents/`:
For agent <name> under <MOSAIC_HOME>/fleet/agents/:
| Path | Owner | Purpose |
| ----------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `<name>.env.generated` | Mosaic projection writer | Complete deterministic launch data rendered from the authoritative roster. |
| `<name>.env.local` | Operator | Optional, constrained local machine data. It cannot shadow generated keys. |
| `<name>.env` | Legacy input only | Read once during projection generation, then regenerated/relocated or privately quarantined. It is never a launch authority. |
| `<name>.env.quarantine` | Mosaic quarantine | Mode-`0600` private record of forbidden legacy input; it is never read by the launcher. |
| Path | Owner | Purpose |
| --------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| <name>.env.generated | Mosaic projection writer | Complete deterministic launch data rendered from the authoritative roster. |
| <name>.env.local | Operator | Optional, constrained local machine data. It cannot shadow generated keys. |
| <name>.env | Legacy input only | Read once during projection generation, then regenerated/relocated or privately quarantined. It is never a launch authority. |
| <name>.env.quarantine | Mosaic quarantine | Mode-`0600` private record of forbidden legacy input; it is never read by the launcher. |
The systemd templates do not load either environment file. They invoke Bash with a fixed, cleared
bootstrap environment; the launcher reads and validates `.env.generated` and `.env.local` itself before
@@ -44,7 +44,7 @@ MOSAIC_AGENT_WORKDIR=<absolute roster work directory>
MOSAIC_TMUX_SOCKET=<roster socket or empty>
```
The generated launch contract supports only `claude`, `codex`, `opencode`, and `pi`. `fleet add`
The generated launch contract supports only `claude`, `codex`, `opencode`, and `pi`. fleet add
uses that same runtime authority and rejects any other runtime before it writes the roster or changes
projection, local, or quarantine files. The legacy dogfood stub on its separate `mosaic-factory`
socket remains an observability canary; it has no generated-launch adapter and cannot be added through
@@ -62,7 +62,7 @@ Local paths must be safe absolute paths and the interval must be a positive inte
quoted/export syntax, duplicate keys, unknown keys, generated-key shadowing, sensitive key names,
and `MOSAIC_AGENT_COMMAND` are rejected. The launcher derives the only executable command from the
validated runtime, model, and reasoning data; no arbitrary command compatibility path exists. When a
Pi runtime writes a fresh `<name>.hb.native` marker, its native heartbeat remains authoritative; the
Pi runtime writes a fresh <name>.hb.native marker, its native heartbeat remains authoritative; the
shell sidecar resumes its `status=ok` fallback only after that marker is stale or absent.
## Legacy disposition
@@ -78,14 +78,14 @@ This card does not add a USC site file, write a USC roster, or run a site canary
consolidated downstream interface packet. Status is deliberately separated from checkout presence: no
product release version has been evidenced for this interface set.
| Interface | Canonical public path and version | Tracker/release status | Downstream limit |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| M1 structural compiler | `parseRosterV2` in `packages/mosaic/src/fleet/roster-v2.ts`; schema `docs/fleet/reference/roster-v2.schema.json`; roster `version: 2` | FCM-M1-001 is recorded done, merged as #764 (`aa5b43b`); no released product version is asserted here. | Parse YAML/JSON and canonicalize a supplied v2 site roster without writes. |
| M1 semantic resolver | `validateRosterV2Semantics` in `packages/mosaic/src/fleet/roster-v2.ts`; baseline `framework/fleet/roles/` plus `roles.local/` | FCM-M1-002 merged as #768 (`a5e8e55`); no released product version is asserted here. | Reuse the shared resolver only; no parallel role resolver or lifecycle action. |
| M1 disposition evidence | `packages/mosaic/src/fleet/example-profile-dispositions.ts`; `docs/fleet/migration/example-profile-disposition.md`; retained fixture `version: 1` | FCM-M1-003 merged as #770 (`e9c4aa3`); checkout evidence remains validation, not migration authorization. | Inspect fixture/profile/service disposition evidence only; it is not migration authorization. |
| M2 generated boundary | `packages/mosaic/src/fleet/generated-env-boundary.ts`; generated projection contract in this document | FCM-M2-001 merged as #772 (`191efae`); no released product version is asserted here. | Render/write a roster-derived projection; local input is never authority. |
| Interface | Canonical public path and version | Tracker/release status | Downstream limit |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| M1 structural compiler | `parseRosterV2` in `packages/mosaic/src/fleet/roster-v2.ts`; schema `docs/fleet/reference/roster-v2.schema.json`; roster version: 2 | FCM-M1-001 is recorded done, merged as #764 (`aa5b43b`); no released product version is asserted here. | Parse YAML/JSON and canonicalize a supplied v2 site roster without writes. |
| M1 semantic resolver | `validateRosterV2Semantics` in `packages/mosaic/src/fleet/roster-v2.ts`; baseline `framework/fleet/roles/` plus `roles.local/` | FCM-M1-002 merged as #768 (`a5e8e55`); no released product version is asserted here. | Reuse the shared resolver only; no parallel role resolver or lifecycle action. |
| M1 disposition evidence | `packages/mosaic/src/fleet/example-profile-dispositions.ts`; `docs/fleet/migration/example-profile-disposition.md`; retained fixture version: 1 | FCM-M1-003 merged as #770 (`e9c4aa3`); checkout evidence remains validation, not migration authorization. | Inspect fixture/profile/service disposition evidence only; it is not migration authorization. |
| M2 generated boundary | `packages/mosaic/src/fleet/generated-env-boundary.ts`; generated projection contract in this document | FCM-M2-001 merged as #772 (`191efae`); no released product version is asserted here. | Render/write a roster-derived projection; local input is never authority. |
The canonical source remains `<MOSAIC_HOME>/fleet/roster.yaml` for the current local fleet path.
The canonical source remains <MOSAIC_HOME>/fleet/roster.yaml for the current local fleet path.
Generated environment data is a rebuildable projection, not an operator-editable source of membership,
runtime policy, or lifecycle state.

View File

@@ -2,19 +2,19 @@
Roster-v2 `lifecycle.enabled` and `lifecycle.desired_state` are the only persisted lifecycle authority. Systemd, tmux, generated environment, and heartbeat state are derived or observed.
| Event | Desired-state write | Runtime effect | Safety boundary |
| --------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fleet create` | Adds enabled/stopped by default; `--persisted-start` records running | None | Generation-guarded; validates full roster/projections. |
| `fleet update` | Preserves the existing enabled/desired state; updates other mutable fields | None | Generation-guarded; stable name and lifecycle are immutable on this path. |
| `fleet delete` | Removes exact roster member | None | Removes only generated projection; retains local/quarantine evidence. |
| `fleet apply` / `reconcile` | Never | Rebuilds projections; starts only enabled/running; stops disabled or stopped roster members | Current generation, private lock/paths, semantic validity, holder ownership, no unmanaged named-socket sessions. |
| `fleet start <name>` | Never | One-shot exact service start | Exact enabled roster name and proven ownership. |
| `fleet stop <name>` | Never | One-shot exact service stop | Exact roster name and proven ownership. |
| `fleet restart <name>` | Never | One-shot exact service restart | Exact enabled roster name and proven ownership. |
| Reboot/service activation | Never | Current installation may activate enabled units without honoring roster lifecycle | **Held for FCM-M3-002:** boot preservation for stopped/disabled agents is not yet proven; inspect/disable units rather than assuming lifecycle-safe reboot. |
| v1 migration preview | Never | None | Observed active+present maps running; inactive+missing maps stopped; ambiguity blocks. |
| Cutover/canary | Held for FCM-M4-002 | Not implemented by preview | Must preserve every observed stopped state. |
| Rollback | Held for FCM-M4-002 | Not implemented | Must restore selected authority/projections without surprise starts or unmanaged targeting. |
| Event | Desired-state write | Runtime effect | Safety boundary |
| ------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| fleet create | Adds enabled/stopped by default; `--persisted-start` records running | None | Generation-guarded; validates full roster/projections. |
| fleet update | Preserves the existing enabled/desired state; updates other mutable fields | None | Generation-guarded; stable name and lifecycle are immutable on this path. |
| fleet delete | Removes exact roster member | None | Removes only generated projection; retains local/quarantine evidence. |
| fleet apply / `reconcile` | Never | Rebuilds projections; starts only enabled/running; stops disabled or stopped roster members | Current generation, private lock/paths, semantic validity, holder ownership, no unmanaged named-socket sessions. |
| fleet start <name> | Never | One-shot exact service start | Exact enabled roster name and proven ownership. |
| fleet stop <name> | Never | One-shot exact service stop | Exact roster name and proven ownership. |
| fleet restart <name> | Never | One-shot exact service restart | Exact enabled roster name and proven ownership. |
| Reboot/service activation | Never | Current installation may activate enabled units without honoring roster lifecycle | **Held for FCM-M3-002:** boot preservation for stopped/disabled agents is not yet proven; inspect/disable units rather than assuming lifecycle-safe reboot. |
| v1 migration preview | Never | None | Observed active+present maps running; inactive+missing maps stopped; ambiguity blocks. |
| Cutover/canary | Held for FCM-M4-002 | Not implemented by preview | Must preserve every observed stopped state. |
| Rollback | Held for FCM-M4-002 | Not implemented | Must restore selected authority/projections without surprise starts or unmanaged targeting. |
Explicit apply/reconcile never starts a stopped roster agent. Direct lifecycle commands are explicit one-shot actions and do not persist intent. The current update operation preserves `existing.lifecycle`; there is no delivered generation-guarded CRUD operation for changing durable lifecycle after creation. Reboot preservation for stopped/disabled agents is not yet guaranteed because current enabled units and launcher projections do not carry the persisted lifecycle fence; that acceptance evidence remains FCM-M3-002.

View File

@@ -16,7 +16,7 @@ Only these legacy class aliases are recognized:
No other alias is inferred. In particular, `worker`, `analyst`, and `canary` are custom classes only
when an operator supplies a readable contract for that exact class. Tess and Ultron are instance
names, not classes. `agents[].alias` is display-only and cannot grant authority.
names, not classes. agents[].alias is display-only and cannot grant authority.
Canonicalization happens before role lookup. For example, requesting `implementer` resolves
`code.md`; a separate `roles.local/implementer.md` cannot redefine the legacy alias. A canonical

View File

@@ -62,26 +62,26 @@ agents:
## Nested fields
All nested fields in the v2 schema are required and have no implicit default. CRUD `create` is the only higher-level convenience: it records `lifecycle.enabled: true` and `desired_state: stopped` unless `--persisted-start` explicitly records running. That convenience still performs no runtime action.
All nested fields in the v2 schema are required and have no implicit default. CRUD `create` is the only higher-level convenience: it records lifecycle.enabled: true and desired_state: stopped unless `--persisted-start` explicitly records running. That convenience still performs no runtime action.
| Path | Required | Constraint |
| ---------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
| `tmux.socket_name` | yes | `[A-Za-z0-9_.-]*`; empty string means the literal default tmux server, while a non-empty value names a socket |
| `tmux.holder_session` | yes | non-empty `[A-Za-z0-9_.-]+` |
| `defaults.working_directory` | yes | non-empty string |
| `defaults.runtime` | yes | `claude`, `codex`, `opencode`, or `pi`; it must be declared in `runtimes` |
| `runtimes.<runtime>.reset_command` | yes | non-empty string; runtime key must be a supported local runtime |
| `agents[].name` | yes | unique `[A-Za-z0-9][A-Za-z0-9_.-]*` stable machine identity |
| `agents[].alias` | yes | non-empty display string |
| `agents[].class` | yes | `[a-z][a-z0-9-]*`; structural only in M1, semantic role resolution is FCM-M1-002 |
| `agents[].runtime` | yes | `claude`, `codex`, `opencode`, or `pi`; it must be declared in `runtimes` |
| `agents[].provider`, `model`, `working_directory` | yes | non-empty strings; provider/model capability resolution is a later card |
| `agents[].reasoning` | yes | `low`, `medium`, or `high` |
| `agents[].tool_policy` | yes | `[a-z][a-z0-9-]*`; structural only in M1 |
| `agents[].persistent_persona`, `reset_between_tasks` | yes | booleans |
| `agents[].lifecycle.enabled` | yes | boolean; stored now, reconciled in FCM-M3-001 |
| `agents[].lifecycle.desired_state` | yes | `running` or `stopped` |
| `agents[].launch.yolo` | yes | boolean; structured data only, not an arbitrary command escape hatch |
| Path | Required | Constraint |
| -------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| `tmux.socket_name` | yes | [A-Za-z0-9_.-]\*; empty string means the literal default tmux server, while a non-empty value names a socket |
| `tmux.holder_session` | yes | non-empty [A-Za-z0-9_.-]+ |
| `defaults.working_directory` | yes | non-empty string |
| `defaults.runtime` | yes | `claude`, `codex`, `opencode`, or `pi`; it must be declared in `runtimes` |
| runtimes.<runtime>.reset_command | yes | non-empty string; runtime key must be a supported local runtime |
| agents[].name | yes | unique [A-Za-z0-9][A-Za-z0-9_.-]\* stable machine identity |
| agents[].alias | yes | non-empty display string |
| agents[].class | yes | [a-z][a-z0-9-]\*; structural only in M1, semantic role resolution is FCM-M1-002 |
| agents[].runtime | yes | `claude`, `codex`, `opencode`, or `pi`; it must be declared in `runtimes` |
| agents[].provider, `model`, `working_directory` | yes | non-empty strings; provider/model capability resolution is a later card |
| agents[].reasoning | yes | `low`, `medium`, or `high` |
| agents[].tool_policy | yes | [a-z][a-z0-9-]\*; structural only in M1 |
| agents[].persistent_persona, `reset_between_tasks` | yes | booleans |
| agents[].lifecycle.enabled | yes | boolean; stored now, reconciled in FCM-M3-001 |
| agents[].lifecycle.desired_state | yes | `running` or `stopped` |
| agents[].launch.yolo | yes | boolean; structured data only, not an arbitrary command escape hatch |
## Semantic handoff
@@ -99,12 +99,12 @@ Semantic validation:
`operator-interaction` to `interaction`;
- canonicalizes `tool_policy` with the same exact alias table;
- rejects protected class/tool-policy mismatches in either direction, while accepting
`class: operator-interaction` with `tool_policy: operator-interaction` as canonical
class: operator-interaction with tool_policy: operator-interaction as canonical
`interaction`;
- derives immutable protected authority only from canonical class; and
- accepts custom baseline or `roles.local` classes without granting protected authority.
`agents[].alias` remains display-only. Tess and Ultron are instance names, never semantic classes.
agents[].alias remains display-only. Tess and Ultron are instance names, never semantic classes.
Canonicalization happens before role-layer lookup, so a legacy-named override cannot redefine an
alias as separate authority. See [Role Classes and Authority](./role-classes.md) and
[Customize Fleet Roles](../how-to/customize-roles.md).
@@ -114,7 +114,7 @@ lifecycle mutation.
## Fail-closed boundary
Every object is `additionalProperties: false`. The compiler rejects unknown, missing, malformed,
Every object is additionalProperties: false. The compiler rejects unknown, missing, malformed,
and wrong-type fields before producing a model. It specifically rejects remote/SSH/host/socket
per-agent fields, connector blocks, secret references, channel fields, arbitrary command fields,
and gateway fields because they are unsupported in the local-tmux M1 contract. It does not silently

View File

@@ -1,6 +1,6 @@
# Local Fleet Status and Drift
`mosaic fleet status [name]`, `verify`, and `doctor` are observational roster-v2 commands. They emit one JSON result and do not write projections, mutate desired state, operate lifecycle, or change tmux.
mosaic fleet status [<name>], `verify`, and `doctor` are observational roster-v2 commands. They emit one JSON result and do not write projections, mutate desired state, operate lifecycle, or change tmux.
## State dimensions