96 lines
7.0 KiB
Markdown
96 lines
7.0 KiB
Markdown
# Fleet Roster v2 Structural Contract
|
||
|
||
**Status:** FCM-M1-001 local-tmux structural compiler contract. This document describes parsing,
|
||
strict structural validation, normalized in-memory representation, and deterministic rendering only.
|
||
It does not authorize role resolution, lifecycle reconciliation, mutation, migration, remote
|
||
placement, connector configuration, secret references, arbitrary commands, channels, gateway
|
||
mapping, or any live-fleet change.
|
||
|
||
The executable schema is [`roster-v2.schema.json`](./roster-v2.schema.json). The compiler exports
|
||
the same schema and its test parses this file and compares it structurally with the executable contract.
|
||
|
||
## Format and canonical shape
|
||
|
||
The compiler accepts YAML or JSON. It reads only snake_case source fields and renders canonical,
|
||
snake_case YAML. Rendering sorts runtime keys and agents by stable name. Agent names, class names,
|
||
and tool-policy names are structural identifiers; whether a class or policy resolves is a later
|
||
shared-resolver concern.
|
||
|
||
```yaml
|
||
version: 2
|
||
generation: 1
|
||
transport: tmux
|
||
tmux:
|
||
socket_name: mosaic-fleet
|
||
holder_session: _holder
|
||
defaults:
|
||
working_directory: ~/src
|
||
runtime: pi
|
||
runtimes:
|
||
pi:
|
||
reset_command: /new
|
||
agents:
|
||
- name: coder0
|
||
alias: Coder 0
|
||
class: code
|
||
runtime: pi
|
||
provider: openai
|
||
model: gpt-5.6-sol
|
||
reasoning: high
|
||
tool_policy: code
|
||
working_directory: ~/src
|
||
persistent_persona: false
|
||
reset_between_tasks: true
|
||
lifecycle:
|
||
enabled: true
|
||
desired_state: stopped
|
||
launch:
|
||
yolo: true
|
||
```
|
||
|
||
## Root fields
|
||
|
||
| Field | Required | Constraint | Meaning |
|
||
| ------------ | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| `version` | yes | integer constant `2` | Identifies this contract. Version `1` is explicitly rejected by this compiler and remains on the existing v1 path until M4 migration. |
|
||
| `generation` | yes | positive safe integer | Desired-state generation. M2 uses it for mutation guards; M1 does not mutate it. |
|
||
| `transport` | yes | constant `tmux` | M1–M5 support local tmux only. |
|
||
| `tmux` | yes | strict object | Explicit local socket and holder-session configuration. |
|
||
| `defaults` | yes | strict object | Default work directory and one supported local runtime. |
|
||
| `runtimes` | yes | non-empty object | Declared local runtime reset policy map. |
|
||
| `agents` | yes | non-empty array | Local fleet entries. Duplicate stable names are rejected. |
|
||
|
||
## Nested fields
|
||
|
||
| Path | Required | Constraint |
|
||
| ---------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
|
||
| `tmux.socket_name` | yes | non-empty `[A-Za-z0-9_.-]+`; an explicit named socket prevents default-versus-named socket ambiguity |
|
||
| `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 |
|
||
|
||
## Fail-closed boundary
|
||
|
||
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
|
||
ignore v1 camelCase input, version `1`, or a source that does not parse to an object.
|
||
|
||
The v2 compiler is intentionally isolated from the existing v1 loader. Existing v1 rosters and
|
||
current examples/profiles continue on their current path; FCM-M4 owns explicit inventory, preview,
|
||
migration, and rollback. FCM-M2 owns generated-file/local-override quarantine, and FCM-M3 owns
|
||
runtime lifecycle and reconciliation.
|