@ours.network/fleet 1.1.0-nightly.1 → 1.1.0-nightly.11
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 +133 -95
- package/dist/agent-recovery-gate.d.ts +17 -0
- package/dist/agent-recovery-gate.js +135 -0
- package/dist/application/fleet-query-service.js +15 -2
- package/dist/application/role-command-service.js +9 -0
- package/dist/application/role-creation-service.d.ts +2 -21
- package/dist/application/role-creation-service.js +26 -64
- package/dist/application/role-removal-service.js +6 -3
- package/dist/application/task-room-service.d.ts +7 -1
- package/dist/application/task-room-service.js +269 -69
- package/dist/application/types.d.ts +1 -1
- package/dist/briefing.js +11 -7
- package/dist/build-info.json +4 -4
- package/dist/canonical-json.d.ts +2 -0
- package/dist/canonical-json.js +10 -0
- package/dist/cli.js +178 -65
- package/dist/config-yaml.d.ts +1 -1
- package/dist/config.d.ts +87 -2
- package/dist/config.js +526 -28
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +2 -2
- package/dist/daemon-recovery.d.ts +93 -0
- package/dist/daemon-recovery.js +328 -0
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +94 -102
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.js +38 -5
- package/dist/fleet-command-audit.d.ts +160 -0
- package/dist/fleet-command-audit.js +437 -0
- package/dist/fleet-proxy.d.ts +2 -0
- package/dist/fleet-proxy.js +30 -8
- package/dist/generated-agent-source.d.ts +9 -0
- package/dist/generated-agent-source.js +53 -0
- package/dist/harness/agent-session.d.ts +18 -0
- package/dist/harness/claude-code-session.d.ts +6 -0
- package/dist/harness/claude-code-session.js +8 -0
- package/dist/harness/claude-code.js +12 -0
- package/dist/harness/codex-session.d.ts +6 -0
- package/dist/harness/codex-session.js +8 -0
- package/dist/harness/codex.js +20 -0
- package/dist/harness/registry.js +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/init-guidance.d.ts +1 -0
- package/dist/init-guidance.js +6 -0
- package/dist/model-env.d.ts +2 -3
- package/dist/model-env.js +3 -5
- package/dist/ops.js +6 -19
- package/dist/owner-channel/channel.d.ts +56 -0
- package/dist/owner-channel/channel.js +269 -29
- package/dist/owner-channel/commands.d.ts +2 -0
- package/dist/owner-channel/commands.js +31 -13
- package/dist/owner-channel/state.d.ts +2 -0
- package/dist/owner-channel/state.js +8 -2
- package/dist/preset-bootstrap.d.ts +10 -0
- package/dist/preset-bootstrap.js +85 -0
- package/dist/preset-migration.d.ts +27 -0
- package/dist/preset-migration.js +200 -0
- package/dist/reports/artifact.d.ts +10 -0
- package/dist/reports/artifact.js +32 -0
- package/dist/reports/index.d.ts +5 -0
- package/dist/reports/index.js +5 -0
- package/dist/reports/render.d.ts +6 -0
- package/dist/reports/render.js +240 -0
- package/dist/reports/service.d.ts +42 -0
- package/dist/reports/service.js +57 -0
- package/dist/reports/tasks.d.ts +52 -0
- package/dist/reports/tasks.js +177 -0
- package/dist/reports/types.d.ts +315 -0
- package/dist/reports/types.js +6 -0
- package/dist/resolved-plan.d.ts +3 -2
- package/dist/resolved-plan.js +25 -5
- package/dist/rooms-tasks/cli.d.ts +2 -0
- package/dist/rooms-tasks/cli.js +342 -65
- package/dist/rooms-tasks/config.js +12 -14
- package/dist/rooms-tasks/external-worker.d.ts +1 -0
- package/dist/rooms-tasks/external-worker.js +14 -9
- package/dist/rooms-tasks/launch-snapshot.d.ts +10 -0
- package/dist/rooms-tasks/launch-snapshot.js +159 -0
- package/dist/rooms-tasks/member-overrides.d.ts +27 -0
- package/dist/rooms-tasks/member-overrides.js +170 -0
- package/dist/rooms-tasks/provision.js +82 -37
- package/dist/rooms-tasks/room-state.js +4 -0
- package/dist/rooms-tasks/task-state.d.ts +2 -0
- package/dist/rooms-tasks/task-state.js +19 -1
- package/dist/rooms-tasks/templates.d.ts +4 -2
- package/dist/rooms-tasks/templates.js +42 -78
- package/dist/rooms-tasks/types.d.ts +36 -17
- package/dist/rooms-tasks/types.js +2 -4
- package/dist/runner.d.ts +9 -2
- package/dist/runner.js +84 -20
- package/dist/sensitive-config.d.ts +2 -0
- package/dist/sensitive-config.js +4 -0
- package/dist/session/acp.d.ts +5 -0
- package/dist/session/acp.js +27 -3
- package/dist/session/control.d.ts +14 -1
- package/dist/session/control.js +35 -0
- package/dist/spawn.d.ts +8 -33
- package/dist/spawn.js +64 -212
- package/dist/temp-lifecycle.d.ts +1 -1
- package/dist/watchdog/config.d.ts +10 -7
- package/dist/watchdog/config.js +29 -19
- package/dist/watchdog/run.js +4 -13
- package/dist/web/fleet-config-service.d.ts +12 -8
- package/dist/web/fleet-config-service.js +404 -185
- package/dist/web/topology-promote.js +25 -15
- package/dist/web/topology.js +2 -2
- package/dist/web/yaml-document-edit.js +2 -0
- package/dist/web-app/assets/index-C0h3ALvs.js +10 -0
- package/dist/web-app/index.html +1 -1
- package/examples/fleet/agents/Alice.yaml +11 -0
- package/examples/fleet/agents/FleetCoordinator.yaml +7 -0
- package/examples/fleet/brains/claude-default.yaml +5 -0
- package/examples/fleet/roles/coordinator.yaml +5 -0
- package/examples/fleet/roles/developer.yaml +3 -0
- package/examples/fleet.yaml +74 -0
- package/package.json +3 -1
- package/presets/brain-catalog.json +16 -0
- package/presets/fleet/agent_templates/Agent.yaml +3 -0
- package/presets/fleet/agent_templates/Architect.yaml +3 -0
- package/presets/fleet/agent_templates/Critic.yaml +3 -0
- package/presets/fleet/agent_templates/Developer.yaml +3 -0
- package/presets/fleet/agent_templates/Secretary.yaml +3 -0
- package/presets/fleet/agent_templates/Tester.yaml +3 -0
- package/presets/fleet/agents/FleetCoordinator.yaml +4 -0
- package/presets/fleet/brains/claude-default.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +5 -0
- package/presets/fleet/roles/Agent.yaml +6 -0
- package/presets/fleet/roles/Architect.yaml +6 -0
- package/presets/fleet/roles/Critic.yaml +6 -0
- package/presets/fleet/roles/Developer.yaml +6 -0
- package/presets/fleet/roles/Secretary.yaml +6 -0
- package/presets/fleet/roles/Tester.yaml +6 -0
- package/presets/fleet/room_templates/pair.yaml +11 -0
- package/presets/fleet/room_templates/single.yaml +8 -0
- package/presets/fleet/room_templates/team.yaml +12 -0
- package/presets/fleet.yaml +7 -0
- package/presets/manifest.json +6 -0
- package/dist/web-app/assets/index-DhMDVRU1.js +0 -10
package/README.md
CHANGED
|
@@ -19,10 +19,10 @@ turns such sessions into **roles**: long-lived agents that
|
|
|
19
19
|
- can **spawn subagents** (permanent or temporary) and **oversee** them: peek into
|
|
20
20
|
a ward's console, answer a stuck prompt, nudge it back to work.
|
|
21
21
|
|
|
22
|
-
The
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
reality match
|
|
22
|
+
The fleet uses a v2 manifest plus typed documents: `~/fleet.yaml` holds
|
|
23
|
+
fleet-wide operational policy and automation, while `~/fleet/agents`,
|
|
24
|
+
`~/fleet/roles`, and `~/fleet/brains` hold bare Agent, Role, and Brain documents.
|
|
25
|
+
`ours-fleet up` makes reality match that trusted split source set.
|
|
26
26
|
|
|
27
27
|
**Harness-agnostic by design.** The core never assumes a specific agent CLI; each
|
|
28
28
|
harness is a small adapter (how to launch, how to resume, how to wire config).
|
|
@@ -31,17 +31,19 @@ public — each additional harness (Gemini CLI, OpenCode, …) is a small adapte
|
|
|
31
31
|
A single fleet can mix harnesses per role:
|
|
32
32
|
|
|
33
33
|
```yaml
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
# ~/fleet/agents/Reviewer.yaml
|
|
35
|
+
role: { ref: reviewer }
|
|
36
|
+
brain: { inline: { harness: claude-code, session: acp } }
|
|
37
|
+
|
|
38
|
+
# ~/fleet/agents/Prototyper.yaml
|
|
39
|
+
role: { inline: { mission: Build prototypes } }
|
|
40
|
+
brain: { inline: { harness: codex, session: acp } }
|
|
39
41
|
```
|
|
40
42
|
|
|
41
43
|
## How it works
|
|
42
44
|
|
|
43
45
|
```
|
|
44
|
-
~/fleet.yaml + ~/fleet
|
|
46
|
+
~/fleet.yaml + ~/fleet/{agents,agent_templates,roles,brains,room_templates}/*.yaml your declaration
|
|
45
47
|
│ ours-fleet up
|
|
46
48
|
▼
|
|
47
49
|
briefing.md per role ──► agent session adapter ──► ACP client/session ──► ACP agent
|
|
@@ -89,7 +91,7 @@ equivalent); logs land in `~/.ours-fleet/logs/`.
|
|
|
89
91
|
|
|
90
92
|
```sh
|
|
91
93
|
npm i -g @ours.network/fleet
|
|
92
|
-
ours-fleet init # units/dirs/linger
|
|
94
|
+
ours-fleet init # units/dirs/linger + missing standard presets
|
|
93
95
|
ours-fleet doctor # verifies everything above, with actionable messages
|
|
94
96
|
```
|
|
95
97
|
|
|
@@ -105,8 +107,9 @@ become that account and repeat.
|
|
|
105
107
|
## Quickstart
|
|
106
108
|
|
|
107
109
|
```sh
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
ours-fleet init # safe to repeat: creates missing files, never replaces edits
|
|
111
|
+
ours-fleet config # validates Agents, Roles, Brains, and Room templates
|
|
112
|
+
$EDITOR ~/fleet/agents/*.yaml # compose Role + Brain and operational settings
|
|
110
113
|
ours-fleet up # boot the fleet (staggered)
|
|
111
114
|
ours-fleet ls # running consoles
|
|
112
115
|
ours-fleet attach Alice # watch one live (Ctrl-b d to leave)
|
|
@@ -123,19 +126,16 @@ ours-fleet spawn Worker --mission "own the worker repo" \
|
|
|
123
126
|
ours-fleet spawn --temp Scout --mission "one-off research" # gone on exit/reboot
|
|
124
127
|
|
|
125
128
|
# Codex role: ours-codex is preferred automatically; plain codex is the fallback
|
|
126
|
-
ours-fleet spawn Coder --
|
|
127
|
-
--
|
|
128
|
-
--profile fleet --search --monitor --coordinator FleetCoordinator
|
|
129
|
-
# Note: --monitor is legacy consent for Codex's native monitor. Choose the
|
|
130
|
-
# wake owner separately in fleet.yaml with monitor.mode: fleet|native.
|
|
129
|
+
ours-fleet spawn Coder --brain codex-fleet --role developer \
|
|
130
|
+
--approval ask --filesystem workspace --coordinator FleetCoordinator
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
Inside a managed ACP role, `ours-fleet spawn` is transparently routed through
|
|
134
|
-
that role's live supervisor. `ours-fleet spawn
|
|
135
|
-
minimal form: omitted
|
|
136
|
-
fleet monitor policy
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
that role's live supervisor. `ours-fleet spawn DeveloperX --temp` is the
|
|
135
|
+
minimal form: omitted Brain/Role selections, cwd, coordinator, neutral permissions,
|
|
136
|
+
and fleet monitor policy inherit from the caller. Identity, environment, owner routing,
|
|
137
|
+
room startup, and sensitive inline Brain values do not. Explicit flags win. After
|
|
138
|
+
creation succeeds, fleet can deterministically notify
|
|
139
139
|
the caller's owner channel with the caller and spawned-role details. This is an
|
|
140
140
|
honest-actor convenience and attribution path, not a security boundary; host
|
|
141
141
|
shells and deliberately bypassed absolute binaries retain direct behavior.
|
|
@@ -252,27 +252,19 @@ Security boundaries:
|
|
|
252
252
|
- tests use temporary fleet homes and fake supervisors/identity providers—never
|
|
253
253
|
active role state.
|
|
254
254
|
|
|
255
|
-
Permanent spawns
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
block sequence — adding or removing an entry under `watch:`, `oversee:`, `roles:`
|
|
269
|
-
or `wake_sources:` — rewrites that one collection as a whole, which drops inline
|
|
270
|
-
comments written on its individual items. The loss is confined to the collection
|
|
271
|
-
you edited, is shown in the diff before anything is written, and can be declined
|
|
272
|
-
by not saving. Each write is revision-guarded, reviewed as a diff of the real
|
|
273
|
-
file, validated with the real loader, and preceded by a timestamped backup.
|
|
274
|
-
Values under `env:` — and the `vars:` entries they interpolate — are masked in
|
|
275
|
-
the diff and never leave the host.
|
|
255
|
+
Permanent spawns write a bare Agent document to
|
|
256
|
+
`~/fleet/agents/<Name>.yaml`; generated-source ownership is recorded so removal
|
|
257
|
+
never deletes an unproven hand-written neighbor. `ours-fleet rm <Name>` unspawns.
|
|
258
|
+
|
|
259
|
+
The web editor reads and writes the split document model explicitly as
|
|
260
|
+
`{manifest, agents}`. Role and Brain presets are visible through Agent refs but
|
|
261
|
+
remain read-only. Saves use one aggregate revision over the manifest and all
|
|
262
|
+
Agent/Role/Brain sources, validate an exact-stem private staging tree, show a
|
|
263
|
+
deterministic redacted diff per document, and hold one manifest-root lock.
|
|
264
|
+
Changed/deleted files are backed up together; any partial failure restores every
|
|
265
|
+
document or reports the private recovery directory. An unchanged save is a
|
|
266
|
+
byte-for-byte no-op and creates no backup. Nested environment, authentication,
|
|
267
|
+
invite, and isolation secrets never leave the host.
|
|
276
268
|
|
|
277
269
|
From inside Claude Code, Codex, or Hermes with the core `ours` plugin installed,
|
|
278
270
|
say **"spawn an ours agent …"**. The core skill checks for `ours-fleet`, installs
|
|
@@ -290,16 +282,16 @@ ours-fleet peek Worker # what is it doing?
|
|
|
290
282
|
ours-fleet send Worker "continue with the tests, then report"
|
|
291
283
|
```
|
|
292
284
|
|
|
293
|
-
Declare standing assignments in
|
|
285
|
+
Declare standing assignments in the overseer's bare Agent document (rendered into its
|
|
294
286
|
briefing) — or just write "keep an eye on Alice and Bob every 5 minutes" in a
|
|
295
287
|
persona; the bundled `oversee-agents` skill defines what that means operationally:
|
|
296
288
|
|
|
297
289
|
```yaml
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
290
|
+
role: { ref: coordinator }
|
|
291
|
+
brain: { ref: claude-default }
|
|
292
|
+
oversee:
|
|
293
|
+
- { agent: Alice, interval: 5m }
|
|
294
|
+
- { agent: Bob, interval: 5m }
|
|
303
295
|
```
|
|
304
296
|
|
|
305
297
|
## Command reference
|
|
@@ -310,7 +302,7 @@ ours-fleet up|down|restart|force-restart [-c FILE] [Name...]
|
|
|
310
302
|
ours-fleet config [-c FILE] validate + print merged plan
|
|
311
303
|
ours-fleet ls | attach | peek | logs [-f] | status <Name>
|
|
312
304
|
ours-fleet send <Name> "text"
|
|
313
|
-
ours-fleet spawn [--temp] [<Name> | --
|
|
305
|
+
ours-fleet spawn [--temp] [<Name> | --name <Name>] --brain <ID|inline:{...}> --role <ID|inline:{...}> [--approval ...]
|
|
314
306
|
ours-fleet loops validate|list|status
|
|
315
307
|
ours-fleet loops reload <Role>
|
|
316
308
|
ours-fleet loops run-now|disable|enable <Role> <Loop>
|
|
@@ -342,33 +334,64 @@ in its state dir) across supervisor-triggered restarts — systemd/launchd re-in
|
|
|
342
334
|
agent process with no arguments, so without this the role would silently fall back to
|
|
343
335
|
the default `~/fleet.yaml` on its very first crash-restart and fail to resolve.
|
|
344
336
|
|
|
345
|
-
##
|
|
337
|
+
## split configuration field reference
|
|
346
338
|
|
|
347
|
-
|
|
339
|
+
The following is a schematic field inventory, not a single YAML document. Host
|
|
340
|
+
settings belong in `~/fleet.yaml`; reusable behavior and harness settings belong
|
|
341
|
+
in `~/fleet/roles/<id>.yaml` and `~/fleet/brains/<id>.yaml`; operational fields
|
|
342
|
+
belong in `~/fleet/agents/<id>.yaml`.
|
|
343
|
+
|
|
344
|
+
```text
|
|
348
345
|
vars: { work_root: /home/me/work } # ${var} substitution anywhere below
|
|
346
|
+
api_version: ours.network/fleet/v2
|
|
349
347
|
start_stagger_ms: 0 # delay between agent LAUNCHES (host-wide, ms); 0 = no stagger
|
|
350
348
|
defaults:
|
|
351
|
-
harness: claude-code # for roles that don't set one
|
|
352
|
-
session: acp # supported Fleet↔agent session path
|
|
353
349
|
permissions: # common intent, translated by each harness/backend
|
|
354
350
|
approval: ask # ask | auto | allow (`deny` is a deprecated alias)
|
|
355
351
|
filesystem: workspace # read-only | workspace | unrestricted
|
|
356
352
|
unattended: deny # deny | wait
|
|
357
|
-
model: claude-fable-5 # default model for roles that don't set one (per-role model / --model wins)
|
|
358
|
-
max_tokens: 500000 # session cap (harness-interpreted)
|
|
359
353
|
monitor:
|
|
360
354
|
mode: fleet # fleet (default) | native
|
|
361
355
|
worklog: # built-ins shown; set false to opt out
|
|
362
356
|
max_kb: 1024 # rotate only above this active-log size
|
|
363
357
|
keep_tail_kb: 256 # UTF-8 tail; line-aligned when one fits
|
|
364
358
|
max_archives: 12 # recent beside log; older preserved cold
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Agent Template document (\`~/fleet/agent_templates/Worker.yaml\`) is inert and reusable:
|
|
362
|
+
|
|
363
|
+
```yaml
|
|
364
|
+
role: { ref: developer }
|
|
365
|
+
brain: { ref: claude-default }
|
|
366
|
+
permissions: { approval: ask, filesystem: workspace, unattended: deny }
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Persistent Agent instance (\`~/fleet/agents/Name.yaml\`) either remains a canonical
|
|
370
|
+
Role/Brain composition or explicitly reuses a template:
|
|
371
|
+
|
|
372
|
+
```yaml
|
|
373
|
+
template: Worker
|
|
374
|
+
overrides:
|
|
375
|
+
cwd: /work/name
|
|
376
|
+
permissions: { approval: allow }
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Templates never create identities, supervisors, sessions, or lifecycle/status rows.
|
|
380
|
+
Map overrides merge recursively; scalars and arrays replace; null deletion is rejected.
|
|
381
|
+
|
|
382
|
+
Canonical Agent document (\`~/fleet/agents/Name.yaml\`):
|
|
383
|
+
|
|
384
|
+
```yaml
|
|
385
|
+
role: { ref: RoleID }
|
|
386
|
+
brain: { ref: BrainID } # Brain owns harness/model/session/reasoning
|
|
387
|
+
identity: "Display Name" # ours identity to bind (default: Name)
|
|
388
|
+
cwd: ${work_root}/repo # where the harness process runs
|
|
389
|
+
coordinator: FleetCoordinator # announce target on boot
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Additional operational field inventory (schematic, not one YAML document):
|
|
393
|
+
|
|
394
|
+
```text
|
|
372
395
|
identity: "Display Name" # ours identity to bind (default: Name)
|
|
373
396
|
cwd: ${work_root}/repo # where the harness process runs
|
|
374
397
|
coordinator: FleetCoordinator # announce target on boot
|
|
@@ -400,7 +423,7 @@ roles:
|
|
|
400
423
|
bio: | # public card (published as bio)
|
|
401
424
|
briefing_file: curated.md # replaces the generated narrative
|
|
402
425
|
env: { KEY: value } # extra session env
|
|
403
|
-
oversee: [{
|
|
426
|
+
oversee: [{ agent: X, interval: 5m }]
|
|
404
427
|
harness_options: # adapter-owned, adapter-validated
|
|
405
428
|
plugins: { "name@marketplace": false } # claude-code: plugin overrides
|
|
406
429
|
# mem_palace: false # claude-code: disable memory plugin
|
|
@@ -438,13 +461,12 @@ loops: # trusted local scheduled ACP turns
|
|
|
438
461
|
If nothing material changed, complete silently without an owner report.
|
|
439
462
|
```
|
|
440
463
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
and
|
|
447
|
-
overrides `defaults.monitor` key-by-key.
|
|
464
|
+
The v2 loader reads the manifest, then sorted bare Role, Brain, and Agent
|
|
465
|
+
documents from its exact stem directory. Duplicate filename-derived IDs are a
|
|
466
|
+
hard error. Identities and Agents are decoupled—removing an Agent never deletes
|
|
467
|
+
an identity. Role, Brain, and operational ownership are composed explicitly;
|
|
468
|
+
there is no generic cross-kind merge. Manifest operational defaults such as
|
|
469
|
+
`monitor` and `permissions` merge only within their owning Agent fields.
|
|
448
470
|
|
|
449
471
|
Every supervised role is a client of the operator-configured ours daemon. Fleet strips the
|
|
450
472
|
obsolete, presence-sensitive `OURS_AUTOSTART` variable from ACP harness
|
|
@@ -453,6 +475,28 @@ installer/setup flows remain responsible for starting it.
|
|
|
453
475
|
|
|
454
476
|
### Rooms and tasks
|
|
455
477
|
|
|
478
|
+
Init installs editable `single`, `pair`, and `team` definitions under
|
|
479
|
+
`~/fleet/room_templates/`, plus every exact-cased Agent, Role, and Brain they
|
|
480
|
+
reference. Inspect them with `ours-fleet template list` and
|
|
481
|
+
`ours-fleet template show team`. After configuring the authenticated owner below:
|
|
482
|
+
|
|
483
|
+
```sh
|
|
484
|
+
ours-fleet task create --title "Solo task" --template single
|
|
485
|
+
ours-fleet task create --title "Reviewed change" --template pair
|
|
486
|
+
ours-fleet task create --title "Phased delivery" --template team
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
`ours-fleet init -c /path/custom.yaml` seeds `/path/custom/` instead. Init reports
|
|
490
|
+
the packaged preset revision and source directory and only seeds missing files.
|
|
491
|
+
It never upgrades an edited preset. To adopt a newer packaged file explicitly,
|
|
492
|
+
copy the reported source file beside the existing target as `.new-default`, review
|
|
493
|
+
`diff -u`, then replace the target yourself. This is the sole adoption operation;
|
|
494
|
+
rerunning init is not an update. Users with the exact generated six-worker legacy
|
|
495
|
+
starter set must migrate explicitly: first run `ours-fleet migrate-agent-templates -c FILE`
|
|
496
|
+
for a zero-write plan, then review every move/addition/recovery path and rerun with
|
|
497
|
+
`--write`. Customized or ambiguous known starters are refused without
|
|
498
|
+
mutation; unrelated custom persistent Agents are preserved.
|
|
499
|
+
|
|
456
500
|
Rooms always use `ours-cowork`; there is no room-provider selector. Configure
|
|
457
501
|
the cowork daemon connection and the room owner directly:
|
|
458
502
|
|
|
@@ -1037,33 +1081,27 @@ the structured CLI watcher, because a detached process cannot wake a Codex turn.
|
|
|
1037
1081
|
wait is re-entered after each handled message; `ours-codex` instead wakes the idle
|
|
1038
1082
|
session through its App Server integration.
|
|
1039
1083
|
|
|
1040
|
-
The main Codex controls
|
|
1084
|
+
The main Codex controls are Brain-owned and also available when spawning:
|
|
1041
1085
|
|
|
1042
1086
|
```yaml
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
roles:
|
|
1058
|
-
Reviewer:
|
|
1059
|
-
harness_options:
|
|
1060
|
-
sandbox: read-only # overrides just this default key
|
|
1087
|
+
# ~/fleet/brains/codex-review.yaml
|
|
1088
|
+
harness: codex
|
|
1089
|
+
session: acp
|
|
1090
|
+
model: gpt-5.4
|
|
1091
|
+
harness_options:
|
|
1092
|
+
launcher: auto
|
|
1093
|
+
profile: fleet
|
|
1094
|
+
sandbox: read-only
|
|
1095
|
+
approval: on-request
|
|
1096
|
+
monitor: true
|
|
1097
|
+
search: true
|
|
1098
|
+
add_dirs: [/data/shared]
|
|
1099
|
+
config: { model_reasoning_effort: high }
|
|
1061
1100
|
```
|
|
1062
1101
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
`--codex-config key=value`, and repeatable `--add-dir`. Use `env.OURS_PORT`/`env.OURS_CONFIG` for a
|
|
1102
|
+
One-off/permanent spawn selects a Brain that owns model, reasoning, native permission,
|
|
1103
|
+
sandbox, profile, launcher, search, monitor consent, native config, and additional roots.
|
|
1104
|
+
Use `env.OURS_PORT`/`env.OURS_CONFIG` for a
|
|
1067
1105
|
role-specific ours daemon, or configure the host default in `~/.ours/config.json`.
|
|
1068
1106
|
|
|
1069
1107
|
## Agent isolation
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConversationEventV1 } from './session/conversation-types.js';
|
|
2
|
+
import type { AgentSession } from './session/types.js';
|
|
3
|
+
export interface AgentRecoveryEvidence {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
reason: 'RECOVERY_TOOLS_VERIFIED' | 'RECOVERY_PROMPT_MISSING' | 'RECOVERY_TURN_INCOMPLETE' | 'RECOVERY_TURN_FAILED' | 'RECOVERY_CHOOSE_MISSING' | 'RECOVERY_CURRENT_MISSING' | 'RECOVERY_GET_MESSAGES_MISSING' | 'RECOVERY_TOOL_ORDER_INVALID';
|
|
6
|
+
chooseIdentity: boolean;
|
|
7
|
+
currentIdentity: boolean;
|
|
8
|
+
getMessages: boolean;
|
|
9
|
+
turnCompleted: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Verify one exact recovery turn from its durable conversation ledger. Tool
|
|
13
|
+
* arguments/results are inspected only to derive these booleans and are never
|
|
14
|
+
* returned or persisted by this gate.
|
|
15
|
+
*/
|
|
16
|
+
export declare function evaluateAgentRecovery(events: readonly ConversationEventV1[], promptId: string, identity: string): AgentRecoveryEvidence;
|
|
17
|
+
export declare function recoverAgentIdentity(session: AgentSession, identity: string): Promise<AgentRecoveryEvidence>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const TOOL_NAMES = {
|
|
2
|
+
choose: new Set(['choose_identity', 'ours.choose_identity', 'mcp__ours__choose_identity']),
|
|
3
|
+
current: new Set(['current_identity', 'ours.current_identity', 'mcp__ours__current_identity']),
|
|
4
|
+
messages: new Set(['get_messages', 'ours.get_messages', 'mcp__ours__get_messages']),
|
|
5
|
+
};
|
|
6
|
+
function recordFor(records, event) {
|
|
7
|
+
if (event.kind !== 'tool.upsert' || !event.toolCallId)
|
|
8
|
+
return undefined;
|
|
9
|
+
const payload = event.payload;
|
|
10
|
+
const previous = records.get(event.toolCallId) ?? {};
|
|
11
|
+
const next = {
|
|
12
|
+
...previous,
|
|
13
|
+
...(payload.title !== undefined ? { title: payload.title } : {}),
|
|
14
|
+
...(payload.status !== undefined ? { status: payload.status } : {}),
|
|
15
|
+
...(payload.rawInput !== undefined ? { rawInput: payload.rawInput } : {}),
|
|
16
|
+
...(payload.status === 'completed' ? { completedSeq: event.seq } : {}),
|
|
17
|
+
};
|
|
18
|
+
records.set(event.toolCallId, next);
|
|
19
|
+
return next;
|
|
20
|
+
}
|
|
21
|
+
function objectInput(input) {
|
|
22
|
+
if (!input || input.truncated || input.redacted || !input.json
|
|
23
|
+
|| typeof input.json !== 'object' || Array.isArray(input.json))
|
|
24
|
+
return undefined;
|
|
25
|
+
return input.json;
|
|
26
|
+
}
|
|
27
|
+
function safeChoose(record, identity) {
|
|
28
|
+
if (!record.title || !TOOL_NAMES.choose.has(record.title) || record.status !== 'completed')
|
|
29
|
+
return false;
|
|
30
|
+
const input = objectInput(record.rawInput);
|
|
31
|
+
if (!input)
|
|
32
|
+
return false;
|
|
33
|
+
const keys = Object.keys(input).sort();
|
|
34
|
+
if (keys.some(key => key !== 'force' && key !== 'name'))
|
|
35
|
+
return false;
|
|
36
|
+
return input.name === identity && (input.force === undefined || input.force === false);
|
|
37
|
+
}
|
|
38
|
+
function safeNoOrBoundedInput(record, names, allowed) {
|
|
39
|
+
if (!record.title || !names.has(record.title) || record.status !== 'completed')
|
|
40
|
+
return false;
|
|
41
|
+
if (!record.rawInput)
|
|
42
|
+
return allowed({});
|
|
43
|
+
const input = objectInput(record.rawInput);
|
|
44
|
+
return input !== undefined && allowed(input);
|
|
45
|
+
}
|
|
46
|
+
function safeCurrent(record) {
|
|
47
|
+
return safeNoOrBoundedInput(record, TOOL_NAMES.current, input => Object.keys(input).length === 0);
|
|
48
|
+
}
|
|
49
|
+
function safeMessages(record) {
|
|
50
|
+
return safeNoOrBoundedInput(record, TOOL_NAMES.messages, input => {
|
|
51
|
+
const keys = Object.keys(input);
|
|
52
|
+
if (keys.some(key => key !== 'limit'))
|
|
53
|
+
return false;
|
|
54
|
+
return input.limit === undefined
|
|
55
|
+
|| (Number.isSafeInteger(input.limit) && input.limit >= 1 && input.limit <= 200);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Verify one exact recovery turn from its durable conversation ledger. Tool
|
|
60
|
+
* arguments/results are inspected only to derive these booleans and are never
|
|
61
|
+
* returned or persisted by this gate.
|
|
62
|
+
*/
|
|
63
|
+
export function evaluateAgentRecovery(events, promptId, identity) {
|
|
64
|
+
const ordered = [...events].sort((a, b) => a.seq - b.seq);
|
|
65
|
+
const admitted = ordered.find(event => event.kind === 'prompt.admitted' && event.promptId === promptId);
|
|
66
|
+
const empty = (reason) => ({
|
|
67
|
+
ok: false, reason, chooseIdentity: false, currentIdentity: false,
|
|
68
|
+
getMessages: false, turnCompleted: false,
|
|
69
|
+
});
|
|
70
|
+
if (!admitted)
|
|
71
|
+
return empty('RECOVERY_PROMPT_MISSING');
|
|
72
|
+
const terminal = ordered.find(event => event.seq > admitted.seq
|
|
73
|
+
&& event.kind === 'turn.completed'
|
|
74
|
+
&& event.promptId === promptId
|
|
75
|
+
&& event.sessionGeneration === admitted.sessionGeneration);
|
|
76
|
+
if (!terminal)
|
|
77
|
+
return empty('RECOVERY_TURN_INCOMPLETE');
|
|
78
|
+
const outcome = terminal.payload.outcome;
|
|
79
|
+
if (outcome !== 'completed')
|
|
80
|
+
return empty('RECOVERY_TURN_FAILED');
|
|
81
|
+
const records = new Map();
|
|
82
|
+
for (const event of ordered) {
|
|
83
|
+
if (event.seq <= admitted.seq || event.seq >= terminal.seq
|
|
84
|
+
|| event.promptId !== promptId
|
|
85
|
+
|| event.sessionGeneration !== admitted.sessionGeneration)
|
|
86
|
+
continue;
|
|
87
|
+
recordFor(records, event);
|
|
88
|
+
}
|
|
89
|
+
const values = [...records.values()];
|
|
90
|
+
const chooses = values.filter(record => safeChoose(record, identity));
|
|
91
|
+
const currents = values.filter(safeCurrent);
|
|
92
|
+
const messages = values.filter(safeMessages);
|
|
93
|
+
const chooseIdentity = chooses.length > 0;
|
|
94
|
+
const currentIdentity = currents.length > 0;
|
|
95
|
+
const getMessages = messages.length > 0;
|
|
96
|
+
const base = { chooseIdentity, currentIdentity, getMessages, turnCompleted: true };
|
|
97
|
+
if (!chooseIdentity)
|
|
98
|
+
return { ok: false, reason: 'RECOVERY_CHOOSE_MISSING', ...base };
|
|
99
|
+
if (!currentIdentity)
|
|
100
|
+
return { ok: false, reason: 'RECOVERY_CURRENT_MISSING', ...base };
|
|
101
|
+
if (!getMessages)
|
|
102
|
+
return { ok: false, reason: 'RECOVERY_GET_MESSAGES_MISSING', ...base };
|
|
103
|
+
const orderedChain = chooses.some(choose => currents.some(current => messages.some(message => choose.completedSeq !== undefined && current.completedSeq !== undefined
|
|
104
|
+
&& message.completedSeq !== undefined
|
|
105
|
+
&& choose.completedSeq < current.completedSeq
|
|
106
|
+
&& current.completedSeq < message.completedSeq)));
|
|
107
|
+
if (!orderedChain)
|
|
108
|
+
return { ok: false, reason: 'RECOVERY_TOOL_ORDER_INVALID', ...base };
|
|
109
|
+
return { ok: true, reason: 'RECOVERY_TOOLS_VERIFIED', ...base };
|
|
110
|
+
}
|
|
111
|
+
export async function recoverAgentIdentity(session, identity) {
|
|
112
|
+
if (!session.subscribeConversation)
|
|
113
|
+
return {
|
|
114
|
+
ok: false, reason: 'RECOVERY_PROMPT_MISSING', chooseIdentity: false,
|
|
115
|
+
currentIdentity: false, getMessages: false, turnCompleted: false,
|
|
116
|
+
};
|
|
117
|
+
const events = [];
|
|
118
|
+
const unsubscribe = session.subscribeConversation(event => events.push(event));
|
|
119
|
+
try {
|
|
120
|
+
const queued = await session.queuePrompt([
|
|
121
|
+
'[fleet-recovery] The shared ours daemon restarted.',
|
|
122
|
+
`Call ours choose_identity with name ${JSON.stringify(identity)} and force false.`,
|
|
123
|
+
'Then call current_identity, then get_messages. Complete all three in that order.',
|
|
124
|
+
'Do not create/delete identities, force-bind, interrupt, or restart any service/session.',
|
|
125
|
+
].join('\n'), { origin: { kind: 'fleet-monitor' } });
|
|
126
|
+
await queued.completion;
|
|
127
|
+
// Conversation publication is synchronous with terminal settlement in the
|
|
128
|
+
// in-tree ACP store; filtering by exact promptId/sessionGeneration remains
|
|
129
|
+
// the authority even if unrelated events arrived concurrently.
|
|
130
|
+
return evaluateAgentRecovery(events, queued.promptId, identity);
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
unsubscribe();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -4,6 +4,7 @@ import { classifyActivity } from '../session/activity.js';
|
|
|
4
4
|
import { controlRequest } from '../session/control.js';
|
|
5
5
|
import { SessionControlError } from '../session/types.js';
|
|
6
6
|
import { readExitRecord, readRestartLedger } from '../runner.js';
|
|
7
|
+
import { readDaemonRecoveryStatus } from '../daemon-recovery.js';
|
|
7
8
|
import { roleCapabilities } from './capabilities.js';
|
|
8
9
|
import { FleetError } from './errors.js';
|
|
9
10
|
const clean = (value, max = 512) => value.replace(/[\0-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '').trim().slice(0, max);
|
|
@@ -46,7 +47,8 @@ function readIsolation(dir) {
|
|
|
46
47
|
function sessionOverall(supervisor, session, restart, monitor, isolation, problems) {
|
|
47
48
|
if (restart.circuit === 'open' || monitor.health === 'failed' || monitor.health === 'degraded'
|
|
48
49
|
|| isolation.degraded
|
|
49
|
-
|| problems.some(problem => problem.severity === 'error'
|
|
50
|
+
|| problems.some(problem => problem.severity === 'error'
|
|
51
|
+
|| problem.source === 'watchdog' || problem.source === 'daemon-recovery')
|
|
50
52
|
|| session.readiness === 'failed')
|
|
51
53
|
return 'attention';
|
|
52
54
|
// A reachable agent session is the user's live interaction surface. Its
|
|
@@ -74,7 +76,8 @@ export class FleetQueryService {
|
|
|
74
76
|
this.control = options.control ?? controlRequest;
|
|
75
77
|
}
|
|
76
78
|
async list() {
|
|
77
|
-
const roles = await this.options.repository.list()
|
|
79
|
+
const roles = (await this.options.repository.list())
|
|
80
|
+
.filter(role => role.configured && role.lifetime === 'permanent');
|
|
78
81
|
return Promise.all(roles.map(async (role) => {
|
|
79
82
|
const status = await this.status(role);
|
|
80
83
|
return { role, status, capabilities: roleCapabilities(role, status, this.options.capabilityContext) };
|
|
@@ -103,6 +106,16 @@ export class FleetQueryService {
|
|
|
103
106
|
const lastExit = dir ? readExitRecord(join(dir, '.exit-status')) ?? undefined : undefined;
|
|
104
107
|
const session = await this.session(role, dir, live.state);
|
|
105
108
|
const problems = [...role.problems];
|
|
109
|
+
const recovery = dir ? readDaemonRecoveryStatus(dir) : undefined;
|
|
110
|
+
if (recovery && recovery.state !== 'recovered') {
|
|
111
|
+
const paths = ['agent', 'owner']
|
|
112
|
+
.filter(name => recovery.paths[name].state !== 'recovered')
|
|
113
|
+
.map(name => `${name}:${recovery.paths[name].state}`);
|
|
114
|
+
problems.push({
|
|
115
|
+
code: 'daemon_recovery', severity: 'warning', source: 'daemon-recovery',
|
|
116
|
+
detail: `${recovery.state}; ${paths.join(', ') || 'no degraded path'}; epoch ${recovery.epoch || 'unavailable'}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
106
119
|
if (live.state === 'running' && session.reachability !== 'online')
|
|
107
120
|
problems.push({
|
|
108
121
|
code: 'supervisor_session_disagreement', severity: 'warning',
|
|
@@ -12,6 +12,10 @@ export class RoleLifecycleService {
|
|
|
12
12
|
const config = input.config ?? loadConfig(this.options.configPath);
|
|
13
13
|
const selected = input.roleIds.length ? input.roleIds : config.roles.map(role => role.name);
|
|
14
14
|
for (const roleId of selected) {
|
|
15
|
+
if (config.agentTemplates?.[roleId] && !config.roles.some(role => role.name === roleId))
|
|
16
|
+
throw new FleetError('capability_unavailable', `'${roleId}' is an inert Agent Template; lifecycle commands target only persistent fleet/agents instances`);
|
|
17
|
+
if (!config.roles.some(role => role.name === roleId))
|
|
18
|
+
throw new FleetError('role_not_found', `no such role '${roleId}'`);
|
|
15
19
|
const role = await this.options.repository.get(roleId);
|
|
16
20
|
if (!role)
|
|
17
21
|
throw new FleetError('role_not_found', `no such role '${roleId}'`);
|
|
@@ -51,6 +55,11 @@ export class RoleCommandService {
|
|
|
51
55
|
throw new FleetError('idempotency_conflict', 'action ID already belongs to another operation');
|
|
52
56
|
return prior;
|
|
53
57
|
}
|
|
58
|
+
const config = loadConfig(this.options.configPath);
|
|
59
|
+
if (config.agentTemplates?.[input.roleId] && !config.roles.some(role => role.name === input.roleId))
|
|
60
|
+
throw new FleetError('capability_unavailable', `'${input.roleId}' is an inert Agent Template; lifecycle commands target only persistent fleet/agents instances`);
|
|
61
|
+
if (!config.roles.some(role => role.name === input.roleId))
|
|
62
|
+
throw new FleetError('role_not_found', `no such role '${input.roleId}'`);
|
|
54
63
|
const role = await this.options.repository.get(input.roleId);
|
|
55
64
|
if (!role)
|
|
56
65
|
throw new FleetError('role_not_found', `no such role '${input.roleId}'`);
|
|
@@ -5,21 +5,14 @@ import type { OpsDeps } from '../ops.js';
|
|
|
5
5
|
import type { ResolvedRole } from '../config.js';
|
|
6
6
|
import { FleetError } from './errors.js';
|
|
7
7
|
import { type ManagedFleetSpawnResult } from '../fleet-proxy.js';
|
|
8
|
-
import { type HarnessModelCatalog, type HarnessModelOption } from './model-catalog.js';
|
|
9
8
|
export interface CreateRoleSessionRequest {
|
|
10
9
|
name: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
model?: string | null;
|
|
14
|
-
reasoningEffort?: string | null;
|
|
15
|
-
session: 'acp';
|
|
10
|
+
brain: import('../config.js').AgentSelection;
|
|
11
|
+
role: import('../config.js').AgentSelection;
|
|
16
12
|
cwd?: string;
|
|
17
13
|
lifetime: 'permanent' | 'temporary';
|
|
18
|
-
mission?: string;
|
|
19
14
|
coordinator?: string;
|
|
20
15
|
permissions: CommonPermissions;
|
|
21
|
-
bio?: string;
|
|
22
|
-
persona?: string;
|
|
23
16
|
monitor?: WebCreationMonitor;
|
|
24
17
|
openAfterCreate: boolean;
|
|
25
18
|
highRiskAcknowledged?: boolean;
|
|
@@ -38,17 +31,6 @@ export type WebCreationMonitor = {
|
|
|
38
31
|
export interface CreationCapabilities {
|
|
39
32
|
available: boolean;
|
|
40
33
|
reasons: string[];
|
|
41
|
-
harnesses: Array<{
|
|
42
|
-
id: 'codex' | 'claude-code';
|
|
43
|
-
available: boolean;
|
|
44
|
-
sessions: Array<'acp'>;
|
|
45
|
-
defaultModel?: string;
|
|
46
|
-
models: string[];
|
|
47
|
-
modelOptions: HarnessModelOption[];
|
|
48
|
-
catalogSource: string;
|
|
49
|
-
customModelAllowed: true;
|
|
50
|
-
warnings: string[];
|
|
51
|
-
}>;
|
|
52
34
|
lifetimes: Array<'permanent' | 'temporary'>;
|
|
53
35
|
identityBootstrap: {
|
|
54
36
|
mode: 'current-fleet-first-boot';
|
|
@@ -123,7 +105,6 @@ export interface RoleCreationServiceOptions {
|
|
|
123
105
|
journalDir?: string;
|
|
124
106
|
probeReady?: (name: string, session: 'acp') => Promise<'ready' | 'attention' | 'unknown'>;
|
|
125
107
|
onProgress?: (action: CreationAction) => void;
|
|
126
|
-
modelCatalogs?: Partial<Record<'codex' | 'claude-code', () => HarnessModelCatalog>>;
|
|
127
108
|
/** Direct/managed callers must not create or restore the web action journal. */
|
|
128
109
|
journal?: boolean;
|
|
129
110
|
}
|