feat(fleet): add generation-guarded agent CRUD (#773)
This commit was merged in pull request #773.
This commit is contained in:
74
docs/fleet/how-to/create-update-delete-agent.md
Normal file
74
docs/fleet/how-to/create-update-delete-agent.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Create, Inspect, Update, and Delete a Local Fleet Agent
|
||||
|
||||
Use the local roster-v2 control plane only. These commands change desired state and derived environment projections; they never start, stop, reconcile, inspect, or otherwise act on systemd, tmux, sessions, or runtimes.
|
||||
|
||||
## Read and plan first
|
||||
|
||||
```sh
|
||||
mosaic fleet get <name>
|
||||
mosaic fleet plan create --expected-generation <n> --agent '<json>'
|
||||
mosaic fleet plan update <name> --expected-generation <n> --agent '<json>'
|
||||
mosaic fleet plan delete <name> --expected-generation <n>
|
||||
```
|
||||
|
||||
`plan create` takes the name from `--agent`. `plan update` and `plan delete` require the target name immediately after the operation. A plan is deterministic and side-effect free: it validates the complete proposed roster and projection targets without changing files. Use `--dry-run` on `create`, `update`, or `delete` for the same no-write result.
|
||||
|
||||
Every successful command prints JSON. `get` returns `{ "generation", "agent" }`; mutation results contain `plan`, `applied`, `authoritativeRoster`, and `projections`.
|
||||
|
||||
## Create safely
|
||||
|
||||
```sh
|
||||
mosaic fleet create --expected-generation 7 --agent '{
|
||||
"name":"coder0",
|
||||
"alias":"Coder 0",
|
||||
"className":"code",
|
||||
"runtime":"pi",
|
||||
"provider":"openai",
|
||||
"model":"gpt-5.6-sol",
|
||||
"reasoning":"high",
|
||||
"toolPolicy":"code",
|
||||
"workingDirectory":"/srv/mosaic",
|
||||
"persistentPersona":false,
|
||||
"resetBetweenTasks":true,
|
||||
"launch":{"yolo":true}
|
||||
}'
|
||||
```
|
||||
|
||||
Create defaults to `enabled: true` and `desired_state: stopped`. It does not start a process. Add `--persisted-start` only to persist `desired_state: running`; that still does not start a runtime in this M2 command. The JSON payload is an allowlist of the roster-v2 fields shown above plus `launch.yolo`; command, channel, secret-reference, and other unknown keys are rejected rather than ignored. The JSON error exposes only a stable code, never the rejected value.
|
||||
|
||||
## Update and delete safely
|
||||
|
||||
```sh
|
||||
mosaic fleet update coder0 --expected-generation 8 --agent '<complete JSON agent payload>'
|
||||
mosaic fleet delete coder0 --expected-generation 9
|
||||
```
|
||||
|
||||
Updates require a complete agent JSON payload and preserve the stable name. Delete removes only the exact roster-owned `coder0.env.generated` projection. It retains `coder0.env.local`, legacy `coder0.env`, `coder0.env.quarantine`, and every unrelated projection. A delete dry-run leaves all of those files byte-identical.
|
||||
|
||||
## Handle generation conflicts
|
||||
|
||||
Every mutation requires the current authoritative `--expected-generation`. A stale value returns JSON `error.code: "stale-generation"` with a non-zero exit. Reload with `mosaic fleet get <name>` or reread the roster, plan again using the returned generation, then retry. A concurrent mutation returns `concurrent-mutation`; do not force or bypass the lock.
|
||||
|
||||
## Interpret partial failures
|
||||
|
||||
The roster is authoritative and is written before derived projections. A late projection I/O failure returns non-zero with redacted, actionable JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"applied": false,
|
||||
"authoritativeRoster": "committed",
|
||||
"projections": "incomplete",
|
||||
"recovery": {
|
||||
"code": "projection-apply-failed",
|
||||
"action": "regenerate-projections-from-roster"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is not a rollback and not a no-op: reload the roster because its generation and membership were committed, regenerate projections from that roster, then plan a new mutation. Recovery output never contains environment values, credentials, or command text.
|
||||
|
||||
## Exit and boundary behavior
|
||||
|
||||
Handled validation errors and partial projection failures exit non-zero. `plan`/`--dry-run` and normal mutation JSON make the state explicit; scripts should use both the exit code and `authoritativeRoster`/`projections`, not `applied` alone.
|
||||
|
||||
The commands operate only on `<mosaic-home>/fleet/roster.yaml`, the local roster desired-state authority. They do not accept arbitrary commands, channels, secrets, remote/connector actions, migration/canary actions, or runtime lifecycle operations.
|
||||
Reference in New Issue
Block a user