@sjawhar/pi-legion 8.3.1 → 8.4.1
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/README.md +3 -2
- package/dist/legion.js +12 -4
- package/dist/skills/legion-architect/SKILL.md +18 -15
- package/dist/skills/legion-controller/SKILL.md +12 -2
- package/dist/skills/legion-retro/SKILL.md +52 -40
- package/dist/skills/legion-worker/SKILL.md +9 -10
- package/dist/skills/legion-worker/references/merge-gate.md +22 -18
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,8 +17,9 @@ pi-envoy").
|
|
|
17
17
|
|
|
18
18
|
The Legion daemon's boot gate (`packages/daemon/internal/daemon/bootgate.go`) refuses to start
|
|
19
19
|
unless the Oh My Pi a pane will run loads this plugin at the daemon's contract
|
|
20
|
-
(`legion.daemonApiVersion` in `package.json`,
|
|
21
|
-
|
|
20
|
+
(`legion.daemonApiVersion` in this package's `package.json`, equal to `DaemonAPIVersion` in
|
|
21
|
+
`packages/daemon/internal/api/version.go`) and loads `@sjawhar/pi-envoy` with it, so both go into
|
|
22
|
+
the Oh My Pi profile the daemon's panes use:
|
|
22
23
|
|
|
23
24
|
```sh
|
|
24
25
|
omp plugin install @sjawhar/pi-envoy && omp plugin install @sjawhar/pi-legion
|
package/dist/legion.js
CHANGED
|
@@ -15193,7 +15193,7 @@ function onEnvoyRoleRegained(listener) {
|
|
|
15193
15193
|
// package.json
|
|
15194
15194
|
var package_default = {
|
|
15195
15195
|
name: "@sjawhar/pi-legion",
|
|
15196
|
-
version: "8.
|
|
15196
|
+
version: "8.4.1",
|
|
15197
15197
|
license: "Apache-2.0",
|
|
15198
15198
|
type: "module",
|
|
15199
15199
|
omp: {
|
|
@@ -15205,7 +15205,7 @@ var package_default = {
|
|
|
15205
15205
|
]
|
|
15206
15206
|
},
|
|
15207
15207
|
legion: {
|
|
15208
|
-
daemonApiVersion:
|
|
15208
|
+
daemonApiVersion: 16
|
|
15209
15209
|
},
|
|
15210
15210
|
repository: {
|
|
15211
15211
|
type: "git",
|
|
@@ -15412,13 +15412,21 @@ var legionAgentSecretsLoginView = exports_external.strictObject({
|
|
|
15412
15412
|
state: exports_external.string(),
|
|
15413
15413
|
code: exports_external.string()
|
|
15414
15414
|
});
|
|
15415
|
+
var legionCapabilityState = exports_external.strictObject({
|
|
15416
|
+
name: nonEmptyString,
|
|
15417
|
+
status: exports_external.enum(["present", "installed", "unchecked", "live", "withheld", "decided", "open"]),
|
|
15418
|
+
detail: nonEmptyString,
|
|
15419
|
+
decision: nonEmptyString.optional(),
|
|
15420
|
+
configLine: nonEmptyString.optional()
|
|
15421
|
+
});
|
|
15415
15422
|
var LegionStateResponse = exports_external.strictObject({
|
|
15416
15423
|
daemon: daemonInfo,
|
|
15417
15424
|
admission: legionAdmission,
|
|
15418
15425
|
issues: exports_external.record(exports_external.string(), legionIssue),
|
|
15419
15426
|
pendingStatusWrites: exports_external.array(legionPendingStatusWrite),
|
|
15420
15427
|
controllerLocator: legionControllerLocator.optional(),
|
|
15421
|
-
agentSecretsLogin: legionAgentSecretsLoginView.optional()
|
|
15428
|
+
agentSecretsLogin: legionAgentSecretsLoginView.optional(),
|
|
15429
|
+
capabilities: exports_external.array(legionCapabilityState)
|
|
15422
15430
|
});
|
|
15423
15431
|
var LegionRegisterResponse = exports_external.strictObject({
|
|
15424
15432
|
claimToken: nonEmptyString,
|
|
@@ -16066,7 +16074,7 @@ function handoffSchemaFields(z2) {
|
|
|
16066
16074
|
ready: z2.boolean().optional()
|
|
16067
16075
|
};
|
|
16068
16076
|
}
|
|
16069
|
-
var HANDOFF_DESCRIPTION = "Handoff actions (phase workers; the daemon accepts a completion only from the role working " + "the issue's current phase, never from an architect): handoff_write writes this phase's handoff " + "(`phase`, and `data`: the phase-specific fields as a JSON object, never the schemaVersion, " + "phase, completed and issue the command writes itself) to `.legion/<issue>/<phase>.json` in " + "the issue workspace; handoff_read returns the handoffs (every phase, or `phase`); " + "handoff_complete reports this phase complete to the daemon (`summary`: two sentences for the " + "architect, or the merger's READY packet; `verdict` pass|fail when your role's instructions " + "require one; `ready: true` for the merger's READY; no `phase` is needed, and one other than " + "your own is refused). Each " + "returns the command's output; a failed action changed nothing. What a later phase needs goes " + "in your handoff; a question for another live role goes to its role topic with envoy_publish.";
|
|
16077
|
+
var HANDOFF_DESCRIPTION = "Handoff actions (phase workers; the daemon accepts a completion only from the role working " + "the issue's current phase, never from an architect): handoff_write writes this phase's handoff " + "(`phase`, and `data`: the phase-specific fields as a JSON object, never the schemaVersion, " + "phase, completed and issue the command writes itself) to `.legion/<issue>/<phase>.json` in " + "the issue workspace; handoff_read returns the handoffs (every phase, or `phase`), a handoff " + "retro's removal of `.legion/<issue>/` took off the head read from the commit before it; " + "handoff_complete reports this phase complete to the daemon (`summary`: two sentences for the " + "architect, or the merger's READY packet; `verdict` pass|fail when your role's instructions " + "require one; `ready: true` for the merger's READY; no `phase` is needed, and one other than " + "your own is refused). Each " + "returns the command's output; a failed action changed nothing. What a later phase needs goes " + "in your handoff; a question for another live role goes to its role topic with envoy_publish.";
|
|
16070
16078
|
function rootArchitectHandoffRefusal(operation) {
|
|
16071
16079
|
return `${operation} is not available to a root architect session; a root architect reads handoffs with \`legion handoff read [--phase <phase>]\` from bash`;
|
|
16072
16080
|
}
|
|
@@ -236,9 +236,10 @@ the implementer's role topic to start retro: the daemon's start is what records
|
|
|
236
236
|
the task.
|
|
237
237
|
|
|
238
238
|
Wait for the implementer to report its durable retro result. Retro output is
|
|
239
|
-
`docs/solutions/`,
|
|
240
|
-
|
|
241
|
-
|
|
239
|
+
`docs/solutions/`, its last commit removing the issue's `.legion/<issue>/` from the head a human
|
|
240
|
+
merges, the PR body content the repository's instructions derive from the pull request's changed
|
|
241
|
+
paths at that head, and one `dispatch_message` on the issue; it must write no handoff or
|
|
242
|
+
rewrite the reviewer-approved head. When the implementer reports that it cannot
|
|
242
243
|
compute that body content or do the work a line of it affirms, that its read of the body failed or
|
|
243
244
|
came back empty, or that GitHub refused the body, it has pushed nothing and is still in its phase.
|
|
244
245
|
Answer it with `envoy_publish` to its role topic, saying how from the deployment instructions;
|
|
@@ -256,20 +257,21 @@ The daemon keeps this order from its fixed table; you start none of its steps:
|
|
|
256
257
|
|
|
257
258
|
1. tester green and review cycles complete;
|
|
258
259
|
2. on a clean review, the reviewer approves the head by SHA, and the daemon moves the issue to
|
|
259
|
-
`retro`.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
260
|
+
`retro`. The approved head still carries the issue's handoffs, `.legion/<issue>/`;
|
|
261
|
+
3. retro commits its learnings under `docs/solutions/` on top of the approved head, then, as the
|
|
262
|
+
one final commit, the removal of `.legion/<issue>/`, so no merge carries a handoff onto the
|
|
263
|
+
default branch (dispatch://LEGION-605); those commits do not void the approval and never return
|
|
264
|
+
the tree to the tester or reviewer;
|
|
265
|
+
4. the merger verifies the current head is the reviewer-approved head plus only retro's commits,
|
|
266
|
+
those that change `docs/solutions/` and that removal (`jj diff --from <approved-sha> --to
|
|
267
|
+
<tip-sha> --summary`, quoted in READY) and sends the READY packet with its completion, which
|
|
268
|
+
refuses a head that still carries `.legion/<issue>/`; the daemon posts
|
|
268
269
|
`READY #<n> at <current sha> (approved at <approved sha>) for <KEY> (<pr url>)` on the Dispatch
|
|
269
270
|
issue and publishes it to the project's merge queue role when one is set. Legion never merges; a human merges under the repository's
|
|
270
271
|
GitHub branch-protection and CODEOWNERS rules. If the merger reports a failed verification,
|
|
271
272
|
treat it like `pr-blocked`: the merger holds the phase, so tell it to move the issue back with
|
|
272
|
-
`request_backward_move`, naming what failed; never bypass.
|
|
273
|
+
`request_backward_move`, naming what failed; never bypass. A READY refused because the head
|
|
274
|
+
still carries `.legion/<issue>/` goes back to `retro`, so the implementer's retro removes it.
|
|
273
275
|
5. a human merges; the daemon then starts the **implementer** once more, on the production check.
|
|
274
276
|
It drives the changed path in production through the user's own access path and records
|
|
275
277
|
what it saw on the pull request and on this issue. Sign off only after the implementer's production
|
|
@@ -279,9 +281,10 @@ The daemon keeps this order from its fixed table; you start none of its steps:
|
|
|
279
281
|
outcome-named options. The issue waits for that answer.
|
|
280
282
|
|
|
281
283
|
What returns the tree to review: a changed diff — a commit above the approved head that
|
|
282
|
-
touches anything outside `docs/solutions
|
|
284
|
+
touches anything outside `docs/solutions/` and the issue's `.legion/<issue>/`, or a
|
|
285
|
+
conflict-resolution merge whose fingerprint
|
|
283
286
|
(the unchanged-diff check, `skill://legion-worker/references/conflicts-and-rewrites.md`) differs from the approved head's. What does not: retro's
|
|
284
|
-
`docs/solutions/` commit
|
|
287
|
+
`docs/solutions/` commit and its removal of `.legion/<issue>/`, and a merge forced by a GitHub-reported conflict whose fingerprint
|
|
285
288
|
is unchanged. For that merge, the worker holding the issue's phase moves it back to `implementing`
|
|
286
289
|
with `request_backward_move`, and the daemon runs the phases from there: the implementer merges
|
|
287
290
|
the bookmark forward with the
|
|
@@ -171,7 +171,13 @@ unsent:
|
|
|
171
171
|
- `tick on <PROJECT>`: the daemon's periodic wake, a minute after it starts and then every
|
|
172
172
|
`controller_wake_interval_seconds` (an hour by default), whatever the slots. An earlier walk
|
|
173
173
|
that found nothing, a day with no event, and [a tree waiting on a root
|
|
174
|
-
claim](#trees-waiting-on-a-root-claim-go-daemon) all get a turn from it.
|
|
174
|
+
claim](#trees-waiting-on-a-root-claim-go-daemon) all get a turn from it. Its payload's
|
|
175
|
+
`openCapabilities`, when present, names the deployment capabilities (the secrets broker, model
|
|
176
|
+
fallback, every role's CPU and memory limits) the deployment's own configuration leaves open with
|
|
177
|
+
no decision recorded. `legion state --json` lists every row under `capabilities`, each open one
|
|
178
|
+
with its `detail` and the `configLine` to write into `legion.yaml`
|
|
179
|
+
(`capabilities.decided.<name>: "<reason>"`); name them in the day's report. A gap is the
|
|
180
|
+
operator's to close or to decide, never yours, and it never stops the walk.
|
|
175
181
|
|
|
176
182
|
**Scope first.** The scope the deployment instructions state decides which issues are candidates
|
|
177
183
|
at all, before anything below. When they say you hand Legion no issue yourself, or that Legion
|
|
@@ -291,6 +297,10 @@ every pull request by its URL.
|
|
|
291
297
|
- **The slots and the walk.** The free slots, as **How many** counts them, then this turn's walk
|
|
292
298
|
when it made one: what it took, and how many candidates each row of the table skipped, so a
|
|
293
299
|
reader can see why a free slot stays empty.
|
|
300
|
+
- **Open capabilities.** Each row of `capabilities` in `legion state --json` whose `status` is
|
|
301
|
+
`open` (the `tick` payload's `openCapabilities`): its name, its `detail`, and its `configLine`,
|
|
302
|
+
the `legion.yaml` line that records a decision. The operator closes or decides it; you only
|
|
303
|
+
report it, and a report with none says nothing of them.
|
|
294
304
|
|
|
295
305
|
A day with nothing finished says so in one sentence. When the lists do not fit, keep the counts
|
|
296
306
|
and the highest-priority issues.
|
|
@@ -328,7 +338,7 @@ priority first, then board rank ([Keeping the slots full](#keeping-the-slots-ful
|
|
|
328
338
|
| New issue created in the Dispatch project, status `triage`: `triage on <KEY>` (payload `{kind: "triage"}`) on the controller topic, for an unrecorded root carrying the `legion` label only ("Issues handed to Legion" above); the start procedure above catches one sent while no controller ran | issue key + triage context (incl. pre-existing children) | Triage: `legion status <KEY> todo` to admit, or set `backlog`/`icebox` to park |
|
|
329
339
|
| `slot-free on <KEY>` from the Go daemon (payload `{kind: "slot-free"}`) | the root whose slot the daemon released with no waiting root to take it | Verify a free slot in `legion state --json`, then fill it ([Keeping the slots full](#keeping-the-slots-full-go-daemon)) |
|
|
330
340
|
| `todo on <KEY>` from the Go daemon (payload `{kind: "todo"}`) | an issue not handed to Legion that changed while in `todo` and a slot stood free, sent half a minute later | Verify a free slot, then walk the whole `todo` list ([Keeping the slots full](#keeping-the-slots-full-go-daemon)) |
|
|
331
|
-
| `tick on <PROJECT>` from the Go daemon (payload `{kind: "tick"}`) | the project key; the daemon's periodic wake, whatever the slots | Recheck the trees waiting on a claim, then walk if a slot is free; post the day's report if this is the day's first turn |
|
|
341
|
+
| `tick on <PROJECT>` from the Go daemon (payload `{kind: "tick", openCapabilities?: [<name>, …]}`) | the project key; the daemon's periodic wake, whatever the slots; `openCapabilities` names the deployment capabilities with no decision, each with its detail and `capabilities.decided.<name>` line under `capabilities` in `legion state --json` | Recheck the trees waiting on a claim, then walk if a slot is free — a gap never stops the walk; post the day's report if this is the day's first turn, naming each open capability in it (the operator closes or decides it) |
|
|
332
342
|
| Architect escalation (controller-actionable only: re-file a child as a root issue, capacity, cross-tree conflicts) | request + context | Judge and act; the owning architect writes an issue-design decision as a decision block and opens `dispatch_ask` only for a human to-do |
|
|
333
343
|
| Mention | Slack/GitHub PR @mention text | Answer, or route to the owning issue's architect role |
|
|
334
344
|
| `held on <KEY>` from the Go daemon (payload `{kind: "held", phase, role?, reason?}`) | the held issue, the phase it left, and the role whose claim failed, or `reason: "escalated"` | Verify the hold in `legion state` (the issue's phase is `held`). Without `reason`, a phase worker's launches or prompts ran out and the tree's architect decides retry or escalate: no action. With `reason: "escalated"` (on the record, `issues.<KEY>.holdReason` is `escalated`), the architect sent it to you: handle it as an architect escalation below. Parking the tree is `legion status <root> backlog`; setting the root back to `todo` later re-admits it as a new generation, which starts again from its architect |
|
|
@@ -19,20 +19,19 @@ Follow this ordering exactly. It keeps the reviewed branch clean while preservin
|
|
|
19
19
|
retrospective's durable output.
|
|
20
20
|
|
|
21
21
|
1. Tester green and all code-review cycles finish.
|
|
22
|
-
2. The reviewer approves the head. It still carries
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
participates only when the repository enables it.
|
|
22
|
+
2. The reviewer approves the head. It still carries the issue's handoffs, `.legion/<issue>/`
|
|
23
|
+
(`<issue>` is your `LEGION_ISSUE`), which every tester and reviewer round writes again.
|
|
24
|
+
3. Run this retro (*Durable outputs*, below): its learnings under `docs/solutions/`, then one final
|
|
25
|
+
commit removing `.legion/<issue>/`, pushed together, and the retro message on the Dispatch
|
|
26
|
+
issue. Retro writes **no handoff**. The removal exists because a squash merge commits the head
|
|
27
|
+
merged into the base, and nothing on the base reads a handoff; the handoffs stay on the issue
|
|
28
|
+
branch below that commit.
|
|
29
|
+
4. The merger verifies the tip is the approved head plus retro's commits, quotes their
|
|
30
|
+
`jj diff --from <approved-sha> --to <tip-sha> --summary` in READY, and sends the READY packet
|
|
31
|
+
with its completion, which refuses a head that still carries `.legion/<issue>/`; the daemon
|
|
32
|
+
posts it on the Dispatch issue and publishes it to the project's merge-queue role when one is
|
|
33
|
+
configured. A human merges under the repository's GitHub branch-protection and CODEOWNERS
|
|
34
|
+
requirements; GitHub's merge queue participates only when the repository enables it.
|
|
36
35
|
5. After that merge, the implementer — not the reviewer or merger — verifies the change in production
|
|
37
36
|
and records it on the PR and the issue: the agent that developed it is responsible for testing
|
|
38
37
|
in production. The architect's sign-off waits for that record.
|
|
@@ -41,10 +40,12 @@ retrospective's durable output.
|
|
|
41
40
|
merge commit. A defect the production check finds becomes a corrective child issue of the same tree,
|
|
42
41
|
owned by the architect and implemented by the same implementer; the parent stays open until it lands.
|
|
43
42
|
|
|
44
|
-
Retro's
|
|
45
|
-
|
|
46
|
-
never back to the tester or reviewer. A conflict-forced
|
|
47
|
-
with the branch
|
|
43
|
+
Retro's commits sit above the reviewer's approved head and the approval stands: commits that
|
|
44
|
+
change only `docs/solutions/`, and the one that removes `.legion/<issue>/`, do not void it, and the
|
|
45
|
+
tree goes from retro to the merger — never back to the tester or reviewer. A conflict-forced
|
|
46
|
+
rebase after retro moves these commits with the branch. Any round after retro (a conflict round, a
|
|
47
|
+
round a red CI sends back, a re-review) writes `.legion/<issue>/` again, and every approval moves
|
|
48
|
+
the issue to retro once more: each retro ends with the removal again, or READY is refused.
|
|
48
49
|
|
|
49
50
|
Do not start retro before step 2 or skip it because the change seems mechanical; the merger's
|
|
50
51
|
`READY` comes only after step 3. The design gate is not a substitute for review and retro.
|
|
@@ -106,24 +107,30 @@ related_issues:
|
|
|
106
107
|
```
|
|
107
108
|
|
|
108
109
|
Commit the documentation on the existing issue branch. Do not create a replacement branch or
|
|
109
|
-
bookmark.
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
bookmark. Then commit the removal of the issue's handoffs as the one final commit, touching
|
|
111
|
+
nothing else, when the head still holds them:
|
|
112
|
+
`cd -- "$LEGION_WORKSPACE" && if [ -e ".legion/${LEGION_ISSUE:?}" ]; then rm -r -- ".legion/${LEGION_ISSUE:?}" && jj -R "$LEGION_WORKSPACE" split -m "retro: remove .legion/${LEGION_ISSUE:?}/ before READY" ".legion/${LEGION_ISSUE:?}"; fi`.
|
|
113
|
+
A retro that commits no learning makes that commit alone; a retro after an earlier removal with no
|
|
114
|
+
handoff written since has nothing to remove and makes none (without the guard, `rm -r` would fail
|
|
115
|
+
on the missing directory and that retro would stop there).
|
|
116
|
+
|
|
117
|
+
Before you push those commits, bring up to date the body content the repository derives from the
|
|
112
118
|
pull request's changed paths. A repository can require such content, a line naming a checklist
|
|
113
119
|
for each class of changed path for instance, and have a required check read it from the PR body.
|
|
114
|
-
When your
|
|
115
|
-
fails at your head; the merger reports a stale body rather
|
|
116
|
-
head whose required check failed, so the tree stops at the
|
|
120
|
+
When your commits add a `docs/solutions/` path the approved body never accounted for, or take away
|
|
121
|
+
the `.legion/` paths it did, that check fails at your head; the merger reports a stale body rather
|
|
122
|
+
than rewriting it, and READY refuses a head whose required check failed, so the tree stops at the
|
|
123
|
+
merger.
|
|
117
124
|
|
|
118
125
|
1. Read what the deployment instructions in your system prompt, and the agent guide and pull
|
|
119
126
|
request template of the repository you are working in, derive from the changed paths. When
|
|
120
127
|
they derive nothing, skip steps 2 to 4 and go on to the push.
|
|
121
|
-
2. Compute it the way they say, for the paths the pull request changes at your
|
|
128
|
+
2. Compute it the way they say, for the paths the pull request changes at your head, the files
|
|
122
129
|
GitHub lists on it:
|
|
123
|
-
`cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" git fetch && jj -R "$LEGION_WORKSPACE" diff --from 'fork_point(<base>@origin | <
|
|
124
|
-
lists them, `<base>` the pull request's base branch and `<
|
|
130
|
+
`cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" git fetch && jj -R "$LEGION_WORKSPACE" diff --from 'fork_point(<base>@origin | <head>)' --to <head> --name-only`
|
|
131
|
+
lists them, `<base>` the pull request's base branch and `<head>` your removal commit. Where a
|
|
125
132
|
line affirms work, such as a checklist completed for a class of path, do that work for the
|
|
126
|
-
paths your
|
|
133
|
+
paths your commits add before you write the line: the line is a claim. That work may change
|
|
127
134
|
files under `docs/solutions/` only, folded into your docs commit before the push, since
|
|
128
135
|
anything else above the approved head voids the approval.
|
|
129
136
|
3. In a fresh `mktemp -d` directory outside `$LEGION_WORKSPACE` (the one place you write outside
|
|
@@ -139,16 +146,17 @@ head whose required check failed, so the tree stops at the merger.
|
|
|
139
146
|
`cd -- "$LEGION_WORKSPACE" && legion gh -- api --method PATCH repos/{owner}/{repo}/pulls/{number} -F body=@<dir>/body.md`.
|
|
140
147
|
The checks the push starts read the body as it stands then; an edit after the push re-runs
|
|
141
148
|
only a check that also starts on an edited body. Such a check re-runs now at the approved
|
|
142
|
-
head, on a diff without your
|
|
149
|
+
head, on a diff without your commits, and may fail there; READY reads the head your push makes.
|
|
143
150
|
|
|
144
151
|
When you cannot compute that content, cannot do the work a line affirms within
|
|
145
152
|
`docs/solutions/`, the body read fails or comes back empty, or GitHub refuses the body, push
|
|
146
153
|
nothing and do not complete: tell the architect with `envoy_publish` to its role topic, naming
|
|
147
154
|
what failed.
|
|
148
155
|
|
|
149
|
-
Then push
|
|
150
|
-
write `<dir>/before.md` back the same way before you report
|
|
151
|
-
body matches the head GitHub has. After the push, post one
|
|
156
|
+
Then push both commits with one `legion push`, so one CI run covers them. When the push is
|
|
157
|
+
refused after step 4 wrote the body, write `<dir>/before.md` back the same way before you report
|
|
158
|
+
the refusal to the architect, so the body matches the head GitHub has. After the push, post one
|
|
159
|
+
Dispatch message on
|
|
152
160
|
the issue — `issue` is your `LEGION_ISSUE`; Legion issues live on Dispatch, never on a GitHub
|
|
153
161
|
issue, and the `gh` shim refuses every GitHub-issue write — naming the documents, the
|
|
154
162
|
one-to-three most useful takeaways, the two proofs you read, and the production check that
|
|
@@ -174,23 +182,27 @@ dispatch_message({
|
|
|
174
182
|
})
|
|
175
183
|
```
|
|
176
184
|
|
|
177
|
-
The `docs/solutions/` commit, the
|
|
178
|
-
are the only retro outputs. Never write a handoff, phase
|
|
179
|
-
completion label, and
|
|
180
|
-
tool's `handoff_complete` alone (its summary: two
|
|
181
|
-
`handoff_write`.
|
|
185
|
+
The `docs/solutions/` commit, the removal of `.legion/<issue>/`, the PR body lines those commits
|
|
186
|
+
make stale, and the Dispatch message are the only retro outputs. Never write a handoff, phase
|
|
187
|
+
artifact, local feedback log, or completion label, and change nothing under `.legion/` but that
|
|
188
|
+
removal. Report completion with the `legion` tool's `handoff_complete` alone (its summary: two
|
|
189
|
+
sentences for the architect) — no `handoff_write`.
|
|
182
190
|
|
|
183
191
|
## Completion check
|
|
184
192
|
|
|
185
193
|
Before returning, verify all of the following:
|
|
186
194
|
|
|
187
|
-
- The reviewer-approved head remains below the retro
|
|
188
|
-
|
|
195
|
+
- The reviewer-approved head remains below the retro commits, and the reviewer's approval of that
|
|
196
|
+
head stands: the merger accepts the approved head plus the documentation commit and the removal.
|
|
189
197
|
- The learning documents and the Dispatch message both exist (never a GitHub issue comment).
|
|
190
198
|
- The PR body carries what the repository's instructions derive from the pull request's changed
|
|
191
199
|
paths at the retro head, written back before that head's push, and each line that affirms work
|
|
192
200
|
affirms work you did; or the instructions derive nothing.
|
|
193
201
|
- Both proofs were read, and any gap in either is recorded as a learning.
|
|
194
|
-
-
|
|
202
|
+
- Retro wrote no handoff, and when the head held `.legion/<issue>/`, its last commit, pushed,
|
|
203
|
+
removed it and nothing else:
|
|
204
|
+
`cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" file list -r <head> "root:.legion/${LEGION_ISSUE:?}"`
|
|
205
|
+
prints nothing (`root:` names the path from the repository root, so a run from another directory
|
|
206
|
+
cannot print nothing by failing).
|
|
195
207
|
- The fresh-eyes analysis was considered alongside the implementer's context.
|
|
196
208
|
- The merger remains a subsequent step, not work performed by retro.
|
|
@@ -121,8 +121,7 @@ moves the issue to `implementing` and interrupts your turn, and the implementer
|
|
|
121
121
|
that turn has ended. Do not resume the interrupted work afterward.
|
|
122
122
|
|
|
123
123
|
On every start, and especially after revival or re-creation, read the issue and then the
|
|
124
|
-
committed predecessor handoffs in lifecycle order
|
|
125
|
-
`$LEGION_WORKSPACE/.legion/<issue>/`:
|
|
124
|
+
committed predecessor handoffs in lifecycle order, with the `legion` tool's `handoff_read`:
|
|
126
125
|
|
|
127
126
|
1. `architect.json`
|
|
128
127
|
2. `plan.json`
|
|
@@ -132,8 +131,8 @@ committed predecessor handoffs in lifecycle order from
|
|
|
132
131
|
|
|
133
132
|
Read only files that precede the assigned phase. Each was held to its phase's rules when it was
|
|
134
133
|
written (`handoff_write`, in the completion gate below): fields the phase does not declare passed
|
|
135
|
-
untouched and reach the next worker. The `legion` tool's `handoff_read` returns
|
|
136
|
-
|
|
134
|
+
untouched and reach the next worker. The `legion` tool's `handoff_read` returns them; its
|
|
135
|
+
description says where it reads each one from.
|
|
137
136
|
Write the phase-specific fields the next phase and the architect need, consistent with what
|
|
138
137
|
predecessor phases already wrote. The durable copy lives in
|
|
139
138
|
`$LEGION_WORKSPACE/.legion/<issue>/<phase>.json`. If a committed handoff conflicts with memory or a prior
|
|
@@ -414,12 +413,12 @@ report to the architect with the output, never a force-push. The merger makes no
|
|
|
414
413
|
pushes nothing.
|
|
415
414
|
|
|
416
415
|
Do not report phase completion until the write, existence check, handoff commit, and push
|
|
417
|
-
succeed. This is the committed copy the next phase reads after revival.
|
|
418
|
-
`.legion
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
416
|
+
succeed. This is the committed copy the next phase reads after revival. Retro's last commit
|
|
417
|
+
removes `.legion/<issue>/` from the head a human merges (`skill://legion-retro`); a round after
|
|
418
|
+
it, such as one a withdrawn READY sends back, writes and commits its own handoff again, since
|
|
419
|
+
`handoff_complete` refuses a handoff that commit removed. Retro and the post-merge production
|
|
420
|
+
check write no `.legion/<issue>/<phase>.json`, commit no handoff, and report with
|
|
421
|
+
`handoff_complete` alone (below).
|
|
423
422
|
|
|
424
423
|
## Completion: report to the architect, then stay
|
|
425
424
|
|
|
@@ -5,15 +5,15 @@ approval, the implementer recording the production check, or the merger building
|
|
|
5
5
|
path it cites is in sjawhar/legion.
|
|
6
6
|
|
|
7
7
|
The order, in full: the tester's evidence green → the reviewer's approval of the head →
|
|
8
|
-
retro → the merger's READY → the human merge → the implementer's production check.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
confirmation or a new round, as the fingerprint decides (*The reviewer*,
|
|
15
|
-
`skill://legion-worker/references/conflicts-and-rewrites.md`), and any other change to
|
|
16
|
-
voids it.
|
|
8
|
+
retro → the merger's READY → the human merge → the implementer's production check. The approved
|
|
9
|
+
head carries the issue's handoffs, `.legion/<issue>/`; retro's last commit removes them from the
|
|
10
|
+
head a human merges (dispatch://LEGION-605), since a squash merge commits that head merged into
|
|
11
|
+
the default branch and nothing there reads a handoff, and READY refuses a head that still
|
|
12
|
+
carries them. After the approval, only retro's commits leave it standing on their own: those that
|
|
13
|
+
change only `docs/solutions/`, and that removal (*Retro*, below). A conflict-forced merge goes back
|
|
14
|
+
to the reviewer for a confirmation or a new round, as the fingerprint decides (*The reviewer*,
|
|
15
|
+
below, and `skill://legion-worker/references/conflicts-and-rewrites.md`), and any other change to
|
|
16
|
+
the head voids it.
|
|
17
17
|
|
|
18
18
|
## The reviewer
|
|
19
19
|
|
|
@@ -63,15 +63,16 @@ review posted without a completion leaves the issue in reviewing until you finis
|
|
|
63
63
|
|
|
64
64
|
## Retro
|
|
65
65
|
|
|
66
|
-
- **Retro's
|
|
67
|
-
head,
|
|
68
|
-
|
|
69
|
-
reviewer. Anything else above the approved head does void
|
|
70
|
-
architect the head must return to review instead of completing. A
|
|
71
|
-
after retro moves those
|
|
66
|
+
- **Retro's commits do not void the reviewer's approval.** Retro's commits above the approved
|
|
67
|
+
head, its `docs/solutions/` learnings and its last commit removing `.legion/<issue>/`
|
|
68
|
+
(`skill://legion-retro` gives the steps), leave the approval standing, and the tree goes to the
|
|
69
|
+
merger — never back to the tester or reviewer. Anything else above the approved head does void
|
|
70
|
+
it, and the merger tells the architect the head must return to review instead of completing. A
|
|
71
|
+
conflict-forced rebase after retro moves those commits with the branch. Every approval moves the
|
|
72
|
+
issue to retro again, so each retro ends with the removal again.
|
|
72
73
|
- **Retro brings the PR body's path-derived content up to date before its push.** Whatever the
|
|
73
74
|
repository's instructions derive from the pull request's changed paths (a checklist named for
|
|
74
|
-
each class of path, read by a required check), retro recomputes for the whole diff at its
|
|
75
|
+
each class of path, read by a required check), retro recomputes for the whole diff at its head
|
|
75
76
|
and writes into the live body before `legion push` (`skill://legion-retro`), since the merger
|
|
76
77
|
reports a stale body rather than rewriting it. A body edit changes no commit, so the approval
|
|
77
78
|
stands.
|
|
@@ -84,8 +85,11 @@ review posted without a completion leaves the issue in reviewing until you finis
|
|
|
84
85
|
exits 1 (report the thread to the architect instead), then proves that rule with two commands.
|
|
85
86
|
First `cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" git fetch && jj -R
|
|
86
87
|
"$LEGION_WORKSPACE" diff --from <approved-sha> --to <tip-sha> --summary`, whose output is quoted
|
|
87
|
-
in READY
|
|
88
|
-
|
|
88
|
+
in READY; then the same with the one fileset `'~(docs/solutions | .legion/<issue>)'` appended,
|
|
89
|
+
which must print nothing (jj unions separate path arguments, so two of them leave nothing out).
|
|
90
|
+
READY itself refuses a head that still carries `.legion/<issue>/` (the merger tells the
|
|
91
|
+
architect, which has it move the issue back to `retro`), and publishes a pull request a person
|
|
92
|
+
already merged unread (`packages/daemon/internal/prompts/go/merger.md`). *The READY packet* is
|
|
89
93
|
`READY #<n> at <current sha> (approved at <approved sha>) for <KEY> (<pr url>)`
|
|
90
94
|
(the shape `packages/daemon/internal/prompts/roles/merger.md` defines), then the PR body's
|
|
91
95
|
`Outcome:` line and its `Not proven / risk:` value — every bullet under that label joined with
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjawhar/pi-legion",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.4.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"omp": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
14
|
"legion": {
|
|
15
|
-
"daemonApiVersion":
|
|
15
|
+
"daemonApiVersion": 16
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|