@ours.network/fleet 1.1.0-nightly.3 → 1.1.0-nightly.30

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 (208) hide show
  1. package/README.md +244 -40
  2. package/dist/agent-recovery-gate.d.ts +17 -0
  3. package/dist/agent-recovery-gate.js +135 -0
  4. package/dist/application/capabilities.js +18 -6
  5. package/dist/application/fleet-query-service.js +20 -5
  6. package/dist/application/role-command-service.js +9 -0
  7. package/dist/application/role-creation-service.d.ts +4 -4
  8. package/dist/application/role-creation-service.js +19 -1
  9. package/dist/application/role-repository.d.ts +4 -2
  10. package/dist/application/role-repository.js +6 -3
  11. package/dist/application/session-control.d.ts +3 -1
  12. package/dist/application/session-control.js +4 -2
  13. package/dist/application/task-room-service.d.ts +93 -40
  14. package/dist/application/task-room-service.js +579 -173
  15. package/dist/briefing.js +85 -24
  16. package/dist/build-info.json +4 -4
  17. package/dist/canonical-json.d.ts +2 -0
  18. package/dist/canonical-json.js +10 -0
  19. package/dist/cli.js +217 -51
  20. package/dist/config-yaml.d.ts +1 -1
  21. package/dist/config.d.ts +38 -3
  22. package/dist/config.js +240 -28
  23. package/dist/creation.d.ts +1 -1
  24. package/dist/creation.js +7 -4
  25. package/dist/daemon-recovery.d.ts +93 -0
  26. package/dist/daemon-recovery.js +328 -0
  27. package/dist/docs.d.ts +1 -1
  28. package/dist/docs.js +213 -42
  29. package/dist/doctor.d.ts +2 -0
  30. package/dist/doctor.js +54 -4
  31. package/dist/fleet-command-audit.d.ts +181 -0
  32. package/dist/fleet-command-audit.js +738 -0
  33. package/dist/fleet-proxy.d.ts +7 -2
  34. package/dist/harness/agent-session.d.ts +5 -0
  35. package/dist/harness/claude-code-session.d.ts +2 -0
  36. package/dist/harness/claude-code-session.js +6 -1
  37. package/dist/harness/claude-code.js +2 -0
  38. package/dist/harness/codex-app-server-proxy.d.ts +40 -0
  39. package/dist/harness/codex-app-server-proxy.js +348 -14
  40. package/dist/harness/codex-session.d.ts +11 -2
  41. package/dist/harness/codex-session.js +22 -2
  42. package/dist/harness/codex.d.ts +5 -1
  43. package/dist/harness/codex.js +110 -10
  44. package/dist/harness/types.d.ts +1 -1
  45. package/dist/index.d.ts +4 -3
  46. package/dist/index.js +3 -2
  47. package/dist/init-guidance.d.ts +1 -1
  48. package/dist/init-guidance.js +4 -3
  49. package/dist/init-wizard.d.ts +98 -0
  50. package/dist/init-wizard.js +631 -0
  51. package/dist/lifecycle-summary.d.ts +134 -0
  52. package/dist/lifecycle-summary.js +179 -0
  53. package/dist/loops/config.d.ts +10 -1
  54. package/dist/loops/config.js +38 -5
  55. package/dist/model-recovery.d.ts +1 -1
  56. package/dist/ops.js +2 -17
  57. package/dist/owner-channel/channel.d.ts +75 -3
  58. package/dist/owner-channel/channel.js +531 -123
  59. package/dist/owner-channel/commands.d.ts +28 -6
  60. package/dist/owner-channel/commands.js +112 -36
  61. package/dist/owner-channel/lifecycle-outbox.d.ts +24 -0
  62. package/dist/owner-channel/lifecycle-outbox.js +87 -0
  63. package/dist/owner-channel/ours-client.d.ts +19 -0
  64. package/dist/owner-channel/ours-client.js +3 -0
  65. package/dist/owner-channel/state.d.ts +2 -0
  66. package/dist/owner-channel/state.js +8 -2
  67. package/dist/permissions.js +1 -1
  68. package/dist/preset-bootstrap.d.ts +10 -0
  69. package/dist/preset-bootstrap.js +85 -0
  70. package/dist/preset-migration.d.ts +42 -0
  71. package/dist/preset-migration.js +450 -0
  72. package/dist/reports/artifact.d.ts +10 -0
  73. package/dist/reports/artifact.js +32 -0
  74. package/dist/reports/index.d.ts +5 -0
  75. package/dist/reports/index.js +5 -0
  76. package/dist/reports/render.d.ts +6 -0
  77. package/dist/reports/render.js +240 -0
  78. package/dist/reports/service.d.ts +42 -0
  79. package/dist/reports/service.js +57 -0
  80. package/dist/reports/tasks.d.ts +52 -0
  81. package/dist/reports/tasks.js +177 -0
  82. package/dist/reports/types.d.ts +315 -0
  83. package/dist/reports/types.js +6 -0
  84. package/dist/resolved-plan.js +13 -1
  85. package/dist/rooms-tasks/cli.d.ts +2 -0
  86. package/dist/rooms-tasks/cli.js +519 -261
  87. package/dist/rooms-tasks/close.d.ts +9 -1
  88. package/dist/rooms-tasks/close.js +23 -7
  89. package/dist/rooms-tasks/config.js +16 -29
  90. package/dist/rooms-tasks/cowork-adapter.d.ts +5 -0
  91. package/dist/rooms-tasks/cowork-adapter.js +13 -0
  92. package/dist/rooms-tasks/deletion.d.ts +51 -0
  93. package/dist/rooms-tasks/deletion.js +217 -0
  94. package/dist/rooms-tasks/external-worker.d.ts +9 -0
  95. package/dist/rooms-tasks/external-worker.js +52 -9
  96. package/dist/rooms-tasks/launch-snapshot.d.ts +19 -0
  97. package/dist/rooms-tasks/launch-snapshot.js +181 -0
  98. package/dist/rooms-tasks/member-overrides.d.ts +30 -0
  99. package/dist/rooms-tasks/member-overrides.js +204 -0
  100. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  101. package/dist/rooms-tasks/member-startup.js +9 -2
  102. package/dist/rooms-tasks/provision.js +146 -56
  103. package/dist/rooms-tasks/room-state.d.ts +1 -0
  104. package/dist/rooms-tasks/room-state.js +12 -1
  105. package/dist/rooms-tasks/task-room-name.d.ts +12 -0
  106. package/dist/rooms-tasks/task-room-name.js +61 -0
  107. package/dist/rooms-tasks/task-state.d.ts +115 -3
  108. package/dist/rooms-tasks/task-state.js +361 -11
  109. package/dist/rooms-tasks/templates.d.ts +4 -2
  110. package/dist/rooms-tasks/templates.js +42 -78
  111. package/dist/rooms-tasks/terminal.d.ts +3 -0
  112. package/dist/rooms-tasks/terminal.js +10 -4
  113. package/dist/rooms-tasks/types.d.ts +94 -8
  114. package/dist/rooms-tasks/types.js +14 -1
  115. package/dist/runner.d.ts +12 -2
  116. package/dist/runner.js +167 -56
  117. package/dist/session/acp.d.ts +9 -1
  118. package/dist/session/acp.js +35 -9
  119. package/dist/session/arbiter.d.ts +2 -1
  120. package/dist/session/arbiter.js +2 -0
  121. package/dist/session/codex-app-server-transport.d.ts +53 -0
  122. package/dist/session/codex-app-server-transport.js +184 -0
  123. package/dist/session/codex-app-server.d.ts +122 -0
  124. package/dist/session/codex-app-server.js +1031 -0
  125. package/dist/session/control.d.ts +14 -1
  126. package/dist/session/control.js +51 -0
  127. package/dist/session/conversation-types.d.ts +4 -4
  128. package/dist/session/types.d.ts +24 -6
  129. package/dist/session/types.js +28 -0
  130. package/dist/spawn.d.ts +9 -0
  131. package/dist/spawn.js +77 -9
  132. package/dist/temp-lifecycle.d.ts +1 -1
  133. package/dist/web/fleet-config-service.d.ts +1 -0
  134. package/dist/web/fleet-config-service.js +27 -8
  135. package/dist/web/runtime.js +11 -6
  136. package/dist/web/server.js +28 -1
  137. package/dist/web-app/assets/{index-BbTc5KtZ.js → index-C0h3ALvs.js} +8 -8
  138. package/dist/web-app/index.html +1 -1
  139. package/package.json +5 -4
  140. package/presets/brain-catalog.json +17 -0
  141. package/presets/fleet/agent_templates/Critic.yaml +5 -0
  142. package/presets/fleet/agent_templates/Developer.yaml +5 -0
  143. package/presets/fleet/agent_templates/LocalCoordinator.yaml +50 -0
  144. package/presets/fleet/agents/FleetCoordinator.yaml +3 -0
  145. package/presets/fleet/brains/claude-default.yaml +5 -0
  146. package/presets/fleet/brains/claude-fable-5-high.yaml +5 -0
  147. package/presets/fleet/brains/claude-fable-5-low.yaml +5 -0
  148. package/presets/fleet/brains/claude-fable-5-max.yaml +5 -0
  149. package/presets/fleet/brains/claude-fable-5-medium.yaml +5 -0
  150. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +5 -0
  151. package/presets/fleet/brains/claude-opus-5-high.yaml +5 -0
  152. package/presets/fleet/brains/claude-opus-5-low.yaml +5 -0
  153. package/presets/fleet/brains/claude-opus-5-max.yaml +5 -0
  154. package/presets/fleet/brains/claude-opus-5-medium.yaml +5 -0
  155. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +5 -0
  156. package/presets/fleet/brains/claude-sonnet-5-high.yaml +5 -0
  157. package/presets/fleet/brains/claude-sonnet-5-low.yaml +5 -0
  158. package/presets/fleet/brains/claude-sonnet-5-max.yaml +5 -0
  159. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +5 -0
  160. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +5 -0
  161. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +5 -0
  162. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +5 -0
  163. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +5 -0
  164. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +5 -0
  165. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +5 -0
  166. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +5 -0
  167. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +5 -0
  168. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +5 -0
  169. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +5 -0
  170. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +5 -0
  171. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +5 -0
  172. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +5 -0
  173. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +5 -0
  174. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +5 -0
  175. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +5 -0
  176. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +5 -0
  177. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +5 -0
  178. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +5 -0
  179. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +5 -0
  180. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +5 -0
  181. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +5 -0
  182. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +5 -0
  183. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +5 -0
  184. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +5 -0
  185. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +5 -0
  186. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +5 -0
  187. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +5 -0
  188. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +5 -0
  189. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +5 -0
  190. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +5 -0
  191. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +5 -0
  192. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +5 -0
  193. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +5 -0
  194. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +5 -0
  195. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +5 -0
  196. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +5 -0
  197. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +5 -0
  198. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +5 -0
  199. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +5 -0
  200. package/presets/fleet/roles/Coordinator.yaml +30 -0
  201. package/presets/fleet/roles/Critic.yaml +28 -0
  202. package/presets/fleet/roles/Developer.yaml +28 -0
  203. package/presets/fleet/roles/LocalCoordinator.yaml +35 -0
  204. package/presets/fleet/room_templates/pair.yaml +13 -0
  205. package/presets/fleet/room_templates/single.yaml +9 -0
  206. package/presets/fleet/room_templates/team.yaml +16 -0
  207. package/presets/fleet.yaml +7 -0
  208. package/presets/manifest.json +6 -0
package/dist/docs.js CHANGED
@@ -6,11 +6,11 @@
6
6
  */
7
7
  export const AI_DOCS = `# ours-fleet reference
8
8
 
9
- ours-fleet runs persistent or temporary, identity-bound AI roles through the
10
- structured ACP session path:
9
+ ours-fleet runs persistent or temporary, identity-bound AI roles through a
10
+ provider-neutral managed-session interface:
11
11
 
12
12
  - harness: \`claude-code\` or \`codex\`
13
- - session: \`acp\` (default and only supported value)
13
+ - session: \`acp\` (default) or \`codex-app-server\` (Codex only)
14
14
  - lifetime: permanent (supervised, restartable) or \`spawn --temp\`
15
15
 
16
16
  ## Discover and validate
@@ -24,15 +24,25 @@ ours-fleet version [--json] # build identity, capabilities, every in
24
24
  \`\`\`
25
25
 
26
26
  Configuration v2 is \`~/fleet.yaml\` plus typed bare documents under the exact
27
- stem directories \`~/fleet/agents\`, \`~/fleet/roles\`, and \`~/fleet/brains\`.
27
+ stem directories \`~/fleet/agents\`, \`~/fleet/agent_templates\`, \`~/fleet/roles\`, \`~/fleet/brains\`, and
28
+ \`~/fleet/room_templates\`.
28
29
  The manifest owns fleet-wide operational defaults and automation; each Agent
29
30
  selects one inline/ref Role and Brain and carries its operational fields.
31
+ Agent Templates under \`~/fleet/agent_templates\` are inert reusable launch definitions;
32
+ only explicit files under \`~/fleet/agents\` are persistent lifecycle instances.
33
+ Room members use \`agent_template\` and receive immutable content-addressed snapshots.
34
+ An Agent Template may declare up to 64 temporary-only named \`loops\`; persistent Agent
35
+ instances reject them. Each loop requires \`interval\` (1m..30d) and bounded
36
+ nonblank \`prompt\`, with optional \`enabled\` (default true), \`initial_delay\`
37
+ (default interval, 0s..30d), and \`jitter\` (default 0s, < interval, <=1h).
38
+ Execution is fixed skip-if-busy with no ordinary missed-tick backlog/replay;
39
+ restart recovery may preserve at most one recent late occurrence.
30
40
  Legacy top-level \`roles:\` and \`fleet.d\` are rejected. Validate the complete
31
41
  trusted source set with \`config\` and \`doctor\` before starting or restarting.
32
42
 
33
43
  Permanent \`spawn\` writes \`~/fleet/agents/Name.yaml\`. The web console edits an
34
- explicit \`{manifest, agents}\` model while Role/Brain presets remain read-only.
35
- Its aggregate revision includes every Agent/Role/Brain source, previews a
44
+ explicit \`{manifest, agents, agent_templates}\` model while Role/Brain presets remain read-only.
45
+ Its aggregate revision includes every Agent/Role/Brain/Room-template source, previews a
36
46
  redacted per-document diff in an exact-stem private staging tree, and saves under
37
47
  one root lock with a private multi-file backup and full rollback. A no-op is
38
48
  byte-identical and creates no backup.
@@ -78,7 +88,7 @@ PATH order.
78
88
  ## Lifecycle and console commands
79
89
 
80
90
  \`\`\`sh
81
- ours-fleet init
91
+ ours-fleet init [-c FILE] # interactive missing-default seed; TTY required
82
92
  ours-fleet up|down [Name...]
83
93
  ours-fleet restart [Name...] # preserve/resume harness context
84
94
  ours-fleet force-restart [Name...] # fresh context; briefing is reloaded
@@ -91,6 +101,27 @@ ours-fleet watchdog-report <name> [run-id] [--list] [--json]
91
101
  ours-fleet watchdog-run <name>
92
102
  \`\`\`
93
103
 
104
+ \`init\` is an interactive missing-default workflow that preserves existing files byte-for-byte.
105
+ It names the resolved manifest and split directory, asks a default-No confirmation,
106
+ then subscriptions (Codex, Claude, or both), model assignment (one explicit model for
107
+ every job or explicit development/review/coordination choices), one reasoning level,
108
+ and a final default-No review. Quick/Balanced/Thorough generate low/medium/high.
109
+ Model pickers show packaged supported IDs; catalog membership is not a recommendation
110
+ or entitlement claim. Run \`ours-fleet doctor\` for local Codex availability; Claude
111
+ entitlement is checked when a role launches. The generated brains contain no
112
+ \`model_chain\`, so Fleet never silently substitutes another model.
113
+
114
+ At either confirmation, N, Enter, Escape, Ctrl-C, Ctrl-D, or EOF cancels. In a picker,
115
+ Escape, Ctrl-C, Ctrl-D, or EOF cancels; Enter records the highlight or continues a
116
+ non-empty multi-select, N is ignored, and an empty subscription selection remains blocked.
117
+ Every cancellation before final approval performs no host or configuration mutation.
118
+ Redirected/non-TTY invocation is refused with the same guarantee. After the final Yes,
119
+ host setup precedes publication. Path ownership/type/mode/symlink and
120
+ same-filesystem checks run before host setup and again under a per-setup lock. Publication
121
+ stages and validates the complete combined setup, backs up whichever old target(s) exist,
122
+ and retains a private recovery record. A hard process/host termination cannot promise
123
+ rollback; inspect host integration and private init stage/recovery evidence.
124
+
94
125
  \`peek\`, \`attach\`, and text \`send\` use the structured agent session.
95
126
  Attachment also accepts \`/permit <permission-id> <option-id>\`, \`/interrupt\`,
96
127
  and \`/detach\`.
@@ -161,7 +192,7 @@ Permanent spawn writes \`~/fleet/agents/Name.yaml\` and starts a supervised role
161
192
  \`--temp\` writes active state under \`~/.ours-fleet/tmp\` and starts an independent
162
193
  transient supervisor (a collected systemd unit or submitted launchd job). It is
163
194
  not enabled across reboot and does not die when the role that spawned it restarts.
164
- Brain definitions own the ACP session backend. When a temporary role's bound identity
195
+ Brain definitions own the managed session backend. When a temporary role's bound identity
165
196
  closes or its session ends, the supervisor, monitor and live roster entry retire
166
197
  together; state moves intact to \`~/.ours-fleet/recovery/temporary\` with a
167
198
  termination record. Failed launches use the same archive rather than deleting
@@ -193,11 +224,19 @@ only sustained authoritative absence closes the role. Unreachable, malformed, or
193
224
  valid-but-empty daemon indexes are ambiguous and reset closure debounce rather
194
225
  than becoming cleanup authority.
195
226
 
196
- Inside a managed ACP role, the same CLI automatically routes a real \`spawn\`
197
- through that role's authenticated supervisor control socket. \`--name Name\` is
198
- accepted as an alternative to the positional Agent name. The supervisor records the
199
- calling role, performs creation, and only after success sends a structured
200
- spawn notice through the caller's owner channel when one is configured.
227
+ Inside a managed role, public \`ours-fleet\` commands cross an authenticated
228
+ supervisor attribution boundary before Commander parsing. The original CLI remains
229
+ the executor inside the role's existing OS sandbox, and ordinary CLI validation is
230
+ the source of truth. Hidden worker entry points remain internal; public lifecycle and
231
+ operator commands are not restricted by the proxy.
232
+
233
+ Command invocation, raw argv, read-only work, validation failures, and generic
234
+ outcomes are never forwarded to the Owner-visible channel. Fleet announces only
235
+ confirmed Agent, Task, and Room lifecycle changes. Local diagnostics retain
236
+ structurally redacted command metadata. Lifecycle delivery uncertainty is logged,
237
+ never recursively announced, and never reruns or blindly retries an effect.
238
+ Room participant summaries describe creation and activation. Fleet has no public
239
+ post-create Room membership mutation, so it does not claim a separate membership event.
201
240
 
202
241
  Omitted Brain and Role selections, working directory, coordinator, neutral permissions,
203
242
  and fleet monitor policy inherit from the calling Agent. Explicit options always win.
@@ -212,6 +251,12 @@ Brain owns harness, session, model, reasoning effort, token limits, and native h
212
251
  options. Removed runtime flags are rejected with migration guidance rather than silently
213
252
  reinterpreted. A selection is a stable ID or an explicit \`inline:{...}\` mapping.
214
253
 
254
+ Packaged Developer, Critic, and LocalCoordinator Agent Templates set
255
+ \`monitor: { mode: fleet, interrupt: after_tool }\`. Every member of the standard
256
+ \`single\`, \`pair\`, and \`team\` Room Templates therefore resolves to fleet-owned,
257
+ after-tool delivery. Explicit per-member and custom Agent Template values remain
258
+ authoritative and merge key by key.
259
+
215
260
  ## fleet.yaml
216
261
 
217
262
  \`\`\`yaml
@@ -245,7 +290,7 @@ An Agent is a separate bare document under \`~/fleet/agents/<ID>.yaml\`:
245
290
 
246
291
  \`\`\`yaml
247
292
  role: { inline: { mission: Coordinate work and delegate implementation. } }
248
- brain: { inline: { harness: codex, session: acp, model: gpt-model-id } }
293
+ brain: { inline: { harness: codex, session: codex-app-server, model: gpt-model-id } }
249
294
  identity: Coordinator
250
295
  cwd: \${work_root}/project
251
296
  oversee: [{ agent: Worker, interval: 5m }]
@@ -274,6 +319,60 @@ the shared daemon only through an explicit operator or installer/setup flow.
274
319
 
275
320
  ## Rooms and tasks
276
321
 
322
+ \`init\` materializes editable \`single\`, \`pair\`, and \`team\` Room templates plus
323
+ their exact-cased Agent, Role, and Brain presets. The command prints the packaged
324
+ preset revision and source directory. Inspect provenance and content before use:
325
+
326
+ \`\`\`sh
327
+ ours-fleet config [-c FILE]
328
+ ours-fleet template list [-c FILE]
329
+ ours-fleet template show team [-c FILE]
330
+ ours-fleet task create --title "Solo task" --template single [-c FILE]
331
+ ours-fleet task create --title "Reviewed change" --template pair [-c FILE]
332
+ ours-fleet task create --title "Phased delivery" --template team [-c FILE]
333
+ ours-fleet spawn --temp Scout --role SELECTION --brain SELECTION --loops-file PRIVATE.yaml
334
+ ours-fleet task start TASK --member developer --loops-file PRIVATE.yaml
335
+ ours-fleet task start TASK --member critic --no-loops
336
+ \`\`\`
337
+
338
+ \`--loops-file\` must be an owner-only, non-symlink regular file <=1 MB containing
339
+ exactly one top-level non-empty \`loops:\` mapping. \`--no-loops\` explicitly
340
+ disables loops. They are mutually exclusive and rejected for permanent spawn.
341
+ For a grouped room member the whole CLI block overrides its Agent Template;
342
+ the template overrides omission. Omission preserves historical no-loop behavior
343
+ and never inherits manifest wildcard loops. Fleet validates before side effects,
344
+ seals normalized timings plus exact private prompts, and reuses that snapshot for
345
+ idempotent start, retry, recovery, and replacement. Trusted authoring and the
346
+ private sealed runtime retain exact prompts; resolved launch, task, room,
347
+ provenance, and audit presentations show source, policy, timing, prompt bytes,
348
+ and prompt SHA-256 instead of prompt text.
349
+
350
+ An alternate manifest \`-c /path/custom.yaml\` uses \`/path/custom/\` as its split
351
+ root. Repeated init only fills missing files and never adopts a newer default.
352
+ Exact known revision-3 through revision-5 packaged-bootstrap and generated role defaults have an exact-semantic,
353
+ fail-closed migration (dry-run by default):
354
+
355
+ \`ours-fleet migrate-role-defaults [-c FILE]\`
356
+ \`ours-fleet migrate-role-defaults [-c FILE] --write\`
357
+
358
+ Review removals, replacements, additions, preserved custom files, staging path,
359
+ and recovery path. Same-named custom files stay byte-identical; dangling custom
360
+ references refuse publication, and a successful rerun is a no-op. For explicit
361
+ single-file adoption, copy from init's reported packaged source beside the target
362
+ as \`.new-default\`, inspect \`diff -u TARGET TARGET.new-default\`, then replace it.
363
+
364
+ The exact generated six-worker legacy starter Agent set has its own fail-closed
365
+ migration (dry-run by default):
366
+
367
+ \`ours-fleet migrate-agent-templates [-c FILE]\`
368
+ \`ours-fleet migrate-agent-templates [-c FILE] --write\`
369
+
370
+ Review the dry-run moves, addition, staging path, and retained recovery-backup path
371
+ before \`--write\`. Customized/partial known starters and unsafe trees refuse without
372
+ mutation; unrelated custom persistent Agents remain persistent. A manifest-level template
373
+ may shadow a same-named file only with \`override_builtin: true\` and a higher
374
+ version; this compatibility marker is deprecated and reported as a diagnostic.
375
+
277
376
  Rooms always use \`ours-cowork\`; there is no room-provider selector. Configure
278
377
  the cowork daemon connection and room owner directly:
279
378
 
@@ -298,8 +397,37 @@ Fleet launches each template member with a dedicated one-time Cowork invite.
298
397
  The generated temporary-agent briefing contains the exact identity name, invite,
299
398
  Cowork role, and task. The agent creates that identity itself with ours MCP
300
399
  \`create_temporary_identity\`, accepts the invite with \`add_contact\`, and starts
301
- work immediately. Fleet activates the room from Cowork's authenticated seat; there
302
- is no briefing hash, startup ACK, or separate role-briefing readiness gate.
400
+ work immediately. A room is ready only after the Cowork room (and its task, when
401
+ task-bound) is durably active, every configured member seat is authenticated and active with its matching
402
+ live Fleet launch, and the configured Owner seat is active when owner attachment is
403
+ enabled. There is no briefing hash, startup ACK, or separate role-briefing readiness
404
+ gate.
405
+
406
+ Normal Task provisioning emits exactly one authenticated Owner lifecycle notice after
407
+ the ready predicate above is true; standalone Room provisioning likewise emits one
408
+ ready notice. Intermediate task, saga, member-spawn, timeout, and recoverable-failure
409
+ transitions stay in local state and logs. A terminal failed Task emits one actionable
410
+ failure notice; the command result carries the exact blocker and canonical recovery
411
+ action.
412
+
413
+ \`task start\` and create-and-start wait for readiness. If their bounded wait expires,
414
+ they return an explicit \`in_progress\` result and start a safe continuation. The detached
415
+ continuation is serialized per Task and remains alive until convergence or an
416
+ Owner-action blocker. Re-running \`task start <id>\` safely resumes the same durable
417
+ provisioning operation after the blocker is corrected or a process restarts.
418
+
419
+ Set \`room.anonymous: true\` on a room template, or pass \`--anonymous\` to
420
+ \`task create\`, \`task start\`, \`task work\`, or \`room create\`, to create an
421
+ anonymous Cowork room. \`--no-anonymous\` explicitly overrides an anonymous
422
+ template. Fleet records the resolved value before room creation so retries keep
423
+ the same choice. Temporary members of an anonymous room are instructed to call
424
+ \`create_temporary_identity\` with \`expose_local=false\`. Their generated briefings
425
+ do not disclose or compare an Owner participant CID. A participant-originated
426
+ instruction has Owner authority only when the authenticated Cowork room envelope
427
+ attributes that participant seat the exact \`Owner\` role. Literal text, display
428
+ names, ordinary direct messages, and room-authored or rest-role messages with an
429
+ Owner-looking label never grant that authority. Non-anonymous rooms remain pinned
430
+ to the exact authenticated Owner CID.
303
431
 
304
432
  Human task and room results use the same compact Markdown presentation in the
305
433
  CLI and authenticated owner channel: a short heading, icon-plus-word status,
@@ -349,11 +477,24 @@ The prerelease configuration names \`tasks.close_room_on_done\` and
349
477
  semantics. Older prerelease \`closed\` room records are deleted directly the next
350
478
  time \`room list\` reconciles Fleet with Cowork.
351
479
 
352
- \`ours-fleet task delete <id> <id>\` removes only a \`done\` task's Fleet backlog
353
- record. The exact task ID is required twice for confirmation. Delete rejects every
354
- other task state, never changes any room state, and reports an already-missing
355
- task as an idempotent no-op. The Owner-channel equivalent is
356
- \`/task delete <id> <id>\`.
480
+ \`ours-fleet task delete <id> <id>\` permanently deletes a task in ANY lifecycle
481
+ state — backlog, provisioning, active, blocked, review, done, cancelled, failed,
482
+ or partially settled. The exact task ID is required twice for confirmation. A
483
+ durable deletion intent is persisted before any side effect; the cleanup worker
484
+ then retires managed room members with evidence, closes and deletes an attached
485
+ room (tolerating already-missing remote rooms), releases the sealed launch
486
+ snapshot, and unlinks the task record last. While cleanup settles the task is
487
+ hidden from normal listings and every lifecycle mutation is rejected; if
488
+ cleanup cannot complete (for example Cowork is unreachable), the deletion stays
489
+ in a precise resumable state — repeat the identical delete command to converge
490
+ after outages, crashes, or restarts. Deletion
491
+ never fabricates a \`done\` transition. A metadata-only deletion receipt
492
+ (acceptance actor, original state, timestamps, completion) is retained under
493
+ \`deletion-receipts/\` as durable audit evidence. An already-missing task is an
494
+ idempotent no-op. The Owner-channel equivalent is \`/task delete <id> <id>\`; the
495
+ management API equivalent is \`DELETE /api/v1/tasks/<id>?confirm=<id>\` (200 when
496
+ settled, 202 while pending; \`GET /api/v1/tasks?includeDeleting=true\` exposes
497
+ deletion-pending tasks to operators).
357
498
 
358
499
  ## Permissions
359
500
 
@@ -362,12 +503,13 @@ Prefer the harness-neutral \`permissions\` block:
362
503
  - \`approval: ask|auto|allow\`: portable permission policy. \`deny\` remains a
363
504
  deprecated, fail-closed compatibility alias for existing fleet files.
364
505
  - \`filesystem: read-only|workspace|unrestricted\`: filesystem intent
365
- - \`unattended: deny|wait\`: what ACP does when no console can answer a request
506
+ - \`unattended: deny|wait\`: what a managed session does when no console can
507
+ answer a request
366
508
 
367
- The backend translates this common intent. Harness-native settings in
368
- \`harness_options\` take precedence where supplied. Do not choose
369
- \`allow\`/\`unrestricted\`, Codex \`never\`/\`danger-full-access\`, or Claude
370
- \`bypassPermissions\` without explicit authorization.
509
+ The backend translates this common intent. Native Codex app-server roles reject
510
+ permission aliases in \`harness_options\`; Codex ACP and Claude retain their
511
+ legacy native-override compatibility. Do not choose \`allow\`/\`unrestricted\`
512
+ or Claude \`bypassPermissions\` without explicit authorization.
371
513
 
372
514
  ### Creation-time isolation
373
515
 
@@ -440,12 +582,14 @@ permissions through its harness and check the result against a fixed floor:
440
582
  deny those requests with nobody to see it; with \`unattended: wait\` it warns,
441
583
  because a human can still attach and answer.
442
584
 
443
- Security meaning: \`ask\` maps to Codex \`untrusted\` and Claude \`default\`.
444
- \`auto\` selects Codex ACP \`agent\` (\`on-request\` + \`workspace-write\`) and
445
- Claude \`acceptEdits\`. \`approval: allow\` selects Codex ACP's fully
446
- non-interactive yolo mode, reported as \`agent-full-access\` (\`never\` +
447
- \`danger-full-access\`), and Claude \`bypassPermissions\`. These modes genuinely
448
- permit the actions the role was authorized to take —
585
+ Security meaning: native Codex maps \`ask\` → \`untrusted\`, \`auto\` →
586
+ \`on-request\`, and \`allow\` → \`never\`; its independent filesystem mapping is
587
+ \`read-only\` → \`read-only\`, \`workspace\` → \`workspace-write\`, and
588
+ \`unrestricted\` → \`danger-full-access\`. Users configure only the Fleet names.
589
+ Claude maps \`ask\` to \`default\`, \`auto\` to \`acceptEdits\`, and \`allow\` to
590
+ \`bypassPermissions\`. Codex ACP retains its adapter-specific coupled modes:
591
+ \`auto\` selects \`agent\`, while \`allow\` selects \`agent-full-access\`. These
592
+ modes genuinely permit the actions the role was authorized to take —
449
593
  \`dontAsk\` only suppresses the prompt while still refusing the action. Nothing
450
594
  other than an explicit \`allow\` becomes non-interactive. Legacy \`deny\` keeps
451
595
  its conservative Codex \`on-request\` / Claude \`plan\` translation. \`allow\` is therefore a real grant and
@@ -500,10 +644,31 @@ refused at validation rather than accepted and dropped. This narrows a role's
500
644
  tool surface; it does not stop the harness deferring tool schemas, which is the
501
645
  harness's own decision.
502
646
 
503
- Codex \`harness_options\`: \`launcher\` (auto, ours-codex, codex), \`sandbox\`
504
- (read-only, workspace-write, danger-full-access), \`approval\` or
505
- \`permission_mode\` (untrusted, on-request, never), \`profile\`, \`search\`,
506
- \`config\`, \`add_dirs\`, and \`monitor\`.
647
+ Codex \`harness_options\`: \`launcher\` (auto, ours-codex, codex), \`search\`,
648
+ \`config\`, \`add_dirs\`, and \`monitor\`; Codex ACP additionally supports
649
+ \`profile\`. Native app-server roles reject \`profile\` because Codex does not
650
+ accept \`--profile\` for \`app-server\`. They
651
+ must express approval and filesystem authority through the shared
652
+ \`permissions:\` block, never through harness options. The adapter translates
653
+ \`ask|auto|allow\` to Codex \`untrusted|on-request|never\` and translates
654
+ \`read-only|workspace|unrestricted\` to Codex
655
+ \`read-only|workspace-write|danger-full-access\`. Native \`config\` currently
656
+ allows only \`model_reasoning_effort\`; ACP retains the broader Codex config surface.
657
+
658
+ For Codex, the opt-in \`session: codex-app-server\` directly runs Codex's native
659
+ JSONL app server behind Fleet's provider-neutral session contract. It supports native item
660
+ streaming, commentary/final phases, prompt admission, steering, interruption,
661
+ permission requests, durable conversation projection, and thread resume. Packaged
662
+ Codex brains and the init wizard continue to select \`session: acp\` for compatibility;
663
+ Claude Code also uses ACP. Native Codex defaults to \`codex app-server\` (or \`ours-codex app-server\`
664
+ when launcher auto finds it). Override the exact command when necessary:
665
+
666
+ \`session_options: { codex_app_server: { command: [codex, app-server] } }\`
667
+
668
+ An exact command override receives no appended profile, search, or subcommand
669
+ arguments. Native sessions persist their Codex thread in Fleet's \`.session-id\`
670
+ and participate in its bounded fresh/resume recovery; cross-provider conversation
671
+ portability is never assumed.
507
672
 
508
673
  ## ACP adapters
509
674
 
@@ -511,8 +676,7 @@ The maintained \`@agentclientprotocol/codex-acp\` and
511
676
  \`@agentclientprotocol/claude-agent-acp\` runtimes are bundled automatically as
512
677
  optional ours-fleet dependencies. The supervisor resolves their executable
513
678
  entrypoints internally, so default ACP roles do not depend on global PATH.
514
- The maintained Claude adapter requires Node 22; Codex ACP continues to work on
515
- the ours-fleet core minimum of Node 20.
679
+ ours-fleet and both maintained adapters require Node 22 or newer.
516
680
 
517
681
  Override an adapter only when necessary with \`session_options.acp.command\`
518
682
  (string or argv list). If optional dependencies were deliberately omitted,
@@ -556,7 +720,7 @@ Inspect \`ours-fleet status Name\`, \`peek Name\`, role logs, and
556
720
 
557
721
  ## Trusted owner channel
558
722
 
559
- An ACP role may declare a separate ours identity which fleet — never the agent —
723
+ Any managed role may declare a separate ours identity which fleet — never the agent —
560
724
  creates when missing and binds:
561
725
 
562
726
  \`\`\`yaml
@@ -609,6 +773,13 @@ adapter executes them locally (claude-code: all three; codex: \`/compact\`
609
773
  only) and are otherwise refused with a notice, so slash text never reaches the
610
774
  model as a prompt.
611
775
 
776
+ The supervisor advertises the same primary registry entries as recipient-scoped
777
+ ours typed commands. Their single arguments field is converted back to the text
778
+ after the slash command name and enters the same dispatcher; aliases stay
779
+ slash-only. Typed handlers repeat the live authenticated Owner-CID check before
780
+ dispatch and return a null protocol completion because the existing correlated
781
+ owner-channel reply remains the result.
782
+
612
783
  While a request runs, the agent's live ACP commentary is relayed as messages
613
784
  prefixed with the single stable label \`🟡 Live update:\`, so an owner can see
614
785
  exactly which messages the setting controls. \`owner_channel.comments\`
@@ -657,12 +828,12 @@ provenance checks.
657
828
  The channel identity must be unique and must not be a role identity. The bridge
658
829
  persists bounded wire IDs only, never message/reply plaintext, and requeues input
659
830
  before starting its turn for at-least-once crash recovery. It currently requires
660
- the structured agent-session interface backed by ACP so correlated final replies
661
- retain their delivery guarantee.
831
+ the structured agent-session interface so correlated final replies retain their
832
+ delivery guarantee.
662
833
 
663
834
  ### Live contact and owner administration
664
835
 
665
- The supervisor which is already running the ACP role remains the sole binder of
836
+ The supervisor which is already running the managed role remains the sole binder of
666
837
  \`owner_channel.identity\`. The CLI reaches that exact live \`OwnerChannel\`
667
838
  through the role's token-authenticated, mode-0600 Unix control socket for contact
668
839
  inspection and setup; it never starts another ours client and never force-binds:
package/dist/doctor.d.ts CHANGED
@@ -15,5 +15,7 @@ export declare function doctor(opts?: {
15
15
  path?: string;
16
16
  argv1?: string;
17
17
  };
18
+ /** Override the local Codex model cache path (tests). */
19
+ codexCatalogPath?: string;
18
20
  }, exec?: Exec, platform?: NodeJS.Platform, fetchImpl?: FetchLike, attachDaemon?: AttachDoctorDaemon): Promise<PrereqReport>;
19
21
  export {};
package/dist/doctor.js CHANGED
@@ -13,6 +13,8 @@ import { authResolutionHint, resolveEndpoint, } from './monitor.js';
13
13
  import { readScheduledLoops, storedLoopHealth } from './loops/state.js';
14
14
  import { controlSocketPath } from './session/control.js';
15
15
  import { analyzeInstalls, buildInfo, buildLabel, discoverInstalls, BIN_NAME, } from './provenance.js';
16
+ import { readDaemonRecoveryStatus } from './daemon-recovery.js';
17
+ import { codexModelCatalog } from './application/model-catalog.js';
16
18
  /** Which cgroup-v2 controllers are delegated to this user manager (advisory). */
17
19
  function cgroupDelegationDetail() {
18
20
  try {
@@ -106,6 +108,35 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
106
108
  ok: true,
107
109
  detail: `warning: ${diagnostic.message}`,
108
110
  });
111
+ if (loaded.ok) {
112
+ const packaged = Object.entries(loaded.brainPresets ?? {}).flatMap(([id, brain]) => brain.harness === 'codex' && typeof brain.model === 'string' && typeof brain.effort === 'string'
113
+ ? [{ id, model: brain.model, effort: brain.effort }] : [])
114
+ .sort((a, b) => a.id.localeCompare(b.id));
115
+ if (packaged.length) {
116
+ const runtime = codexModelCatalog(opts.codexCatalogPath);
117
+ const available = new Set(runtime.models.flatMap(model => model.reasoningEfforts.map(effort => `${model.id}\0${effort}`)));
118
+ const missing = packaged.filter(({ model, effort }) => !available.has(`${model}\0${effort}`));
119
+ checks.push({ name: 'brain catalog: Codex runtime drift', ok: true,
120
+ detail: runtime.models.length
121
+ ? missing.length ? `warning: packaged Brain preset(s) absent from local Codex catalog: ${missing
122
+ .map(({ id, model, effort }) => `${id} (${model}/${effort})`).join(', ')}`
123
+ : `all ${packaged.length} packaged Codex model/effort pairs are present locally`
124
+ : runtime.warnings.join('; ') });
125
+ }
126
+ }
127
+ for (const role of roles) {
128
+ const recovery = readDaemonRecoveryStatus(agentDir(role.name));
129
+ if (!recovery)
130
+ continue;
131
+ const paths = ['agent', 'owner']
132
+ .map(name => `${name}=${recovery.paths[name].state}`)
133
+ .join(', ');
134
+ checks.push({
135
+ name: `daemon recovery: ${role.name}`,
136
+ ok: recovery.state === 'recovered',
137
+ detail: `${recovery.state}; ${paths}; epoch ${recovery.epoch || 'unavailable'}`,
138
+ });
139
+ }
109
140
  // ── Rooms/tasks checks ────────────────────────────────────────
110
141
  if (loaded.ok && loaded.rooms) {
111
142
  const rooms = loaded.rooms;
@@ -146,16 +177,16 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
146
177
  const { listTemplates, resolveTemplate } = await import('./rooms-tasks/templates.js');
147
178
  const customs = loaded.roomTemplates ?? {};
148
179
  const templates = listTemplates(customs);
149
- const roleNames = new Set(roles.map(r => r.name));
180
+ const agentTemplateNames = new Set(Object.keys(loaded.agentTemplates ?? {}));
150
181
  for (const t of templates) {
151
182
  const badRefs = t.members
152
- .filter(m => 'ref' in m.agent && !roleNames.has(m.agent.ref))
153
- .map(m => 'ref' in m.agent ? m.agent.ref : '');
183
+ .filter(m => !agentTemplateNames.has(m.agent_template))
184
+ .map(m => m.agent_template);
154
185
  if (badRefs.length) {
155
186
  checks.push({
156
187
  name: `template: ${t.name}@${t.version}`,
157
188
  ok: true,
158
- detail: `warning: Agent ref(s) ${badRefs.join(', ')} not found in configured Agents`,
189
+ detail: `warning: Agent Template(s) ${badRefs.join(', ')} not found`,
159
190
  });
160
191
  }
161
192
  }
@@ -513,6 +544,23 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
513
544
  : `${command} not found or failed — install the ACP adapter or set session_options.acp.command`,
514
545
  });
515
546
  }
547
+ for (const role of roles.filter(role => role.session === 'codex-app-server')) {
548
+ const configured = role.session_options?.codex_app_server?.command;
549
+ const launcher = role.harness_options?.launcher;
550
+ const command = Array.isArray(configured)
551
+ ? configured[0]
552
+ : typeof configured === 'string'
553
+ ? configured.trim().split(/\s+/)[0]
554
+ : launcher === 'ours-codex' ? 'ours-codex' : 'codex';
555
+ const result = await exec('sh', ['-c', 'command -v "$1" >/dev/null 2>&1', 'sh', command]);
556
+ checks.push({
557
+ name: `codex-app-server: ${role.name}`,
558
+ ok: result.code === 0,
559
+ detail: result.code === 0
560
+ ? `${command} available`
561
+ : `${command} not found — install Codex CLI or set session_options.codex_app_server.command`,
562
+ });
563
+ }
516
564
  return { ok: checks.every(c => c.ok), checks };
517
565
  }
518
566
  function loadConfigResult(configPath, yamlMode) {
@@ -521,6 +569,8 @@ function loadConfigResult(configPath, yamlMode) {
521
569
  return {
522
570
  ok: true, roles: cfg.roles, files: cfg.files, diagnostics: cfg.diagnostics,
523
571
  rooms: cfg.rooms, roomTemplates: cfg.roomTemplates, tasks: cfg.tasks,
572
+ agentTemplates: cfg.agentTemplates,
573
+ brainPresets: cfg.brainPresets,
524
574
  ownerInviteFingerprint: cfg.ownerInviteFingerprint,
525
575
  };
526
576
  }