cyberlegion 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,15 @@
1
1
  ---
2
2
  name: init-cyberlegion
3
- description: "Use this skill to set up or onboard cyberlegion in this session or repo — probe the environment, register the mail-surfacing hook, and (in a root session, on your yes) bind this pane as the durable legate owner inbox. Triggers: 'set up cyberlegion', 'onboard the legion', 'register the cyberlegion surfacing hook', 'make this pane my main legion inbox', 'get cyberlegion working in this repo'. Not for spawning/messaging/dispatching a peer (that is legate), reading or acking owner mail (that is manage-inbox), or unrelated init like a git repo, npm package, or commit discipline."
3
+ description: "Use this skill to set up or onboard cyberlegion in this session or repo — probe the environment, register the mail-surfacing hook, (in a root session, on your yes) allow the cyberlegion CLI in Claude Code's permissions, and bind this pane as the durable legate owner inbox. Triggers: 'set up cyberlegion', 'onboard the legion', 'register the cyberlegion surfacing hook', 'make this pane my main legion inbox', 'get cyberlegion working in this repo'. Not for spawning/messaging/dispatching a peer (that is legate), reading or acking owner mail (that is manage-inbox), or unrelated init like a git repo, npm package, or commit discipline."
4
4
  ---
5
5
 
6
6
  # init-cyberlegion
7
7
 
8
8
  The onboarding front door to the Legion — a thin, user-invocable wrapper that walks a session through
9
9
  getting `cyberlegion` working in this repo: probe the environment, register the surfacing hook, and
10
- (only in a root session, only on an explicit yes) bind this pane as the durable `legate` owner inbox.
10
+ (only in a root session, only on an explicit yes) allow the `cyberlegion` CLI in Claude Code's
11
+ permissions and bind this pane as the durable `legate` owner inbox, offering that owner a **home** to
12
+ wake in when nobody is standing in for it.
11
13
  It is a **thin wrapper**: every mechanic is a `cyberlegion` CLI call. The skill holds the *conversation
12
14
  and the judgment* — is this a root session? should we ask to bind? what does the environment look
13
15
  like? — the CLI holds all the *mechanism*.
@@ -37,21 +39,54 @@ node scripts/cyberlegion.mjs mux doctor
37
39
  ```
38
40
 
39
41
  Run this **before** touching the hook or any identity. It reports `harness`, `mux`, `pane`,
40
- `hubRoot`, and `selfId` — read it to learn the environment (is there a multiplexer? a pane?) and to
41
- detect root vs spawned (see step 3). Narrate a short, grounded summary of what it found — do not
42
- invent facts the probe did not report.
42
+ `hubRoot`, `selfId`, and `permissionRule` — read it to learn the environment (is there a
43
+ multiplexer? a pane? does Claude Code allow the CLI?) and to detect root vs spawned (see step 3).
44
+ Narrate a short, grounded summary of what it found, including the permission rule (e.g. "permission
45
+ rule: missing") — do not invent facts the probe did not report.
43
46
 
44
- ### 2. Register the surfacing hook
47
+ `permissionRule` is whether Claude Code's user settings carry a `permissions.allow` rule covering
48
+ `cyberlegion`: `present`, `missing`, `unreadable`, or `n/a` (not Claude Code). Without it, Claude
49
+ Code's auto-mode classifier can deny a unit's `cyberlegion mail send` as *External System Writes*,
50
+ so a unit that finished its work cannot report back. Step 2 handles it.
51
+
52
+ ### 2. Register the surfacing hook (and, on a yes, allow the CLI)
45
53
 
46
54
  ```bash
47
55
  node scripts/cyberlegion.mjs init --pin <version>
48
56
  ```
49
57
 
58
+ **The permission rule — ask first, never silent.** When the probe reported `permissionRule: missing`
59
+ in a **root** session with a broader onboarding intent (see step 3 for how root is derived), ask
60
+ before running `init`, e.g.:
61
+
62
+ > "Claude Code has no permission rule for `cyberlegion`, so its auto-mode classifier can block a
63
+ > unit's `cyberlegion mail send` and the unit's report never reaches you. Add
64
+ > `Bash(cyberlegion *)` to `permissions.allow` in your Claude Code user settings
65
+ > (`~/.claude/settings.json`)? It is merged into your existing list."
66
+
67
+ On an explicit yes, add `--allow-cli` to the `init` call — the CLI merges the rule into the existing
68
+ array, never replaces it, and refuses to rewrite a settings file it cannot parse:
69
+
70
+ ```bash
71
+ node scripts/cyberlegion.mjs init --pin <version> --allow-cli
72
+ ```
73
+
74
+ On a decline, run `init` without `--allow-cli` and say the rule stays missing. Never edit the
75
+ settings file by hand. Do not ask, and do not pass `--allow-cli`, when:
76
+
77
+ - the rule is `present` or `n/a` — nothing to do;
78
+ - the rule is `unreadable` — tell the user the settings file could not be parsed and must be fixed
79
+ by hand; `--allow-cli` would refuse it;
80
+ - this is a **spawned** unit — it never changes the user's global settings; report the rule as
81
+ missing in its result so the human can run this skill from a root session;
82
+ - the request is hook-only — report the rule's state and stop (see step 3).
83
+
50
84
  Pass `--pin <version>` with the version resolved above so a project hook's npx fallback fetches the
51
85
  shipped version; **omit `--pin`** when the map yielded no version.
52
86
 
53
87
  Auto-detect is the default — no `--agent` flag. Pass `--agent <name>` **only** when `mux doctor` could
54
- not auto-detect the harness, or the user named one explicitly (it composes with `--pin`):
88
+ not auto-detect the harness, or the user named one explicitly (it composes with `--pin` and
89
+ `--allow-cli`):
55
90
 
56
91
  ```bash
57
92
  node scripts/cyberlegion.mjs init --pin <version> --agent <name>
@@ -60,7 +95,9 @@ node scripts/cyberlegion.mjs init --pin <version> --agent <name>
60
95
  This step is **idempotent**: if the hook is already registered, `init` reports `already present` —
61
96
  that is a clean no-op, never a duplicate registration and never an error. On Claude Code and Codex the
62
97
  plugin ships the hook itself, so `init` reports `provided by plugin` (or `removed project hook` when it
63
- cleared one an earlier `init` wrote); both mean the hook is set up.
98
+ cleared one an earlier `init` wrote); both mean the hook is set up. On Claude Code its summary also
99
+ reports `permission rule <state>` — `added` after `--allow-cli`, `present` when a covering rule was
100
+ already there.
64
101
 
65
102
  ### 3. Detect root vs spawned — derived, never asked
66
103
 
@@ -72,7 +109,18 @@ has it set. Derive this from the probe — never ask the user to declare it.
72
109
  - **A hook-only request in a root session** ("just register the surfacing hook") — also stop here.
73
110
  Registering the hook satisfies the ask; do not proceed to the bind offer unasked.
74
111
  - **Root session, broader onboarding intent, no `legate` owner bound yet** — continue to step 4.
75
- - **Root session where a `legate` owner is already bound** — stop; do not re-ask, do not re-mint.
112
+ - **Root session where a `legate` owner is already bound** — do not re-ask the bind and do not mint a
113
+ second owner; go to step 6 to offer a home. A bind request ("make this pane my main legion inbox")
114
+ made when the owner already exists lands here too.
115
+
116
+ To tell whether the owner exists, list the standing owners:
117
+
118
+ ```bash
119
+ node scripts/cyberlegion.mjs unit register --standing --format json
120
+ ```
121
+
122
+ A record with `"handle": "legate"` is the owner. Its `home` field says where its presence is
123
+ spawned (`dir` plus `harness` or `agent`); no `home` field means it has none.
76
124
 
77
125
  ### 4. Ask before binding — never silent
78
126
 
@@ -85,27 +133,105 @@ Only a root session with no `legate` owner bound is offered the bind. Ask plainl
85
133
  - **User agrees explicitly** — proceed to step 5.
86
134
  - **Already bound** — never reach this ask (see step 3).
87
135
 
88
- ### 5. On an explicit yes — mint and bind
136
+ ### 5. On an explicit yes — offer a home, then mint and bind
137
+
138
+ **No multiplexer or pane in the probe** → skip the home: mint bare and continue (see *Non-mux parity*
139
+ below). `unit claim` refuses a caller with no multiplexer, and a home is spawned the same way
140
+ `unit spawn` opens a session.
141
+
142
+ Otherwise, before minting, explain the presence and ask for a home. Mail to the `legate` owner
143
+ reaches whoever stands in for it, in this order:
144
+
145
+ 1. **A live presence** — a session that ran `unit claim legate`. The claim holds until another
146
+ session claims the owner, until `unit claim legate --clear` unbinds it, or until that session
147
+ exits.
148
+ 2. **The home** — when nobody holds the presence, a session is started in the home folder, bound as
149
+ the presence, and woken to read the owner's inbox. A home **outranks this pane**: with a home set,
150
+ a delivery with no live presence starts a session there instead of ringing the pane `attach` binds.
151
+ Say this in the question: setting a home means unclaimed mail no longer rings this pane.
152
+ 3. **This pane** (`attach`) — rung only when focused, when there is neither a presence nor a home.
153
+
154
+ Ask plainly, e.g.:
155
+
156
+ > "Should the legate owner have a home — a folder where a session is started to act for it when
157
+ > mail arrives and nobody is live? While you're here, `cyberlegion unit claim legate` makes this
158
+ > session the one that gets the mail, until another session claims it, you run
159
+ > `unit claim legate --clear`, or this one exits; the home is only used when nobody holds it — and
160
+ > once it is set, mail nobody holds starts a session there instead of ringing this pane.
161
+ > A session started there has the folder's trust prompt accepted for it, since you named the
162
+ > folder. Name a folder, or say none."
163
+
164
+ **A folder** → mint with the home and **exactly one** launch:
165
+
166
+ ```bash
167
+ node scripts/cyberlegion.mjs unit register --standing --handle legate --home <dir> --harness <harness>
168
+ node scripts/cyberlegion.mjs attach
169
+ ```
170
+
171
+ `<harness>` is the `harness` the probe reported, or the one the user names instead — one of
172
+ `claude`, `cursor`, or `codex`. When the user
173
+ names an agent definition to launch there, pass `--agent <definition>` and **no** `--harness`. This
174
+ `--agent` is `unit register`'s — an agent definition resolved from the home — not `init --agent`.
175
+ If the probe reported `harness: unknown` and the user named no agent definition, ask for one — never
176
+ run `--home` without a launch, and never pass `--harness unknown`. Pass `<dir>` as an absolute path.
177
+
178
+ **None** → mint bare, as before:
89
179
 
90
180
  ```bash
91
181
  node scripts/cyberlegion.mjs unit register --standing --handle legate
92
182
  node scripts/cyberlegion.mjs attach
93
183
  ```
94
184
 
95
- Run these **in this order** and only after the explicit yes: mint the durable, session-independent
96
- `legate` owner inbox first, then bind the current pane as that owner's live presence.
185
+ Run the mint and `attach` **in this order** and only after the explicit yes: mint the durable,
186
+ session-independent `legate` owner inbox first, then bind the current pane as the owner's main pane.
187
+
188
+ **The CLI refuses a home** (the folder does not exist, it is a repository's primary checkout, the
189
+ agent definition does not resolve from it) — it writes nothing. Tell the user its reason and ask for
190
+ another folder or none; do not pick a folder yourself and do not fall back to a bare mint unasked.
191
+ If it rejects `--home` as an unknown option, the CLI is older than homes: say so, and mint bare only
192
+ if the user agrees. On a decline, mint nothing and skip `attach`; the hook stays.
97
193
 
98
194
  **Non-mux parity.** If the probe reported no multiplexer or pane, `attach` is a no-op —
99
195
  that is expected, not a failure. Still run `unit register --standing --handle legate` on yes, and complete
100
196
  **without erroring**. The root session surfaces owner mail via the `!spawnedBy` fallback instead of a
101
197
  bound pane.
102
198
 
199
+ ### 6. An owner already minted — add or drop a home
200
+
201
+ Reached only from step 3, in a root session with a broader onboarding intent, when `legate` is
202
+ already minted. Never re-ask the bind and never run `attach` here. Re-registering a standing owner
203
+ refreshes the same record — the same id, its bound presence kept — so it is not a second mint.
204
+
205
+ With no multiplexer or pane in the probe, offer nothing here — neither adding nor dropping a home.
206
+
207
+ - **No home** — explain the presence and the trust-prompt acceptance as in step 5 and offer to give the owner one. On a folder, run
208
+ `unit register --standing --handle legate --home <dir>` with exactly one of `--harness` /
209
+ `--agent`, exactly as in step 5; a refusal is handled the same way.
210
+ If the CLI rejects `--home` (or `--clear-home`) as an unknown option, say it predates homes and
211
+ change nothing.
212
+ - **A home** — name its folder and offer to drop it. On a yes:
213
+
214
+ ```bash
215
+ node scripts/cyberlegion.mjs unit register --standing --handle legate --clear-home
216
+ ```
217
+
218
+ - **A decline** — run nothing.
219
+
220
+ ## Troubleshooting
221
+
222
+ **A unit's `cyberlegion mail send` was denied by the auto-mode classifier** (*Permission for this
223
+ action was denied by the Claude Code auto mode classifier. Reason: [External System Writes]*) — the
224
+ `Bash(cyberlegion *)` permission rule is missing. Run this skill from a root session and say yes to
225
+ the permission ask, or run `cyberlegion init --allow-cli` there.
226
+
103
227
  ## Boundaries
104
228
 
105
- - Every mechanic here is a `cyberlegion` CLI call — this skill writes no hub state and invents no
106
- config format. Its only filesystem read is the plugin's own bundled `${CLAUDE_PLUGIN_ROOT}/.plugin/pins.json`
229
+ - Every mechanic here is a `cyberlegion` CLI call — this skill writes no hub state, invents no
230
+ config format, and never edits Claude Code's settings by hand (the permission rule goes in only
231
+ through `init --allow-cli`, only on an explicit yes in a root session). Its only filesystem read is the plugin's own bundled `${CLAUDE_PLUGIN_ROOT}/.plugin/pins.json`
107
232
  version map, to resolve the CLI pin.
108
- - It never mints or binds an owner identity without an explicit user yes.
233
+ - It never mints or binds an owner identity without an explicit user yes, and never sets or drops
234
+ an owner's home except on a folder or a drop the user named.
109
235
  - It is distinct from `legate` — sending/spawning/dispatching to a peer is `legate`'s job, not this
110
236
  skill's.
111
237
  - It is distinct from `manage-inbox` — reading or acking owner mail once bound is `manage-inbox`'s
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process'
11
11
  import { existsSync } from 'node:fs'
12
12
  import { fileURLToPath } from 'node:url'
13
13
 
14
- const FALLBACK = 'npx -y cyberlegion@1.2.0'
14
+ const FALLBACK = 'npx -y cyberlegion@1.4.0'
15
15
  const bin = new URL('../../../bin/cyberlegion.mjs', import.meta.url)
16
16
 
17
17
  if (existsSync(fileURLToPath(bin))) {
@@ -13,7 +13,7 @@ logic, loads no other governance, and writes no state of its own.
13
13
  > **Running the CLI.** Every `node scripts/cyberlegion.mjs …` command below runs the `cyberlegion` CLI
14
14
  > this plugin ships. The path is relative to this skill's own directory, not the working directory.
15
15
  > If you cannot resolve it, run the published CLI of the version that shipped this skill instead,
16
- > with the same arguments: `npx -y cyberlegion@1.2.0`.
16
+ > with the same arguments: `npx -y cyberlegion@1.4.0`.
17
17
 
18
18
  ## Doorbell vs mailbox
19
19
 
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process'
11
11
  import { existsSync } from 'node:fs'
12
12
  import { fileURLToPath } from 'node:url'
13
13
 
14
- const FALLBACK = 'npx -y cyberlegion@1.2.0'
14
+ const FALLBACK = 'npx -y cyberlegion@1.4.0'
15
15
  const bin = new URL('../../../bin/cyberlegion.mjs', import.meta.url)
16
16
 
17
17
  if (existsSync(fileURLToPath(bin))) {
@@ -13,7 +13,7 @@ the one owner mailbox from wherever they are.
13
13
  > **Running the CLI.** Every `node scripts/cyberlegion.mjs …` command below runs the `cyberlegion` CLI
14
14
  > this plugin ships. The path is relative to this skill's own directory, not the working directory.
15
15
  > If you cannot resolve it, run the published CLI of the version that shipped this skill instead,
16
- > with the same arguments: `npx -y cyberlegion@1.2.0`.
16
+ > with the same arguments: `npx -y cyberlegion@1.4.0`.
17
17
 
18
18
  ## Resolve the owner handle
19
19
 
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process'
11
11
  import { existsSync } from 'node:fs'
12
12
  import { fileURLToPath } from 'node:url'
13
13
 
14
- const FALLBACK = 'npx -y cyberlegion@1.2.0'
14
+ const FALLBACK = 'npx -y cyberlegion@1.4.0'
15
15
  const bin = new URL('../../../bin/cyberlegion.mjs', import.meta.url)
16
16
 
17
17
  if (existsSync(fileURLToPath(bin))) {
@@ -15,7 +15,7 @@ agent (`headless-legate`, `sdd-automaton`, the cold judges) to know how *it* rep
15
15
  > **Running the CLI.** Every `node scripts/cyberlegion.mjs …` command below runs the `cyberlegion` CLI
16
16
  > this plugin ships. The path is relative to this skill's own directory, not the working directory.
17
17
  > If you cannot resolve it, run the published CLI of the version that shipped this skill instead,
18
- > with the same arguments: `npx -y cyberlegion@1.2.0`.
18
+ > with the same arguments: `npx -y cyberlegion@1.4.0`.
19
19
 
20
20
  ## The one probe: who, if anyone, collects my return?
21
21
 
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process'
11
11
  import { existsSync } from 'node:fs'
12
12
  import { fileURLToPath } from 'node:url'
13
13
 
14
- const FALLBACK = 'npx -y cyberlegion@1.2.0'
14
+ const FALLBACK = 'npx -y cyberlegion@1.4.0'
15
15
  const bin = new URL('../../../bin/cyberlegion.mjs', import.meta.url)
16
16
 
17
17
  if (existsSync(fileURLToPath(bin))) {
@@ -14,7 +14,7 @@ the unit's **role** — see *Mid-turn messaging is scoped by role*, below.
14
14
  > **Running the CLI.** Every `node scripts/cyberlegion.mjs …` command below runs the `cyberlegion` CLI
15
15
  > this plugin ships. The path is relative to this skill's own directory, not the working directory.
16
16
  > If you cannot resolve it, run the published CLI of the version that shipped this skill instead,
17
- > with the same arguments: `npx -y cyberlegion@1.2.0`.
17
+ > with the same arguments: `npx -y cyberlegion@1.4.0`.
18
18
 
19
19
  ## 1. Resolve the agent def
20
20
 
@@ -11,7 +11,7 @@ import { spawnSync } from 'node:child_process'
11
11
  import { existsSync } from 'node:fs'
12
12
  import { fileURLToPath } from 'node:url'
13
13
 
14
- const FALLBACK = 'npx -y cyberlegion@1.2.0'
14
+ const FALLBACK = 'npx -y cyberlegion@1.4.0'
15
15
  const bin = new URL('../../../bin/cyberlegion.mjs', import.meta.url)
16
16
 
17
17
  if (existsSync(fileURLToPath(bin))) {