@sjawhar/opencode-legion-envoy 0.12.2 → 0.13.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/dist/src/server.js
CHANGED
|
@@ -13881,7 +13881,7 @@ var DISPATCH_URGENCIES = ["low", "med", "high", "blocking"];
|
|
|
13881
13881
|
var DISPATCH_TOOL_DESCRIPTION = "Raise a durable question to the human as a Dispatch thread (a GitHub issue shown on the dashboard), or continue an existing thread with a follow-up question. The reader has NOT seen your transcript. Open a thread with `subject`; continue one with `thread`. The reply arrives in this session as a steer.";
|
|
13882
13882
|
var DISPATCH_ARGUMENTS = {
|
|
13883
13883
|
subject: "Open a new thread: one line naming the decision needed (the issue title). Omit when continuing a thread with `thread`.",
|
|
13884
|
-
thread:
|
|
13884
|
+
thread: 'Continue an existing thread: "<n>" (an open issue in the repo; a plain work issue is adopted as a thread) or "owner/name#<n>". When set, omit subject, urgency, repo, and parent.',
|
|
13885
13885
|
context: `What you are doing, what you found, why you are stuck \u2014 at most ${DISPATCH_CONTEXT_MAX} characters, at most three short paragraphs or a bullet list. The reader has NOT seen your transcript: no nouns you coined this session, no internal identifiers unless the question is about them. GitHub references (#N, owner/repo#N, URLs) may be bare; the dashboard unfurls them.`,
|
|
13886
13886
|
question: `The ask, at most ${DISPATCH_QUESTION_MAX} characters, as a list: current state \u2192 desired state \u2192 your recommendation and why; options go in \`ask\`.`,
|
|
13887
13887
|
ask: "Structured questions rendered as buttons on the dashboard. Each: { question, header?, options: [{ label, description? }], multiple?, custom? }. Use this whenever the answer is one of N choices.",
|
package/package.json
CHANGED
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -154,7 +154,8 @@ dispatch({
|
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
- `thread` replaces `subject`; `urgency`, `repo`, and `parent` are not accepted with it.
|
|
157
|
-
|
|
157
|
+
`thread` names an open issue in the repo; a plain work issue is adopted as a thread on
|
|
158
|
+
first use. The issue must be open and not a pull request, or the tool says so
|
|
158
159
|
(`#N is not a dispatch thread`, `#N is closed; open a new thread`).
|
|
159
160
|
- Same decision → same thread. A genuinely new decision → a new thread, even if it came
|
|
160
161
|
up in the reply.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: legion-controller
|
|
3
|
-
description: Use when handling Legion controller wakes for root-issue triage, backlog admission, architect escalation, resync healing, human interaction
|
|
3
|
+
description: Use when handling Legion controller wakes for root-issue triage, backlog admission, architect escalation, resync healing, or human interaction.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Legion Controller
|
|
@@ -23,8 +23,8 @@ For an interactive takeover, start OMP with `LEGION_CONTROLLER_SECRET` and
|
|
|
23
23
|
|
|
24
24
|
The command resolves the project from daemon state, claims the Envoy role for the current
|
|
25
25
|
session, and posts readiness before controller commands can act. It retains the environment
|
|
26
|
-
capability for `legion admit
|
|
27
|
-
|
|
26
|
+
capability for `legion admit` and `legion backlog`. Never pass a secret as a command argument
|
|
27
|
+
or copy it into a transcript.
|
|
28
28
|
|
|
29
29
|
This handshake lets the daemon redeliver held controller work. It does not turn the controller
|
|
30
30
|
into a state holder: daemon state and GitHub artifacts remain authoritative.
|
|
@@ -49,7 +49,7 @@ into a state holder: daemon state and GitHub artifacts remain authoritative.
|
|
|
49
49
|
| Architect escalation (controller-actionable only: re-file a child as a root issue, capacity, cross-tree conflicts) | request + context | Judge and act; issue-scoped human Q&A goes through `dispatch` from the owning architect, not here |
|
|
50
50
|
| Resync report | artifact-driven anomaly list (zero-owner trees, erroring issues) | Verify against fresh state, then dispatch/heal |
|
|
51
51
|
| Mention | Slack/GitHub @mention text | Answer, or route to the owning issue's architect role |
|
|
52
|
-
|
|
|
52
|
+
| Closed-tree activity (comment, review, CI on a closed tree) | issue, root, event summary | Read the artifact; if work should resume, `legion admit <root>`; otherwise no action — the event is not held or redelivered |
|
|
53
53
|
| Direct user message | — | Always first |
|
|
54
54
|
|
|
55
55
|
## New issue triage
|
|
@@ -111,19 +111,6 @@ human-facing information. Otherwise resolve the authoritative owning architect r
|
|
|
111
111
|
route the verified context with `envoy_publish`. Do not route raw event traffic or invent a
|
|
112
112
|
role token from a partial issue reference.
|
|
113
113
|
|
|
114
|
-
## Approval interpretation
|
|
115
|
-
|
|
116
|
-
For an ambiguous human comment on a gated issue, verify the current issue, gate state, and
|
|
117
|
-
comment's meaning. If it is Sami's approval, apply the daemon transition:
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
legion approve <issue>
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
This applies `human-approved` and clears `needs-approval` atomically. It is not a generic
|
|
124
|
-
label-edit operation. The design gate remains skill-enforced by the architect, and the
|
|
125
|
-
merge gate remains config-armed until Sami approves the final reviewed head.
|
|
126
|
-
|
|
127
114
|
## Label vocabulary
|
|
128
115
|
|
|
129
116
|
Use only the project labels below, with their stated ownership:
|
|
@@ -1,47 +1,88 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: legion-worker
|
|
3
|
-
description: Use when dispatched as
|
|
3
|
+
description: Use when dispatched as a per-process Legion phase worker — architect (on a child issue), planner, implementer, tester, reviewer, or merger — booted from the daemon's LEGION_* environment.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Legion Phase Worker
|
|
7
7
|
|
|
8
|
-
You are one phase in a shared issue workspace,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
You are one phase in a shared issue workspace, running as your own OMP process — not a
|
|
9
|
+
`task`-spawned subagent and not a pipeline coordinator. The architect owns the tree; each
|
|
10
|
+
phase gets its own long-lived process against the same jj workspace, run in turn. Complete
|
|
11
|
+
the phase assigned to you, report its completion to the architect, and leave the durable
|
|
12
|
+
copy the next phase can trust.
|
|
12
13
|
|
|
13
14
|
## Identity, scope, and role
|
|
14
15
|
|
|
15
|
-
The
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
The daemon spawns you as a separate `omp --mode rpc` process (behind `legion worker-shim`,
|
|
17
|
+
in a tmux pane) with `LEGION_TREE`, `LEGION_ISSUE`, `LEGION_ROLE`, `LEGION_GENERATION`,
|
|
18
|
+
`LEGION_BOOT_TOKEN`, `LEGION_DAEMON_URL`, `LEGION_STATE_DIR`, and `LEGION_WORKSPACE` in your
|
|
19
|
+
environment (`LEGION_PROJECT` is also supplied, but nothing reads it). The extension
|
|
20
|
+
completes the boot handshake for you at session start — it registers with the daemon, claims
|
|
21
|
+
your role, and signals readiness. You never call `envoy_role_set` yourself.
|
|
22
|
+
|
|
23
|
+
Your role token is not the issue key spelled out literally. The daemon encodes it as
|
|
24
|
+
`legion-<project>-<encoded-owner>__<encoded-repo>-<number>-<role>`, escaping `_`, `.`, and
|
|
25
|
+
`-` within the owner and repo names (`_u`, `_d`, `_h`) so `__` is always the one safe
|
|
26
|
+
separator. For example, project `acme`, issue `sjawhar/legion#41`, role `architect` encodes
|
|
27
|
+
to `legion-acme-sjawhar__legion-41-architect`. Never hand-format one for another role: the
|
|
28
|
+
daemon's boot response already gives you your own token, and the `roleToken` helper in
|
|
29
|
+
`@legion/contracts` computes any other one exactly the way the daemon does — reuse a token
|
|
30
|
+
you've already been given before recomputing it.
|
|
31
|
+
|
|
32
|
+
If the handshake fails (a rejected boot token, or a bootstrap failure after your role
|
|
33
|
+
registered), the extension logs it and exits the process outright — it does not retry, and
|
|
34
|
+
you do not troubleshoot it by hand. The daemon resumes this same session from its recorded
|
|
35
|
+
session file the next time this role is needed; that is not an instant automatic respawn.
|
|
36
|
+
|
|
37
|
+
Once ready, your assignment arrives as the first prompt in your session — you do not fetch
|
|
38
|
+
it. Read the current issue and its acceptance criteria before changing the workspace. Work
|
|
39
|
+
only on this phase's artifact.
|
|
40
|
+
|
|
41
|
+
You never spawn another Legion role: spawning a worker
|
|
42
|
+
(`legion({op: "spawn_worker", ... })`) is architect-only. You may still use ordinary `task`
|
|
43
|
+
scouts, reviewers, and oracle subagents for your own phase work; they are not Legion roles.
|
|
44
|
+
Escalate a product, scope, cross-phase, or lifecycle decision to the owning architect with
|
|
45
|
+
`envoy_publish` to its role topic (`notifications.role.` followed by its encoded token, see
|
|
46
|
+
above), carrying the verified facts and the decision needed. `hub` only reaches subagents
|
|
47
|
+
inside your own process, not the architect's separate one. For a durable question that needs
|
|
48
|
+
Sami directly, you may use the raw `dispatch` MCP tool yourself; replies return to your own
|
|
49
|
+
session.
|
|
50
|
+
|
|
51
|
+
Because the same agent is always resumed for its phase, you may receive more than one
|
|
52
|
+
assignment across your lifetime: after you complete and go idle, a later event (a review
|
|
53
|
+
round, a question) can deliver a new prompt to this same session. Treat it as a
|
|
54
|
+
continuation — re-read the current issue and your own prior handoff, since time has
|
|
55
|
+
passed — never as a fresh identity.
|
|
56
|
+
|
|
57
|
+
## Asking another role
|
|
58
|
+
|
|
59
|
+
Reach any live role on this issue the same way you reach the architect: `envoy_publish` to
|
|
60
|
+
`notifications.role.` followed by that role's encoded token. Use it when you need context an
|
|
61
|
+
earlier phase has that its handoff doesn't cover — ask the planner why a constraint was
|
|
62
|
+
scoped that way, ask the implementer what a commit actually did. A role that finished its
|
|
63
|
+
phase is still alive and idle in its pane; it answers.
|
|
26
64
|
|
|
27
65
|
## Workspace and handoff precedence
|
|
28
66
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
path with:
|
|
67
|
+
`LEGION_WORKSPACE` is the authoritative issue workspace. Before reading repository files or
|
|
68
|
+
handoffs, you **MUST** bind to that exact path with:
|
|
32
69
|
|
|
33
70
|
```bash
|
|
34
|
-
cd -- "
|
|
71
|
+
cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" status
|
|
35
72
|
```
|
|
36
73
|
|
|
37
74
|
Never rely on the inherited cwd. Every later repository shell command **MUST** begin
|
|
38
|
-
`cd -- "
|
|
39
|
-
filesystem tool paths **MUST** be absolute under that workspace. Do not create an
|
|
40
|
-
worktree, change the workspace topology, or mix another issue's work into it.
|
|
41
|
-
issues have disjoint workspaces;
|
|
75
|
+
`cd -- "$LEGION_WORKSPACE" &&`; every jj command **MUST** use `-R "$LEGION_WORKSPACE"`; and
|
|
76
|
+
native filesystem tool paths **MUST** be absolute under that workspace. Do not create an
|
|
77
|
+
isolated worktree, change the workspace topology, or mix another issue's work into it.
|
|
78
|
+
Concurrent issues have disjoint workspaces; only the currently active phase mutates this
|
|
79
|
+
one. After you complete and go idle, treat `$LEGION_WORKSPACE` as read-only: you are kept
|
|
80
|
+
alive to answer questions, not to keep editing. Do not create new commits, run
|
|
81
|
+
`jj -R "$LEGION_WORKSPACE" new`, or touch tracked files once your own handoff is committed
|
|
82
|
+
and pushed — a code change belongs to whichever phase is active now.
|
|
42
83
|
|
|
43
84
|
On every start, and especially after revival or re-creation, read the issue and then the
|
|
44
|
-
committed predecessor handoffs in lifecycle order from
|
|
85
|
+
committed predecessor handoffs in lifecycle order from `$LEGION_WORKSPACE/.legion/`:
|
|
45
86
|
|
|
46
87
|
1. `architect.json`
|
|
47
88
|
2. `plan.json`
|
|
@@ -49,39 +90,42 @@ committed predecessor handoffs in lifecycle order from `<workspace>/.legion/`:
|
|
|
49
90
|
4. `test.json`
|
|
50
91
|
5. `review.json`
|
|
51
92
|
|
|
52
|
-
Read only files that precede the assigned phase.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
93
|
+
Read only files that precede the assigned phase. There is no handoff schema (rejected
|
|
94
|
+
design — no schema validation runs anywhere in this pipeline): write the phase-specific
|
|
95
|
+
fields the next phase and the architect need, consistent with what predecessor phases
|
|
96
|
+
already wrote. The durable copy lives in `$LEGION_WORKSPACE/.legion/<phase>.json`. If a
|
|
97
|
+
committed handoff conflicts with memory or a prior transcript, the committed file wins: it
|
|
98
|
+
is the copy that survived.
|
|
56
99
|
|
|
57
100
|
## jj Safety Rules
|
|
58
101
|
|
|
59
|
-
- **Always `jj -R "
|
|
60
|
-
`jj -R "
|
|
61
|
-
and makes `jj abandon` dangerous.
|
|
62
|
-
- **Never `jj -R "
|
|
63
|
-
stop and send the owning architect the `jj -R "
|
|
64
|
-
- **Before pushing, check ancestry:** `jj -R "
|
|
65
|
-
verify only your issue's commits are in the chain, not unrelated work.
|
|
102
|
+
- **Always `jj -R "$LEGION_WORKSPACE" new` to create isolated commits.** Never
|
|
103
|
+
`jj -R "$LEGION_WORKSPACE" edit @-` to go back to a parent — this changes what `@` points
|
|
104
|
+
to and makes `jj abandon` dangerous.
|
|
105
|
+
- **Never `jj -R "$LEGION_WORKSPACE" abandon`.** If a mistake would require abandoning
|
|
106
|
+
work, stop and send the owning architect the `jj -R "$LEGION_WORKSPACE" log` evidence.
|
|
107
|
+
- **Before pushing, check ancestry:** `jj -R "$LEGION_WORKSPACE" log -r 'ancestors(@, 5)'`
|
|
108
|
+
— verify only your issue's commits are in the chain, not unrelated work.
|
|
66
109
|
|
|
67
|
-
**Shared operation safety:** Never run `jj op restore` in a Legion workspace. It rewrites
|
|
68
|
-
shared operation log. If a mistake reaches that point, stop and send the owning
|
|
69
|
-
`jj -R "
|
|
110
|
+
**Shared operation safety:** Never run `jj op restore` in a Legion workspace. It rewrites
|
|
111
|
+
the shared operation log. If a mistake reaches that point, stop and send the owning
|
|
112
|
+
architect the `jj -R "$LEGION_WORKSPACE" log` evidence; recover only through the approved,
|
|
113
|
+
path-scoped workflow.
|
|
70
114
|
|
|
71
115
|
## Phase work
|
|
72
116
|
|
|
73
|
-
Follow the repository's normal engineering workflow and the assigned issue's acceptance
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
or a local status model.
|
|
117
|
+
Follow the repository's normal engineering workflow and the assigned issue's acceptance
|
|
118
|
+
criteria. Your phase's own charter and the predecessor handoffs you read define the phase
|
|
119
|
+
artifact and its completion evidence. Do not replace architect-owned decomposition, gate
|
|
120
|
+
discipline, scheduling, or human communication with labels or a local status model.
|
|
77
121
|
|
|
78
|
-
Commit attribution is automatic: the
|
|
79
|
-
|
|
122
|
+
Commit attribution is automatic: the extension exports a `JJ_CONFIG` overlay when your
|
|
123
|
+
session starts, so every jj commit you make carries an `Omp-Session: <this-session-id>`
|
|
80
124
|
trailer with no action from you. Do not add attribution trailers by hand.
|
|
81
125
|
|
|
82
|
-
The jj configuration already supplies
|
|
83
|
-
identity. Do not override Git identity configuration.
|
|
84
|
-
|
|
126
|
+
The jj configuration already supplies your phase's plus-addressed author and committer
|
|
127
|
+
identity. Do not override Git identity configuration. Your session receives the credential
|
|
128
|
+
capability it needs; invoke GitHub through the credential helper:
|
|
85
129
|
|
|
86
130
|
```bash
|
|
87
131
|
legion gh -- <gh args…>
|
|
@@ -89,9 +133,9 @@ legion gh -- <gh args…>
|
|
|
89
133
|
|
|
90
134
|
## GitHub comment attribution
|
|
91
135
|
|
|
92
|
-
Append this exact structured footer to **every** GitHub issue comment, pull-request
|
|
93
|
-
and review that this phase posts. It preserves session provenance on the artifact
|
|
94
|
-
work stays attributable to the session that produced it:
|
|
136
|
+
Append this exact structured footer to **every** GitHub issue comment, pull-request
|
|
137
|
+
comment, and review that this phase posts. It preserves session provenance on the artifact
|
|
138
|
+
itself so work stays attributable to the session that produced it:
|
|
95
139
|
|
|
96
140
|
```html
|
|
97
141
|
<!-- legion: {"session":"<session-id>","phase":"<phase>"} -->
|
|
@@ -107,71 +151,132 @@ legion gh -- issue comment <issue-number> \
|
|
|
107
151
|
|
|
108
152
|
## Implementer push and pull request
|
|
109
153
|
|
|
110
|
-
Only the implementer creates the issue bookmark, pushes it, and opens the pull request.
|
|
111
|
-
its implementation commit and verification, it uses this exact branch name and push
|
|
154
|
+
Only the implementer creates the issue bookmark, pushes it, and opens the pull request.
|
|
155
|
+
After its implementation commit and verification, it uses this exact branch name and push
|
|
156
|
+
procedure:
|
|
112
157
|
|
|
113
158
|
```bash
|
|
114
|
-
cd -- "
|
|
115
|
-
jj -R "
|
|
116
|
-
jj -R "
|
|
159
|
+
cd -- "$LEGION_WORKSPACE" && \
|
|
160
|
+
jj -R "$LEGION_WORKSPACE" bookmark set legion/issue-<n> && \
|
|
161
|
+
jj -R "$LEGION_WORKSPACE" git push --bookmark legion/issue-<n> --allow-new
|
|
117
162
|
```
|
|
118
163
|
|
|
119
164
|
The provisioned issue workspace configures `credential.helper` with the daemon's absolute
|
|
120
|
-
credential command, so `jj -R "
|
|
121
|
-
same session capability. Never handle a token.
|
|
165
|
+
credential command, so `jj -R "$LEGION_WORKSPACE" git push` authenticates transparently
|
|
166
|
+
through the same session capability. Never handle a token.
|
|
122
167
|
|
|
123
168
|
Then create the pull request with the `github` tool's `pr_create` operation. The credential
|
|
124
|
-
helper and `legion gh` provide the GitHub identity; never export, fetch, or replace a
|
|
125
|
-
Other phases advance the existing branch rather than creating a replacement
|
|
169
|
+
helper and `legion gh` provide the GitHub identity; never export, fetch, or replace a
|
|
170
|
+
token. Other phases advance the existing branch rather than creating a replacement
|
|
171
|
+
bookmark or PR.
|
|
126
172
|
|
|
127
|
-
##
|
|
173
|
+
## PR body and merge-queue discipline
|
|
174
|
+
|
|
175
|
+
The implementer writes the PR body in the merge queue's READY format from the moment the
|
|
176
|
+
PR opens, and every later phase keeps it current rather than replacing it:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
## Verification
|
|
180
|
+
|
|
181
|
+
**CI:** `pr-checks-result` run <run-id> — success at <head-sha>.
|
|
182
|
+
|
|
183
|
+
**Threads:** <n> resolved, 0 unresolved. Each disposed individually, never in bulk:
|
|
184
|
+
- Thread <id>: fixed in <commit-sha> — <one line>.
|
|
185
|
+
- Thread <id>: not a defect — <reason>.
|
|
186
|
+
|
|
187
|
+
**Thermo:** thermonuclear-deep-review + thermonuclear-code-quality run once at <head-sha>:
|
|
188
|
+
<verdict>. (omitted entirely on a docs-only PR — no thermo pass runs)
|
|
189
|
+
|
|
190
|
+
**E2E:** <surface> — ran `<command or run id>`, observed <result>, at head <sha>.
|
|
191
|
+
Negative control: <deliberately broken input> → <refusal or failure observed>.
|
|
128
192
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
193
|
+
**Fast-follow:** <one named cleanup item and where it will land>, or "none".
|
|
194
|
+
|
|
195
|
+
**Chain:** stacked on <base bookmark> frozen at <sha> / not stacked.
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
- **Threads are dispositioned individually, never resolved in bulk.** Every open review
|
|
199
|
+
thread gets its own line naming the fixing commit or the reason it isn't a defect before
|
|
200
|
+
it is marked resolved.
|
|
201
|
+
- **Correctness fixes land in this PR; cleanup is one named fast-follow.** A finding that
|
|
202
|
+
changes behavior, hides an error, or breaks a gate is fixed here — never deferred.
|
|
203
|
+
Findings about naming, duplication, or wording are batched into the single `Fast-follow`
|
|
204
|
+
line instead of iterating per push.
|
|
205
|
+
- The tester fills in the `E2E` section: the real surface a user reaches the criterion
|
|
206
|
+
through, the exact command or run id, what was observed, the head SHA, and one negative
|
|
207
|
+
control — a deliberately broken input and the refusal or failure it produced. A unit or
|
|
208
|
+
integration test is a regression lock, never proof of a criterion.
|
|
209
|
+
- The reviewer verifies the `CI`, `Threads`, and `E2E` facts against GitHub directly —
|
|
210
|
+
never from a handoff — then runs `task(agent="thermonuclear-deep-review")` and
|
|
211
|
+
`task(agent="thermonuclear-code-quality")` once at that head and records the verdict.
|
|
212
|
+
Skip the `Thermo` line entirely on a docs-only PR. Post every correctness finding as a
|
|
213
|
+
PR review comment and return the issue to the architect; when clean, delete `.legion/`,
|
|
214
|
+
push, review **that** head, and approve it by name.
|
|
215
|
+
- Once a base is frozen for others to stack on, never rewrite it — fixes land as new
|
|
216
|
+
commits on top, and the `Chain` line records what is frozen.
|
|
217
|
+
- The merger confirms the approved head still equals the current head, then publishes
|
|
218
|
+
`READY #<n> at <sha>` plus the PR body's gate facts to the merge queue's role
|
|
219
|
+
(`notifications.role.pr-queue`) with `envoy_publish`. The merger never merges; the queue
|
|
220
|
+
merges under its own authority.
|
|
221
|
+
|
|
222
|
+
## Completion gate: handoff write, verification, and persistence
|
|
133
223
|
|
|
134
224
|
Write the phase-specific handoff:
|
|
135
225
|
|
|
136
226
|
```bash
|
|
137
|
-
cd -- "
|
|
227
|
+
cd -- "$LEGION_WORKSPACE" && \
|
|
138
228
|
legion handoff write --phase <p> --data '<JSON object of phase-specific fields only>'
|
|
139
229
|
```
|
|
140
230
|
|
|
141
231
|
Then verify the durable artifact exists:
|
|
142
232
|
|
|
143
233
|
```bash
|
|
144
|
-
test -f "
|
|
234
|
+
test -f "$LEGION_WORKSPACE/.legion/<phase>.json"
|
|
145
235
|
```
|
|
146
236
|
|
|
147
237
|
Then commit that exact handoff file onto the issue branch:
|
|
148
238
|
|
|
149
239
|
```bash
|
|
150
|
-
cd -- "
|
|
151
|
-
jj -R "
|
|
240
|
+
cd -- "$LEGION_WORKSPACE" && \
|
|
241
|
+
jj -R "$LEGION_WORKSPACE" split -m "<phase>: record handoff" .legion/<phase>.json
|
|
152
242
|
```
|
|
153
243
|
|
|
154
|
-
If the issue bookmark exists locally, advance it and push it with the provisioned
|
|
155
|
-
helper. `--allow-new` also publishes the locally provisioned bookmark on its
|
|
244
|
+
If the issue bookmark exists locally, advance it and push it with the provisioned
|
|
245
|
+
credential helper. `--allow-new` also publishes the locally provisioned bookmark on its
|
|
246
|
+
first push:
|
|
156
247
|
|
|
157
248
|
```bash
|
|
158
|
-
cd -- "
|
|
159
|
-
jj -R "
|
|
160
|
-
jj -R "
|
|
249
|
+
cd -- "$LEGION_WORKSPACE" && \
|
|
250
|
+
jj -R "$LEGION_WORKSPACE" bookmark set legion/issue-<n> && \
|
|
251
|
+
jj -R "$LEGION_WORKSPACE" git push --bookmark legion/issue-<n> --allow-new
|
|
161
252
|
```
|
|
162
253
|
|
|
163
|
-
Do not report phase completion until the write, existence check, and handoff commit
|
|
164
|
-
when an issue branch exists, its push is also required. This is the committed
|
|
165
|
-
phase reads after revival. The reviewer later removes `.legion/` as its final
|
|
166
|
-
workers do not remove it.
|
|
254
|
+
Do not report phase completion until the write, existence check, and handoff commit
|
|
255
|
+
succeed; when an issue branch exists, its push is also required. This is the committed
|
|
256
|
+
copy the next phase reads after revival. The reviewer later removes `.legion/` as its final
|
|
257
|
+
commit; phase workers do not remove it.
|
|
258
|
+
|
|
259
|
+
## Completion: report to the architect, then stay
|
|
167
260
|
|
|
168
|
-
|
|
261
|
+
Report completion to the architect with:
|
|
169
262
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
263
|
+
```bash
|
|
264
|
+
cd -- "$LEGION_WORKSPACE" && \
|
|
265
|
+
legion handoff complete --summary '<two sentences for the architect>'
|
|
266
|
+
```
|
|
174
267
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
268
|
+
This publishes your phase's completion to the architect's role and clears the daemon's
|
|
269
|
+
record of this issue's active phase. Do not add pipeline labels, run a controller loop, or
|
|
270
|
+
invent a different completion protocol — this is the whole contract.
|
|
271
|
+
|
|
272
|
+
**Stay in this session afterward.** Your process does not exit when your phase completes;
|
|
273
|
+
it goes idle in its pane. Other roles on this issue may reach you through Envoy with
|
|
274
|
+
questions about the work you did — answer them, reading `$LEGION_WORKSPACE` and your own
|
|
275
|
+
committed handoff as needed, without mutating anything (see Workspace and handoff
|
|
276
|
+
precedence above). You will also be the one resumed, with a new prompt in this same
|
|
277
|
+
session, if this phase's work needs to run again.
|
|
278
|
+
|
|
279
|
+
When blocked on lifecycle, scope, or cross-phase matters, `envoy_publish` the owning
|
|
280
|
+
architect a concise message: issue, phase, verified observation, what you tried, and the
|
|
281
|
+
decision required. Reach for `dispatch` yourself only for a standalone human question
|
|
282
|
+
outside that coordination.
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
# Repository Configuration (.legion/config.yml)
|
|
2
|
-
|
|
3
|
-
Workers load repository-specific configuration from `.legion/config.yml` at the workspace root. This file allows teams to customize Legion behavior per repository without modifying workflows.
|
|
4
|
-
|
|
5
|
-
## Schema Overview
|
|
6
|
-
|
|
7
|
-
The config file is YAML with the following top-level sections:
|
|
8
|
-
|
|
9
|
-
```yaml
|
|
10
|
-
merge:
|
|
11
|
-
require_smoke_test: boolean
|
|
12
|
-
require_reporter_approval: boolean
|
|
13
|
-
auto_merge_allowed: boolean
|
|
14
|
-
|
|
15
|
-
testing:
|
|
16
|
-
require_specific_task: boolean
|
|
17
|
-
require_taiga_evidence: boolean
|
|
18
|
-
|
|
19
|
-
notifications:
|
|
20
|
-
slack_channel: string
|
|
21
|
-
ping_reporter_on_pr: boolean
|
|
22
|
-
|
|
23
|
-
skills:
|
|
24
|
-
required:
|
|
25
|
-
- skill_name_1
|
|
26
|
-
- skill_name_2
|
|
27
|
-
|
|
28
|
-
phases:
|
|
29
|
-
architect:
|
|
30
|
-
# Phase-specific overrides (same keys as top-level)
|
|
31
|
-
plan:
|
|
32
|
-
# Phase-specific overrides
|
|
33
|
-
implement:
|
|
34
|
-
# Phase-specific overrides
|
|
35
|
-
test:
|
|
36
|
-
# Phase-specific overrides
|
|
37
|
-
review:
|
|
38
|
-
# Phase-specific overrides
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Field Reference
|
|
42
|
-
|
|
43
|
-
### merge
|
|
44
|
-
|
|
45
|
-
Controls merge behavior and approval gates.
|
|
46
|
-
|
|
47
|
-
| Field | Type | Default | Description |
|
|
48
|
-
|-------|------|---------|-------------|
|
|
49
|
-
| `require_smoke_test` | boolean | `false` | If `true`, merge workflow requires evidence of smoke testing before auto-merge |
|
|
50
|
-
| `require_reporter_approval` | boolean | `false` | If `true`, merge workflow requires explicit reporter approval before merging |
|
|
51
|
-
| `auto_merge_allowed` | boolean | `false` | If `true`, merge workflow may auto-merge PRs that pass all gates |
|
|
52
|
-
|
|
53
|
-
### testing
|
|
54
|
-
|
|
55
|
-
Controls test requirements and evidence gates.
|
|
56
|
-
|
|
57
|
-
| Field | Type | Default | Description |
|
|
58
|
-
|-------|------|---------|-------------|
|
|
59
|
-
| `require_specific_task` | boolean | `false` | If `true`, test workflow requires evidence of specific task testing (not just unit tests) |
|
|
60
|
-
| `require_taiga_evidence` | boolean | `false` | If `true`, test workflow requires Taiga evidence (e.g., screenshots, logs) attached to the issue |
|
|
61
|
-
|
|
62
|
-
### notifications
|
|
63
|
-
|
|
64
|
-
Controls notifications and pings.
|
|
65
|
-
|
|
66
|
-
| Field | Type | Default | Description |
|
|
67
|
-
|-------|------|---------|-------------|
|
|
68
|
-
| `slack_channel` | string | `null` | Slack channel ID (e.g., `#eng-legion`) where implementation status updates are posted. If set and `slack-bot` skill is available, implement workflow posts PR URL and CI state |
|
|
69
|
-
| `ping_reporter_on_pr` | boolean | `false` | If `true`, notify the issue reporter when a PR is created |
|
|
70
|
-
|
|
71
|
-
### skills
|
|
72
|
-
|
|
73
|
-
Specifies skills that should be invoked for all phases.
|
|
74
|
-
|
|
75
|
-
| Field | Type | Default | Description |
|
|
76
|
-
|-------|------|---------|-------------|
|
|
77
|
-
| `required` | string[] | `[]` | List of skill names to invoke in addition to plan handoff `requiredSkills` and independently discovered skills. Additive with other skill sources |
|
|
78
|
-
|
|
79
|
-
### phases
|
|
80
|
-
|
|
81
|
-
Phase-specific overrides. Each phase (`architect`, `plan`, `implement`, `test`, `review`) can override any top-level key.
|
|
82
|
-
|
|
83
|
-
**Merge behavior:** Phase-specific values override top-level values. For example:
|
|
84
|
-
|
|
85
|
-
```yaml
|
|
86
|
-
merge:
|
|
87
|
-
require_reporter_approval: false
|
|
88
|
-
|
|
89
|
-
phases:
|
|
90
|
-
implement:
|
|
91
|
-
merge:
|
|
92
|
-
require_reporter_approval: true # Override for implement phase only
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Recognized Keys
|
|
96
|
-
|
|
97
|
-
Workers recognize the following keys (case-sensitive):
|
|
98
|
-
|
|
99
|
-
- `merge.require_smoke_test`
|
|
100
|
-
- `merge.require_reporter_approval`
|
|
101
|
-
- `merge.auto_merge_allowed`
|
|
102
|
-
- `testing.require_specific_task`
|
|
103
|
-
- `testing.require_taiga_evidence`
|
|
104
|
-
- `notifications.slack_channel`
|
|
105
|
-
- `notifications.ping_reporter_on_pr`
|
|
106
|
-
- `skills.required`
|
|
107
|
-
- `phases.<mode>.*` (any of the above keys under a phase)
|
|
108
|
-
|
|
109
|
-
Unknown keys are silently ignored. Malformed YAML causes the config to be skipped (fallback to defaults).
|
|
110
|
-
|
|
111
|
-
## Worker Behavior
|
|
112
|
-
|
|
113
|
-
### Loading
|
|
114
|
-
|
|
115
|
-
Each workflow loads config at startup:
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
if [ -f .legion/config.yml ]; then cat .legion/config.yml; fi
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
If the file is missing or malformed, workers proceed with defaults (no error).
|
|
122
|
-
|
|
123
|
-
### Parsing
|
|
124
|
-
|
|
125
|
-
Workers parse recognized keys and echo them for auditability:
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
Repo config constraints from .legion/config.yml:
|
|
129
|
-
- merge.require_reporter_approval: true
|
|
130
|
-
- testing.require_specific_task: true
|
|
131
|
-
- skills.required: [test-driven-development, verification-before-completion]
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Application
|
|
135
|
-
|
|
136
|
-
Config values are applied to shape workflow behavior:
|
|
137
|
-
|
|
138
|
-
- **Plan phase:** Config constraints inform the plan preamble (e.g., "reporter approval required before merge")
|
|
139
|
-
- **Implement phase:** Config-required skills are invoked additively with plan handoff skills
|
|
140
|
-
- **Test phase:** Config gates (e.g., `require_specific_task`) are enforced
|
|
141
|
-
- **Review phase:** Config-required skills are invoked additively
|
|
142
|
-
- **Merge phase:** Config gates (e.g., `require_reporter_approval`) are enforced
|
|
143
|
-
|
|
144
|
-
## Example Configuration
|
|
145
|
-
|
|
146
|
-
### Minimal (all defaults)
|
|
147
|
-
|
|
148
|
-
```yaml
|
|
149
|
-
# Empty file or omitted entirely
|
|
150
|
-
# All defaults apply
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Strict Testing
|
|
154
|
-
|
|
155
|
-
```yaml
|
|
156
|
-
testing:
|
|
157
|
-
require_specific_task: true
|
|
158
|
-
require_taiga_evidence: true
|
|
159
|
-
|
|
160
|
-
skills:
|
|
161
|
-
required:
|
|
162
|
-
- test-driven-development
|
|
163
|
-
- verification-before-completion
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Slack Notifications + Approval Gate
|
|
167
|
-
|
|
168
|
-
```yaml
|
|
169
|
-
notifications:
|
|
170
|
-
slack_channel: "#eng-legion"
|
|
171
|
-
ping_reporter_on_pr: true
|
|
172
|
-
|
|
173
|
-
merge:
|
|
174
|
-
require_reporter_approval: true
|
|
175
|
-
require_smoke_test: true
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Phase-Specific Overrides
|
|
179
|
-
|
|
180
|
-
```yaml
|
|
181
|
-
# Default: no approval required
|
|
182
|
-
merge:
|
|
183
|
-
require_reporter_approval: false
|
|
184
|
-
|
|
185
|
-
# But for implement phase, require approval
|
|
186
|
-
phases:
|
|
187
|
-
implement:
|
|
188
|
-
merge:
|
|
189
|
-
require_reporter_approval: true
|
|
190
|
-
|
|
191
|
-
# And require specific task testing only in test phase
|
|
192
|
-
phases:
|
|
193
|
-
test:
|
|
194
|
-
testing:
|
|
195
|
-
require_specific_task: true
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Full Example
|
|
199
|
-
|
|
200
|
-
```yaml
|
|
201
|
-
merge:
|
|
202
|
-
require_smoke_test: true
|
|
203
|
-
require_reporter_approval: false
|
|
204
|
-
auto_merge_allowed: false
|
|
205
|
-
|
|
206
|
-
testing:
|
|
207
|
-
require_specific_task: true
|
|
208
|
-
require_taiga_evidence: false
|
|
209
|
-
|
|
210
|
-
notifications:
|
|
211
|
-
slack_channel: "#eng-legion"
|
|
212
|
-
ping_reporter_on_pr: true
|
|
213
|
-
|
|
214
|
-
skills:
|
|
215
|
-
required:
|
|
216
|
-
- test-driven-development
|
|
217
|
-
- verification-before-completion
|
|
218
|
-
|
|
219
|
-
phases:
|
|
220
|
-
plan:
|
|
221
|
-
skills:
|
|
222
|
-
required:
|
|
223
|
-
- brainstorming
|
|
224
|
-
implement:
|
|
225
|
-
merge:
|
|
226
|
-
require_reporter_approval: true
|
|
227
|
-
test:
|
|
228
|
-
testing:
|
|
229
|
-
require_taiga_evidence: true
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## Defaults
|
|
233
|
-
|
|
234
|
-
If a key is not specified in `.legion/config.yml`, the following defaults apply:
|
|
235
|
-
|
|
236
|
-
```yaml
|
|
237
|
-
merge:
|
|
238
|
-
require_smoke_test: false
|
|
239
|
-
require_reporter_approval: false
|
|
240
|
-
auto_merge_allowed: false
|
|
241
|
-
|
|
242
|
-
testing:
|
|
243
|
-
require_specific_task: false
|
|
244
|
-
require_taiga_evidence: false
|
|
245
|
-
|
|
246
|
-
notifications:
|
|
247
|
-
slack_channel: null
|
|
248
|
-
ping_reporter_on_pr: false
|
|
249
|
-
|
|
250
|
-
skills:
|
|
251
|
-
required: []
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## Notes
|
|
255
|
-
|
|
256
|
-
- **Additive skills:** Config-required skills are additive with plan handoff `requiredSkills` and independently discovered skills. All sources are combined.
|
|
257
|
-
- **Phase overrides:** Phase-specific values completely override top-level values for that phase. Partial overrides are not merged.
|
|
258
|
-
- **Missing file:** If `.legion/config.yml` is missing or malformed, workers proceed with defaults (no error).
|
|
259
|
-
- **Auditability:** Workers echo recognized keys and effective values at the start of each phase for transparency.
|