@crvouga/dev-fleet 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -7
- package/agents/audit.md +18 -18
- package/ansible/agents/agents.yml +134 -0
- package/ansible/agents/templates/antigravity.settings.json.j2 +3 -0
- package/ansible/agents/templates/claude.settings.json.j2 +3 -0
- package/ansible/agents/templates/codex.config.toml.j2 +11 -0
- package/ansible/agents/templates/gemini.settings.json.j2 +14 -0
- package/ansible/agents/templates/grok.config.toml.j2 +19 -0
- package/ansible/agents/templates/opencode.json.j2 +24 -0
- package/ansible/agents/templates/receipt.json.j2 +10 -0
- package/ansible/ansible.cfg +14 -0
- package/ansible/github/git.yml +82 -0
- package/ansible/macos/manager-privilege.yml +83 -0
- package/ansible/macos/manager.yml +164 -9
- package/ansible/macos/policy.json +13 -0
- package/ansible/macos/t3-policy.yml +5 -3
- package/ansible/macos/vault-renew.yml +85 -0
- package/ansible/macos/worker-host-key.yml +33 -0
- package/ansible/monitoring/agent-darwin.yml +3 -0
- package/ansible/monitoring/agent.yml +2 -0
- package/ansible/monitoring/hub-darwin.yml +3 -0
- package/ansible/monitoring/hub-route-darwin.yml +1 -0
- package/ansible/net/remote-probe.sh +4 -1
- package/ansible/platforms.json +2 -2
- package/ansible/pyproject.toml +5 -0
- package/ansible/ubuntu/baseline.yml +39 -13
- package/ansible/ubuntu/disk-gc.py +6 -2
- package/ansible/ubuntu/firewall.nft.j2 +50 -0
- package/ansible/ubuntu/policy.json +125 -6
- package/ansible/ubuntu/reboot.yml +89 -0
- package/ansible/ubuntu/recovery.yml +13 -3
- package/ansible/ubuntu/t3/policy.json +3 -0
- package/ansible/ubuntu/t3-desktop.yml +23 -2
- package/ansible/ubuntu/t3-headless.yml +128 -0
- package/ansible/ubuntu/t3-health.sh +24 -10
- package/ansible/ubuntu/t3-idle.py +37 -2
- package/ansible/ubuntu/t3-policy.yml +4 -1
- package/ansible/ubuntu/t3-route.yml +1 -0
- package/ansible/ubuntu/tailscale.yml +54 -8
- package/ansible/ubuntu/tasks/browser.yml +3 -0
- package/ansible/ubuntu/tasks/containers-off.yml +43 -0
- package/ansible/ubuntu/tasks/docker.yml +53 -6
- package/ansible/ubuntu/tasks/dpkg.yml +4 -0
- package/ansible/ubuntu/tasks/features.yml +22 -0
- package/ansible/ubuntu/tasks/firewall.yml +172 -0
- package/ansible/ubuntu/tasks/install.yml +2 -1
- package/ansible/ubuntu/tasks/packages.yml +4 -2
- package/ansible/ubuntu/tasks/release.yml +6 -0
- package/ansible/ubuntu/tasks/resources.yml +6 -4
- package/ansible/ubuntu/tasks/services.yml +2 -2
- package/ansible/ubuntu/tasks/sizing.yml +49 -0
- package/ansible/ubuntu/tasks/snapshot.yml +14 -3
- package/ansible/ubuntu/tasks/ssh.yml +61 -4
- package/ansible/ubuntu/tasks/t3-restart.yml +3 -1
- package/ansible/ubuntu/tasks/user.yml +1 -0
- package/ansible/ubuntu/worker-account.yml +117 -0
- package/ansible/uv.lock +265 -0
- package/bin/devfleet.mjs +42 -4
- package/bootstrap/fleet-remote-bootstrap.sh +91 -25
- package/bootstrap/global-config.ts +29 -3
- package/bootstrap/package-smoke.ts +127 -0
- package/bootstrap/pins.ts +189 -0
- package/bootstrap/release-notes.ts +88 -0
- package/bootstrap/release-version.ts +41 -7
- package/bootstrap/worker-features.ts +114 -0
- package/bootstrap/worker-seed.yaml +65 -0
- package/bootstrap/worker-tools.ts +39 -9
- package/cliproxy/README.md +1 -1
- package/cliproxy/docs/health-workflow.example.yml +20 -143
- package/docs/authentication.md +21 -11
- package/docs/consumer-setup.md +74 -58
- package/docs/convergence.md +67 -0
- package/docs/declared.md +61 -34
- package/docs/machine-setup.md +73 -7
- package/docs/manager-setup.md +34 -0
- package/docs/operations.md +64 -9
- package/docs/releasing.md +49 -1
- package/docs/runbooks.md +112 -7
- package/docs/state.md +23 -11
- package/docs/support-matrix.md +40 -4
- package/docs/topology.md +82 -12
- package/docs/ubuntu-sync.md +98 -42
- package/docs/worker-contract.md +122 -19
- package/docs/worker-requirements.md +107 -0
- package/examples/fleet.json +1 -0
- package/examples/workers-from-infrastructure/main.tf +132 -0
- package/examples/workers-from-infrastructure/worker-records.json +14 -0
- package/llms.txt +3 -1
- package/mise.lock +29 -0
- package/mise.toml +5 -3
- package/package.json +2 -2
- package/schema/check-ids.json +1991 -162
- package/schema/check-ids.schema.json +34 -0
- package/schema/fleet.schema.json +349 -10
- package/schema/output/check.schema.json +1 -1
- package/schema/output/fleet-state-definition.schema.json +14 -0
- package/schema/output/fleet-sync-schedule.schema.json +26 -0
- package/schema/output/fleet-sync.schema.json +18 -0
- package/schema/output/report.schema.json +3 -2
- package/schema/worker-record.schema.json +76 -0
- package/src/agents/converge.ts +140 -24
- package/src/agents/files.ts +2 -32
- package/src/agents/native-verify.ts +34 -3
- package/src/agents/secrets.ts +39 -4
- package/src/check-owners.ts +62 -2
- package/src/check-registry.ts +630 -0
- package/src/cli/agent-guide.ts +3 -3
- package/src/cli/cli.ts +4 -0
- package/src/cli/fleet-manifest.ts +108 -0
- package/src/cli/fleet-node-lifecycle.ts +704 -0
- package/src/cli/fleet-node-park.ts +238 -0
- package/src/cli/fleet-node-seed.ts +167 -0
- package/src/cli/fleet-state.ts +2 -1
- package/src/cli/fleet-sync-checkout.ts +7 -0
- package/src/cli/fleet-sync-enrollment.ts +193 -32
- package/src/cli/fleet-sync-forward.ts +6 -0
- package/src/cli/fleet-sync-manager.ts +123 -8
- package/src/cli/fleet-sync-output.ts +31 -11
- package/src/cli/fleet-sync-plan.ts +65 -9
- package/src/cli/fleet-sync-records.ts +113 -0
- package/src/cli/fleet-sync-remote.ts +172 -15
- package/src/cli/fleet-sync-schedule.ts +14 -4
- package/src/cli/fleet-sync-state.ts +31 -10
- package/src/cli/fleet-sync-vault.ts +152 -26
- package/src/cli/fleet-sync-worker.ts +214 -0
- package/src/cli/fleet-sync.ts +172 -21
- package/src/cli/fleet-validate.ts +277 -0
- package/src/cli/fleet-watch.ts +7 -1
- package/src/cli/fleet.ts +87 -5
- package/src/cli/managed-health.ts +25 -1
- package/src/cli/register-fleet.ts +251 -4
- package/src/cli/registry.ts +47 -0
- package/src/cli/tailnet.ts +43 -10
- package/src/cli/ui-data.ts +3 -1
- package/src/cli/worker-usage-report.ts +63 -0
- package/src/clock.ts +42 -0
- package/src/definition.ts +762 -232
- package/src/diagnostics.ts +5 -2
- package/src/exposure.ts +102 -0
- package/src/fleet-config.ts +3 -1
- package/src/git-identity.ts +76 -3
- package/src/ide/ide.ts +5 -0
- package/src/ide/t3.ts +12 -2
- package/src/input-hashes.ts +6 -0
- package/src/machine/machine-class.ts +59 -0
- package/src/machine/platform.ts +90 -11
- package/src/machine/state.ts +70 -16
- package/src/machine/support-matrix.ts +11 -9
- package/src/machine-health.ts +28 -5
- package/src/manager-health.ts +148 -2
- package/src/manager-sync.ts +89 -8
- package/src/monitoring/beszel.ts +8 -8
- package/src/monitoring/enroll.ts +8 -1
- package/src/monitoring/hub-access.ts +10 -4
- package/src/monitoring/systems.ts +138 -0
- package/src/network-definition.ts +13 -4
- package/src/node-converge-linux.ts +136 -27
- package/src/node-converge.ts +13 -3
- package/src/platform/ansible-receipt.ts +17 -2
- package/src/platform/ansible.ts +40 -4
- package/src/platform/manager-host.ts +25 -8
- package/src/platform/resource-verify.ts +18 -7
- package/src/platform/t3-policy.ts +24 -10
- package/src/platform/t3-service.ts +109 -34
- package/src/platform/ubuntu-release.ts +24 -0
- package/src/platform/ubuntu-verify.ts +31 -3
- package/src/platform/ubuntu-worker.ts +58 -0
- package/src/platform/worker-platform.ts +72 -0
- package/src/protocol.ts +1 -1
- package/src/public-reachability.ts +186 -0
- package/src/remote-bootstrap.ts +50 -12
- package/src/remote-operation.ts +18 -4
- package/src/repair-plan.ts +23 -12
- package/src/report.ts +2 -1
- package/src/schedule-check.ts +21 -2
- package/src/secrets.ts +7 -0
- package/src/service-auth.ts +55 -48
- package/src/ssh-connection.ts +141 -0
- package/src/ssh.ts +63 -24
- package/src/state/store.ts +4 -2
- package/src/state/sync.ts +35 -6
- package/src/state/workers.ts +140 -0
- package/src/t3/pairing.ts +59 -0
- package/src/t3/peer-link.ts +333 -0
- package/src/t3/version.ts +1 -1
- package/src/tailnet-cleanup.ts +185 -0
- package/src/tailnet-control.ts +346 -0
- package/src/tailscale.ts +1 -1
- package/src/toolchain-checks.ts +11 -1
- package/src/types.ts +4 -2
- package/src/worker-account.ts +63 -0
- package/src/worker-activity.ts +303 -0
- package/src/worker-capacity.ts +31 -0
- package/src/worker-credentials.ts +201 -0
- package/src/worker-exposure.ts +388 -0
- package/src/worker-features.ts +201 -0
- package/src/worker-host-checks.ts +71 -20
- package/src/worker-manifest.ts +224 -0
- package/src/worker-parking.ts +70 -0
- package/src/worker-policy.ts +38 -36
- package/src/worker-readiness.ts +15 -3
- package/src/worker-reboot.ts +129 -0
- package/src/worker-records.ts +305 -0
- package/src/worker-seed.ts +143 -0
- package/src/worker-sizing.ts +76 -0
- package/src/cli/schedule-logs.ts +0 -36
package/docs/authentication.md
CHANGED
|
@@ -8,14 +8,14 @@ rewrites them).
|
|
|
8
8
|
|
|
9
9
|
## Where credentials live
|
|
10
10
|
|
|
11
|
-
| Credential | Lives in
|
|
12
|
-
| ----------------------------------- |
|
|
13
|
-
| The fleet's secrets (table below) | The provider `secrets` names in `fleet.json`
|
|
14
|
-
| The bucket's two keys | The environment of the `devfleet` command; `~/.config/dev-fleet/bucket.json` (0600) on the manager after `fleet-state --init`
|
|
15
|
-
| A node's Vault token | That node's own Vault session (`~/.vault-token`)
|
|
16
|
-
| A node's GitHub login | `gh`'s own store on that node
|
|
17
|
-
| Provider accounts (Claude, Codex …) | The CLI proxy's store on the manager
|
|
18
|
-
| Tailscale and T3 pairing | Each machine, signed in by a person
|
|
11
|
+
| Credential | Lives in | Read by |
|
|
12
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------ |
|
|
13
|
+
| The fleet's secrets (table below) | The provider `secrets` names in `fleet.json` | The node that needs it, through `src/secrets.ts` |
|
|
14
|
+
| The bucket's two keys | The environment of the `devfleet` command; `~/.config/dev-fleet/bucket.json` (0600) on the manager after `fleet-state --init` | The manager only |
|
|
15
|
+
| A node's Vault token | That node's own Vault session (`~/.vault-token`) | That node only; never copied |
|
|
16
|
+
| A node's GitHub login | `gh`'s own store on that node | `gh`, and git through its credential helper |
|
|
17
|
+
| Provider accounts (Claude, Codex …) | The CLI proxy's store on the manager | The proxy; nodes hold only the proxy client key |
|
|
18
|
+
| Tailscale and T3 pairing | Each machine, signed in by a person; a replaced worker's T3 is paired by the manager with a one-time code it never writes down | That machine |
|
|
19
19
|
|
|
20
20
|
## How they reach each node
|
|
21
21
|
|
|
@@ -30,14 +30,19 @@ rewrites them).
|
|
|
30
30
|
makes `gh` git's credential helper and writes the declared identity
|
|
31
31
|
(`git` in `fleet.json`, `ansible/github/git.yml`) on every node.
|
|
32
32
|
- **The proxy client key** is read by each node from its own secrets provider
|
|
33
|
-
whenever a launcher starts an agent.
|
|
33
|
+
whenever a launcher starts an agent. The node keeps the last key it read in
|
|
34
|
+
`~/.cache/dev-fleet/proxy-client-key` (0600) and uses it only while the
|
|
35
|
+
provider cannot answer, so an unreachable Vault or an expired session leaves
|
|
36
|
+
that node's agents working until the Vault checks below are fixed.
|
|
34
37
|
- **The monitoring hub's backup storage keys** are read on the manager by
|
|
35
38
|
`fleet-sync` and handed to the hub's playbook in a private variables file.
|
|
36
39
|
|
|
37
40
|
## Rotation and failure
|
|
38
41
|
|
|
39
|
-
Rotate a secret where the provider keeps it; the next read uses it
|
|
40
|
-
|
|
42
|
+
Rotate a secret where the provider keeps it; the next read uses it. Only the
|
|
43
|
+
proxy client key is remembered, and only as a fallback; a rotated key reaches
|
|
44
|
+
every node at its next launch, and `retire-key` should wait until every node
|
|
45
|
+
has launched an agent since the rotation. A Vault token that is not renewed expires: `worker:vault-renewal`
|
|
41
46
|
fails and the fix is one login of that machine. A GitHub token that stops
|
|
42
47
|
working fails `auth:github` and `worker:git-push-auth`; store the new one in
|
|
43
48
|
Vault and the worker restores itself within ten minutes. During a proxy
|
|
@@ -59,6 +64,8 @@ Every failure code is in [the runbooks](runbooks.md).
|
|
|
59
64
|
| `monitoring-backup-secret-key` | when its feature is declared | `DEVFLEET_SECRET_MONITORING_BACKUP_SECRET_KEY` | `~/.config/dev-fleet/secrets/monitoring-backup-secret-key` |
|
|
60
65
|
| `notify-webhook-url` | when its feature is declared | `DEVFLEET_SECRET_NOTIFY_WEBHOOK_URL` | `~/.config/dev-fleet/secrets/notify-webhook-url` |
|
|
61
66
|
| `notify-ntfy-url` | when its feature is declared | `DEVFLEET_SECRET_NOTIFY_NTFY_URL` | `~/.config/dev-fleet/secrets/notify-ntfy-url` |
|
|
67
|
+
| `tailnet-auth-key` | when its feature is declared | `DEVFLEET_SECRET_TAILNET_AUTH_KEY` | `~/.config/dev-fleet/secrets/tailnet-auth-key` |
|
|
68
|
+
| `tailnet-admin` | when its feature is declared | `DEVFLEET_SECRET_TAILNET_ADMIN` | `~/.config/dev-fleet/secrets/tailnet-admin` |
|
|
62
69
|
|
|
63
70
|
<!-- end: secrets -->
|
|
64
71
|
|
|
@@ -70,8 +77,11 @@ Every failure code is in [the runbooks](runbooks.md).
|
|
|
70
77
|
| ----------------------------- | ------------------------------------------ |
|
|
71
78
|
| `auth:github` | `src/github/checks.ts` |
|
|
72
79
|
| `auth:vault` | `src/cli/fleet-sync-vault.ts` |
|
|
80
|
+
| `auth:vault-isolation` | `src/cli/fleet-sync-vault.ts` |
|
|
81
|
+
| `worker:credential-renewal` | `src/worker-host-checks.ts` |
|
|
73
82
|
| `worker:git-identity` | `src/git-identity.ts` |
|
|
74
83
|
| `worker:git-push-auth` | `src/definition.ts`, `src/git-identity.ts` |
|
|
84
|
+
| `worker:git-signing` | `src/definition.ts`, `src/git-identity.ts` |
|
|
75
85
|
| `worker:github-sync` | `src/worker-access-checks.ts` |
|
|
76
86
|
| `worker:proxy-authentication` | `src/worker-access-checks.ts` |
|
|
77
87
|
| `worker:vault-renewal` | `src/worker-access-checks.ts` |
|
package/docs/consumer-setup.md
CHANGED
|
@@ -24,13 +24,13 @@ Nothing else is needed. You never clone dev-fleet, copy its files or write a
|
|
|
24
24
|
wrapper script around a checkout of it: the npm package is the tool, and the
|
|
25
25
|
version in `package.json` is the commit every machine runs.
|
|
26
26
|
|
|
27
|
-
| Concept | Meaning
|
|
28
|
-
| ----------- |
|
|
29
|
-
| manager | The one macOS machine you run `devfleet fleet-sync` on. Hosts the CLI proxy and the monitoring hub.
|
|
30
|
-
| worker | An Ubuntu 26.04 machine the manager converges over SSH. Stateless: rebuilt from Git and your secrets.
|
|
31
|
-
| fleet state | One SQLite database (roster, approved revision, configuration last applied) replicated to your bucket.
|
|
32
|
-
| bucket | Any S3-compatible bucket you own, or a directory. The source of truth for the fleet state.
|
|
33
|
-
| revision | The dev-fleet commit the installed package was published from (`npx devfleet --version`).
|
|
27
|
+
| Concept | Meaning |
|
|
28
|
+
| ----------- | -------------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| manager | The one macOS machine you run `devfleet fleet-sync` on. Hosts the CLI proxy and the monitoring hub. |
|
|
30
|
+
| worker | An Ubuntu 26.04 or 24.04 machine the manager converges over SSH. Stateless: rebuilt from Git and your secrets. |
|
|
31
|
+
| fleet state | One SQLite database (roster, approved revision, configuration last applied) replicated to your bucket. |
|
|
32
|
+
| bucket | Any S3-compatible bucket you own, or a directory. The source of truth for the fleet state. |
|
|
33
|
+
| revision | The dev-fleet commit the installed package was published from (`npx devfleet --version`). |
|
|
34
34
|
|
|
35
35
|
## Rules for agents
|
|
36
36
|
|
|
@@ -75,25 +75,30 @@ On the manager (the Mac this project is checked out on):
|
|
|
75
75
|
| Tailscale signed in | `tailscale status --json` (look for `"BackendState":"Running"`) |
|
|
76
76
|
| An SSH alias per worker that works without a prompt | `ssh -o BatchMode=yes WORKER_ALIAS true` for each worker |
|
|
77
77
|
|
|
78
|
-
On every worker
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
`
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
On every worker, check each row of
|
|
79
|
+
[what a machine must offer to be a worker](worker-requirements.md): the
|
|
80
|
+
image, architecture and size, the access, the first-boot data and the
|
|
81
|
+
network. Each row says how to verify it. If `sudo -n true` fails, that is fine
|
|
82
|
+
for the first, interactive run, which asks for the password once and installs
|
|
83
|
+
a sudo rule for the fleet; it is not fine for unattended runs.
|
|
84
|
+
|
|
85
|
+
A worker is reached in one of two ways, always with `BatchMode=yes` and
|
|
86
|
+
`StrictHostKeyChecking=yes`; never add `StrictHostKeyChecking=no` or
|
|
87
|
+
`accept-new`.
|
|
88
|
+
|
|
89
|
+
- **From declared data (no alias).** Leave `ssh` out: dev-fleet connects as
|
|
90
|
+
`network.user` on `network.sshPort` to `network.tailscaleName`, and checks
|
|
91
|
+
the host key against a known_hosts file of its own, rendered from the key
|
|
92
|
+
the fleet state pins. The human's `~/.ssh/config` and `~/.ssh/known_hosts`
|
|
93
|
+
are neither needed nor changed. The key is pinned without trusting a first
|
|
94
|
+
connection: `npx devfleet fleet-node-seed --id ID --output PATH --apply
|
|
95
|
+
--yes` generates it for a new machine, `npx devfleet fleet-node-replace
|
|
96
|
+
--id ID --host-key "TYPE BASE64" --apply --yes` pins one the human verified
|
|
97
|
+
out of band, and a worker record (below) may carry it as `hostKey`.
|
|
98
|
+
- **Through the human's own alias.** `ssh` names a Host alias in the
|
|
99
|
+
manager's `~/.ssh/config`, and its host key must already be in their
|
|
100
|
+
`known_hosts`. **Ask** the human to verify each fingerprint out of band and
|
|
101
|
+
connect once by hand. A typical alias:
|
|
97
102
|
|
|
98
103
|
```
|
|
99
104
|
Host worker-one
|
|
@@ -153,36 +158,37 @@ npx devfleet fleet-state --example > fleet.json
|
|
|
153
158
|
Then replace every placeholder. Each field, from
|
|
154
159
|
[`schema/fleet.schema.json`](../schema/fleet.schema.json):
|
|
155
160
|
|
|
156
|
-
| Field | Value
|
|
157
|
-
| ----------------------------------------------------- |
|
|
158
|
-
| `version` | `3`
|
|
159
|
-
| `source.repository` | `https://github.com/crvouga/dev-fleet.git`, or your fork if you publish one. Machines only accept code from it.
|
|
160
|
-
| `state` | `{ "bucket", "endpoint"?, "region"?, "prefix"? }` or `{ "directory": "/absolute/path" }`. Never credentials.
|
|
161
|
-
| `secrets` | See [secrets](#secrets).
|
|
162
|
-
| `manager.id` | A short lowercase id, `^[a-z][a-z0-9-]{0,62}$`, e.g. `manager-mac`.
|
|
163
|
-
| `manager.os` | `"macOS"`
|
|
164
|
-
| `manager.network.tailscaleName` | The manager's MagicDNS name: `tailscale status --json` → `.Self.DNSName` without the trailing dot.
|
|
165
|
-
| `manager.network.user` | The manager's login name (`id -un`).
|
|
166
|
-
| `manager.neverSleepOnPower` | `true` (workers depend on the manager's services).
|
|
167
|
-
| `workers[].id` | A short lowercase id. The
|
|
168
|
-
| `
|
|
169
|
-
| `workers[].
|
|
170
|
-
| `workers[].
|
|
171
|
-
| `workers[].network.
|
|
172
|
-
| `workers[].network.
|
|
173
|
-
| `workers[].network.
|
|
174
|
-
| `
|
|
175
|
-
| `services.
|
|
176
|
-
| `services.monitoring.
|
|
177
|
-
| `services.monitoring.
|
|
178
|
-
| `services.monitoring.
|
|
179
|
-
| `
|
|
180
|
-
| `
|
|
181
|
-
| `worker.
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `worker.
|
|
185
|
-
| `worker.
|
|
161
|
+
| Field | Value |
|
|
162
|
+
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
163
|
+
| `version` | `3` |
|
|
164
|
+
| `source.repository` | `https://github.com/crvouga/dev-fleet.git`, or your fork if you publish one. Machines only accept code from it. |
|
|
165
|
+
| `state` | `{ "bucket", "endpoint"?, "region"?, "prefix"? }` or `{ "directory": "/absolute/path" }`. Never credentials. |
|
|
166
|
+
| `secrets` | See [secrets](#secrets). |
|
|
167
|
+
| `manager.id` | A short lowercase id, `^[a-z][a-z0-9-]{0,62}$`, e.g. `manager-mac`. |
|
|
168
|
+
| `manager.os` | `"macOS"` |
|
|
169
|
+
| `manager.network.tailscaleName` | The manager's MagicDNS name: `tailscale status --json` → `.Self.DNSName` without the trailing dot. |
|
|
170
|
+
| `manager.network.user` | The manager's login name (`id -un`). |
|
|
171
|
+
| `manager.neverSleepOnPower` | `true` (workers depend on the manager's services). |
|
|
172
|
+
| `workers[].id` | A short lowercase id. The first reachable worker is the canary: a new revision must pass there before the others get it. |
|
|
173
|
+
| `canary` | Optional: the id of the worker to prefer as canary. When it is unreachable, the next reachable worker is used. |
|
|
174
|
+
| `workers[].ssh` | The worker's alias in the manager's `~/.ssh/config`. |
|
|
175
|
+
| `workers[].os` | `"linux"` |
|
|
176
|
+
| `workers[].network.tailscaleName` | The worker's MagicDNS name (from `tailscale status --json` → `.Peer[].DNSName` on the manager). |
|
|
177
|
+
| `workers[].network.sshPort` | `22` unless the worker's sshd listens elsewhere. |
|
|
178
|
+
| `workers[].network.user` | The worker account (`ssh WORKER_ALIAS id -un`). |
|
|
179
|
+
| `workers[].network.t3Port` | `3773` |
|
|
180
|
+
| `services.proxy.endpoint` | The public HTTPS origin of the CLI proxy, e.g. `https://cli-proxy.example.com`. |
|
|
181
|
+
| `services.monitoring.hubPort` | `8443` |
|
|
182
|
+
| `services.monitoring.publicUrl` | The public HTTPS origin of the monitoring dashboard. |
|
|
183
|
+
| `services.monitoring.managerAccount` | The email of the monitoring account the manager enrolls machines with. |
|
|
184
|
+
| `services.monitoring.viewerAccount` | The email of the read-only account visitors are signed in as. |
|
|
185
|
+
| `ubuntu` | `{ "release": "26.04", "architectures": ["amd64", "arm64"] }`: a release of the [support matrix](support-matrix.md). |
|
|
186
|
+
| `worker.requiredCapabilities` | Normally all of `github`, `vault`, `t3`, `toolchain`, `workstation`, `worker`. |
|
|
187
|
+
| `worker.githubLogin` | The GitHub login every worker must be signed in as. |
|
|
188
|
+
| `github` (optional) | Who the manager signs in to GitHub as, per-node tokens, required scopes; see [GitHub](github.md). |
|
|
189
|
+
| `worker.vaultUser` | The Vault user each worker's token is issued for. |
|
|
190
|
+
| `worker.toolchain`, `agentProfile` | `"mise.lock"`, `"proxy"` (fixed). |
|
|
191
|
+
| `worker.unattendedSudo`, `persistentT3`, `neverSleep` | `true` (fixed policy). |
|
|
186
192
|
|
|
187
193
|
Use the same values in every place they repeat. Validate before going on:
|
|
188
194
|
|
|
@@ -301,6 +307,14 @@ An agent cannot answer those prompts, and `--json`, `--non-interactive` or a
|
|
|
301
307
|
npx devfleet fleet-sync
|
|
302
308
|
```
|
|
303
309
|
|
|
310
|
+
A worker that needs none of those prompts is enrolled without the human: a
|
|
311
|
+
run with `--json` or `--non-interactive` enrolls a declared worker when its
|
|
312
|
+
pinned host key matched, `sudo -n` works on it, and exactly one tailnet device
|
|
313
|
+
matches it (or none, when `fleet.json` declares `tailnet` and its secret
|
|
314
|
+
`tailnet-admin`, so the run joins it with a single-use key). The report lists
|
|
315
|
+
what it enrolled (`enrolled` in the JSON). A machine made with
|
|
316
|
+
`devfleet fleet-node-seed` meets all of these.
|
|
317
|
+
|
|
304
318
|
It converges the manager first, then the canary worker, then the rest. It
|
|
305
319
|
prints one table and the path of the full JSON report
|
|
306
320
|
(`~/.local/share/personal/fleet/manager/last-sync.json`, readable by the human
|
|
@@ -363,7 +377,7 @@ Read `summary` and `remedy.action` of the failing check. The common ones:
|
|
|
363
377
|
| `ROOT_DEVELOPMENT_USER_REJECTED` | The worker's SSH user is root. Use a normal account with sudo. |
|
|
364
378
|
| `BOOTSTRAP_DISK_CAPACITY_REQUIRED` | Less than 2 GiB free (or too few inodes) where the fleet keeps its files on the worker. |
|
|
365
379
|
| `FLEET_REMOTE_LOCKED` | Another operation is running on that worker. Wait and run again. |
|
|
366
|
-
| `FLEET_PROMOTION_BLOCKED` | The canary (
|
|
380
|
+
| `FLEET_PROMOTION_BLOCKED` | The canary (the report names it under `canary`) failed, so the new revision went no further. Fix the canary first. |
|
|
367
381
|
| `VAULT_LOGIN_REQUIRED` | The manager is not logged in to Vault. The human logs in; the next sync issues worker tokens. |
|
|
368
382
|
| `PROVIDER_UNATTENDED_CREDENTIAL_REQUIRED` | A coding agent has no credential a background service can use. The human signs in on the proxy. |
|
|
369
383
|
| `BESZEL_ACCOUNT_REQUIRED` | The monitoring hub has no account yet. Follow the remedy; other workers are not blocked. |
|
|
@@ -381,7 +395,9 @@ and codes; leave out everything private.
|
|
|
381
395
|
- **Remove a worker.** Delete its entry, commit, run `npx devfleet fleet-sync`.
|
|
382
396
|
- **Upgrade the fleet.** `npm install --save-dev --save-exact @crvouga/dev-fleet@latest`,
|
|
383
397
|
commit, `npx devfleet fleet-sync`. The canary proves the new revision first.
|
|
384
|
-
|
|
398
|
+
`npx devfleet fleet-sync --rollback` goes back to the revision applied
|
|
399
|
+
before (the revision, tools and T3; system packages roll forward only, as
|
|
400
|
+
the [README](../README.md#the-version) says).
|
|
385
401
|
- **Replace the manager.** Follow
|
|
386
402
|
[replacing the manager](manager-recovery.md).
|
|
387
403
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# What converges a machine, and what is not Ansible yet
|
|
2
|
+
|
|
3
|
+
The goal is one convergence engine: Ansible, on every platform, with the CLI
|
|
4
|
+
as an orchestrator that validates the fleet configuration, runs playbooks,
|
|
5
|
+
reads their results and reports checks. Today three mechanisms change a
|
|
6
|
+
machine: the playbooks under `ansible/`, the bootstrap scripts, and some
|
|
7
|
+
TypeScript. This page lists every step that is not an Ansible task yet, each
|
|
8
|
+
with the reason it is not, so the list can only shrink.
|
|
9
|
+
`features/rules/convergence.feature` fails when a file that changes a machine
|
|
10
|
+
is missing from it.
|
|
11
|
+
|
|
12
|
+
## Ansible
|
|
13
|
+
|
|
14
|
+
| Playbook | Converges |
|
|
15
|
+
| ----------------------------------------- | ----------------------------------------------------------------------------- |
|
|
16
|
+
| `ansible/ubuntu/baseline.yml` | A worker's packages, Docker, services, power, user, SSH, disk |
|
|
17
|
+
| `ansible/ubuntu/tailscale.yml` | Tailscale on a worker |
|
|
18
|
+
| `ansible/ubuntu/t3-desktop.yml` | The T3 desktop app on a desktop worker |
|
|
19
|
+
| `ansible/ubuntu/t3-headless.yml` | The T3 server as a lingering user service on a headless worker |
|
|
20
|
+
| `ansible/ubuntu/t3-policy.yml` | T3's administrator policy |
|
|
21
|
+
| `ansible/ubuntu/t3-route.yml` | T3's private tailnet route |
|
|
22
|
+
| `ansible/ubuntu/recovery.yml` | Recovery of a stopped T3 desktop app or server |
|
|
23
|
+
| `ansible/ubuntu/worker-account.yml` | The declared account on an image that lets only root in, from the manager |
|
|
24
|
+
| `ansible/ubuntu/reboot.yml` | One worker's first-converge or maintenance reboot, from the manager |
|
|
25
|
+
| `ansible/monitoring/agent.yml` | The Beszel agent on a worker |
|
|
26
|
+
| `ansible/monitoring/agent-darwin.yml` | The Beszel agent on the manager |
|
|
27
|
+
| `ansible/monitoring/hub-darwin.yml` | The Beszel hub and its tunnel on the manager |
|
|
28
|
+
| `ansible/monitoring/hub-route-darwin.yml` | The hub's private tailnet route |
|
|
29
|
+
| `ansible/macos/manager.yml` | The manager's power settings, network time and fleet-watch job, unattended |
|
|
30
|
+
| `ansible/macos/t3-policy.yml` | T3's administrator policy on the manager |
|
|
31
|
+
| `ansible/macos/manager-privilege.yml` | The one administrator grant: sudoers, job log rotation and the T3 policy |
|
|
32
|
+
| `ansible/macos/worker-host-key.yml` | A worker's pinned SSH host key in the manager's known_hosts |
|
|
33
|
+
| `ansible/macos/vault-renew.yml` | The launch agent that renews the manager's own Vault session |
|
|
34
|
+
| `ansible/github/git.yml` | The Git identity and GitHub credentials of every node |
|
|
35
|
+
| `ansible/agents/agents.yml` | Each agent CLI's dedicated profile, rendered from `ansible/agents/templates/` |
|
|
36
|
+
|
|
37
|
+
Every playbook passes `ansible-lint` in the production profile, every command
|
|
38
|
+
in it says when it changes something and runs, or is skipped, in a dry run
|
|
39
|
+
(`features/rules/playbooks.feature`). The Beszel agent playbook is proven on a
|
|
40
|
+
systemd machine to report no change on a second run and in `--check`, and to
|
|
41
|
+
report drift, and only that drift (`features/monitoring/agent-lifecycle.feature`).
|
|
42
|
+
|
|
43
|
+
## Not Ansible yet
|
|
44
|
+
|
|
45
|
+
| Step | Where | Why it is not a task yet |
|
|
46
|
+
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| Install Git, curl, CA certificates, Python and Ansible | `bootstrap/fleet-remote-bootstrap.sh` | It must run before Ansible exists on the machine; it is the minimal bootstrap |
|
|
48
|
+
| Create the worker account, its host key, the privilege rule and Tailscale on first boot | `bootstrap/worker-seed.yaml` (written by `fleet-node-seed`) | cloud-init runs it before the manager can reach the machine; fleet-sync converges everything else with Ansible afterwards |
|
|
49
|
+
| Install mise and the pinned toolchain | `bootstrap/bootstrap.sh`, `bootstrap/setup.ts` | mise must exist before any tool does, and `mise install --locked` already converges from a lock |
|
|
50
|
+
| Install a worker's subset of tools | `bootstrap/worker-tools.ts`, `bootstrap/worker-features.ts` | It chooses which locked tools `mise install` gets; moving it means a toolchain role |
|
|
51
|
+
| Publish the global mise configuration | `bootstrap/global-config.ts` | Derived from `mise.toml` and the agent worktree roots on every run; a `toolchain` role with a template would replace it |
|
|
52
|
+
| `PATH` lines in shell profiles | `bootstrap/shell-path.ts` | Edits files a person owns, guarded by markers; a `blockinfile` task would replace it |
|
|
53
|
+
| The `devfleet` launcher link | `bootstrap/install-launcher.sh` | Points at the fleet-owned checkout of the revision, known only during the run |
|
|
54
|
+
| The T3 server archive | `bootstrap/native-t3.ts` | Installed with the toolchain, checked against the digest in `mise.toml`; a `t3` role would replace it |
|
|
55
|
+
| The AWS CLI on Windows | `bootstrap/native-aws.ts` | Windows is not a fleet role |
|
|
56
|
+
| Docker Desktop on the manager | `bootstrap/docker-desktop.sh` | A person installs and approves it on macOS; dev-fleet only measures it |
|
|
57
|
+
| A worker's service credentials from Vault | `bootstrap/worker-github.ts`, `bootstrap/worker-auth.ts` | A login belongs to a machine and a person; it is read from a session, never declared |
|
|
58
|
+
| The manager's own convergence: proxy, profiles, hub, agent | `src/cli/fleet-sync-manager.ts` | Orchestrates the manager playbooks and the proxy's own installer; the proxy is not a playbook yet (`docs/declared.md`) |
|
|
59
|
+
| Scheduled runs | `src/cli/fleet-sync-schedule.ts`, `src/platform/launchd.ts`, `src/platform/systemd-user.ts` | Writes a launchd job or systemd timer from TypeScript; listed in `docs/declared.md` as a schedule that should be a playbook |
|
|
60
|
+
|
|
61
|
+
## Still to do
|
|
62
|
+
|
|
63
|
+
Roles with a common interface (`baseline`, `toolchain`, `agents`, `t3`,
|
|
64
|
+
`network`, `monitoring`, `recovery`, `manager`), an inventory generated from
|
|
65
|
+
the fleet configuration, and `site.yml`, `manager.yml` and `workers.yml` that
|
|
66
|
+
bring a fresh manager and worker to ready with no other mutating step. Each
|
|
67
|
+
row of the table above moves into one of those roles.
|
package/docs/declared.md
CHANGED
|
@@ -12,29 +12,33 @@ may only shrink.
|
|
|
12
12
|
|
|
13
13
|
## Declared
|
|
14
14
|
|
|
15
|
-
| What
|
|
16
|
-
|
|
|
17
|
-
| The fleet: machines, services, accounts
|
|
18
|
-
| Tools: languages, CLIs, coding agents
|
|
19
|
-
| mise itself
|
|
20
|
-
| JavaScript dependencies
|
|
21
|
-
| T3 Code, server and desktop app
|
|
22
|
-
| T3 policy on the manager (updates off)
|
|
23
|
-
| Worker work-in-progress guard
|
|
24
|
-
| Ubuntu packages
|
|
25
|
-
| Tailscale on workers
|
|
26
|
-
| Worker policy: power, SSH, sudo, memory, disk
|
|
27
|
-
| Monitoring: hub, tunnel, agents
|
|
28
|
-
| The manager's private route to the hub
|
|
29
|
-
| The manager's power settings
|
|
30
|
-
| Ansible on the manager
|
|
31
|
-
| Ansible on a worker
|
|
32
|
-
| The CLI proxy
|
|
33
|
-
| Agent profiles and T3 providers
|
|
34
|
-
| Worker time service
|
|
35
|
-
| The manager's
|
|
36
|
-
|
|
|
37
|
-
|
|
|
15
|
+
| What | Declared in | Pinned by | Applied by | Measured by |
|
|
16
|
+
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
17
|
+
| The fleet: machines, services, accounts | Your `fleet.json` | The dev-fleet version in your `package.json`, which names one commit | `fleet-sync` | `fleet-status` |
|
|
18
|
+
| Tools: languages, CLIs, coding agents | `mise.toml` | `mise.lock`: version and checksum for each platform | `mise install --locked` | Tool and `agent:verification` checks |
|
|
19
|
+
| mise itself | `min_version` and `mise_*_sha256` in `mise.toml` | The digest of its release archive, held here | `bootstrap/bootstrap.sh` | Its version, at every toolchain setup |
|
|
20
|
+
| JavaScript dependencies | `package.json` | `bun.lock` | `bun install --frozen-lockfile` | The install fails on a difference |
|
|
21
|
+
| T3 Code, server and desktop app | `t3_*` under `[vars]` in `mise.toml` | SHA-256 of each artifact | `bootstrap/native-t3.ts`; `ansible/ubuntu/t3-desktop.yml` | T3 checks; `t3:version` on every machine |
|
|
22
|
+
| T3 policy on the manager (updates off, linked environments on) | `ansible/ubuntu/t3/policy.json`, shared with the workers | The commit | `ansible/macos/t3-policy.yml`, once, as an administrator (`manager-privilege.yml`) | `t3:updates` |
|
|
23
|
+
| Worker work-in-progress guard | `ansible/ubuntu/wip-guard.py`, `ansible/ubuntu/tasks/recovery.yml` | The commit | `fleet-sync` | `features/ide/work-in-progress.feature` |
|
|
24
|
+
| Ubuntu packages | `packages` and `snapshot` in `ansible/ubuntu/policy.json` | Exact versions from a dated archive snapshot | `ansible/ubuntu/tasks/packages.yml` | `package:*` |
|
|
25
|
+
| Tailscale on workers | `tailscale` in `ansible/ubuntu/policy.json` | Exact version; digest of the signing key | `ansible/ubuntu/tailscale.yml` | `package:tailscale` |
|
|
26
|
+
| Worker policy: power, SSH, sudo, memory, disk | `ansible/ubuntu/*.yml`, values shared with checks in `policy.json` | The commit | `fleet-sync` | Host and resource checks |
|
|
27
|
+
| Monitoring: hub, tunnel, agents | `ansible/monitoring/*.yml`, `compose.yml`, `lock.json` | Image digests; SHA-256 of each agent archive | `fleet-sync` | `beszel:*` |
|
|
28
|
+
| The manager's private route to the hub | `ansible/monitoring/hub-route-darwin.yml` | The commit | `fleet-sync` | The route, read back |
|
|
29
|
+
| The manager's power settings | `pmset` in `ansible/macos/policy.json` | The commit | `ansible/macos/manager.yml`, on every `fleet-sync`, after one grant (`manager-privilege.yml`) | `manager:power` |
|
|
30
|
+
| Ansible on the manager | `ansible/pyproject.toml` | `ansible/uv.lock`: one release, one Python, every dependency hashed | `uv run --locked --isolated` | A hash that differs stops the run |
|
|
31
|
+
| Ansible on a worker | `ansible-core` in `ansible/ubuntu/policy.json` | Exact version | `ansible/ubuntu/tasks/packages.yml` | `package:ansible-core` |
|
|
32
|
+
| The CLI proxy | `cliproxy/compose.yaml`, `image.lock.json`, `requirements.lock`, `launchd/`, `config.template.yaml` | Image digests; hashed Python dependencies | `devfleet cliproxy install`, and `fleet-sync` after it | The proxy's audit |
|
|
33
|
+
| Agent profiles and T3 providers | `agents/registry.json`, `agents/t3.json`; each CLI's configuration from `ansible/agents/templates/` | The commit | `fleet-sync` (agent profiles through `ansible/agents/agents.yml`) | Profile receipts; the plan after every apply; `agent:*:session` |
|
|
34
|
+
| Worker time service | `ansible/ubuntu/tasks/services.yml`, offsets in `clock` in `ansible/ubuntu/policy.json` | The commit | `fleet-sync` | `worker:clock` |
|
|
35
|
+
| The manager's playbook and its receipt | `ansible/macos/manager.yml` | The commit | `fleet-sync`, check mode first, then applied; re-applied at least daily | `manager:playbook` |
|
|
36
|
+
| The manager's network time | `ansible/macos/manager.yml` (an assert) | The commit | macOS | `manager:clock`, `worker:clock-offset` |
|
|
37
|
+
| fleet-watch on a schedule | `fleetWatch` in `ansible/macos/policy.json`, `manager.schedule.watchMinutes` in `fleet.json` | The commit | `fleet-sync` (`manager.yml`) | `manager:watch` |
|
|
38
|
+
| Rotation of the scheduled jobs' logs | `jobLogs` in `ansible/macos/policy.json` | The commit | `ansible/macos/manager-privilege.yml`, once, as an administrator | `manager:job-logs` |
|
|
39
|
+
| The manager's container watchdog | `ansible/monitoring/container-watchdog.py`, `containerWatchdog` in `ansible/macos/policy.json` | The commit | `fleet-sync` (`hub-darwin.yml`) | `manager:container-watchdog` |
|
|
40
|
+
| Docker Desktop on the manager | `docker_desktop_*` under `[vars]` in `mise.toml` | Version and build | You | `manager:docker` (warns) |
|
|
41
|
+
| CI | `.github/workflows/` | Each action at a commit; tools from `mise.lock` | GitHub | `features/rules/` |
|
|
38
42
|
|
|
39
43
|
A value lives in a policy file when something besides the playbook reads it,
|
|
40
44
|
so the check and the playbook cannot disagree. A value only a playbook uses
|
|
@@ -62,11 +66,11 @@ stays in the playbook: the playbook is its declaration.
|
|
|
62
66
|
scripts from the declarative files above, not by a playbook.
|
|
63
67
|
- **Files TypeScript and shell still write.** The installed `fleet.json`, the
|
|
64
68
|
`current` and `devfleet` links, the `PATH` lines in shell profiles, the
|
|
65
|
-
global mise configuration, the T3 server archive
|
|
66
|
-
settings. Each is derived
|
|
69
|
+
global mise configuration, the T3 server archive and T3 settings. Each is derived
|
|
67
70
|
from a tracked file and rewritten on every run, but by code.
|
|
68
71
|
- **Logins.** Tailscale, Vault, GitHub, each provider account and T3 pairing
|
|
69
|
-
|
|
72
|
+
(except a replaced worker's, which the manager pairs itself) belong to a
|
|
73
|
+
machine and a person. They are checked, never copied.
|
|
70
74
|
- **Windows.** `bootstrap/bootstrap.ps1` exists; Windows is not a fleet role
|
|
71
75
|
and nothing tests it.
|
|
72
76
|
|
|
@@ -80,13 +84,36 @@ moving to it entirely means NixOS workers and nix-darwin on the manager, which
|
|
|
80
84
|
replaces every unit and path that exists today. The one thing above that Nix
|
|
81
85
|
would settle and the current tools do not is the rest of a worker's packages.
|
|
82
86
|
|
|
87
|
+
## Keeping pins current
|
|
88
|
+
|
|
89
|
+
A pin that is only moved by hand goes stale and is then moved in a large
|
|
90
|
+
batch, the riskiest way to change a fleet. Each pin is moved by a machine,
|
|
91
|
+
one pull request at a time, which CI, the fresh workers and the VM test then
|
|
92
|
+
judge like any change, unless it says below why a person moves it.
|
|
93
|
+
|
|
94
|
+
| Pin | Moved by |
|
|
95
|
+
| ---------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
96
|
+
| Tools in `mise.toml` and `mise.lock` | Renovate (`mise`), one pull request per tool |
|
|
97
|
+
| JavaScript and Python dependencies | Renovate, with lock file maintenance |
|
|
98
|
+
| Actions and CI service images | Renovate, each action at a commit |
|
|
99
|
+
| mise itself | The [Pins workflow](../.github/workflows/pins.yml): `bun bootstrap/pins.ts mise`, weekly |
|
|
100
|
+
| T3 Code (nightly) | The Pins workflow: `bun bootstrap/pins.ts t3`, weekly, every artifact hashed |
|
|
101
|
+
| The tunnel image of the monitoring hub | Renovate, by tag and digest (a custom manager in `renovate.json`) |
|
|
102
|
+
| Beszel (hub image and agents) | A person, because the agents' binary digests need the archives unpacked; `pins.ts` cannot yet |
|
|
103
|
+
| Docker Desktop on the manager | A person, because a person installs it and dev-fleet only measures the version |
|
|
104
|
+
| The Ubuntu snapshot and package versions | A person, because a new snapshot moves every package at once and each needs its exact version |
|
|
105
|
+
|
|
106
|
+
The workflows never name the mise release: they install it through
|
|
107
|
+
[`.github/actions/mise`](../.github/actions/mise/action.yml), which reads
|
|
108
|
+
`min_version` from `mise.toml`.
|
|
109
|
+
|
|
83
110
|
## Changing a pin
|
|
84
111
|
|
|
85
|
-
| To change | Edit | Then
|
|
86
|
-
| ----------------------- | -------------------------------------------------------------------- |
|
|
87
|
-
| A tool | Its version in `mise.toml` | Update `mise.lock` with `mise lock`
|
|
88
|
-
| mise | `
|
|
89
|
-
| An Ubuntu package | `packages` in `ansible/ubuntu/policy.json`, and `snapshot` if needed | The VM test in `ansible/ubuntu/tests`
|
|
90
|
-
| Ansible on the manager | `ansible/pyproject.toml` | `uv lock` in `ansible/`
|
|
91
|
-
| Beszel | `ansible/monitoring/lock.json`, `compose.yml`, the agent unit | `bun test features/rules`
|
|
92
|
-
| A manager power setting | `pmset` in `ansible/macos/policy.json` |
|
|
112
|
+
| To change | Edit | Then |
|
|
113
|
+
| ----------------------- | -------------------------------------------------------------------- | ------------------------------------- |
|
|
114
|
+
| A tool | Its version in `mise.toml` | Update `mise.lock` with `mise lock` |
|
|
115
|
+
| mise | `bun bootstrap/pins.ts mise` moves `min_version` and the digests | The fresh-box run |
|
|
116
|
+
| An Ubuntu package | `packages` in `ansible/ubuntu/policy.json`, and `snapshot` if needed | The VM test in `ansible/ubuntu/tests` |
|
|
117
|
+
| Ansible on the manager | `ansible/pyproject.toml` | `uv lock` in `ansible/` |
|
|
118
|
+
| Beszel | `ansible/monitoring/lock.json`, `compose.yml`, the agent unit | `bun test features/rules` |
|
|
119
|
+
| A manager power setting | `pmset` in `ansible/macos/policy.json` | The next `fleet-sync` applies it |
|