@microck/raft 0.5.0 → 0.7.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.
Files changed (63) hide show
  1. package/README.md +27 -15
  2. package/deploy/build-image.py +4 -2
  3. package/deploy/raft-expire.py +109 -31
  4. package/deploy/verify-controls.py +6 -6
  5. package/deploy/verify-features.py +329 -19
  6. package/deploy/verify-jobs.py +264 -0
  7. package/deploy/verify-limits.py +22 -3
  8. package/deploy/verify-live.py +31 -6
  9. package/deploy/verify-output.py +208 -0
  10. package/deploy/verify-release.py +33 -4
  11. package/deploy/verify-run.py +571 -0
  12. package/deploy/verify-self-update.py +9 -1
  13. package/deploy/verify-sync.py +122 -0
  14. package/docs/benchmarks/read-latency-2026-10-29.json +70 -0
  15. package/docs/boat-capabilities.md +60 -7
  16. package/docs/boat-parity-design.md +1 -0
  17. package/docs/boot-performance.mdx +21 -0
  18. package/docs/contract.md +88 -13
  19. package/docs/first-box.mdx +22 -19
  20. package/docs/guides/background-jobs.mdx +38 -31
  21. package/docs/guides/backup-recovery.mdx +4 -3
  22. package/docs/guides/ci-jobs.mdx +209 -0
  23. package/docs/guides/config-policy.mdx +109 -35
  24. package/docs/guides/files.mdx +2 -2
  25. package/docs/guides/index.mdx +31 -0
  26. package/docs/guides/long-running-services.mdx +9 -3
  27. package/docs/guides/meta.json +7 -2
  28. package/docs/guides/project-setup.mdx +1 -1
  29. package/docs/guides/scripting-ci.mdx +36 -14
  30. package/docs/guides/snapshots-forks.mdx +4 -2
  31. package/docs/guides/troubleshooting.mdx +19 -2
  32. package/docs/guides/upgrades.mdx +11 -9
  33. package/docs/index.mdx +26 -28
  34. package/docs/maintainers/index.mdx +18 -0
  35. package/docs/maintainers/meta.json +12 -0
  36. package/docs/meta.json +5 -9
  37. package/docs/operations.mdx +17 -10
  38. package/docs/publishing.md +14 -4
  39. package/docs/reference/capacity.mdx +2 -1
  40. package/docs/reference/cli.md +135 -43
  41. package/docs/reference/configuration.mdx +10 -6
  42. package/docs/reference/meta.json +3 -1
  43. package/docs/releases/0.2.0.md +1 -0
  44. package/docs/releases/0.2.1.md +1 -0
  45. package/docs/releases/0.3.0.md +1 -0
  46. package/docs/releases/0.4.0.md +1 -0
  47. package/docs/releases/0.5.0.md +1 -0
  48. package/docs/releases/0.6.0.md +17 -0
  49. package/docs/releases/0.7.0.md +23 -0
  50. package/docs/releases/index.mdx +21 -0
  51. package/docs/releases/meta.json +15 -0
  52. package/docs/requirements.mdx +1 -1
  53. package/docs/reviews/docs-audit-2026-10-24.md +92 -0
  54. package/docs/reviews/performance-audit-2026-10-29.md +90 -0
  55. package/docs/site-development.md +1 -0
  56. package/docs/verification.mdx +22 -4
  57. package/package.json +3 -1
  58. package/raft.py +526 -193
  59. package/raft_files.py +13 -1
  60. package/raft_jobs.py +390 -0
  61. package/raft_output.py +166 -0
  62. package/raft_run.py +330 -0
  63. package/skills/raft-cli/SKILL.md +78 -182
@@ -8,15 +8,16 @@ description: Complete command-line reference for the Raft controller CLI.
8
8
  Command-line reference for the `raft` controller tool.
9
9
 
10
10
  Syntax:
11
- `raft <subcommand> [options] [arguments]`
11
+ `raft [--json] <subcommand> [options] [arguments]`
12
12
 
13
- `raft --help` lists commands, `raft <subcommand> --help` lists its arguments,
13
+ `raft --help` lists commands, `raft <subcommand> --help` explains its behavior and arguments,
14
14
  and `raft --version` prints the installed version without loading configuration.
15
- Output is command-specific; see [Scripting and CI](../guides/scripting-ci.mdx).
15
+ Global `--json` emits JSONL events for structured results, byte streams, errors and exit codes.
16
+ Without it, output is command-specific; see [Scripting and CI](../guides/scripting-ci.mdx).
16
17
 
17
- At most once a day, after a command finishes, Raft checks GitHub for a newer
18
- release and prints one line on stderr, such as
19
- `raft 0.6.0 is available (you have 0.5.0). Run: raft self-update`. It never
18
+ At most once a day, Raft checks GitHub for a newer release in the background
19
+ while a command runs, then prints one line on stderr after it finishes, such as
20
+ `raft 0.7.0 is available (you have 0.6.0). Run: raft self-update`. It never
20
21
  installs anything or changes stdout, and network failures stay silent. See
21
22
  [`self-update`](#self-update) to turn it off.
22
23
 
@@ -27,9 +28,10 @@ Workspaces are referenced by location-qualified handles formatted as `<location>
27
28
  | Task | Commands |
28
29
  | --- | --- |
29
30
  | Workspace lifecycle | [`new`](#new), [`stop`](#stop), [`resume`](#resume), [`extend`](#extend), [`destroy`](#destroy) |
31
+ | Disposable CI jobs | [`run`](#run) |
30
32
  | Execution and inspection | [`exec`](#exec), [`ssh`](#ssh), [`info`](#info), [`usage`](#usage) |
31
33
  | Background job | [`status`](#status), [`logs`](#logs), [`cancel`](#cancel) |
32
- | File transfer | [`upload`](#upload), [`download`](#download) |
34
+ | File transfer | [`upload`](#upload), [`download`](#download), [`sync`](#sync) |
33
35
  | Snapshots and cloning | [`snapshot`](#snapshot), [`snapshots`](#snapshots), [`restore`](#restore), [`snapshot-delete`](#snapshot-delete), [`fork`](#fork) |
34
36
  | Port forwarding and desktop | [`forward`](#forward), [`desktop`](#desktop) |
35
37
  | Backup and recovery | [`backup`](#backup), [`recover`](#recover) |
@@ -38,13 +40,40 @@ Workspaces are referenced by location-qualified handles formatted as `<location>
38
40
  | Host inspection and maintenance | [`capacity`](#capacity), [`doctor`](#doctor), [`list`](#list), [`gc`](#gc), [`prune`](#prune) |
39
41
  | CLI maintenance | [`self-update`](#self-update) |
40
42
 
43
+ ## Disposable CI command
44
+
45
+ ### `run`
46
+
47
+ **Unreleased 0.7.0 feature.** Not present in published 0.6.0. See the
48
+ [development requirements](../guides/ci-jobs.mdx) before using these commands.
49
+
50
+ `raft run [--location LOCATION | --from LOCATION:BOX/SNAPSHOT] [--cpu N] [--memory SIZE] [--disk SIZE] [--timeout SECONDS] [--push DIRECTORY | --push-all DIRECTORY] [--cwd GUEST_PATH] [--pull GUEST_DIRECTORY NEW_LOCAL_DIRECTORY]... [--purpose TEXT [--owner TEXT] [--next TEXT]] -- COMMAND [ARG ...]`
51
+
52
+ Create a disposable box, probe readiness, optionally upload source, stream the
53
+ command, collect result directories and attempt ownership-checked cleanup.
54
+ `--timeout` defaults to 600 and covers the entire job, with separate 30-second
55
+ collection and cleanup grace periods. The host expiry is established before
56
+ start at timeout + 120 seconds. No renewal, detach, persistent or keep option.
57
+
58
+ `--push` requires a Git working tree and copies tracked/unignored files without
59
+ `.git`; submodules are refused. `--push-all` explicitly copies the full tree,
60
+ including ignored files. Uploads require a new guest destination with an existing
61
+ parent, defaulting to `/workspace/project`. Without upload, cwd is `/workspace`.
62
+ Pulls are directory transfers to new local paths and run after a failed payload.
63
+
64
+ Payload failure status takes precedence; a successful payload with failed
65
+ collection/cleanup returns 1. Timeout is 124, Ctrl-C 130 and SIGTERM 143.
66
+ Lifecycle messages and the allocated handle go to stderr, not stdout. Unknown
67
+ remote outcomes are not automatically retried. See the [CI guide](../guides/ci-jobs.mdx)
68
+ for trust restrictions, template caching, recovery limits and a GitHub example.
69
+
41
70
  ## Workspace lifecycle commands
42
71
 
43
72
  ### `new`
44
73
 
45
74
  Create and launch a new workspace container.
46
75
 
47
- `raft new [--location LOCATION] [--ttl TTL] [--cpu N] [--memory SIZE] [--disk SIZE] [--disposable] [--from LOCATION:BOX/SNAPSHOT] [--purpose TEXT [--owner TEXT] [--next TEXT]]`
76
+ `raft new [--location LOCATION] [--ttl TTL] [--cpu N] [--memory SIZE] [--disk SIZE] [--disposable | --persistent] [--from LOCATION:BOX/SNAPSHOT] [--purpose TEXT [--owner TEXT] [--next TEXT]]`
48
77
 
49
78
  - `--location LOCATION`: Target host location in `~/.config/raft/incus.json`. Built-in default: first configured location.
50
79
  - `--ttl TTL`: Lifetime in seconds before automatic stop (`60` to `2592000`). Built-in default: `600`.
@@ -57,7 +86,8 @@ then the built-in default. With `--from`, configured `cpu`, `memory` and `disk`
57
86
  defaults do not apply: the box keeps the snapshot's size unless a flag overrides
58
87
  it, and `--disk shared` is refused.
59
88
 
60
- - `--disposable`: Delete the box and snapshots on stop or expiry. Off by default.
89
+ - `--disposable`: Delete the box and snapshots on stop or expiry. Built-in default: persistent.
90
+ - `--persistent`: Keep the box and its disk on stop or expiry, overriding a configured `disposable` default. Cannot be combined with `--disposable`.
61
91
  - `--from LOCATION:BOX/SNAPSHOT`: Copy a named snapshot on its source host instead of the configured image. The box keeps the snapshot's CPU, RAM and disk unless `--cpu`, `--memory` or `--disk` overrides them; the source can be running. Cannot target a different location.
62
92
  - `--purpose TEXT`, `--owner TEXT`, `--next TEXT`: Record a [box note](#note). `--owner` and `--next` need `--purpose`. Without them the box starts with no note, including boxes created `--from` a noted snapshot. A host [policy](#policy) can require fields.
63
93
 
@@ -139,30 +169,31 @@ Display active resource consumption for a running workspace: cgroup memory, CPU
139
169
 
140
170
  ## Background job commands
141
171
 
142
- `status`, `logs` and `cancel` require a job ID returned by `exec --detach` in the selected running workspace. Unknown jobs return an error.
143
-
144
- Cancelled jobs remain inspectable while their guest journal records exist. Rotating old logs does not prevent inspection of a live job.
172
+ `status`, `logs` and `cancel` require the exact workspace handle and job ID returned by `exec --detach`. Status and logs remain available after workspace stop or deletion. Unknown or expired jobs return an error. Guest journal rotation does not affect retained results.
145
173
 
146
174
  ### `status`
147
175
 
148
- Check the execution state of a detached background job.
149
-
150
176
  `raft status <box> <job>`
151
177
 
152
- Queries `systemctl show` inside the container and outputs `ActiveState`, `SubState`, and `ExecMainStatus`.
178
+ Read retained JSON state, exit code, timestamps and dropped output bytes from the
179
+ host, including after workspace stop or deletion. `completed` means execution
180
+ ended; inspect `exitCode` for success. Unknown or expired jobs are rejected.
153
181
 
154
182
  ### `logs`
155
183
 
156
- Retrieve journal output from a detached background job using `journalctl --no-pager -o cat -u <job>`.
157
-
158
184
  `raft logs <box> <job>`
159
185
 
160
- ### `cancel`
186
+ Read the first 1 MiB of combined output retained on the host. Results expire
187
+ seven days after completion and are pruned on access. The store allows at most
188
+ 512 records. See [Background jobs](../guides/background-jobs.mdx).
161
189
 
162
- Terminate a running detached background job using `systemctl stop <job>`.
190
+ ### `cancel`
163
191
 
164
192
  `raft cancel <box> <job>`
165
193
 
194
+ Stop the guest job control group. Retained results remain available. Cancellation
195
+ can fail while the guest unit is still starting; inspect before retrying.
196
+
166
197
  ## File transfer commands
167
198
 
168
199
  ### `upload`
@@ -222,7 +253,7 @@ Clone a stopped workspace into an independent container on the same host and sta
222
253
  - `--ttl TTL`: Lifetime in seconds for the clone. Required.
223
254
  - `--purpose TEXT`, `--owner TEXT`, `--next TEXT`: Replace the clone's whole note. Without them the clone keeps the source note.
224
255
 
225
- Omitted CPU/RAM values inherit the source limits; controller defaults never apply to forks. The clone keeps the source's disk: the shared pool, or an own disk of the same size as a thin snapshot, which reserves that size in `raft-disks`. To copy a box onto a disk of another size, snapshot it and use `new --from BOX/SNAPSHOT --disk SIZE`. The clone is persistent unless `--disposable` is supplied, regardless of the source policy.
256
+ Omitted CPU/RAM values inherit the source limits; controller defaults never apply to forks. The clone keeps the source's disk: the shared pool, or an own disk of the same size as a thin snapshot, which reserves that size in `raft-disks`. To copy a box onto a disk of another size, snapshot it and use `new --from BOX/SNAPSHOT --disk SIZE`. The clone is persistent unless `--disposable` is supplied, regardless of the source and of a configured `disposable` default.
226
257
  The note the clone ends up with must satisfy the host [policy](#policy).
227
258
 
228
259
  Returns the qualified handle of the clone.
@@ -353,12 +384,16 @@ would leave them out. Otherwise Raft does not interpret notes.
353
384
 
354
385
  Show or change the controller defaults for `new`.
355
386
 
356
- `raft config`
387
+ `raft config [--location LOCATION]`
357
388
  `raft config set KEY VALUE`
358
389
  `raft config unset KEY`
359
390
 
360
- - `KEY`: One of `location`, `ttl`, `cpu`, `memory`, `disk`.
361
- - `VALUE`: Accepted exactly when the same text is accepted by the matching `new` flag. A `location` must be configured.
391
+ - `KEY`: One of `location`, `ttl`, `cpu`, `memory`, `disk`, `disposable`.
392
+ - `VALUE`: Accepted exactly when the same text is accepted by the matching `new` flag. A `location` must be configured. `disposable` takes `true` or `false`.
393
+
394
+ `disposable true` makes `new` create disposable boxes, including `new --from`,
395
+ because a snapshot carries no lifecycle; `--persistent` keeps one box. `fork`
396
+ ignores it: a fork is persistent unless it gets `--disposable`.
362
397
 
363
398
  `cpu`, `memory` and `disk` size only boxes created from the image. `new --from`
364
399
  and `fork` keep the source's CPU, RAM and disk; only explicit flags change them.
@@ -373,29 +408,51 @@ file makes `new` fail with the file path and key; `set` or `unset` that key to
373
408
  repair it.
374
409
 
375
410
  `raft config` prints one JSON object: `file`, `defaults` (each key's `value` and
376
- `source`, `config` or `built-in`) and `policy` (each location's `require` list
377
- and `changed` record). It contacts every configured host to read policies.
378
- See [Defaults and note policies](../guides/config-policy.mdx).
411
+ `source`, `config` or `built-in`) and `policy`. For each location, `policy` has
412
+ `require` (the required note fields), `deleteStoppedAfterHours` (`null` without
413
+ retention), `deleteStoppedAfterSince` (when retention was set, Unix seconds) and
414
+ the last change records `requireChanged` and `deleteStoppedAfterChanged`. It
415
+ contacts every configured host to read policies unless `--location LOCATION`
416
+ selects one. This filter affects the policy report, not controller defaults,
417
+ and is rejected with `set` or `unset`. Location-scoped config and doctor are
418
+ development-branch additions, not available in published 0.6.0.
419
+ See [Defaults and host policies](../guides/config-policy.mdx).
379
420
 
380
421
  ### `policy`
381
422
 
382
- Set or clear the box note fields a location's host requires.
423
+ Set or clear a location's host policies: the box note fields it requires and
424
+ how long it keeps stopped boxes.
383
425
 
384
- `raft policy LOCATION --require FIELDS`
385
- `raft policy LOCATION --clear`
426
+ `raft policy LOCATION [--require FIELDS|none] [--delete-stopped-after HOURS|never]`
386
427
 
387
- - `--require FIELDS`: Comma-separated fields from `purpose`, `owner`, `next`. Must include `purpose`.
388
- - `--clear`: Stop requiring fields.
428
+ - `--require FIELDS`: Comma-separated fields from `purpose`, `owner`, `next`. Must include `purpose`. `--require none` stops requiring fields.
429
+ - `--delete-stopped-after HOURS`: Delete boxes that stay stopped for HOURS, a positive whole number, with their snapshots. `--delete-stopped-after never` keeps stopped boxes.
389
430
 
390
- The policy is stored on the host in the Incus project key `user.raft.require`,
391
- so it applies to every controller. `new`, `fork`, `recover` and `note` check it
392
- on the controller for an actionable error, then again in the host transaction
393
- that writes the note. The command prints the change and the host records the
394
- time, SSH account and controller in `user.raft.require.changed` and the host
431
+ Give either option or both; each changes only its own policy. Both values are
432
+ checked before the host changes.
433
+
434
+ Policies are stored on the host in the Incus project `raft`, so they apply to
435
+ every controller. The command prints each change and the host records the time,
436
+ SSH account and controller in a `.changed` key beside the policy and in the host
395
437
  journal (`journalctl -t raft`).
396
438
 
397
- This is a guardrail for agents, not a security boundary: SSH and sudo on the
398
- host can change the policy or bypass it, and older controllers do not check it.
439
+ The note policy lives in `user.raft.require`. `new`, `fork`, `recover` and
440
+ `note` check it on the controller for an actionable error, then again in the
441
+ host transaction that writes the note.
442
+
443
+ Retention lives in `user.raft.delete-stopped-after`, with the time it was set in
444
+ `user.raft.delete-stopped-after.since`. The host expiry worker deletes a stopped
445
+ box once HOURS have passed since the later of its stop and that time, so a new
446
+ or shorter policy never deletes a box sooner than HOURS after the change. The
447
+ worker runs every 15 seconds and on [`gc`](#gc), logs each deletion to the host
448
+ journal and never touches running boxes. A stopped box with no recorded stop
449
+ time, such as one powered off from inside, stopped with native `incus` or
450
+ recovered from a backup, starts its clock when the worker first sees it.
451
+ [`list`](#list) shows each box's `deleteAt`. Setting retention needs the current
452
+ host worker; on an older one it fails with redeploy guidance.
453
+
454
+ Policies are guardrails for agents, not a security boundary: SSH and sudo on the
455
+ host can change or bypass them, and older controllers do not check note policies.
399
456
 
400
457
  ## Host inspection and maintenance commands
401
458
 
@@ -416,7 +473,9 @@ if any. See [Box sizing and capacity](./capacity.mdx) for the fields.
416
473
 
417
474
  Inspect host connectivity, Incus version, expiry-worker compatibility, active systemd units (`incus`, `raft-expire.timer`, `raft-network.service`), root filesystem usage, status of the shared `raft-data` pool and, when own box disks are enabled, the `raft-disks` pool, and saved box count across configured hosts. Without `raft-disks` it prints `own box disks: not enabled (redeploy with --disk-pool SIZE)` and does not fail. An incompatible worker returns a nonzero exit status and names the failing location without running expiry or modifying boxes.
418
475
 
419
- `raft doctor`
476
+ `raft doctor [--location LOCATION]`
477
+
478
+ Pass `--location` to inspect one configured host independently of offline hosts.
420
479
 
421
480
  ### `list`
422
481
 
@@ -424,7 +483,9 @@ List existing workspace containers across configured hosts.
424
483
 
425
484
  `raft list [--location LOCATION]`
426
485
 
427
- Prints one JSON object per box (JSONL), with `box`, `state`, `stopAt`, `disk` and `note` fields.
486
+ Prints one JSON object per box (JSONL), with `box`, `state`, `stopAt`, `deleteAt`, `disk` and `note` fields.
487
+ `deleteAt` is the Unix time when the location's [retention](#policy) deletes a
488
+ stopped box, as a string like `stopAt`, or `""` when no deletion is due.
428
489
  `disk` is `"shared"` for the shared pool or the own disk's size, such as `"20GiB"`.
429
490
  `note` is the box note object, or `null` when the box has none.
430
491
  An empty inventory prints no records. See [Scripting and CI](../guides/scripting-ci.mdx)
@@ -432,7 +493,7 @@ for output formats, exit codes, readiness, and failure handling.
432
493
 
433
494
  ### `gc`
434
495
 
435
- Enforce deadlines immediately. Persistent boxes stop; disposable boxes are deleted.
496
+ Enforce deadlines and retention immediately. Persistent boxes stop; disposable boxes are deleted; stopped boxes past the location's [retention](#policy) are deleted.
436
497
 
437
498
  `raft gc [--location LOCATION]`
438
499
 
@@ -442,9 +503,9 @@ Preview deletion of persistent stopped boxes older than the selected number of d
442
503
 
443
504
  `raft prune --older-than DAYS [--location LOCATION] [--yes]`
444
505
 
445
- Days must be at least one. Without `--yes`, this only prints JSONL candidates. With `--yes`, it deletes matching boxes and their snapshots under the host lock. Running boxes and boxes without a recorded stop time are excluded. Stop timestamps come from Raft stop/expiry, not box creation. No automatic retention policy is enabled.
506
+ Days must be at least one. Without `--yes`, this only prints JSONL candidates. With `--yes`, it deletes matching boxes and their snapshots under the host lock. Running boxes and boxes without a recorded stop time are excluded. Stop timestamps come from Raft stop/expiry, or from the host worker when it first sees a box stopped another way, never from box creation. For automatic deletion, set a [retention policy](#policy).
446
507
 
447
- Disposable creation/fork and prune require the current expiry worker installed through the deployer. A mismatch fails with deployment guidance; the CLI does not install or adapt an older worker.
508
+ Disposable creation/fork, prune and setting retention require the current expiry worker installed through the deployer. A mismatch fails with deployment guidance; the CLI does not install or adapt an older worker.
448
509
 
449
510
  ## CLI maintenance commands
450
511
 
@@ -481,3 +542,34 @@ pinned or scripted runs. The notice caches its last result in
481
542
  `$XDG_CACHE_HOME/raft/update.json` (default `~/.cache/raft/update.json`). It
482
543
  waits at most 2 seconds for GitHub and is skipped for `self-update` and
483
544
  `--version`.
545
+
546
+ ### `completions`
547
+
548
+ `raft completions bash|zsh|fish`
549
+
550
+ Print a shell integration script. Source it in the matching shell, for example
551
+ `source <(raft completions bash)`. Completions discover the installed parser on
552
+ each request, including nested commands, flags and fixed choices. They never
553
+ load host configuration or contact a host. The private `_complete` command is
554
+ used by these scripts, not needed in ordinary workflows.
555
+
556
+ ### `sync`
557
+
558
+ `raft sync BOX SOURCE DESTINATION [--all] [--dry-run]`
559
+
560
+ Sync source into an existing running workspace, replacing matching files and
561
+ preserving guest-only files. Checksums detect content changes even if timestamps
562
+ and sizes match; unchanged content is not resent. Requires rsync on the
563
+ controller and guest. Install it explicitly if an older image lacks it.
564
+
565
+ Git selects tracked and unignored files by default, excluding `.git` and rejecting
566
+ submodules. `--all` includes ignored and hidden files too. Deleted source files
567
+ are not deleted remotely. Rsync reports skipped unsafe symlinks and special files.
568
+ Destination is an absolute non-root guest directory with an existing parent.
569
+ `--dry-run` previews changes without writing files. Updates are atomic per file,
570
+ not per tree; rerun after an interruption to finish syncing.
571
+
572
+ ```sh
573
+ raft sync "$BOX" . /workspace/project --dry-run
574
+ raft sync "$BOX" . /workspace/project
575
+ ```
@@ -80,7 +80,8 @@ controller and is separate from the location inventory:
80
80
  "ttl": 3600,
81
81
  "cpu": 2,
82
82
  "memory": "4GiB",
83
- "disk": "20GiB"
83
+ "disk": "20GiB",
84
+ "disposable": true
84
85
  }
85
86
  }
86
87
  ```
@@ -92,15 +93,18 @@ controller and is separate from the location inventory:
92
93
  | `cpu` | A positive whole number | `1` |
93
94
  | `memory` | Whole GiB, e.g. `16GiB` | `2GiB` |
94
95
  | `disk` | Whole GiB for an own box disk, or `shared` | `shared` |
96
+ | `disposable` | `true` or `false` | `false` (persistent) |
95
97
 
96
- Explicit flags win over these values. `cpu`, `memory` and `disk` size only boxes
97
- created from the image: `new --from` and `fork` keep the source's size unless a
98
- flag overrides it. A `disk` default needs the `raft-disks` pool on the target
98
+ Explicit flags win over these values; `--persistent` overrides `disposable`.
99
+ `cpu`, `memory` and `disk` size only boxes created from the image: `new --from`
100
+ and `fork` keep the source's size unless a flag overrides it. `disposable`
101
+ applies to `new` and `new --from`, never to `fork`. A `disk` default needs the `raft-disks` pool on the target
99
102
  host, like `--disk`. Unknown keys and invalid values make
100
103
  `raft new` fail with the file path and key. Edit the file with
101
104
  `raft config set KEY VALUE` and `raft config unset KEY`, and inspect it with
102
- `raft config`. Required box note fields are a host policy, not part of this
103
- file; see [Defaults and note policies](../guides/config-policy.mdx).
105
+ `raft config`. Required box note fields and stopped-box retention are host
106
+ policies, not part of this file; see
107
+ [Defaults and host policies](../guides/config-policy.mdx).
104
108
 
105
109
  ## SSH configuration and connection behavior
106
110
 
@@ -5,6 +5,8 @@
5
5
  "pages": [
6
6
  "cli",
7
7
  "configuration",
8
- "capacity"
8
+ "capacity",
9
+ "[Runtime contract](/docs/contract/)",
10
+ "[Boot measurements](/docs/boot-performance/)"
9
11
  ]
10
12
  }
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Raft 0.2.0
3
+ description: Historical changes and upgrade requirements for Raft 0.2.0.
3
4
  ---
4
5
 
5
6
  # Raft 0.2.0
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Raft 0.2.1
3
+ description: Historical changes and upgrade requirements for Raft 0.2.1.
3
4
  ---
4
5
 
5
6
  # Raft 0.2.1
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Raft 0.3.0
3
+ description: Historical changes and upgrade requirements for Raft 0.3.0.
3
4
  ---
4
5
 
5
6
  # Raft 0.3.0
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Raft 0.4.0
3
+ description: Historical changes and upgrade requirements for Raft 0.4.0.
3
4
  ---
4
5
 
5
6
  # Raft 0.4.0
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Raft 0.5.0
3
+ description: Historical changes and upgrade requirements for Raft 0.5.0.
3
4
  ---
4
5
 
5
6
  # Raft 0.5.0
@@ -0,0 +1,17 @@
1
+ ---
2
+ title: Raft 0.6.0
3
+ description: Historical changes and upgrade requirements for Raft 0.6.0.
4
+ ---
5
+
6
+ # Raft 0.6.0
7
+
8
+ - **Disposable by default.** `raft config set disposable true` makes `raft new` create disposable boxes, which are deleted with their snapshots when they stop or expire. `raft new --persistent` keeps one box anyway, and `--disposable` still works the other way. The default also applies to `new --from`; a fork stays persistent unless you pass `--disposable`. `raft config` shows the setting.
9
+ - **Delete boxes left stopped.** `raft policy LOCATION --delete-stopped-after 48` makes a host delete boxes, with their snapshots, once they have been stopped for 48 hours. The host applies it every 15 seconds and on `raft gc`, even with no controller online, logs each deletion to its journal (`journalctl -t raft`) and never touches running boxes. A new or shorter policy never deletes a box sooner than its hours after the change, and resuming a box resets its clock. `raft list` shows each stopped box's `deleteAt`. `--delete-stopped-after never` turns it off.
10
+ - **Stop times for every stopped box.** The host now records a stop time for boxes stopped outside `raft stop`, such as a poweroff inside the box, a native `incus stop` or a recovered backup, when it first sees them. `raft prune` can therefore select them later; before, it skipped them forever.
11
+ - **`raft policy` changes.** `--require` and `--delete-stopped-after` can be set together or alone, and each changes only its own policy. `--require none` replaces `--clear`, which is gone. In `raft config`, each location's `changed` field is now `requireChanged`, beside the new `deleteStoppedAfterHours`, `deleteStoppedAfterSince` and `deleteStoppedAfterChanged`.
12
+
13
+ Install on Linux with Python 3.11.8+ using `npm install -g @microck/raft@0.6.0`, or install the attached Python wheel; existing installs can run `raft self-update`.
14
+
15
+ Redeploy each host with this release's `deploy/deploy.py`. The host expiry worker changed, and until a host is redeployed `raft doctor` reports it, while `new --disposable` (including a disposable default), `fork --disposable`, `raft prune` and `raft policy --delete-stopped-after HOURS` fail on it with redeploy guidance. Redeploying changes nothing else on the host and sets no retention policy.
16
+
17
+ ARM64 and AMD64 development images accompany this release. Verify `SHA256SUMS` before importing an image for your host architecture.
@@ -0,0 +1,23 @@
1
+ ---
2
+ title: Raft 0.7.0
3
+ description: Changes and upgrade requirements for Raft 0.7.0.
4
+ ---
5
+
6
+ # Raft 0.7.0
7
+
8
+ - **Disposable foreground CI jobs.** `raft run -- COMMAND ...` creates a fresh disposable box, waits for readiness, streams one command and attempts ownership-checked cleanup after success, failure or cancellation. Use the existing location, size, snapshot-template and note options. This is remote job orchestration, not a registered GitHub runner or paid Boat integration.
9
+ - **Source and result transfers.** `--push DIRECTORY` uploads Git-tracked and unignored files without Git metadata; submodules are rejected. `--push-all DIRECTORY` explicitly includes hidden and ignored files. Repeated `--pull GUEST_DIRECTORY NEW_LOCAL_DIRECTORY` options collect results before cleanup, including after a failed command. `--cwd` selects the guest working directory.
10
+ - **Bounded lifetimes and cancellation-safe cleanup.** A single timeout covers preparation through command execution, followed by bounded collection and cleanup grace periods. A unique run identity and fixed expiry are set before startup. Private cancellation records prevent a queued creation from starting after confirmed cleanup. Payload failures retain their exit status; timeout returns 124, Ctrl-C 130 and SIGTERM 143. Collection or unconfirmed cleanup turns an otherwise successful run into failure.
11
+ - **Transfer deadline fix.** An interrupted receive now kills and reaps its child even when stdout has already closed, instead of waiting indefinitely for process exit.
12
+ - **Retained background jobs.** `raft exec --detach` returns a job ID. Use `status`, `logs` and `cancel` to manage it. Results and bounded output remain available after the workspace stops or is deleted.
13
+ - **Source sync.** `raft sync` transfers changed files into an existing workspace, with Git-aware selection and a dry-run option.
14
+ - **Structured output.** Global `--json` emits JSONL events for results, streams, errors and exit codes.
15
+ - **Documentation and verification.** A trusted-job GitHub Actions example, package checks and real AMD64/ARM64 tests cover source transfers, failing-command artifacts, timeout, cancellation and template isolation. The static documentation build uses patched Next.js 16.4.1.
16
+
17
+ Install with `npm install -g @microck/raft@0.7.0` or the attached Python wheel. Existing installs can use `raft self-update`.
18
+
19
+ Use dedicated hosts and trusted code only. The controller uses existing passwordless-sudo SSH access; it is not a scoped CI identity. Incus boxes share the host kernel and do not provide VM isolation. Templates retain their complete filesystem, including secrets. No credentials, repository secrets, runner registration or paid capacity are provisioned by `raft run`.
20
+
21
+ The current expiry worker (protocol 2, introduced in 0.6.0) is required. This release does not change that protocol or configure a retention policy. Host expiry remains a backstop when cleanup cannot be confirmed, not a guarantee of instantaneous deletion or rollback of command side effects.
22
+
23
+ Verify `SHA256SUMS` before installing packages or importing the image for your host architecture.
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Release notes
3
+ description: Published Raft versions and clearly marked upcoming changes.
4
+ ---
5
+
6
+ # Release notes
7
+
8
+ The setup examples use **0.6.0**, the latest published npm package and GitHub
9
+ release checked on 2026-10-24. [GitHub releases](https://github.com/Microck/raft/releases)
10
+ are the source for downloadable packages, images and checksums.
11
+
12
+ - [0.7.0 — unreleased](./0.7.0.md): disposable foreground CI jobs on the development branch.
13
+ - [0.6.0](./0.6.0.md): disposable defaults and stopped-box retention.
14
+ - [0.5.0](./0.5.0.md): flexible sizing, own box disks, defaults and self-update.
15
+ - [0.4.0](./0.4.0.md): box notes.
16
+ - [0.3.0](./0.3.0.md): guided host onboarding.
17
+ - [0.2.1](./0.2.1.md): worker compatibility checks.
18
+ - [0.2.0](./0.2.0.md): extended workspace lifecycle and transfer commands.
19
+
20
+ Historical notes describe their own release, not the current command contract.
21
+ For upgrades, follow [Upgrades and image changes](../guides/upgrades.mdx).
@@ -0,0 +1,15 @@
1
+ {
2
+ "title": "Release notes",
3
+ "collapsible": true,
4
+ "defaultOpen": false,
5
+ "pages": [
6
+ "index",
7
+ "0.7.0",
8
+ "0.6.0",
9
+ "0.5.0",
10
+ "0.4.0",
11
+ "0.3.0",
12
+ "0.2.1",
13
+ "0.2.0"
14
+ ]
15
+ }
@@ -21,7 +21,7 @@ Each workspace host must be a dedicated physical machine or virtual instance:
21
21
 
22
22
  `raft host add` checks these requirements read-only before it changes a host.
23
23
 
24
- Host CPU and RAM reserves are advisory estimates for `raft capacity`, not enforced cgroup locks. Raft limits neither how many boxes a host runs nor their size.
24
+ Host CPU and RAM reserves are advisory estimates for `raft capacity`, not enforced cgroup locks. There is no product-tier box-count cap. Individual CPU/RAM requests must fit the host, and own disks must pass storage reservation checks.
25
25
 
26
26
  <Callout type="warn" title="Dedicated host requirement">
27
27
  Do not deploy Raft on hosts with existing Incus storage pools or shared virtualization workloads. Deployment configures dedicated nftables rules, storage pools, and system services.
@@ -0,0 +1,92 @@
1
+ # Documentation audit — 2026-10-24
2
+
3
+ ## Scope and comparison
4
+
5
+ Reviewed the 34 existing published-source documentation pages, including seven
6
+ release-note pages, and added three navigation hubs (37 pages total). Review
7
+ reports are deliberately excluded from the public site; the repository-only
8
+ `setup-explained.html` is not part of the site's generated routes.
9
+
10
+ Compared Boat's complete 206-entry documentation index and representative
11
+ quickstart, concepts, setup, snapshots, background tasks, CI, security, desktop,
12
+ hosting and troubleshooting material. This is a documentation comparison, not a
13
+ claim to have tested Boat's service or every one of its 206 pages.
14
+
15
+ Primary references: https://docs.boat.dev/llms.txt,
16
+ https://docs.boat.dev/quickstart, https://docs.boat.dev/concepts,
17
+ https://docs.boat.dev/long-running-tasks/background-commands,
18
+ https://docs.boat.dev/troubleshooting. The useful pattern is task-first pages and
19
+ progressive disclosure, not copying Boat's managed-service promises into Raft.
20
+
21
+ ## Findings
22
+
23
+ 1. The main sidebar mixed first-run tasks with architecture, publishing and test
24
+ histories. New guide/maintainer/release hubs separate audiences without moving
25
+ established page URLs.
26
+ 2. Onboarding linked nonexistent 0.7.0 packages and images. GitHub's latest release
27
+ and npm both reported 0.6.0; the v0.7.0 release endpoint returned 404. Stable
28
+ examples now pin 0.6.0 and development-only CI is labeled and commit-pinned.
29
+ 3. Several persistent tutorials inherited a disposable controller default, and
30
+ one sequence resumed a box immediately before forking a source that must be
31
+ stopped. The examples now state the required lifecycle explicitly.
32
+ 4. Backup instructions asked for permissions on a destination that must not
33
+ exist. Verified against raft.py: the temporary archive is created and checked
34
+ privately before no-overwrite publication. Wording now matches that behavior.
35
+ 5. Search flooded the dialog with repeated paragraphs from reference/history
36
+ pages. Matching page titles now rank first, initial results show up to eight
37
+ pages with two sections each, and an explicit action restores every match.
38
+
39
+ ## Verification
40
+
41
+ - Production static build, type checking and lint passed.
42
+ - All 37 routes, local links and fragment targets, search index, Markdown exports,
43
+ asset downloads and 404 behavior passed the exported-site checks.
44
+ - 120 shell examples passed Bash syntax checks. Help for new/fork/run was checked.
45
+ This is not execution against Incus; no hosts, credentials or workspaces changed.
46
+ - Real cloud-browser interactions exercised navigation, advanced setup disclosure
47
+ and search. The separate automated Chromium suite could not download a valid
48
+ browser archive in this environment; no passing result is claimed for that suite.
49
+ - Historical benchmark and runtime evidence remains labeled with its original
50
+ dates/limits. This docs-only work does not re-certify runtime behavior.
51
+
52
+ ## Page-by-page disposition
53
+
54
+ | Page | Review / change |
55
+ | --- | --- |
56
+ | `boat-capabilities.md` | Renamed parity to comparison; added a short operating-model summary; folded the detailed matrix and marked run as preview. |
57
+ | `boat-parity-design.md` | Retained architecture rationale; added description and grouped under Maintainers. |
58
+ | `boot-performance.mdx` | Retained dated samples and limitations; added search description and moved under Reference. |
59
+ | `contract.md` | Marked maintainer audience and unreleased CI contract; clarified persistent-only stop retention; moved navigation into Reference. |
60
+ | `first-box.mdx` | Made persistence explicit; separated destructive cleanup from stop/resume; reduced the next-step list. |
61
+ | `guides/background-jobs.mdx` | Retained start/status/log/cancel flow and the important exit-status versus completion distinction. |
62
+ | `guides/backup-recovery.mdx` | Clarified persistent source and private archive creation; removed impossible pre-existing destination permission instruction. |
63
+ | `guides/ci-jobs.mdx` | Marked unreleased 0.7.0; replaced nonexistent npm installation with a reviewed full source commit in an isolated environment. |
64
+ | `guides/config-policy.mdx` | Retained defaults/host-policy separation and destructive-retention warnings; reachable from the operator guide group. |
65
+ | `guides/desktop-services.mdx` | Retained tunnel foreground behavior, binding requirements and exact noVNC path. |
66
+ | `guides/docker.mdx` | Retained daemon checks, runnable build example, storage guidance and pruning warning. |
67
+ | `guides/files.mdx` | Resolved running-only wording versus supported stopped single-file transfers. |
68
+ | `guides/index.mdx` | Added a task-oriented Develop / Automate / Operate hub. |
69
+ | `guides/long-running-services.mdx` | Kept restart semantics and TTL limits; made the persistent creation example independent of controller defaults. |
70
+ | `guides/project-setup.mdx` | Kept the upload/setup/template sequence; made persistent template source explicit. |
71
+ | `guides/scripting-ci.mdx` | Kept output/exit-code tables and retry safety; made persistent cleanup example explicit. |
72
+ | `guides/snapshots-forks.mdx` | Warned before stopping disposable sources and corrected the sequential resume-then-fork example. |
73
+ | `guides/troubleshooting.mdx` | Retained symptom/error sections and safe no-wildcard recovery guidance; checked command references and anchors. |
74
+ | `guides/upgrades.mdx` | Updated stale 0.2.0 pins to published 0.6.0; kept component separation and backup/redeploy warnings. |
75
+ | `index.mdx` | Replaced the 12-row task catalogue with a short setup path and focused task links; explicit persistent example and release status. |
76
+ | `maintainers/index.mdx` | Added an audience-specific hub instead of four competing top-level implementation links. |
77
+ | `operations.mdx` | Pinned real 0.6.0 assets/packages; kept guided onboarding primary and folded manual steps without changing URLs or anchors. |
78
+ | `publishing.md` | Retained maintainer release gates; added description and moved out of the onboarding navigation. |
79
+ | `reference/capacity.mdx` | Corrected fork-after-resume ordering and persistent source; retained detailed accounting as reference, not onboarding. |
80
+ | `reference/cli.md` | Kept the complete command lookup and anchors; labeled run as unreleased rather than a stable command. |
81
+ | `reference/configuration.mdx` | Retained schema, required image fingerprint, precedence and SSH behavior; checked examples and links. |
82
+ | `releases/0.2.0.md` | Retained historical release content; added an explicit historical description and a release-notes navigation home. |
83
+ | `releases/0.2.1.md` | Retained historical release content; added an explicit historical description and a release-notes navigation home. |
84
+ | `releases/0.3.0.md` | Retained historical release content; added an explicit historical description and a release-notes navigation home. |
85
+ | `releases/0.4.0.md` | Retained historical release content; added an explicit historical description and a release-notes navigation home. |
86
+ | `releases/0.5.0.md` | Retained historical release content; added an explicit historical description and a release-notes navigation home. |
87
+ | `releases/0.6.0.md` | Retained historical release content; added an explicit historical description and a release-notes navigation home. |
88
+ | `releases/0.7.0.md` | Marked as unreleased; removed claims that packages/images already exist. |
89
+ | `releases/index.mdx` | Added explicit published versus unreleased status and links to historical notes. |
90
+ | `requirements.mdx` | Clarified product caps versus real CPU/RAM/storage limits; kept the dedicated-host warning. |
91
+ | `site-development.md` | Retained build/export guidance; added description and grouped under Maintainers. |
92
+ | `verification.mdx` | Corrected obsolete shared-pool-only statement; retained dated evidence and uncertainty; grouped under Maintainers. |