@sjawhar/opencode-legion-envoy 5.11.2 → 6.0.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.
@@ -15809,7 +15809,7 @@ function followsAsk(owner) {
15809
15809
  return `You follow this ask: its answer and replies reach you directly. For every event on ${owner.label}: envoy_subscribe ${owner.topic}`;
15810
15810
  }
15811
15811
  var triageAdviceShown = new Set;
15812
- var SPEC_CHECK_REMINDER = 'Has a fresh reader checked this spec? Each claim about how a system works today should trace to code read or a command run, and each requirement to the human\'s words or a cited fact. If not, have a fresh read-only subagent (`plan-gap-analyst` on Oh My Pi) check it now and fix what it finds. See the `dispatch-first` skill, "Design in the spec".';
15812
+ var SPEC_CHECK_REMINDER = 'Has a fresh reader checked this spec? Each claim about how a system works today should trace to code read or a command run, and each requirement to the human\'s words or a cited fact. If not, have a fresh read-only subagent check it now and fix what it finds: on Oh My Pi, `task(agent="scout")`, or whatever read-only agent your host bundles; a Legion architect\'s own spec uses the Legion plugin\'s `plan-gap-analyst` agent instead, which only a Legion session has. See the `dispatch-first` skill, "Design in the spec".';
15813
15813
  function renderAdvice(tool, key, advice, opts) {
15814
15814
  if (advice === undefined)
15815
15815
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/opencode-legion-envoy",
3
- "version": "5.11.2",
3
+ "version": "6.0.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/src/server.js",
package/skills/AGENTS.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Skills Layer
2
2
 
3
3
  Legion skills guide the architect and its sequential phase workers in a shared issue workspace.
4
- They are Markdown instructions loaded by Oh My Pi sessions; the daemon and OMP extension own
5
- event intake, process lifecycle, credentials, and role delivery.
4
+ They are Markdown instructions loaded by Oh My Pi sessions; the daemon and the two Oh My Pi plugins
5
+ (`packages/pi-envoy`, `packages/pi-legion`) own event intake, process lifecycle, credentials, and role delivery.
6
6
 
7
7
  | Skill | Who reads it | What it owns |
8
8
  | --- | --- | --- |
@@ -20,8 +20,9 @@ event intake, process lifecycle, credentials, and role delivery.
20
20
  | `thermonuclear-deep-review/` | the `thermonuclear-deep-review` agent, and the reviewer (the Security Guidelines) | the correctness rubric of the reviewer's pair, with its tagged, diff-triggered Security Guidelines and the attack on the PR body's claims (adapted from the MIT-licensed Thermos plugin in `cursor/plugins`; `LICENSE` beside it) |
21
21
 
22
22
  The owning skill above is where each contract is defined; a role prompt that needs a contract from its own seat points there or restates only its own step. This file lists and does not restate.
23
- A Legion prompt (a skill here, a role prompt, or an agent definition in `packages/pi-envoy/agents/`) names a task agent only as `task(agent="<name>")` and a skill it tells the model to load only as `skill://<name>`. Those are the two forms the Go daemon's boot gate and `legion probe-image` resolve through Oh My Pi, refusing by name one it cannot find; a dispatch or a load written any other way goes unchecked. An agent or skill Legion's prompts name is shipped here or in `packages/pi-envoy/agents/`, unless Oh My Pi bundles it.
24
- A skill file an agent loads stays under 51,200 bytes, Oh My Pi's spill threshold (a longer one arrives with its middle cut out), and a skill's detail lives in `references/` files linked as `skill://<name>/references/<file>.md`, never by relative path, which a read by path cuts at 300 lines. `packages/pi-envoy/src/skills-guard.test.ts` fails on a file at the threshold, on any `SKILL.md` body of 500 lines or more, on a skill whose frontmatter `name` is not its directory's name, on a `dispatch-first` over its budget, on a `skill://<name>/<path>` link that names a missing file or a missing `#heading`, and on a `legion-worker` reference nothing links.
23
+ The skills here ship in two Oh My Pi plugins, and the partition is kept in one place, `scripts/pi-plugin-prepack.sh` at the repository root, keyed by package name: `@sjawhar/pi-envoy` (`packages/pi-envoy`) ships `dispatch`, `dispatch-first`, `dispatch-brainstorming` and `envoy`, the skills every session with Dispatch reads; `@sjawhar/pi-legion` (`packages/pi-legion`) ships `legion-architect`, `legion-controller`, `legion-oracle`, `legion-retro`, `legion-worker`, `ce-simplify-code`, `thermonuclear-code-quality` and `thermonuclear-deep-review`, the skills a Legion pane's prompts load. Each plugin's prepack stages its list into its `dist/skills`, and `packages/pi-shared/test/skills-partition.test.ts` holds the two lists to this directory: together they are every skill directory here, and none is in both. A link from a skill in one partition into a skill in the other (a Legion skill's link into `dispatch`) is written `skill://<name>/<path>`, never as a relative path: a staged partition is installed on its own, so a relative link out of it dangles, while a `skill://` link resolves by name once both plugins are installed.
24
+ A Legion prompt (a skill here, a role prompt, or an agent definition in `packages/pi-legion/agents/`) names a task agent only as `task(agent="<name>")` and a skill it tells the model to load only as `skill://<name>`. Those are the two forms the Go daemon's boot gate and `legion probe-image` resolve through Oh My Pi, refusing by name one it cannot find; a dispatch or a load written any other way goes unchecked. An agent or skill Legion's prompts name is shipped here or in `packages/pi-legion/agents/`, unless Oh My Pi bundles it.
25
+ A skill file an agent loads stays under 51,200 bytes, Oh My Pi's spill threshold (a longer one arrives with its middle cut out), and a skill's detail lives in `references/` files linked as `skill://<name>/references/<file>.md`, never by relative path, which a read by path cuts at 300 lines. The rules are `packages/pi-shared/test/skills-guard.ts`, run over each plugin's staged partition: `packages/pi-envoy/src/skills-guard.test.ts` over the Envoy plugin's four skills, with the `dispatch-first` budget check, and `packages/pi-legion/src/skills-guard.test.ts` over the Legion plugin's eight, with the daemon's prompts as linking roots and every `legion-worker` reference linked from somewhere. Each fails on a file at the threshold, on any `SKILL.md` body of 500 lines or more, on a skill whose frontmatter `name` is not its directory's name, on a `skill://<name>/<path>` link that names a missing file or a missing `#heading` (resolved against this directory, where both partitions live), and on a relative link that leaves the staged partition or names no file. The Envoy guard also fails on a `task(agent="<name>")` in the Envoy plugin's skills that names an agent neither that plugin nor Oh My Pi bundles (the bundled list read off the pinned binary's `omp agents unpack` under `LEGION_TEST_OMP`, never written down), since those skills reach a session with no other plugin installed; a `skill://legion-*` mention there is a sentence conditioned on a Legion role, inert for a person and right for a pane with both plugins, which the guard leaves alone.
25
26
  The text a worker boots with (its role prompt) lives in `packages/daemon/internal/prompts/roles/`,
26
27
  embedded in the `legion` binary and composed per role by `packages/daemon/internal/prompts/prompts.go`;
27
28
  `packages/daemon/internal/prompts/roles_test.go` holds the structural rules for those parts.
@@ -50,7 +50,7 @@ found yourself.
50
50
  A design conversation with a person, or the implementation plan that follows one, uses
51
51
  `skill://dispatch-brainstorming`: read it before your first design question on a change, the spec,
52
52
  or that plan. It replaces superpowers' `brainstorming` and `writing-plans` here, even when the user
53
- invokes one by name. A Legion architect's own issue spec follows `skill://legion-architect`. Before a spec's first version and each approval request, have a fresh read-only subagent (on Oh My Pi, `task(agent="plan-gap-analyst")`) check it against the code, the human's words and any command output a claim rests on, and resolve what it flags.
53
+ invokes one by name. Before a spec's first version and each approval request, have a fresh read-only subagent (on Oh My Pi, `task(agent="scout")`, or whatever read-only agent the host bundles) check it against the code, the human's words and any command output a claim rests on, and resolve what it flags. A Legion architect's own issue spec follows `skill://legion-architect`, and its fresh reader in that Legion session is the Legion plugin's `plan-gap-analyst` agent.
54
54
 
55
55
  ## Load the full skill before you write
56
56
 
@@ -77,14 +77,14 @@ exercise a criterion end to end, building that path is a child issue of this tre
77
77
  answers the tree's asks); under a personal token it goes to that token's owner, whom
78
78
  `dispatch_whoami` names. Set it only when a human told you a specific person owns that child.
79
79
 
80
- Specifications written into Dispatch follow `skill://dispatch`'s "Writing a spec" section.
80
+ Specifications written into Dispatch follow `skill://dispatch`'s [Writing a spec](skill://dispatch/SKILL.md#writing-a-spec).
81
81
  Wave releases, child closures, and your own status are visible from the issue tree and the
82
82
  handoffs; do not narrate them into the spec or a `dispatch_message`. A to-do only a human can
83
83
  clear is a `dispatch_ask`.
84
84
 
85
85
  The issue's primary document **is** the root specification. Extend it in place: a new version
86
86
  that adds only the evidence each decision needs and what the human decides, each as a
87
- decision block (`skill://dispatch`, "Decision blocks"). The decomposition and its waves, how each
87
+ [decision block](skill://dispatch/SKILL.md#decision-blocks). The decomposition and its waves, how each
88
88
  outcome is proven, and the integration test are your own calls: they go in the child issues and
89
89
  the planner's `.legion/<issue>/plan.json`, not the root spec. Never post a second "spec" artifact beside
90
90
  it (`dispatch_artifact` with the primary document's name replaces the human's document; do not do
@@ -112,7 +112,7 @@ legion({
112
112
  ```
113
113
 
114
114
  The decision blocks come first: settle every one as
115
- "Approval of a spec" (`skill://dispatch`) says before you request approval;
115
+ [Approval of a spec](skill://dispatch/SKILL.md#approval-of-a-spec) says before you request approval;
116
116
  `dispatch_request_approval` refuses while one is open. Each answer reaches you, since you follow
117
117
  every ask you open. An approval request carries nothing new: request it only once the human has
118
118
  agreed to every point in the spec, so a point they have not agreed to gets its own decision block
@@ -26,8 +26,8 @@ For an interactive takeover from a hand-started OMP session, start OMP with
26
26
  `LEGION_DAEMON_URL`, `LEGION_PROJECT` (the daemon's project), `LEGION_STATE_DIR`, and `LEGION_GRANT_FILE`
27
27
  (an absolute path to a file only you can read, under a 0700 directory; the extension writes
28
28
  each command's grant there and every `bash` call is blocked without it) in its environment. Do
29
- not set `LEGION_CONTROLLER=1` — that marker is `legion controller start`'s own, and a session
30
- carrying it claims at startup. Then run:
29
+ not set `LEGION_CONTROLLER=1` — that marker is the launched controller's own (`legion controller
30
+ start`'s session, or the daemon's pod), and a session carrying it claims at startup. Then run:
31
31
 
32
32
  ```text
33
33
  /legion-claim-controller
@@ -50,12 +50,27 @@ retry. And the role does not follow `/new` or `/fork` in a takeover session —
50
50
  `LEGION_CONTROLLER=1` the new session is not a Legion session to the extension — so after either
51
51
  command run `/legion-claim-controller` again.
52
52
 
53
- The daemon holds nothing for a controller: daemon state and the Dispatch project remain
54
- authoritative, and the start procedure below reads what happened while no controller ran.
53
+ Daemon state and the Dispatch project remain authoritative, and the start procedure below reads
54
+ what happened while no controller ran. Who launched you is the deployment's `controller` setting:
55
+ the operator, or the daemon itself. The `How this controller runs` part of your system prompt says
56
+ which.
57
+
58
+ ### Started by the daemon
59
+
60
+ Under `controller: daemon` the daemon launched you as a pod in the cluster and supervises you like
61
+ a root architect: you run headless (`omp --mode rpc`), nobody types into your session, and nobody
62
+ reads your replies as they appear. The extension registered with your launch's boot token, claimed
63
+ the role, subscribed to the controller topic and reported ready; the daemon then sent your start
64
+ message. When your pod dies the daemon relaunches it and resumes this same session, with a new
65
+ start message, so run the start procedure each time one arrives. A human reaches you through
66
+ Dispatch (a message to your session on the Agents page, a reply to an ask you opened, a mention) or
67
+ Envoy: answer them where they will read it, a Dispatch message or reply, since text left only in
68
+ your session reaches no one. `legion state` and `legion status <KEY> <status>` work as below. There
69
+ is no `legion controller start` against this daemon, and nobody can replace you with one.
55
70
 
56
71
  ### Started by the operator
57
72
 
58
- The daemon launches no controller, under either runtime: the operator ran
73
+ Under `controller: operator`, the default, the daemon launches no controller: the operator ran
59
74
  `legion controller start --config controller.yaml [--daemon-url <url>]` on
60
75
  their own machine, and you are that foreground OMP session. The command fetched a fresh controller
61
76
  secret from the daemon with the operator's token, wrote it to a 0600 file under `LEGION_STATE_DIR`
@@ -78,8 +93,10 @@ mints a new secret, so your grants stop working and the role moves to the new se
78
93
  The Go daemon's controller topic is a wake for a session that is running when it is published.
79
94
  Envoy hands an Oh My Pi session no retained copy of a notice published before it subscribed, so a
80
95
  hold, a tree architect's failed claim, a new triage root, or a freed slot from while no controller
81
- ran never arrives as a wake. `legion controller start` opens your first turn with a start message
82
- (`Legion controller start: …`), so every start and restart runs this procedure with nothing typed.
96
+ ran never arrives as a wake. Every launch opens your first turn with a start message
97
+ (`Legion controller start: …`) — `legion controller start` passes it, and the daemon sends it to a
98
+ controller it launched once that controller is ready — so every start and restart runs this
99
+ procedure with nothing typed.
83
100
  At every start, after the claim recheck ([Turn discipline](#turn-discipline)) and before anything
84
101
  else:
85
102
 
@@ -350,7 +367,7 @@ priority first, then board rank ([Keeping the slots full](#keeping-the-slots-ful
350
367
  `unassigned`, `Unassigned — nobody's Inbox shows this tree's questions or its design approval
351
368
  until someone takes it from the issue header (Assignee, beside Priority)`. The design approval
352
369
  is promised only when the `Design gate policy:` line of your system prompt, which
353
- `legion controller start` writes from the daemon's own configuration, says
370
+ whoever launched you writes from the daemon's own configuration, says
354
371
  `gates.design: root-issues`. Under `gates.design: off` nobody approves a design, so drop "and
355
372
  its design approval" (and "or its design approval") from the sentence. An unassigned root
356
373
  still runs; the architect's asks wait in every Inbox's Unassigned band.
@@ -167,7 +167,7 @@ other tree paused.
167
167
 
168
168
  ## Phase work
169
169
 
170
- Specifications written into Dispatch follow `skill://dispatch`'s "Writing a spec" section, except that a phase worker writes no decision block: it sends an open product, scope or design decision to its architect, which writes the block.
170
+ Specifications written into Dispatch follow `skill://dispatch`'s [Writing a spec](skill://dispatch/SKILL.md#writing-a-spec), except that a phase worker writes no decision block: it sends an open product, scope or design decision to its architect, which writes the block.
171
171
 
172
172
  Follow the repository's normal engineering workflow and the assigned issue's acceptance
173
173
  criteria. Your phase's own charter and the predecessor handoffs you read define the phase