@ours.network/fleet-claude-code 0.9.5 → 0.9.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/fleet-claude-code",
3
- "version": "0.9.5",
3
+ "version": "0.9.7",
4
4
  "description": "Claude Code plugin for ours-fleet — spawn and oversee fleet agents from inside a session. Bundles the spawn-ours-agent and oversee-agents skills; the ours-fleet CLI (@ours.network/fleet) does the actual work.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Adapt Framework Solutions Ltd",
@@ -32,26 +32,50 @@ Schedule a repeating check every N minutes using your harness's mechanism
32
32
  ward once. Keep the loop armed across restarts — re-arm it right after re-binding
33
33
  your identity.
34
34
 
35
- ## 3. Each tick: peek and judge
35
+ ## 3. One console command is not a liveness verdict
36
36
 
37
- Run `ours-fleet peek <Name>` per ward and classify the console:
37
+ This is the mistake that gets busy agents killed. `peek` and `send` tell you what
38
+ happened to YOUR REQUEST. Only one of their outcomes is evidence that the agent
39
+ is gone. Each tick, run BOTH — they answer different questions:
40
+
41
+ ```sh
42
+ ours-fleet status <Name> # is the role supervised and alive?
43
+ ours-fleet peek <Name> # what is on its console right now?
44
+ ```
45
+
46
+ Read the result you actually got:
47
+
48
+ - **queued** — the session accepted the prompt for '<Name>'; a turn already running is not a failure. → Nothing. Do not resend, and do not read the absence of a reply as a stall — check progress with: ours-fleet peek <Name>
49
+ - **timeout** — '<Name>' did not answer in time; a busy agent looks exactly like this. Check: ours-fleet status <Name> → Treat delivery as UNCERTAIN — the request may already have been acted on, so do not resend it blindly.
50
+ - **rejected** — '<Name>' is running and refused the request. → Fix the request, not the agent. A refusal is proof of life.
51
+ - **control-unavailable** — this says nothing about whether '<Name>' is alive — its control plane did not answer; check: ours-fleet status <Name> → Read the role logs as well. The control plane and the agent are separate things, and one being unreachable is not evidence about the other.
52
+ - **backend** — this is a transport failure, not evidence that '<Name>' is gone; check: ours-fleet status <Name> → Investigate the transport, not the agent.
53
+ - **offline** — '<Name>' is confirmed offline. → This is the ONLY result that justifies a restart on its own: ours-fleet restart <Name> for a permanent role. Read the logs first.
54
+
55
+ Never translate any other result into "dead". `ours-fleet` prints the same
56
+ liveness note the CLI derived the result from, so quote what it said rather than
57
+ paraphrasing it as "not running".
58
+
59
+ ## 4. Judge the console content
60
+
61
+ Once you know the role is alive, classify what the console actually shows:
38
62
 
39
63
  | Console shows | Action |
40
64
  |---|---|
41
65
  | Permission prompt or trust dialog | Answer only within already-authorized scope. Use `send --key` for tmux or the `/permit` control shown by ACP `attach`. |
42
66
  | A question the agent asked its (absent) user | Answer with what you know of the mission: `ours-fleet send <Name> "<answer>"`. |
43
- | Crashed to a shell prompt / error text | Investigate (`ours-fleet logs <Name>`); for permanent roles `ours-fleet restart <Name>`; report to the owner. |
67
+ | Crashed to a shell prompt / error text | Investigate (`ours-fleet logs <Name>`); restart a permanent role only once `status` confirms it is offline. |
44
68
  | Idle with work still assigned | Nudge: `ours-fleet send <Name> "Status? Continue with <task> or declare BLOCKED."` |
45
- | Actively working / healthy | Nothing. Do not interrupt. |
69
+ | Actively working / healthy | Nothing. Do not interrupt, and do not mistake a long turn for a stall. |
46
70
 
47
- ## 4. Escalate when unsure
71
+ ## 5. Escalate when unsure
48
72
 
49
73
  If the resolution would make a decision that is not yours (spending, deleting,
50
74
  publishing, changing scope), do NOT press through it — message the owner or
51
75
  coordinator over ours messaging (`send_message`) with the session snapshot and your
52
76
  recommendation.
53
77
 
54
- ## 5. Log
78
+ ## 6. Log
55
79
 
56
80
  Append notable interventions (ward, what was stuck, what you did) to your
57
81
  WORKLOG so the history survives restarts.
@@ -8,42 +8,84 @@ description: Spawn and configure an ours-fleet agent from Claude Code, using a p
8
8
  Use the `ours-fleet` CLI to create the role. Do not simulate a subagent inside
9
9
  the current conversation.
10
10
 
11
- ## 1. Read the installed CLI reference
12
-
13
- Run:
11
+ ## 1. Read the installed CLI reference — this step is not optional
14
12
 
15
13
  ```sh
16
14
  ours-fleet docs
17
15
  ours-fleet doctor
18
16
  ```
19
17
 
20
- The installed CLI reference is authoritative for supported harnesses, session
21
- backends, common permissions, and flags. Stop at a failed required doctor check.
22
-
23
- ## 2. Resolve the role design
24
-
25
- Ask the requester (skip only if they already said):
26
-
27
- - **Permanent** written to `~/fleet.d/<Name>.yaml`, supervised (auto-restart,
28
- survives reboot). For roles that should stay.
29
- - **Temporary** detached supervisor, auto-cleaned when it exits, gone on
30
- reboot. For one-off background work.
31
- - **Session:** `tmux` (detached interactive TUI) or `acp` (structured session
32
- with attach/peek/send control). Both lifetimes support both backends.
33
- - **Harness:** `claude-code` or `codex`.
34
- - **Permissions:** prefer common `approval`, `filesystem`, and `unattended`
35
- intent from `ours-fleet docs`; use harness-native flags only when requested.
36
-
37
- Default to `--harness claude-code --session tmux --approval ask --filesystem
38
- workspace --unattended deny`. Never grant `bypassPermissions`, unrestricted
39
- filesystem access, or unattended approval without explicit user authorization.
40
-
41
- ## 3. Pick a name
18
+ `ours-fleet docs` from the INSTALLED CLI is authoritative for supported
19
+ harnesses, session backends, permissions, and flags. This skill ships with a
20
+ plugin and the CLI is upgraded separately, so where the two differ the installed
21
+ reference wins. Stop at a failed required doctor check.
22
+
23
+ ## 2. Understand the two permission traps before you choose anything
24
+
25
+ Both traps produce the same symptom: an agent that does less than its briefing
26
+ told it to and reports no error, because the refusal happened inside the harness
27
+ with no console attached to see it.
28
+
29
+ **Trap 1 a mode that suppresses the prompt without granting the action.**
30
+ Claude's `dontAsk` hides the permission prompt and still refuses the action. It
31
+ reads like a grant and is not one. This is why neutral `--approval allow` maps
32
+ to `bypassPermissions`, which genuinely permits what the role was authorized to
33
+ do. Nothing else is elevated: `ask` stays on Claude's default mode and `deny`
34
+ maps to `plan`.
35
+
36
+ **Trap 2 — the unattended capability floor.** A role with no console cannot
37
+ answer a permission request, so the request is refused. `ours-fleet` checks each
38
+ role's resolved permissions against a fixed floor before launch:
39
+
40
+ - `read-state` — read its briefing, ROUTINES.md, and WORKLOG.md
41
+ - `write-state` — append its WORKLOG and its own state files
42
+ - `messaging` — bind its identity, send and receive ours mail
43
+ - `monitor` — arm and observe its mail monitor
44
+ - `workspace-edit` — edit and test files in its working directory
45
+ - `status-commands` — run the inspection commands its briefing prescribes
46
+
47
+ `ours-fleet config` and `ours-fleet doctor` report this per role as
48
+ `unattended floor: <Name>`. Under `--unattended deny` a shortfall FAILS doctor,
49
+ because those requests will be denied silently. Under `--unattended wait` it
50
+ warns, because a human can still attach and answer.
51
+
52
+ What this means in practice, on this harness:
53
+
54
+ | Neutral intent | Native mode | Meets the floor? |
55
+ | --- | --- | --- |
56
+ | `--approval allow --filesystem workspace` | `bypassPermissions` | yes |
57
+ | `--approval allow --filesystem read-only` | `bypassPermissions` | no — no `write-state`, no `workspace-edit` |
58
+ | `--approval ask` | Claude's default | no — `read-state` only |
59
+ | `--approval deny` | `plan` | no — `read-state` only |
60
+ | `harness_options.permission_mode: dontAsk` | `dontAsk` | no — `read-state`, `status-commands` |
61
+
62
+ ## 3. Choose permissions from the job, not from a default
63
+
64
+ There is no safe blanket default. Ask what the role has to do and whether the
65
+ user authorizes it, then pick:
66
+
67
+ - **It must work with nobody watching** (the usual reason to spawn a fleet
68
+ role): it needs `--approval allow --filesystem workspace`. That is a real
69
+ grant, so get the user's explicit authorization for it, and confine the role
70
+ with `--isolation-file` rather than by withholding permissions it needs.
71
+ Use `--unattended deny` so the role never blocks on an unanswerable request.
72
+ - **A human will attach and answer prompts**: `--approval ask --filesystem
73
+ workspace --unattended wait`. Doctor warns that the floor is unmet — that
74
+ warning is correct and expected; the role will block until someone answers.
75
+ - **The user will not authorize `allow`, and nobody will attend it**: say so
76
+ plainly. That role cannot do its job, and doctor will fail it. Reduce the
77
+ job or get the authorization; do not paper over it with `dontAsk`.
78
+
79
+ Never choose `--filesystem unrestricted`, `harness_options.permission_mode:
80
+ bypassPermissions` written directly, or `dontAsk` without the user asking for
81
+ it by name and understanding what it grants.
82
+
83
+ ## 4. Pick a name
42
84
 
43
85
  `<Name>` must match `[A-Za-z0-9_-]+` (it becomes the role/service name). Check it
44
86
  is free: `ours-fleet config` must not list it and `ours-fleet ls` must not show it.
45
87
 
46
- ## 4. Co-draft bio and persona
88
+ ## 5. Co-draft bio and persona
47
89
 
48
90
  Draft WITH the requester, iterating until they approve:
49
91
 
@@ -55,45 +97,83 @@ Draft WITH the requester, iterating until they approve:
55
97
  Write approved text to uniquely named files under `/tmp` without interpolating
56
98
  untrusted text into shell commands.
57
99
 
58
- ## 5. Spawn
100
+ ## 6. Confine the role at creation, not later
101
+
102
+ `--isolation-file <path>` supplies the role's sandbox policy at creation, so the
103
+ FIRST launch is already confined. A role that only gains `isolation:` on a later
104
+ `up` ran unsandboxed until then. The file holds exactly the `isolation:` mapping
105
+ documented in `ours-fleet docs` and nothing else:
106
+
107
+ ```yaml
108
+ network: deny
109
+ fs:
110
+ read: [/opt/reference]
111
+ resources:
112
+ mem: 2G
113
+ ```
114
+
115
+ An invalid file is rejected before anything is created — no config, no state
116
+ directory, no identity reservation. This is the right control for a role that
117
+ needs `--approval allow`: isolation is the outer boundary a permission mode
118
+ cannot cross.
119
+
120
+ ## 7. Spawn
59
121
 
60
- Permanent (announce it to yourself if you are its coordinator):
122
+ Permanent, unattended (announce it to yourself if you are its coordinator):
61
123
 
62
124
  ```sh
63
125
  ours-fleet spawn <Name> \
64
126
  --harness claude-code --session <tmux|acp> \
65
127
  --mission "<one-line mission>" \
66
128
  --bio-file /tmp/spawn-bio.md --persona-file /tmp/spawn-persona.md \
67
- --approval ask --filesystem workspace --unattended deny \
129
+ --approval allow --filesystem workspace --unattended deny \
130
+ --isolation-file /tmp/spawn-isolation.yaml \
68
131
  [--cwd <dir>] [--coordinator <YourRoleName>]
69
132
  ```
70
133
 
71
- Temporary:
134
+ Permanent, attended — a human will answer its prompts:
135
+
136
+ ```sh
137
+ ours-fleet spawn <Name> \
138
+ --harness claude-code --session <tmux|acp> \
139
+ --mission "<one-line mission>" \
140
+ --bio-file /tmp/spawn-bio.md --persona-file /tmp/spawn-persona.md \
141
+ --approval ask --filesystem workspace --unattended wait
142
+ ```
143
+
144
+ Temporary — add `--temp`; it supports both session backends:
72
145
 
73
146
  ```sh
74
147
  ours-fleet spawn --temp <Name> \
75
148
  --harness claude-code --session <tmux|acp> \
76
149
  --mission "<one-line mission>" \
77
150
  --bio-file /tmp/spawn-bio.md --persona-file /tmp/spawn-persona.md \
78
- --approval ask --filesystem workspace --unattended deny
151
+ --approval allow --filesystem workspace --unattended deny
79
152
  ```
80
153
 
81
154
  Pass model, permission, session, and coordinator choices exactly as approved.
82
155
  Do not persist secrets in fleet YAML.
83
156
 
84
- ## 6. Verify
157
+ ## 8. Verify
85
158
 
86
159
  ```sh
160
+ ours-fleet doctor
87
161
  ours-fleet peek <Name> 60
88
162
  ours-fleet status <Name>
89
163
  ```
90
164
 
165
+ Read doctor's `permissions: <Name>` and `unattended floor: <Name>` lines for the
166
+ role you just created. `permissions:` shows the neutral intent and the native
167
+ settings it translated to; the floor line lists what the role actually grants,
168
+ or names what is missing. A failure there means the role will silently do less
169
+ than its briefing says — fix the permissions rather than starting it.
170
+
91
171
  For ACP, `status` must report `backend: acp`, `alive: true`, and a running/idle
92
172
  readiness. For tmux, the pane is authoritative. Confirm the role loaded its
93
173
  briefing and reached identity binding. Never answer a permission prompt beyond
94
174
  the scope already approved by the user.
95
175
 
96
- ## 7. Arm oversight
176
+ ## 9. Arm oversight
97
177
 
98
178
  The spawner babysits its subagent. Ask the requester for a check interval
99
179
  (default **5m**), then follow the **oversee-agents** skill for `<Name>` at that