@ours.network/fleet 1.2.0-nightly.44 → 1.2.0-nightly.46
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 +75 -0
- package/dist/application/role-removal-service.js +2 -0
- package/dist/briefing.d.ts +2 -0
- package/dist/briefing.js +8 -1
- package/dist/build-info.json +5 -4
- package/dist/capabilities.d.ts +3 -1
- package/dist/capabilities.js +3 -0
- package/dist/cli.js +180 -12
- package/dist/config.d.ts +10 -0
- package/dist/config.js +13 -2
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +82 -0
- package/dist/doctor.js +27 -0
- package/dist/fleet-command-audit.d.ts +6 -0
- package/dist/fleet-command-audit.js +15 -3
- package/dist/managed-cli.d.ts +253 -0
- package/dist/managed-cli.js +922 -0
- package/dist/notifications/fleet-producer.d.ts +1 -0
- package/dist/notifications/fleet-producer.js +82 -3
- package/dist/notifications/outbox.d.ts +4 -0
- package/dist/notifications/outbox.js +9 -0
- package/dist/notifications/target-cleanup.d.ts +8 -0
- package/dist/notifications/target-cleanup.js +41 -0
- package/dist/ops.js +5 -1
- package/dist/resolved-plan.js +1 -0
- package/dist/runner.js +9 -1
- package/dist/spawn.js +1 -1
- package/dist/tunnel-setup-input.d.ts +11 -0
- package/dist/tunnel-setup-input.js +42 -0
- package/dist/web/workspace-devices.d.ts +2 -0
- package/dist/web/workspace-devices.js +13 -0
- package/dist/workspace-enrollment.d.ts +30 -2
- package/dist/workspace-enrollment.js +205 -12
- package/dist/workspace-replacement.d.ts +66 -0
- package/dist/workspace-replacement.js +220 -0
- package/docs/validation/managed-cli-permissions.md +222 -3
- package/package.json +1 -1
|
@@ -1,5 +1,223 @@
|
|
|
1
1
|
# Managed Fleet CLI from Codex and Claude Code workspace sandboxes
|
|
2
2
|
|
|
3
|
+
> **Use the generated setup.** Since `managed-cli.setup-v1`, Fleet prepares the
|
|
4
|
+
> native policy for the packaged task workflow itself. The hand-written rules
|
|
5
|
+
> further down remain as background and for operations outside that workflow
|
|
6
|
+
> (for example `room delete`).
|
|
7
|
+
|
|
8
|
+
## Fleet-generated setup (issue #233)
|
|
9
|
+
|
|
10
|
+
Declare the workflow on the Agent, or let Fleet add the one key for you:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
ours-fleet managed-cli setup --enable FleetCoordinator # adds managed_cli: [task-workflow]
|
|
14
|
+
ours-fleet managed-cli setup # generate / reconcile, starts nothing
|
|
15
|
+
ours-fleet managed-cli status # compare only, exit 1 when not current
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The declaration is explicit configuration. It is never inferred from a role or
|
|
19
|
+
display name, and `--enable` changes no permission. The same preparation runs at
|
|
20
|
+
every agent start (`up`, `restart`, `spawn`, task-room agents), so newly created
|
|
21
|
+
agents need no separate step. `ours-install` runs `managed-cli setup` from the
|
|
22
|
+
exact Fleet it installed after `init` and on update.
|
|
23
|
+
|
|
24
|
+
An agent invokes a prepared command through the pinned entry form printed in its
|
|
25
|
+
briefing:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
/abs/node /abs/fleet/dist/cli.js --managed-configuration /abs/fleet.yaml task create --title "..." --backlog --no-room
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### What is prepared
|
|
32
|
+
|
|
33
|
+
| Prepared (runs outside the command sandbox) | Not prepared (stays sandboxed) |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `task create`, `task start`, `task finish`, `task block`, `task unblock`, `task review`, `task list`, `task show` | `task cancel`, `task delete` |
|
|
36
|
+
| `room show`, `room members` | `room create`, `room delete`, `room close` |
|
|
37
|
+
| `template list`, `template show`, `template validate`, `config`, `docs` | `spawn`, `ours tools`, `ours call`, `status`, `peek`, `send` |
|
|
38
|
+
| `--help`, `task --help`, `room --help`, `template --help` | service administration, identity and contact commands, oversight |
|
|
39
|
+
|
|
40
|
+
`task start` and `task finish` provision and retire rooms and agents. That is
|
|
41
|
+
real authority, and it is disclosed by `setup`, `status` and the installer.
|
|
42
|
+
|
|
43
|
+
### Actual invocation boundary
|
|
44
|
+
|
|
45
|
+
- The native rule fixes four things: the Node executable, this Fleet CLI, the
|
|
46
|
+
pinned configuration and the command words. It is an argv **prefix** and admits
|
|
47
|
+
every trailing option and argument. It is not argument validation, target
|
|
48
|
+
authorization or per-agent isolation.
|
|
49
|
+
- A later `-c`/`--configuration` naming another file is refused by the Fleet CLI
|
|
50
|
+
after the process has already started outside the sandbox and been audited.
|
|
51
|
+
That is Fleet runtime validation, not a native policy denial.
|
|
52
|
+
- The pinned form requires a managed session. Outside one, where no supervisor
|
|
53
|
+
would audit it, the CLI refuses it. Commands outside the inventory are refused
|
|
54
|
+
by the CLI even if a hand-written rule would admit them.
|
|
55
|
+
- The supervisor audit, CLI validation, confirmations, SDK credential checks and
|
|
56
|
+
any outer container or host sandbox are unchanged. There is no blanket
|
|
57
|
+
Node/Bash/Fleet grant, no sandbox is disabled, and no new transport exists.
|
|
58
|
+
- Compound (`&&`, `;`), piped, redirected, `$(...)`, backslash-escaped and
|
|
59
|
+
`VAR=value`-prefixed command lines do not match and stay sandboxed.
|
|
60
|
+
|
|
61
|
+
### Quoting, measured natively
|
|
62
|
+
|
|
63
|
+
Measured with real Codex 0.160.0 and Claude Code 2.1.289 on Linux:
|
|
64
|
+
|
|
65
|
+
| Spelling | Codex | Claude |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| Single-quoted CLI / configuration path or option value containing spaces | matches | matches |
|
|
68
|
+
| Double-quoted later token | matches | does not match |
|
|
69
|
+
| Quoted **executable** token | never matches | never matches |
|
|
70
|
+
| Unquoted symlinked executable | matches | matches |
|
|
71
|
+
|
|
72
|
+
Fleet therefore spells a CLI or configuration path containing spaces in single
|
|
73
|
+
quotes (Codex >= 0.160.0 required; older or unreadable versions are reported as
|
|
74
|
+
unsupported for such paths), and requires the Node executable at a path needing
|
|
75
|
+
no quoting. A path containing anything but letters, digits, spaces and
|
|
76
|
+
`_@%+=:,./-` (so no quotes, backslashes, `*` or other pattern characters, which
|
|
77
|
+
Claude's entries would not treat literally), or one that is or resolves
|
|
78
|
+
inside the agent's workspace, is reported as unsupported rather than widened.
|
|
79
|
+
|
|
80
|
+
### What is written, and ownership
|
|
81
|
+
|
|
82
|
+
- **Codex**: `<workspace>/.codex/rules/ours-fleet-<id>.rules`, one file per Fleet
|
|
83
|
+
configuration, carrying a Fleet marker header. It applies to every trusted
|
|
84
|
+
Codex session in that workspace, not to one identity, and Codex must already
|
|
85
|
+
trust the workspace: Fleet reports missing trust and never changes it. A file
|
|
86
|
+
shared by several agents is held in `~/.ours-fleet/managed-cli/registry.json`
|
|
87
|
+
and removed only when its last holder is gone. Files without the Fleet marker,
|
|
88
|
+
including a hand-written `ours-fleet.rules`, are never modified; one occupying
|
|
89
|
+
the generated name is reported as a conflict.
|
|
90
|
+
- **Claude**: `permissions.allow` and `sandbox.excludedCommands` entries in the
|
|
91
|
+
agent's own Fleet settings overlay, delivered to the bundled ACP adapter. The
|
|
92
|
+
operator's Claude settings are not modified. Fleet never sets
|
|
93
|
+
`sandbox.enabled`; if no readable settings file enables the OS sandbox, or a
|
|
94
|
+
`deny` rule would override the entries, `status` and `doctor` say so.
|
|
95
|
+
- Setup is idempotent. Changed Node/CLI/configuration paths rewrite the Fleet
|
|
96
|
+
entries; entries for agents or configurations that no longer exist are removed
|
|
97
|
+
and listed.
|
|
98
|
+
|
|
99
|
+
### Diagnostics
|
|
100
|
+
|
|
101
|
+
`ours-fleet doctor` and `managed-cli status` report three separate facts:
|
|
102
|
+
|
|
103
|
+
| Row | Source | Meaning |
|
|
104
|
+
| --- | --- | --- |
|
|
105
|
+
| setup | generated files compared with this installation | static configuration only |
|
|
106
|
+
| session | the role's launch record | whether the last start loaded the current policy, or a restart is required |
|
|
107
|
+
| observed | the supervisor audit ledger | which pinned forms actually completed since that start |
|
|
108
|
+
|
|
109
|
+
A prepared setup is not evidence of supervisor access. An observed `--help`
|
|
110
|
+
proves only its own audited path; lifecycle forms that were never observed are
|
|
111
|
+
listed as such. `task create --help` is reported as `task create --help`, a help
|
|
112
|
+
call, not as `task create`. Rows from before the current launch are reported as
|
|
113
|
+
historical. The ledger stores the pinned configuration as a fingerprint, never
|
|
114
|
+
as its path; a row pinned to another configuration, or to none that can be told,
|
|
115
|
+
is counted separately and is not evidence for this policy. Rows whose content
|
|
116
|
+
was erased with their task or room keep what they prove.
|
|
117
|
+
|
|
118
|
+
A launch also gives up what the role held before: opting out, losing support or
|
|
119
|
+
moving to another workspace or configuration removes that role's Codex rules at
|
|
120
|
+
the next start, without touching a file another agent still holds.
|
|
121
|
+
|
|
122
|
+
### Unsupported combinations
|
|
123
|
+
|
|
124
|
+
Reported, with the reason, and left exactly as sandboxed as before: Windows and
|
|
125
|
+
other platforms; Hermes and other harnesses; custom ACP or app-server session
|
|
126
|
+
commands; roles declaring `isolation:`; unspellable paths; a Node path needing
|
|
127
|
+
quotes; Codex older than 0.160.0 with quoted paths; and any pinned file the
|
|
128
|
+
agent could replace — inside its workspace or a `harness_options.add_dirs`
|
|
129
|
+
directory, lexically or through a symlink. Codex roles with
|
|
130
|
+
`harness_options.config` or `harness_options.profile` are unsupported too:
|
|
131
|
+
those change the native sandbox (for example extra writable roots) in ways Fleet
|
|
132
|
+
does not inspect. Native user settings Fleet cannot read are outside this check.
|
|
133
|
+
|
|
134
|
+
### Qualification
|
|
135
|
+
|
|
136
|
+
`test/managed-cli-workflow.integration.mjs` runs real Codex / Claude Code through
|
|
137
|
+
Fleet's own adapters and launch preparation against a real supervisor control
|
|
138
|
+
server and audit ledger. A scripted local provider only requests commands; no
|
|
139
|
+
external model, account, production identity or room is used.
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
FLEET_TEST_HARNESS=codex FLEET_CODEX_BIN=/absolute/codex FLEET_TEST_SESSION=codex-app-server \
|
|
143
|
+
FLEET_TEST_TMP_PREFIX=/absolute/private-test-parent/fleet-mc- \
|
|
144
|
+
node test/managed-cli-workflow.integration.mjs
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Use `FLEET_TEST_SESSION=acp` for bundled Codex ACP, and
|
|
148
|
+
`FLEET_TEST_HARNESS=claude FLEET_CLAUDE_BIN=/absolute/claude` for bundled Claude
|
|
149
|
+
ACP. `FLEET_TEST_QUOTED=1` installs the CLI and configuration under paths
|
|
150
|
+
containing spaces. `FLEET_TEST_CLAUDE_SANDBOX=0` checks the diagnostics when the
|
|
151
|
+
operator has not enabled Claude's sandbox. `FLEET_TEST_NESTED_SANDBOX=1` is for
|
|
152
|
+
unprivileged containers only. `FLEET_TEST_EVIDENCE=/file.json` records every
|
|
153
|
+
command, exit code and output.
|
|
154
|
+
|
|
155
|
+
Each run checks: unpinned `--help` denied at the socket; an unrelated write
|
|
156
|
+
outside the workspace still denied by the OS; pinned help; `task create` with
|
|
157
|
+
quoted variable options, `task list|show|block|unblock`, template and plan
|
|
158
|
+
inspection completing with audit rows; `task review|start|finish` and
|
|
159
|
+
`room show|members` reaching the supervisor and Fleet validation (their
|
|
160
|
+
successful run is the lifecycle fixture below); `template show|validate` and
|
|
161
|
+
`docs`; a late
|
|
162
|
+
`--configuration` refused by Fleet; unprepared commands, a missing or different
|
|
163
|
+
pin, preload injection, chaining and redirection staying sandboxed; and `status`
|
|
164
|
+
listing exactly the forms the audit ledger observed.
|
|
165
|
+
|
|
166
|
+
`test/managed-cli-lifecycle.integration.mjs` is the full stack: the real role
|
|
167
|
+
runner (`ours-fleet _run`) launches the Coordinator, with a real local ours
|
|
168
|
+
daemon and Cowork service (`FLEET_COWORK_CLI=/abs/cowork/dist/cli.js`). From
|
|
169
|
+
inside the command sandbox the Coordinator's session creates a task, starts it —
|
|
170
|
+
a Cowork room is provisioned and a room member agent is really spawned through
|
|
171
|
+
the supervisor — runs `task show`, `room show`, `room members`, `task block`,
|
|
172
|
+
`task unblock`, `task review` and `task finish`, which retires the member and
|
|
173
|
+
the room. Every command is typed in the pinned form and must have a successful
|
|
174
|
+
audit row; the task must end `done`. `FLEET_TEST_HARNESS=claude` puts the
|
|
175
|
+
Coordinator on bundled Claude ACP with its OS sandbox enabled (the member stays
|
|
176
|
+
on Codex). Only the model provider is scripted; the daemon runs without a broker.
|
|
177
|
+
|
|
178
|
+
Two outcomes of that run are Fleet's existing lifecycle behaviour, not policy,
|
|
179
|
+
and are recorded rather than hidden: the first `task start` can answer
|
|
180
|
+
"readiness is unknown" while the member's session is still starting, and the
|
|
181
|
+
first `task finish` can report that the member's live state disappeared while it
|
|
182
|
+
is still stopping. In both cases the task is already durably in the right state
|
|
183
|
+
and re-running the same command, as its message says, succeeds.
|
|
184
|
+
|
|
185
|
+
Linux x86_64 host (kernel 7.0, Node 22.23.1, Codex 0.160.0, Claude Code 2.1.289):
|
|
186
|
+
|
|
187
|
+
| Harness / session | Plain paths | Paths with spaces |
|
|
188
|
+
| --- | --- | --- |
|
|
189
|
+
| Codex native app-server | PASS | PASS |
|
|
190
|
+
| Bundled Codex ACP | PASS | PASS |
|
|
191
|
+
| Bundled Claude ACP, OS sandbox enabled | PASS | PASS |
|
|
192
|
+
| Bundled Claude ACP, OS sandbox not enabled (diagnostic) | PASS | not run |
|
|
193
|
+
|
|
194
|
+
| Full-stack lifecycle (real runner, room, spawned member) | Result |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| Codex native app-server Coordinator, Codex native member | PASS |
|
|
197
|
+
| Bundled Codex ACP Coordinator, Codex ACP member | PASS |
|
|
198
|
+
| Bundled Claude ACP Coordinator (OS sandbox enabled), Codex native member | PASS |
|
|
199
|
+
|
|
200
|
+
Across repeated runs the re-runs described above occurred zero or one time per
|
|
201
|
+
command; each run prints how many. The spawned member's Agent Template declares
|
|
202
|
+
`managed_cli` itself, and the run asserts what that member's own launch
|
|
203
|
+
prepared: a Codex native member gets its own record, rules in its own workspace
|
|
204
|
+
and a temporary holder; a Codex ACP member with `approval: allow` has no command
|
|
205
|
+
sandbox, so its launch records `not-required` and generates nothing. After
|
|
206
|
+
`task finish` the run asserts that the member's live state, Fleet's room record
|
|
207
|
+
and the Cowork room are gone, and that the member's rules were removed.
|
|
208
|
+
|
|
209
|
+
Not qualified, and not claimed:
|
|
210
|
+
|
|
211
|
+
- **macOS.** The generated setup has not been run there. `managed-cli status`
|
|
212
|
+
discloses this on macOS. The mechanisms are the ones the hand-written policy
|
|
213
|
+
below used on macOS, but that is not a run of this matrix.
|
|
214
|
+
- **Service-managed supervisors and a real model.** The lifecycle run starts
|
|
215
|
+
the runner directly (`OURS_FLEET_SUPERVISOR=none`), not through systemd or
|
|
216
|
+
launchd, uses a scripted provider, attaches no owner to the room and has no
|
|
217
|
+
broker. The spawned member only starts and stops; it does no work.
|
|
218
|
+
- Paths with spaces in the full-stack lifecycle run (covered by the matrix
|
|
219
|
+
above), Claude standalone, Hermes, Windows and isolated roles.
|
|
220
|
+
|
|
3
221
|
A managed Fleet CLI invocation sends `fleet_audit_begin` to the supervisor's Unix
|
|
4
222
|
socket before parsing commands, including `--help`. A socket that exists and is
|
|
5
223
|
owned by the current user can still return `connect EPERM` from a restricted
|
|
@@ -7,7 +225,7 @@ command sandbox. This is not evidence that the supervisor is down or Fleet needs
|
|
|
7
225
|
reinstallation. Check filesystem permissions too: `EACCES`/`EPERM` alone does not
|
|
8
226
|
identify which policy denied access.
|
|
9
227
|
|
|
10
|
-
##
|
|
228
|
+
## Background: hand-written native execution rules
|
|
11
229
|
|
|
12
230
|
Keep the role's `approval: auto`, `filesystem: workspace`, and `unattended: deny`.
|
|
13
231
|
For an operator authorized to manage rooms, explicitly approve the necessary CLI
|
|
@@ -57,8 +275,9 @@ No runtime services or installed packages need restarting for this policy change
|
|
|
57
275
|
outside the command sandbox. These restrictions take precedence; do not remove
|
|
58
276
|
them implicitly to make Fleet work.
|
|
59
277
|
- On tested Codex 0.159.0, quoting the executable/script tokens prevented the rule
|
|
60
|
-
from granting execution outside the sandbox.
|
|
61
|
-
invocation above.
|
|
278
|
+
from granting execution outside the sandbox. For hand-written rules use the
|
|
279
|
+
canonical simple-token invocation above. The generated setup qualifies quoted
|
|
280
|
+
script and argument paths on Codex 0.160.0; see "Quoting, measured natively".
|
|
62
281
|
- Merely enabling network inside the Linux command sandbox was insufficient:
|
|
63
282
|
its user namespace maps ancestor directory owners to UID 65534, which the SDK's
|
|
64
283
|
strict credential ancestry checks reject. Approved CLI execution avoids that
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "1.2.0-nightly.
|
|
3
|
+
"version": "1.2.0-nightly.46",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, managed native/ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|