cyberlegion 0.3.2 → 0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberlegion",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Harness-agnostic agent session spawning and messaging over the filesystem",
5
5
  "keywords": [
6
6
  "agent",
@@ -30,7 +30,13 @@
30
30
  },
31
31
  "files": [
32
32
  "bin",
33
- "dist"
33
+ "dist",
34
+ "plugin.json",
35
+ ".claude-plugin",
36
+ ".codex-plugin",
37
+ ".plugin",
38
+ "skills",
39
+ "agents"
34
40
  ],
35
41
  "dependencies": {
36
42
  "commander": "^14.0.3",
package/plugin.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "cyberlegion",
4
+ "version": "0.4.0",
5
+ "description": "Agent session spawning, messaging, and dispatch — the Legion and its Legate.",
6
+ "author": {
7
+ "name": "unional"
8
+ },
9
+ "homepage": "https://github.com/cyberuni/cyberlegion",
10
+ "repository": "https://github.com/cyberuni/cyberlegion",
11
+ "keywords": ["agent", "dispatch", "inter-agent", "multiplexer"],
12
+ "extensions": {
13
+ "org.cyberuni.universal-plugin": {
14
+ "vendors": ["claude-code", "codex"],
15
+ "packagePath": ".",
16
+ "skills": "./skills",
17
+ "agents": ["./agents/headless-legate.md"],
18
+ "harnesses": {
19
+ "claude-code": {},
20
+ "codex": {}
21
+ }
22
+ }
23
+ }
24
+ }
package/readme.md CHANGED
@@ -98,6 +98,66 @@ Top-level shortcuts are provided for the common verbs: `spawn`, `send`, `inbox`,
98
98
  | `--space <path>` | Isolate the hub root (overrides the global hub / `$CYBERLEGION_ROOT`) |
99
99
  | `--format <format>` | Output format: `toon` (default) or `json` |
100
100
 
101
+ ## Agent plugin
102
+
103
+ Agent session spawning, messaging, and dispatch — harness-agnostic, MCP-free. The foundation both
104
+ SDD and cyberfleet build on: a **Legion** of addressable agent units, mustered and reaped, commanded
105
+ and communicating over the filesystem.
106
+
107
+ ### The console
108
+
109
+ The `cyberlegion` CLI is the cold, deterministic mechanism: identity (`unit register`, `unit claim`,
110
+ `unit who`), warm peer sessions in their own git worktrees (`unit spawn`, `unit close`,
111
+ `unit prune`), durable mail (`mail send`, `mail inbox`, `mail read`, `mail await`),
112
+ agent-definition resolution (`agent resolve`), hook registration (`init`), and
113
+ admin/diagnostics (`mux doctor`, `admin migrate`). It never decides *when* to spawn a peer
114
+ versus a subagent, and it carries no dispatch/result-slot primitives of its own — a cold subagent
115
+ returns via the caller's own Task-result, a warm peer via `mail await`.
116
+
117
+ ### The Legate
118
+
119
+ The **Legate** is the routing brain on top of the console — the judgment the CLI deliberately does
120
+ not carry. In an attended session it runs in-session as `dispatch-governance`; with no user channel
121
+ it is realized headless as the `headless-legate` agent. Given an intent (fulfill a role with a brief, expect a
122
+ verdict), it reads the target agent-definition's `warm`/`interactive` tags and the environment's
123
+ multiplexer availability, then picks exactly one strategy:
124
+
125
+ - **channel** — a warm, interactive peer in its own pane (`unit spawn` + `mail await` on the thread)
126
+ - **run-inline** — no multiplexer to host a peer, so the caller does the work itself, in-session
127
+ - **subagent** — a cold, one-shot unit realized via the caller's own Task tool, taking its
128
+ Task-result (final returned message) as the verdict
129
+
130
+ ### The gateway
131
+
132
+ `legate` (the skill) is the thin front door — classify the request (send mail, check inbox,
133
+ spawn/close a unit, wait for a reply, dispatch work) and either run the matching CLI call directly or
134
+ hand routing judgment to `dispatch-governance`. It loads no governance itself and writes no state.
135
+
136
+ ### Onboarding and the owner mailbox
137
+
138
+ Two more user-facing skills sit beside the gateway:
139
+
140
+ - **`init-cyberlegion`** — the onboarding front door: probe the environment, register the
141
+ mail-surfacing hook so incoming mail reaches you mid-session, and (only in a root session, only on
142
+ an explicit yes) bind this pane as the durable `legate` owner inbox. Every step is a
143
+ `cyberlegion` CLI call; the skill holds the conversation and the judgment.
144
+ - **`manage-inbox`** — the human's surface for that **owner mailbox**: the hub-level,
145
+ session-independent inbox a standing identity holds, where frameless agents (cron-started, no
146
+ parent frame) push their reports. It's how you read and ack those reports from whichever session
147
+ you happen to be in.
148
+
149
+ ### Installation
150
+
151
+ ```bash
152
+ npx skills add cyberuni/cyberplace --plugin cyberlegion --global
153
+ ```
154
+
155
+ This package doubles as the plugin root: `plugin.json`, the generated `.claude-plugin/` and
156
+ `.codex-plugin/` manifests, `skills/`, and `agents/` all ship in the npm tarball. The bundle
157
+ carries the version it was built against in `.plugin/pins.json`, and its skills read that pin to invoke `npx cyberlegion@<version> …` rather than inventing a version. In a
158
+ workspace checkout with no bundled pin, they fall back to the unpinned `npx cyberlegion …` form or
159
+ the local bin (`packages/cyberlegion/bin/cyberlegion.mjs`).
160
+
101
161
  ## License
102
162
 
103
163
  MIT
@@ -0,0 +1,29 @@
1
+ # dispatch-governance
2
+
3
+ Partial Skill: invoke by name only — the Legate's routing brain. Not user-invocable — loaded by the `legate` gateway
4
+ in-session on a dispatch intent, and by the `headless-legate` agent when there is no user channel.
5
+
6
+ ## When it loads
7
+
8
+ - The `legate` gateway classified a request as "dispatch work to fulfill a role and expect a
9
+ verdict back."
10
+ - The `headless-legate` agent realizes the same flow headless.
11
+
12
+ ## What it does
13
+
14
+ - Resolves the target agent definition's `warm`/`interactive` tags (`cyberlegion agent resolve`).
15
+ - Probes the environment for a multiplexer (`cyberlegion mux doctor`).
16
+ - Picks exactly one of three strategies — **channel** (warm peer: `unit spawn` + `mail await`),
17
+ **run-inline** (caller does the work itself), or **subagent** (cold, one-shot, via
18
+ `subagent-backend-governance`) — and executes it by composing the `cyberlegion` CLI primitives.
19
+ - Folds in the wake-matrix decision (bounded await vs doorbell vs run-inline, gated on a verified
20
+ multiplexer) that the CLI no longer encodes.
21
+ - Defines the `subagent | channel` seam a dependent (SDD, ADR-0023) references by intent, never by
22
+ a literal command name.
23
+
24
+ ## What it does not do
25
+
26
+ - Never lets the CLI auto-route — there is no `--backend auto` flag, and no `dispatch` command
27
+ group at all; `unit spawn`/`mail await`/`unit nudge` are composed here deliberately.
28
+ - Never invokes a harness's Task tool directly (that happens inside `subagent-backend-governance`,
29
+ using the caller's own tool).
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: dispatch-governance
3
+ description: "Partial Skill: invoke by name only — the Legate's routing brain — picks and executes a dispatch strategy for a role intent. Loaded in-session by the legate gateway, and by the headless-legate agent headless. Not triggered by users directly."
4
+ user-invocable: false
5
+ ---
6
+
7
+ # Dispatch Governance
8
+
9
+ The judgment the `cyberlegion` CLI deliberately does not carry. The CLI is dumb hands — it never
10
+ auto-routes, never picks a backend, never invokes a Task tool itself. This governance is the one
11
+ place that judgment lives, loaded in-session by the `legate` gateway on a dispatch intent, and
12
+ realized headless by the `headless-legate` agent. Both loads run the exact same procedure below.
13
+
14
+ **Input:** an intent to fulfill role `R` with brief `B`, optionally expecting a result that
15
+ satisfies verdict schema `V`.
16
+
17
+ ## 1. Resolve the agent definition
18
+
19
+ ```bash
20
+ npx cyberlegion@0.3.1 agent resolve <R> --format json
21
+ ```
22
+
23
+ Read `model`, `effort`, `harness`, `warm`, `interactive` off the resolved def. `warm` marks a role
24
+ that should run as a live peer session (not a fire-and-forget unit); `interactive` marks a role that
25
+ may need to grill the caller or converse over multiple rounds, not just return one result.
26
+
27
+ ## 2. Probe the environment
28
+
29
+ ```bash
30
+ npx cyberlegion@0.3.1 mux doctor --format json
31
+ ```
32
+
33
+ Read whether a multiplexer was ancestry-discovered (tmux/herdr) — a **channel** strategy needs one
34
+ to open a pane in; its absence rules that strategy out regardless of what the agent def wants.
35
+
36
+ ## 3. Pick exactly one strategy
37
+
38
+ | `warm` | `interactive` | mux present | Strategy |
39
+ |---|---|---|---|
40
+ | true | true | true | **channel** |
41
+ | true | true | false | **run-inline** |
42
+ | false or true | false | — | **subagent** |
43
+ | false | true | — | **error** — unroutable def |
44
+
45
+ - **channel** — warm, interactive, and a pane is available: spin up a live peer that can converse
46
+ and mail back over rounds. Compose the primitives directly — no single CLI command does this:
47
+
48
+ mint a thread id, weave it (and an instruction to reply on it) into brief `B`, then:
49
+
50
+ ```bash
51
+ npx cyberlegion@0.3.1 unit spawn --agent <R> --brief-file <B> --at <placement>
52
+ npx cyberlegion@0.3.1 mail await --thread <the-minted-thread-id> [--timeout <ms>] [--max-wait <s>]
53
+ ```
54
+
55
+ `unit spawn` launches the peer (its brief tells it what thread to reply on); `mail await` then
56
+ blocks on that reply thread. Use `--at` to place the pane, `--timeout`/`--max-wait` to bound the
57
+ wait; a `waiting` outcome at `--max-wait` means re-run `mail await` on the same thread to keep
58
+ polling, not a failure.
59
+
60
+ **The wake-matrix decision** (which sub-mode of channel to run) belongs here too, since the CLI
61
+ carries no `selectWakePath` helper of its own:
62
+
63
+ | Environment | Wake mode |
64
+ |---|---|
65
+ | Portable default (mux unknown, or nothing verified) | Bounded await — poll `mail await` with `--max-wait`, re-arming on `waiting` ("A-loop"). |
66
+ | Claude Code, with an observable background task | Bounded await plus a background-task check-in ("A-prime") — same polling, but the harness's own background-task surface can short-circuit a wait. |
67
+ | A live foreign session behind a **verified** multiplexer (`mux doctor` reports tmux/herdr, not `none`) | Doorbell — `unit nudge` the peer's pane, then `mail await` ("B"). |
68
+ | Multiplexer is `none` | **Never** pick doorbell (B) — there is no pane to ring. Fall back to bounded await (A). |
69
+
70
+ - **run-inline** — the role is warm and interactive (needs a live back-and-forth), but there is no
71
+ multiplexer to host a peer in. **Do not delegate.** Return a `run-inline` verdict and let the
72
+ caller (the session that loaded this governance — e.g. the SDD conductor) do the work itself,
73
+ in-session. A cold subagent is the wrong substitute here: it cold-reloads its whole context every
74
+ round and holds no user channel, so a role that needs to converse cannot be served that way.
75
+
76
+ - **subagent** — the role is cold and one-shot (no live conversation expected, one result back).
77
+ Realize it via `subagent-backend-governance`: resolve the agent def → the caller's **own** harness
78
+ Task/subagent tool → the subagent's Task-result (its own final returned message) is the verdict.
79
+ The CLI cannot invoke a Task tool itself — that is always the caller's own tool, never
80
+ `cyberlegion`'s — and it collects nothing on the caller's behalf; there is no result file.
81
+
82
+ - **error (unroutable def)** — `interactive` with `warm` unset (`false`) has no strategy. A role that
83
+ needs live back-and-forth (`interactive`) must be a live peer (`warm`); a cold one-shot must not be
84
+ `interactive` (`subagent-backend-governance` is one-shot by design). So this pair is a **malformed
85
+ def**, not a routing choice — **fail loud** here, naming the def and the contradictory tags, so the
86
+ author fixes it. It is **not** a `needsInput` (that is for an under-specified task, not a bad def),
87
+ and it is **never** silently swept into **subagent**. This is the Legate's judgment, not the CLI's:
88
+ `agent resolve` reports the raw tags; only this governance holds the table that knows the pair maps
89
+ to nothing.
90
+
91
+ The CLI never chooses between these on its own — `unit spawn` + `mail await` only run in this
92
+ sequence when this governance picked **channel**; the caller's Task tool only runs when it picked
93
+ **subagent**; picking **run-inline** means neither runs at all.
94
+
95
+ ## The `subagent | channel` seam
96
+
97
+ This is the seam a dependent (e.g. SDD, ADR-0023) references **by intent** — "dispatch a role
98
+ fulfillment and expect a verdict" — never by pinning `subagent` or `channel` as a literal command
99
+ name. The dependent states its intent (role, brief, verdict schema) and this governance decides the
100
+ mechanism; a dependent that hardcodes "always subagent" or "always channel" has broken the seam and
101
+ coupled itself to a mechanism instead of an intent.
102
+
103
+ ## Result shape — DispatchResult
104
+
105
+ Every strategy resolves to one shape the caller can handle uniformly:
106
+
107
+ ```jsonc
108
+ {
109
+ "strategy": "subagent" | "channel" | "run-inline",
110
+ "id": "<unit id, when one was spawned>", // omitted for run-inline
111
+ "verdict": "matched" | "waiting" | "timed-out" | "run-inline",
112
+ "result": { /* the subagent's Task-result, or the mail-await reply body, as-is */ },
113
+ "needsInput": ["<question>", "..."] // present only when the callee could not complete
114
+ }
115
+ ```
116
+
117
+ `result` is carried through unvalidated today — structured verdict-schema checking against `V` is a
118
+ deferred capability (`mail --verdict-schema`), not present in this CLI.
119
+
120
+ `waiting` (channel path, `--max-wait` cap hit) and `timed-out` (channel path, `--timeout` elapsed)
121
+ are re-armable and terminal respectively — treat them the same way `mail await`'s own three
122
+ outcomes are treated; never silently retry past a `timed-out`. A `needsInput` result on the subagent
123
+ path means the unit hit its own leash and returned a needs-input result rather than guessing.
124
+
125
+ **How you relay that `needsInput` (or your own) is `relay-governance`, not this skill.** Report/ask
126
+ transport is keyed on the reporting agent's own lifecycle — a framed callee returns `needsInput` to
127
+ its caller; a bare cron session with no frame pushes mail to the standing owner and exits. Load
128
+ `relay-governance` for the fork; this skill owns **strategy** choice (channel / run-inline /
129
+ subagent), relay owns how the result or an unanswerable question gets home.
130
+
131
+ ## Non-goals
132
+
133
+ - **No auto-routing in the CLI.** The CLI carries no `dispatch` command group at all — `unit spawn`,
134
+ `mail await`, `unit nudge`, and the caller's own Task tool are invoked deliberately by this
135
+ governance (or `subagent-backend-governance`), never by a `--backend auto` flag — no such flag
136
+ exists.
137
+ - **No mid-flight strategy switch.** Once a strategy is picked for one dispatch, it runs to its one
138
+ of the three outcomes above; a failed subagent is not silently retried as a channel.
@@ -0,0 +1,14 @@
1
+ # init-cyberlegion
2
+
3
+ The onboarding front door to the Legion — walks a session through getting `cyberlegion` working in
4
+ this repo: probe the environment, register the surfacing hook, and (root session only, only on an
5
+ explicit yes) bind this pane as the durable `legate` owner inbox.
6
+
7
+ User-facing. Triggers on "set up cyberlegion", "onboard the legion", "register the cyberlegion
8
+ surfacing hook", "make this pane my main legion inbox", "get cyberlegion working in this repo". Wraps
9
+ `cyberlegion mux doctor` / `init` / `unit register --standing` / `attach` — every mechanic is a
10
+ CLI call, no filesystem or hub state touched directly.
11
+
12
+ Distinct from `legate` (spawn/mail/dispatch a peer) and `manage-inbox` (read/ack owner mail once
13
+ bound). See `SKILL.md` for the full flow (probe → register hook → detect root vs spawned →
14
+ consent-gated bind).
@@ -0,0 +1,110 @@
1
+ ---
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."
4
+ ---
5
+
6
+ # init-cyberlegion
7
+
8
+ The onboarding front door to the Legion — a thin, user-invocable wrapper that walks a session through
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.
11
+ It is a **thin wrapper**: every mechanic is a `cyberlegion` CLI call. The skill holds the *conversation
12
+ and the judgment* — is this a root session? should we ask to bind? what does the environment look
13
+ like? — the CLI holds all the *mechanism*.
14
+
15
+ > **Version pin.** Resolve the CLI version **once, before the flow**, by reading the plugin's bundled
16
+ > map at `${CLAUDE_PLUGIN_ROOT}/.plugin/pins.json` — a flat `{ "<package>": "<version>" }` map the
17
+ > `universal-plugin bundle` step emits at release time. Look up the `cyberlegion` key:
18
+ >
19
+ > - **A version is found** → use it for every `npx cyberlegion@0.3.1 ...` call below, **and** pass
20
+ > it to the hook registration in step 2 as `init --pin <version>` so the installed surfacing hook is
21
+ > pinned to the same shipped version.
22
+ > - **No `pins.json`, no `cyberlegion` key, or a malformed map** (an unbundled workspace checkout) →
23
+ > fall back to the unpinned `npx cyberlegion ...` form and pass **no** `--pin`. **Never invent a
24
+ > version number.**
25
+ >
26
+ > Do not scrape the version from prose. (`legion-publish` — actually publishing `cyberlegion` to npm —
27
+ > is a later extraction CR; until then the npx pin is dormant and the local workspace bin serves.)
28
+
29
+ ## Flow
30
+
31
+ ### 1. Probe the environment
32
+
33
+ ```bash
34
+ npx cyberlegion@0.3.1 mux doctor
35
+ ```
36
+
37
+ Run this **before** touching the hook or any identity. It reports `harness`, `mux`, `pane`,
38
+ `hubRoot`, and `selfId` — read it to learn the environment (is there a multiplexer? a pane?) and to
39
+ detect root vs spawned (see step 3). Narrate a short, grounded summary of what it found — do not
40
+ invent facts the probe did not report.
41
+
42
+ ### 2. Register the surfacing hook
43
+
44
+ ```bash
45
+ npx cyberlegion@0.3.1 init --pin <version>
46
+ ```
47
+
48
+ Pass `--pin <version>` with the version resolved above so the installed hook is pinned to the shipped
49
+ version; **omit `--pin`** (and use the unpinned `npx cyberlegion init`) when the map yielded no version.
50
+
51
+ Auto-detect is the default — no `--agent` flag. Pass `--agent <name>` **only** when `mux doctor` could
52
+ not auto-detect the harness, or the user named one explicitly (it composes with `--pin`):
53
+
54
+ ```bash
55
+ npx cyberlegion@0.3.1 init --pin <version> --agent <name>
56
+ ```
57
+
58
+ This step is **idempotent**: if the hook is already registered, `init` reports `already present` —
59
+ that is a clean no-op, never a duplicate registration and never an error.
60
+
61
+ ### 3. Detect root vs spawned — derived, never asked
62
+
63
+ Read the probe's `selfId` from step 1. A **root** session has `spawnedBy` unset; a **spawned** unit
64
+ has it set. Derive this from the probe — never ask the user to declare it.
65
+
66
+ - **Spawned (non-root) unit** — stop here, right after the hook. Do not offer to bind; a spawned unit
67
+ is never the owner inbox.
68
+ - **A hook-only request in a root session** ("just register the surfacing hook") — also stop here.
69
+ Registering the hook satisfies the ask; do not proceed to the bind offer unasked.
70
+ - **Root session, broader onboarding intent, no `legate` owner bound yet** — continue to step 4.
71
+ - **Root session where a `legate` owner is already bound** — stop; do not re-ask, do not re-mint.
72
+
73
+ ### 4. Ask before binding — never silent
74
+
75
+ Only a root session with no `legate` owner bound is offered the bind. Ask plainly, e.g.:
76
+
77
+ > "This looks like a root session with no legate owner bound yet. Bind this pane as the main legate
78
+ > owner inbox?"
79
+
80
+ - **User declines** — the registered hook stays in place; nothing else runs. Do not mint or bind.
81
+ - **User agrees explicitly** — proceed to step 5.
82
+ - **Already bound** — never reach this ask (see step 3).
83
+
84
+ ### 5. On an explicit yes — mint and bind
85
+
86
+ ```bash
87
+ npx cyberlegion@0.3.1 unit register --standing --handle legate
88
+ npx cyberlegion@0.3.1 attach
89
+ ```
90
+
91
+ Run these **in this order** and only after the explicit yes: mint the durable, session-independent
92
+ `legate` owner inbox first, then bind the current pane as that owner's live presence.
93
+
94
+ **Non-mux parity.** If the probe reported no multiplexer or pane, `attach` is a no-op —
95
+ that is expected, not a failure. Still run `unit register --standing --handle legate` on yes, and complete
96
+ **without erroring**. The root session surfaces owner mail via the `!spawnedBy` fallback instead of a
97
+ bound pane.
98
+
99
+ ## Boundaries
100
+
101
+ - Every mechanic here is a `cyberlegion` CLI call — this skill writes no hub state and invents no
102
+ config format. Its only filesystem read is the plugin's own bundled `${CLAUDE_PLUGIN_ROOT}/.plugin/pins.json`
103
+ version map, to resolve the CLI pin.
104
+ - It never mints or binds an owner identity without an explicit user yes.
105
+ - It is distinct from `legate` — sending/spawning/dispatching to a peer is `legate`'s job, not this
106
+ skill's.
107
+ - It is distinct from `manage-inbox` — reading or acking owner mail once bound is `manage-inbox`'s
108
+ job, not this skill's.
109
+ - An unrelated `init` intent (a git repo, an npm package, commit discipline) is out of scope — defer
110
+ to the matching unrelated skill or decline.
@@ -0,0 +1,22 @@
1
+ # legate (gateway)
2
+
3
+ The Legate's front door to the Legion — a thin classifier skill that routes an agent-to-agent
4
+ messaging or dispatch request to the matching `cyberlegion` CLI call, or to `dispatch-governance`
5
+ when the request needs routing judgment.
6
+
7
+ ## When to use
8
+
9
+ - You need to send or check mail with another agent session.
10
+ - You need to spawn, close, or nudge a peer session.
11
+ - You need to wait for a threaded reply.
12
+ - You need work done to fulfill a role and a verdict back — but do not yet know whether that should
13
+ be a warm peer, a cold subagent, or done inline.
14
+
15
+ ## What it does
16
+
17
+ - Classifies the request against a fixed intent → CLI-call table (mail, session, identity, admin).
18
+ - Hands any dispatch intent to `dispatch-governance` rather than guessing a strategy.
19
+ - Spawns the `headless-legate` agent when there is no user channel to relay through.
20
+ - Loads no other governance and writes no state — a front door only.
21
+
22
+ Every mechanic is a `cyberlegion` CLI call — harness-agnostic, MCP-free.
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: legate
3
+ description: "Use this skill when you need to reach another agent session — send a message to a named peer or \"the pane on the right\", check your inbox, wait for a reply, spawn or close a peer session, or dispatch work to fulfill a role and get a verdict back."
4
+ ---
5
+
6
+ # legate
7
+
8
+ The Legate — gateway skill for the Legion, the front door to agent session spawning, messaging, and dispatch.
9
+ It **classifies** the request and either runs the matching `cyberlegion` CLI call directly or hands
10
+ routing judgment to `dispatch-governance`. It is a **thin classifier**: it holds no production
11
+ logic, loads no other governance, and writes no state of its own.
12
+
13
+ > **Version pin.** Every invocation below reads `npx cyberlegion@0.3.1 ...` — a placeholder.
14
+ > The package is not yet published to npm (`legion-publish` is a later CR in the extraction); until
15
+ > then, resolve the CLI from a workspace checkout (`packages/cyberlegion/bin/cyberlegion.mjs`) or
16
+ > whatever pinned version the project has declared. Never invent a version number.
17
+
18
+ ## Doorbell vs mailbox
19
+
20
+ Two different primitives, never confused: a **nudge** (`unit nudge <ref>`) is a dumb doorbell —
21
+ it rings a peer's pane and carries no content. The **payload always lives in the mailbox**
22
+ (`mail send`, or the brief file `unit spawn` drops for a new unit) — a peer that receives a nudge
23
+ reads its mail to learn *why* it was rung. Never encode meaning in a nudge itself; never skip the
24
+ mailbox because a nudge already fired.
25
+
26
+ ## Classification map
27
+
28
+ | User intent | Handling |
29
+ |---|---|
30
+ | Send a message to a named peer, "the pane on the right", a claude/cursor peer | `npx cyberlegion@0.3.1 mail send --to <handle>` (or `unit nudge <ref>` first if the peer needs waking, then `mail send`) |
31
+ | Check inbox / read unread mail | `npx cyberlegion@0.3.1 mail inbox` — `mail read <msg-id>` to peek, `mail ack <msg-id>` once handled |
32
+ | Spawn a new peer session | `npx cyberlegion@0.3.1 unit spawn --agent <name> ...` — cyberlegion owns worktree creation; pass `--cwd <dir>` only when the caller already has a directory to spawn into (e.g. reusing an existing worktree) |
33
+ | Close / tear down a peer session | `npx cyberlegion@0.3.1 unit close <id>` |
34
+ | Wait for a threaded reply | `npx cyberlegion@0.3.1 mail await --thread <id>` |
35
+ | Watch mail as it streams in (observer, never acks) | `npx cyberlegion@0.3.1 mail watch` |
36
+ | List addressable peers | `npx cyberlegion@0.3.1 unit who` |
37
+ | Sweep dead peers | `npx cyberlegion@0.3.1 unit prune` |
38
+ | Onboard / set up cyberlegion (register the surfacing hook, bind the main owner pane, first-run setup) | **invoke the `init-cyberlegion` skill** — the interactive onboarding front door over `cyberlegion init` / `unit register --standing` / `attach` |
39
+ | Diagnose the environment (harness, multiplexer, pane, hub root) | `npx cyberlegion@0.3.1 mux doctor` |
40
+ | Register the surfacing hook by hand (low-level, explicit harness) | `npx cyberlegion@0.3.1 init --agent <harness>` — the `init-cyberlegion` skill wraps this; use directly only when scripting a known harness |
41
+ | Dispatch work to fulfill a role with a brief and expect a verdict back (routing judgment needed — which strategy, which agent def, warm vs cold) | **hand off to `dispatch-governance`** — do not compose `unit spawn`/`mail await`/the Task tool yourself |
42
+ | No user channel at all (unattended trigger, multi-unit fan-out) | **spawn the `headless-legate` agent** by name — it realizes this same gateway + `dispatch-governance` flow headless |
43
+
44
+ ## Load the handling skill in-session
45
+
46
+ For an attended session (a user or peer session holds this gateway), classify and act directly —
47
+ spawn nothing. The one exception is a **dispatch** intent: routing which strategy to use (warm
48
+ channel, cold subagent, or run-inline) is judgment this gateway does not carry — load
49
+ `dispatch-governance` in-session and let it decide.
50
+
51
+ **Headless (no user channel): spawn `headless-legate`.** When this gateway is reached with no live
52
+ user or peer channel to relay through — an unattended scheduler, a multi-unit fan-out — spawn the
53
+ `headless-legate` agent by name. It is not a separate role: it is this same classify-then-route flow,
54
+ realized headless, batching `needs-input` instead of asking live.
55
+
56
+ ## Boundaries
57
+
58
+ This skill never talks to the filesystem or another session directly — every mechanic is a
59
+ `cyberlegion` CLI call. It never chooses a dispatch strategy itself (that is
60
+ `dispatch-governance`'s one job) and never invokes a harness's Task/subagent tool (that is the
61
+ caller's own tool, used only inside `dispatch-governance`'s subagent path via
62
+ `subagent-backend-governance`).
@@ -0,0 +1,12 @@
1
+ # manage-inbox
2
+
3
+ The human's surface for the **owner mailbox** — the durable, session-independent inbox where
4
+ frameless (cron-started, no-parent-frame) agents push their reports via `relay-governance`.
5
+
6
+ User-facing. Triggers on "check my inbox", "any reports for me", "read that report", "ack that",
7
+ "clear my owner inbox", or when a surfaced owner-mail doorbell needs acting on. Wraps the
8
+ `cyberlegion` CLI's owner-scoped mail commands (`mail inbox/read/ack --owner <handle>`) so a human
9
+ roaming across sessions manages the one owner mailbox from anywhere.
10
+
11
+ Read is a deliberate `mail ack --owner` — surfacing shows a report inline but is never a read
12
+ receipt. See `SKILL.md` for the full flow (resolve owner → list → read → ack → reply).
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: manage-inbox
3
+ description: "Use this skill when the user wants to check, read, or clear the owner mailbox — the durable inbox where headless and cron-started agents send their reports. Triggers: 'check my inbox', 'any reports for me', 'what did the agents send', 'read that report', 'ack that', 'mark it read', 'clear my owner inbox', or acting on a surfaced owner-mail doorbell."
4
+ ---
5
+
6
+ # manage-inbox
7
+
8
+ The human's surface for the **owner mailbox** — the hub-level, session-independent inbox a standing
9
+ owner identity holds, where frameless agents (cron-started, no parent frame) push their reports. It
10
+ wraps the `cyberlegion` CLI's owner-scoped mail commands so a human roaming across sessions manages
11
+ the one owner mailbox from wherever they are.
12
+
13
+ > **Version pin.** Invocations read `npx cyberlegion@0.3.1 …` as a placeholder. Until the package
14
+ > is published, resolve the CLI from the workspace checkout (`packages/cyberlegion/bin/cyberlegion.mjs`)
15
+ > or the project's pinned version. Never invent a version number.
16
+
17
+ ## Resolve the owner handle
18
+
19
+ The owner mailbox is a **standing** identity. Find it first:
20
+
21
+ ```bash
22
+ npx cyberlegion@0.3.1 unit register --standing # lists the standing owner record(s)
23
+ ```
24
+
25
+ Use `$CYBERLEGION_OWNER` if set, else the single standing handle listed. If **no** standing owner
26
+ exists, there is no owner mailbox yet — create one with `unit register --standing --handle <name>` (that is a
27
+ deliberate act; do not auto-create it while just checking mail).
28
+
29
+ ## List — what is waiting
30
+
31
+ ```bash
32
+ npx cyberlegion@0.3.1 mail inbox --owner <handle> # all owner mail, oldest-first
33
+ npx cyberlegion@0.3.1 mail inbox --owner <handle> --unread # only what is new
34
+ ```
35
+
36
+ The aggregate line reports `<N> messages (<U> unread)`. This is a **pull** from any session — the
37
+ same unread also **surfaces** into a root session automatically (the doorbell), so you may already
38
+ have seen it inline; listing is how you review deliberately.
39
+
40
+ ## Read — peek without consuming
41
+
42
+ ```bash
43
+ npx cyberlegion@0.3.1 mail read <msg-id> --owner <handle>
44
+ ```
45
+
46
+ Prints the report body (sender, subject, id). **Read does not ack** — the message stays unread and
47
+ keeps surfacing until you explicitly clear it. Peeking is safe; it changes nothing.
48
+
49
+ ## Ack — the only thing that clears it
50
+
51
+ ```bash
52
+ npx cyberlegion@0.3.1 mail ack <msg-id> --owner <handle>
53
+ ```
54
+
55
+ Ack is the sole read-state change and the sole signal that a report is handled — a surfaced message
56
+ that was merely printed into a session is **not** read until you ack it. Ack once you have actually
57
+ acted on (or consciously dismissed) the report; acking an already-acked or unknown id errors rather
58
+ than silently succeeding. Two concurrent acks of the same message resolve to exactly one success —
59
+ nothing is double-consumed.
60
+
61
+ ## Reply — answer a frameless agent's question
62
+
63
+ A report may be a **question** a frameless agent could not ask live. Reply on its thread so a later
64
+ tick (or the agent's next run) picks up the answer:
65
+
66
+ ```bash
67
+ npx cyberlegion@0.3.1 mail send --to <agent-or-thread-origin> --thread <t> --body "<answer>"
68
+ ```
69
+
70
+ The thread carries the state across the agent's stateless re-runs.
71
+
72
+ ## Boundaries
73
+
74
+ - This skill only manages the **owner** mailbox (`--owner`). A session's own inbox is the plain
75
+ `mail inbox`/`read`/`ack` (no `--owner`) and is not this skill's concern.
76
+ - It is a thin CLI wrapper — it decides *nothing* about routing or dispatch (that is the Legate /
77
+ `dispatch-governance`), and writes no state beyond the ack/reply the human directs.
@@ -0,0 +1,36 @@
1
+ # relay-governance
2
+
3
+ Internal cyberlegion governance. The Legion's **report/ask contract**: how a headless agent (no live
4
+ user channel) returns a result or surfaces a question it cannot answer, keyed on its own lifecycle —
5
+ plus the **receive side**: how an agent triages a relayed steer by authority level.
6
+
7
+ - **Subagent** (Task-spawned, a caller frame awaits) → return `needsInput` in the `DispatchResult`.
8
+ - **Spawned peer / channel** (spawner awaits) → return the packet or reply on the mail thread.
9
+ - **Bare top-level / cron** (no frame) → push `mail send` to the standing owner and exit; a later
10
+ tick or the owner's reply resumes, state carried on the thread.
11
+
12
+ Loaded by `dispatch-governance` (to relay a callee's `needsInput`) and by any headless agent
13
+ (`headless-legate`, `sdd-automaton`, cold judges). Not user-invocable — see `SKILL.md`.
14
+
15
+ **Receiving a steer:** decompose by authority level, never bundle-adopt or bundle-reject. An
16
+ in-scope refinement (testable against the receiver's own frozen spec / CR acceptance / leash) adopts
17
+ in-band, no provenance needed; cross-cutting / out-of-leash doctrine escalates up the relay for
18
+ ratification. Provenance over peer mail cannot be established, so a receiver acts only on what it
19
+ can verify against its own loaded contract — a ratification it fetched from a peer is invalid.
20
+
21
+ **The ownership chain:** keyed on relationship, not on transport alone. A decision relayed by the
22
+ receiver's **own owner** **and** arriving on a **turn** in its own session — carrying the Council's
23
+ verbatim words, where they were said, the relaying unit, and its scope (one action on one target) —
24
+ is adoptable within that named scope and nothing adjacent, spent once acted on, attenuating at every
25
+ hop. Either half alone leaves it a peer steer. The four parts are a **well-formedness** requirement:
26
+ presence is checkable on its face, so a missing part gates adoption, and truth is not, so the parts
27
+ buy **audit** after the fact, never verification in the moment. Not forgery-proof: `unit nudge
28
+ --message` records no caller identity, so position is a structural fact, not a proof.
29
+
30
+ This is the **single home** of that rule. `subagent-backend-governance` references it for the
31
+ owner's mid-turn channel rather than restating it, and the revision part of the scope is a named
32
+ **open cross-repo seam** — a sibling corpus states a three-part scope; this one states two.
33
+
34
+ The frameless→owner branch composes the `cyberlegion` CLI's standing owner identity (`identity
35
+ owner`), owner mail (`mail send` / `mail --owner`), and owner-mail surfacing (the `surfacing` hook).
36
+ Read is a deliberate `mail ack --owner`; surfacing shows a message but is never a read receipt.