@sjawhar/opencode-legion-envoy 8.29.0 → 8.30.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/package.json +1 -1
- package/skills/envoy/SKILL.md +47 -286
- package/skills/envoy/references/check-settlement.md +62 -0
- package/skills/envoy/references/deliveries.md +62 -0
- package/skills/envoy/references/legion.md +12 -0
- package/skills/envoy/references/roles.md +10 -0
- package/skills/envoy/references/sources.md +41 -0
- package/skills/legion-architect/SKILL.md +41 -419
- package/skills/legion-architect/references/acceptance.md +153 -0
- package/skills/legion-architect/references/decomposition.md +77 -0
- package/skills/legion-architect/references/design-gate.md +148 -0
- package/skills/legion-architect/references/wake-routing.md +11 -6
- package/skills/legion-controller/SKILL.md +96 -469
- package/skills/legion-controller/references/admission.md +7 -6
- package/skills/legion-controller/references/backlog-stewardship.md +32 -27
- package/skills/legion-controller/references/daily-report.md +72 -0
- package/skills/legion-controller/references/escalation.md +37 -0
- package/skills/legion-controller/references/finding-asks.md +32 -14
- package/skills/legion-controller/references/session.md +98 -0
- package/skills/legion-controller/references/slack-mentions.md +10 -9
- package/skills/legion-controller/references/triage.md +81 -0
- package/skills/legion-controller/references/wakes.md +90 -0
- package/skills/legion-oracle/SKILL.md +26 -57
- package/skills/legion-retro/SKILL.md +116 -240
- package/skills/legion-retro/references/learnings.md +58 -0
- package/skills/legion-retro/references/pr-body-content.md +78 -0
- package/skills/legion-worker/SKILL.md +40 -462
- package/skills/legion-worker/references/conflicts-and-rewrites.md +2 -2
- package/skills/legion-worker/references/default-branch-check.md +16 -0
- package/skills/legion-worker/references/findings.md +2 -2
- package/skills/legion-worker/references/pr-body.md +1 -1
- package/skills/legion-worker/references/review-threads.md +1 -1
- package/skills/legion-worker/references/tools.md +7 -11
- package/skills/thermonuclear-code-quality/SKILL.md +34 -82
- package/skills/thermonuclear-deep-review/SKILL.md +34 -33
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Wakes
|
|
2
|
+
|
|
3
|
+
Read this when a wake's row in the skill's table is not enough to act on it. The daemon publishes
|
|
4
|
+
these on your controller topic, `notifications.legion.<project>.controller`, only while you are
|
|
5
|
+
registered, and sends no second wake of a kind while one is still unsent. Other agents' messages
|
|
6
|
+
(READY packets, finding asks, escalations) reach you on your role topic,
|
|
7
|
+
`notifications.role.legion-<project>-controller`; you hear both. Check each in `read_state` before
|
|
8
|
+
you act, because a wake can be stale.
|
|
9
|
+
|
|
10
|
+
## `triage on <KEY>` (`{kind: "triage"}`)
|
|
11
|
+
|
|
12
|
+
An unrecorded root in `triage` that carries the `legion` label. The daemon sends it when the issue
|
|
13
|
+
is created with the label, and on each later change while it stays in `triage`, the change that
|
|
14
|
+
adds the label included: the dashboard creates an issue without labels, so a person adds it from
|
|
15
|
+
the issue header. Triage it as `skill://legion-controller/references/triage.md` says.
|
|
16
|
+
|
|
17
|
+
## `slot-free on <KEY>` (`{kind: "slot-free"}`)
|
|
18
|
+
|
|
19
|
+
The daemon released `<KEY>`'s slot, because its tree finished or left the workflow, and no waiting
|
|
20
|
+
root took it. Name the free slots; take nothing.
|
|
21
|
+
|
|
22
|
+
## `todo on <KEY>` (`{kind: "todo"}`)
|
|
23
|
+
|
|
24
|
+
`<KEY>`, an issue nobody handed to Legion, changed while in `todo` and a slot stood free; the
|
|
25
|
+
daemon waits half a minute and folds that window's events into one wake. Take nothing: it is not
|
|
26
|
+
Legion's.
|
|
27
|
+
|
|
28
|
+
## `tick on <PROJECT>` (`{kind: "tick", openCapabilities?}`)
|
|
29
|
+
|
|
30
|
+
The daemon's periodic wake, a minute after it starts and then every
|
|
31
|
+
`controller_wake_interval_seconds` (an hour by default), whatever the slots. Run the skill's every-turn
|
|
32
|
+
steps.
|
|
33
|
+
|
|
34
|
+
`openCapabilities`, when present, names the open capability rows; `read_state`'s `capabilities`
|
|
35
|
+
gives each one's `detail`. A deployment row (the secrets broker, model fallback, a role's CPU and
|
|
36
|
+
memory limits, the pool's capacity at boot) has a `configLine`, the `legion.yaml` line
|
|
37
|
+
(`capabilities.decided.<name>`) that would record a decision. A live row (`subagents`,
|
|
38
|
+
`web-search`, `mcp`, `repository-extensions`, `dispatch-envoy-tools`, `github`) is a running
|
|
39
|
+
session's failed check: its `detail` names the session (pod or pane), role, issue and fact, and it
|
|
40
|
+
has no `configLine`. The next daily report names each row still open; take no other action,
|
|
41
|
+
because the operator closes or decides a deployment row, and the operator or the issue's architect
|
|
42
|
+
fixes a live row's session.
|
|
43
|
+
|
|
44
|
+
## `unslotted on <KEY>` (`{kind: "unslotted", reason}`)
|
|
45
|
+
|
|
46
|
+
A root that waited for a slot was moved from `todo` to the status `reason` names, by a person or by
|
|
47
|
+
another session, so the daemon took it out of the workflow (`phase: done`) and starts nothing for
|
|
48
|
+
it. Re-admit nothing, because the move was someone else's; `dispatch read` shows who claims it now.
|
|
49
|
+
Tell the person in your summary: "<KEY> left Legion's waiting line: it was set to <status> while it
|
|
50
|
+
waited for a slot, so Legion let it go; `todo` with the `legion` label queues it again". Other
|
|
51
|
+
admission states: `skill://legion-controller/references/admission.md`.
|
|
52
|
+
|
|
53
|
+
## `held on <KEY>` (`{kind: "held", phase, role?, reason?}`)
|
|
54
|
+
|
|
55
|
+
Check that the issue's `phase` is `held`. Without `reason`, a phase worker's launches or prompts
|
|
56
|
+
ran out, and the tree's architect decides whether to retry or escalate: do nothing. With
|
|
57
|
+
`reason: "escalated"` (`issues.<KEY>.holdReason` is `escalated`), the architect handed it to you:
|
|
58
|
+
handle it as an escalation (`skill://legion-controller/references/escalation.md`). A held issue
|
|
59
|
+
with no `holdReason` while its tree lingers (the time after its root closes when a reopen resumes
|
|
60
|
+
it) or is closed waits for the tree's re-admission and needs nothing from you.
|
|
61
|
+
|
|
62
|
+
When an escalated hold's cause is not gone, park the tree: `set_status` the root to `backlog`. Set
|
|
63
|
+
the root back to `todo` only when you checked that the hold's cause is gone, or a person asks,
|
|
64
|
+
because `todo` re-admits it as a new generation: a new run of the tree that starts again from its
|
|
65
|
+
architect.
|
|
66
|
+
|
|
67
|
+
## `worker-died on <KEY>` (`role: "architect"`)
|
|
68
|
+
|
|
69
|
+
The tree's architect ran out of launches or prompts, and the daemon relaunches nothing. Every other
|
|
70
|
+
notice of the tree goes to that architect, so nobody inside the tree can act. Check that
|
|
71
|
+
`issues.<KEY>.architect.state` is `failed`. When the root's `phase` is `done`, the tree is already
|
|
72
|
+
parked: do nothing (a failed architect reads `failed` until the tree closes). Otherwise look for
|
|
73
|
+
the cause: an open `capabilities` row whose `detail` names the architect's session, or the
|
|
74
|
+
architect's last message on the root issue. When you find none, or it is gone, re-admit the tree
|
|
75
|
+
(`set_status` the root to `backlog`, then to `todo`: a new generation whose architect starts with
|
|
76
|
+
fresh budgets). When it stays, park the tree (`set_status` the root to `backlog`) and say why on
|
|
77
|
+
the issue, because a relaunch would fail the same way.
|
|
78
|
+
|
|
79
|
+
## GitHub mentions
|
|
80
|
+
|
|
81
|
+
Read the mention and its artifact. Answer a mention that asks you for triage or for information
|
|
82
|
+
that `read_state` or Dispatch holds.
|
|
83
|
+
Send any other to the owning architect: find its role in `read_state` and `envoy_publish` the
|
|
84
|
+
mention's URL, its text and the issue key you checked. Never build a role token from a partial
|
|
85
|
+
issue reference, because a wrong token reaches nobody.
|
|
86
|
+
|
|
87
|
+
A person who asks how to let a root past its design gate approves the root's spec document in
|
|
88
|
+
Dispatch: the `Approve` control in the document's header, or the approval question the architect's
|
|
89
|
+
request opened in the Inbox. No operator command opens a gate; a project that wants no gate sets
|
|
90
|
+
`gates.design: off` in `legion.yaml`.
|
|
@@ -1,75 +1,44 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: legion-oracle
|
|
3
|
-
description:
|
|
3
|
+
description: Use when you are about to ask a human a question about a pattern, convention, solved problem or technical approach that the repository or its docs/solutions/ might already answer.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Legion Oracle
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
If this skill disagrees with the code, a command's output or its `--help`, follow those and say which line of this skill is wrong.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## When to research instead of asking
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
- Research when the answer is a fact a file, command or document can show (a pattern, convention, solved problem or technical approach), because `docs/solutions/` records what past work learned and a human should not answer it twice.
|
|
13
|
+
- Ask the human directly when the answer is a choice between options that each work (a preference, requirement, scope decision or judgment call), because no file can choose. Quote any earlier decision a file records (`file:line`), so the human can confirm it in one word.
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Research steps
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
If the deployment instructions (the `# Deployment instructions` part of your system prompt, from
|
|
18
|
+
`legion.yaml`'s `instructions:`) name a role and say it answers research questions (a role, not the
|
|
19
|
+
`oracle` task agent), send your question to it first with
|
|
20
|
+
`envoy_publish(topic="notifications.role.<name>", expects_reply="required")`, because that role may
|
|
21
|
+
already hold the answer. Then end your turn: the reply arrives as a delivery that starts your next
|
|
22
|
+
one, and research before it duplicates the role's work. If the publish returns an error (no session
|
|
23
|
+
holds the role), put the error in your output and research at once.
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"Might be documented?" -> "Ask user directly" [label="no"];
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**Use oracle for:** patterns, conventions, solved problems, technical approaches
|
|
34
|
-
|
|
35
|
-
**Ask directly for:** preferences, requirements, scope decisions, human judgment
|
|
36
|
-
|
|
37
|
-
## Research Strategy
|
|
38
|
-
|
|
39
|
-
If the deployment instructions name a librarian (or oracle) role, publish your question to
|
|
40
|
-
`notifications.role.<name>` with `expects_reply: required` and wait for the reply before
|
|
41
|
-
researching yourself. Then run steps 1-2 (parallel OK), and 3-4 if needed, with tools a Legion
|
|
42
|
-
pane actually has: `read`, `grep`, `web_search`, and `task(agent="scout")` (fast read-only
|
|
43
|
-
codebase search) or `task(agent="oracle")` (deeper read-only analysis when the answer needs
|
|
44
|
-
judgment across many files). Do not name any other agent.
|
|
25
|
+
Run steps 1 and 2, in parallel if you choose, since neither needs the other's result. Run step 3
|
|
26
|
+
when the question names a library, and step 4 when it asks for general practice, each only when
|
|
27
|
+
steps 1 and 2 give no `file:line` source for some part of the question. Use only `read`, `grep`,
|
|
28
|
+
`web_search`, the `envoy_publish` above, and `task` with `scout` or `oracle`: the daemon's boot
|
|
29
|
+
gate checks that the agents Legion's prompts name exist, and no other.
|
|
45
30
|
|
|
46
31
|
| Step | Tool | Query |
|
|
47
32
|
|------|------|-------|
|
|
48
|
-
| 1. Institutional learnings | `grep
|
|
49
|
-
| 2. Codebase patterns | `task(agent="scout")
|
|
50
|
-
| 3. Framework docs | `read` the library's
|
|
51
|
-
| 4. External practices | `web_search`, then `read` the
|
|
33
|
+
| 1. Institutional learnings | `grep`, then `read`, over `docs/solutions/` (front-matter `tags` first, then the body) | each name the question gives (module, file, function, error text), then two or three words for the problem |
|
|
34
|
+
| 2. Codebase patterns | `task(agent="scout")` for a read-only search; `task(agent="oracle")` when scout's answer spans two or more modules or shows patterns that disagree | how [module] handles [topic] |
|
|
35
|
+
| 3. Framework docs | `web_search`, then `read` the library's official docs page | [library] docs [topic] |
|
|
36
|
+
| 4. External practices | `web_search`, then `read` what the tool's or standard's maintainer publishes (docs, RFC, changelog); give its URL | current practice for [topic] |
|
|
52
37
|
|
|
53
|
-
Before
|
|
54
|
-
(`docs/solutions/<its-path>`). A hit in another file's front matter under its `supersedes:` key
|
|
55
|
-
(on that line, or as an item of the list below it) supersedes what you found; a line
|
|
56
|
-
`Extends docs/solutions/<its-path>` extends it. Legion runs no pass that reconciles these links,
|
|
57
|
-
so following them is the only way to know the hit is still current.
|
|
38
|
+
Before you rely on a step 1 hit, `grep` `docs/solutions/` for its path. If another file lists that path under its front-matter `supersedes:` key (on that line or as a list item below it), use that file instead; if one has a line `Extends docs/solutions/<hit path>`, read both. Nothing else reconciles these links.
|
|
58
39
|
|
|
59
40
|
## Output
|
|
60
41
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## Example
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
Question: How should I paginate a GraphQL connection?
|
|
69
|
-
|
|
70
|
-
grep pagination docs/solutions/ → no matches
|
|
71
|
-
task(agent="scout") → packages/daemon/src/state/fetch.ts loops on
|
|
72
|
-
pageInfo.hasNextPage / endCursor (contextsPage)
|
|
73
|
-
|
|
74
|
-
Answer: cursor-based, per the `while (page.hasNextPage)` loop in packages/daemon/src/state/fetch.ts
|
|
75
|
-
```
|
|
42
|
+
- Found: the answer with its source (`file:line` or a URL), so the reader can check it.
|
|
43
|
+
- Partly found: each part found with its source, then each part not found.
|
|
44
|
+
- Not found: "Checked docs/solutions/ (queries: ...) and codebase (scout query: ...) - no file answers this", so the reader knows what was searched. Then ask the human the part no step answered.
|
|
@@ -1,244 +1,120 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: legion-retro
|
|
3
|
-
description: Use when
|
|
3
|
+
description: "Use when the Legion daemon starts you, the implementer, on `Phase: retro` after the architect accepted the reviewed head, or when READY was refused `READY_HEAD_CARRIES_HANDOFFS` and the issue came back to retro. Also when the `.legion/<issue>/` handoff directory must be removed from the head that merges."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Legion
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
`
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
the
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Commit the documentation on the existing issue branch. Do not create a replacement branch or
|
|
125
|
-
bookmark. Then commit the removal of the issue's handoffs as the one final commit, touching
|
|
126
|
-
nothing else, when the head still holds them:
|
|
127
|
-
`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`.
|
|
128
|
-
A retro that commits no learning makes that commit alone; a retro after an earlier removal with no
|
|
129
|
-
handoff written since has nothing to remove and makes none (without the guard, `rm -r` would fail
|
|
130
|
-
on the missing directory and that retro would stop there).
|
|
131
|
-
|
|
132
|
-
Before you push those commits, bring up to date the body content the repository derives from the
|
|
133
|
-
pull request's changed paths. A repository can require such content, a line naming a checklist
|
|
134
|
-
for each class of changed path for instance, and have a required check read it from the PR body.
|
|
135
|
-
When your commits add a `docs/solutions/` path the approved body never accounted for, or take away
|
|
136
|
-
the `.legion/` paths it did, that check fails at your head; the merger reports a stale body
|
|
137
|
-
rather than rewriting it, and GitHub will not merge a head whose required check failed, so the
|
|
138
|
-
merge waits.
|
|
139
|
-
|
|
140
|
-
1. Read what the deployment instructions in your system prompt, and the agent guide and pull
|
|
141
|
-
request template of the repository you are working in, derive from the changed paths. When
|
|
142
|
-
they derive nothing, skip steps 2 to 4 and go on to the push.
|
|
143
|
-
2. Compute it the way they say, for the paths the pull request changes at your head, the files
|
|
144
|
-
GitHub lists on it:
|
|
145
|
-
`base=$(gh pr view <n> -R <owner>/<repo> --json baseRefName -q '.baseRefName | @json') && cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" git fetch && jj -R "$LEGION_WORKSPACE" diff --from "fork_point(${base}@origin | <head>)" --to <head> --name-only`
|
|
146
|
-
lists them, `base` the pull request's base branch as a jj string literal (never a name pasted between quotes) and `<head>` your removal commit. Where a
|
|
147
|
-
line affirms work, such as a checklist completed for a class of path, do that work for the
|
|
148
|
-
paths your commits add before you write the line: the line is a claim. That work may change
|
|
149
|
-
files under `docs/solutions/` only, folded into your docs commit before the push, since
|
|
150
|
-
anything else above the approved head voids the approval.
|
|
151
|
-
3. In a fresh `mktemp -d` directory outside `$LEGION_WORKSPACE` (the one place you write outside
|
|
152
|
-
it: jj snapshots a file inside it, and a fixed name in a shared `/tmp` can hold another
|
|
153
|
-
session's body), save the live body twice, and stop unless the read succeeded and is not
|
|
154
|
-
empty. `pipefail` makes a failed read fail the line (without it the line exits with `tee`'s
|
|
155
|
-
status and leaves two empty files), and the parentheses keep it to that line, since your
|
|
156
|
-
session's shell persists and a later `cmd | head` would exit 141 under it:
|
|
157
|
-
`cd -- "$LEGION_WORKSPACE" && ( set -o pipefail && gh api repos/{owner}/{repo}/pulls/{number} --jq .body | tee <dir>/before.md <dir>/body.md ) && test -s <dir>/before.md`.
|
|
158
|
-
In `<dir>/body.md`, change the lines it carries for that content and add any it lacks where
|
|
159
|
-
the instructions place them; other phases' lines stay as they wrote them.
|
|
160
|
-
4. Write it back before the push:
|
|
161
|
-
`cd -- "$LEGION_WORKSPACE" && gh api --method PATCH repos/{owner}/{repo}/pulls/{number} -F body=@<dir>/body.md`.
|
|
162
|
-
The checks the push starts read the body as it stands then; an edit after the push re-runs
|
|
163
|
-
only a check that also starts on an edited body. Such a check re-runs now at the approved
|
|
164
|
-
head, on a diff without your commits, and may fail there; READY reads the head your push makes.
|
|
165
|
-
|
|
166
|
-
When you cannot compute that content, cannot do the work a line affirms within
|
|
167
|
-
`docs/solutions/`, the body read fails or comes back empty, or GitHub refuses the body, push
|
|
168
|
-
nothing and do not complete: tell the architect with `envoy_publish` to its role topic, naming
|
|
169
|
-
what failed.
|
|
170
|
-
|
|
171
|
-
Then push both commits with one push, so one CI run covers them (`<KEY>` is your `LEGION_ISSUE`):
|
|
172
|
-
`cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" bookmark set legion/<KEY> -r @- && jj -R "$LEGION_WORKSPACE" git push --bookmark legion/<KEY>`.
|
|
173
|
-
Its head's message never ends with `skip-checks: true` and carries none of GitHub's
|
|
174
|
-
`[skip ci]`-family keywords (`skill://legion-worker`, *Every role pushes its own commits*).
|
|
175
|
-
Retro's push never carries the line, whatever paths it touches, because it is the last push before the merge and a base that requires a check will not merge a head whose checks never ran.
|
|
176
|
-
When the push is refused after step 4 wrote the body (`jj git push` refuses a branch another role
|
|
177
|
-
moved; never force), write `<dir>/before.md` back the same way before you report the refusal to
|
|
178
|
-
the architect with its output, so the body matches the head GitHub has.
|
|
179
|
-
|
|
180
|
-
When you have already pushed a head that wrongly carries the line — under an older copy of these
|
|
181
|
-
instructions, say — read that pushed head's own commit message first and confirm it ends with
|
|
182
|
-
`skip-checks: true`:
|
|
183
|
-
`cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" log -r <the pushed head> --no-graph -T description`.
|
|
184
|
-
The fix is to describe that same commit again without the line and push it once, which is the
|
|
185
|
-
rewrite of an already-pushed commit:
|
|
186
|
-
`skill://legion-worker/references/conflicts-and-rewrites.md#rewriting-pushed-commits`. Run that
|
|
187
|
-
section's guard first; a non-empty guard result means another tree's work is built on the commit,
|
|
188
|
-
so do not rewrite it — report the listed commits to the architect instead. Once the guard has
|
|
189
|
-
cleared, the bookmark moves backwards with `--allow-backwards` and the branch is pushed once:
|
|
190
|
-
that is the one non-fast-forward move the rewrite section sanctions, and not the force this
|
|
191
|
-
skill's push step forbids when `jj git push` refuses a branch another role moved. The rewritten
|
|
192
|
-
head is a code head, so GitHub runs the base branch's required checks on it from scratch, and the
|
|
193
|
-
merge waits for them.
|
|
194
|
-
|
|
195
|
-
After the push, post one Dispatch message on the issue — `--issue` is your `LEGION_ISSUE`; Legion
|
|
196
|
-
issues live on Dispatch, never on a GitHub
|
|
197
|
-
issue, so no `gh issue` write and no GitHub-issue comment — naming the documents, the
|
|
198
|
-
one-to-three most useful takeaways, the two proofs you read, and the production check that
|
|
199
|
-
follows the merge's close of the issue. The message must carry this revived implementer's structured
|
|
200
|
-
attribution footer with `phase` set to `retro`; the body is capped at 32,000 characters:
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
dispatch message --issue <KEY> --body-file - <<'EOF'
|
|
204
|
-
## Retro Complete
|
|
205
|
-
|
|
206
|
-
**Learnings documented in:**
|
|
207
|
-
- docs/solutions/<path>.md
|
|
208
|
-
|
|
209
|
-
**Key takeaways:**
|
|
210
|
-
- <reusable lesson>
|
|
211
|
-
|
|
212
|
-
**Proofs read:** implementer <surface/command>, tester <surface/command>.
|
|
213
|
-
|
|
214
|
-
**Production check:** <what the implementer will drive in production once the merge closes the issue and production carries it, and the deploy or restart that carries it there, with the agent or role the deployment instructions name to perform it, or the person it asks when they name none; no reply is awaited, the daemon wakes the check on the deploy's event>
|
|
215
|
-
|
|
216
|
-
<!-- legion: {"session":"<session-id>","phase":"retro"} -->
|
|
217
|
-
EOF
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
The `docs/solutions/` commit, the removal of `.legion/<issue>/`, the PR body lines those commits
|
|
221
|
-
make stale, and the Dispatch message are the only retro outputs. Never write a handoff, phase
|
|
222
|
-
artifact, local feedback log, or completion label, and change nothing under `.legion/` but that
|
|
223
|
-
removal. Report completion with the `legion` tool's `handoff_complete` alone (its summary: two
|
|
224
|
-
sentences for the architect); retro writes no handoff, so the commit it reports is the one your
|
|
225
|
-
workspace stands on, the removal commit your push made, so push before you complete.
|
|
226
|
-
|
|
227
|
-
## Completion check
|
|
228
|
-
|
|
229
|
-
Before returning, verify all of the following:
|
|
230
|
-
|
|
231
|
-
- The reviewer-approved head remains below the retro commits, and the reviewer's approval of that
|
|
232
|
-
head stands: READY accepts the approved head plus the documentation commit and the removal.
|
|
233
|
-
- The learning documents and the Dispatch message both exist (never a GitHub issue comment).
|
|
234
|
-
- The PR body carries what the repository's instructions derive from the pull request's changed
|
|
235
|
-
paths at the retro head, written back before that head's push, and each line that affirms work
|
|
236
|
-
affirms work you did; or the instructions derive nothing.
|
|
237
|
-
- Both proofs were read, and any gap in either is recorded as a learning.
|
|
238
|
-
- Retro wrote no handoff, and when the head held `.legion/<issue>/`, its last commit, pushed,
|
|
239
|
-
removed it and nothing else:
|
|
240
|
-
`cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" file list -r <head> "root:.legion/${LEGION_ISSUE:?}"`
|
|
241
|
-
prints nothing (`root:` names the path from the repository root, so a run from another directory
|
|
242
|
-
cannot print nothing by failing).
|
|
243
|
-
- The fresh-eyes analysis was considered alongside the implementer's context.
|
|
244
|
-
- The merger remains a subsequent step, not work performed by retro.
|
|
6
|
+
# Legion retro
|
|
7
|
+
|
|
8
|
+
If this skill disagrees with the code, a command's output or its `--help`, follow those and say which line of this skill is wrong.
|
|
9
|
+
|
|
10
|
+
Retro runs on the reviewed head, after the architect's acceptance and before the merger's READY
|
|
11
|
+
(its `handoff_complete` with `ready: true`, which the daemon checks;
|
|
12
|
+
`skill://legion-worker/references/merge-gate.md` has the whole order). `<issue>` is your
|
|
13
|
+
`LEGION_ISSUE`. Run steps 1-8 even when the change looks mechanical; each gives its reason.
|
|
14
|
+
|
|
15
|
+
## What READY refuses
|
|
16
|
+
|
|
17
|
+
- **A change after the approved head outside `docs/solutions/` and `.legion/<issue>/`**
|
|
18
|
+
(`READY_UNREVIEWED_CHANGE`): the daemon diffs the reviewer's approved head against the head on
|
|
19
|
+
GitHub, and the issue goes back to the reviewer for another review. Commits that change only
|
|
20
|
+
`docs/solutions/`, and the one that removes `.legion/<issue>/`, leave the approval standing.
|
|
21
|
+
- **A head that still holds `.legion/<issue>/`** (`READY_HEAD_CARRIES_HANDOFFS`), because a squash
|
|
22
|
+
merge would carry the handoffs onto the base, where nothing reads them. Every implement, test or
|
|
23
|
+
review phase after a retro writes the directory again, so every retro ends with the removal.
|
|
24
|
+
|
|
25
|
+
Work on the existing issue branch: never rebase it onto another base, never make another branch or
|
|
26
|
+
bookmark, and push only fast-forward, because READY reads this branch's head and a forced push can
|
|
27
|
+
drop another role's commits. Reordering your own unpushed commits (the `jj rebase -r @- -B` in
|
|
28
|
+
`pr-body-content.md`) is not a rebase of the branch. The one exception is the rewrite in
|
|
29
|
+
`skill://legion-retro/references/pr-body-content.md#a-pushed-head-that-carries-skip-checks`.
|
|
30
|
+
|
|
31
|
+
## When retro stops
|
|
32
|
+
|
|
33
|
+
When a step fails (the body cannot be computed, read or written, or the push is refused), push
|
|
34
|
+
nothing more and do not call `handoff_complete`. Report it with `envoy_publish` to the architect's
|
|
35
|
+
topic in the `Legion addressing` line of your system prompt, with the command and its output. A
|
|
36
|
+
missing proof goes back as step 1 says. The Dispatch message (step 7) is for a finished retro only.
|
|
37
|
+
|
|
38
|
+
## Steps
|
|
39
|
+
|
|
40
|
+
1. **Read the evidence:** the issue and its acceptance criteria, the pull request, and the tester's
|
|
41
|
+
and reviewer's handoffs (`.legion/<issue>/test.json`, `review.json`). Confirm the body has an
|
|
42
|
+
`E2E (implementer)` and an `E2E (tester)` line, each a proof as
|
|
43
|
+
`skill://legion-worker/references/pr-body.md#what-a-proof-is` defines it. In sjawhar/legion a
|
|
44
|
+
surface may also be the daemon's real-process tests, a live proof under `scripts/e2e/`, or a
|
|
45
|
+
live check at the operator's next daemon restart recorded on the pull request. When either line
|
|
46
|
+
is missing or links only a unit suite, commit nothing and call the `legion` tool's
|
|
47
|
+
`request_backward_move` with `to: implementing` for your own proof or `to: testing` for the
|
|
48
|
+
tester's, its `reason` naming the missing line. When retro runs again, that gap is your first
|
|
49
|
+
learning.
|
|
50
|
+
2. **Get a second reading**, because a reader without your context sees what you stopped seeing.
|
|
51
|
+
First list, in your session, the constraints the issue did not state, choices between two
|
|
52
|
+
working options, approaches you abandoned, and code another issue could reuse, so the second
|
|
53
|
+
answer does not set your list. Then run `task(agent="oracle")` (read-only) with the issue, the
|
|
54
|
+
pull request body and the diff in its brief, asking for reusable learnings. You decide which
|
|
55
|
+
points to keep. Drop one that cites no file, line or commit of this pull request.
|
|
56
|
+
3. **Commit the learnings.** Start your turn's first commit with the `jj log -r @ -T 'empty'`
|
|
57
|
+
check your role prompt gives, so it does not carry the previous role's author. Write each kept
|
|
58
|
+
point you can state as a rule a worker on another issue could follow as a document under
|
|
59
|
+
`docs/solutions/`, per `skill://legion-retro/references/learnings.md`. When none qualifies,
|
|
60
|
+
commit none.
|
|
61
|
+
4. **Commit the removal last**, after every learning commit, touching nothing else:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
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
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
When an earlier retro removed it and no phase ran since, this does nothing.
|
|
68
|
+
5. **Update the PR body before the push**, per `skill://legion-retro/references/pr-body-content.md`,
|
|
69
|
+
when the repository derives body lines from changed paths.
|
|
70
|
+
6. **Push all your commits in one push**, so one CI run covers them:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cd -- "$LEGION_WORKSPACE" && jj -R "$LEGION_WORKSPACE" bookmark set "legion/${LEGION_ISSUE:?}" -r @- && jj -R "$LEGION_WORKSPACE" git push --bookmark "legion/${LEGION_ISSUE:?}"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
First check that `jj -R "$LEGION_WORKSPACE" log -r @- --no-graph -T description` has no
|
|
77
|
+
`skip-checks: true` line and none of `[skip ci]`, `[ci skip]`, `[no ci]`, `[skip actions]`,
|
|
78
|
+
`[actions skip]`.
|
|
79
|
+
Retro's push never carries the line, whatever paths it touches, because it is the last push before the merge and a base that requires a check will not merge a head whose checks never ran.
|
|
80
|
+
7. **Post one Dispatch message on the issue**, the record of the retro that the architect reads.
|
|
81
|
+
No `gh issue` write: Legion issues live on Dispatch. The body is at most 32,000 characters,
|
|
82
|
+
Dispatch's message limit, and ends with your attribution footer:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
dispatch message --issue "$LEGION_ISSUE" --body-file - <<'EOF'
|
|
86
|
+
## Retro Complete
|
|
87
|
+
|
|
88
|
+
**Learnings documented in:** docs/solutions/<path>.md, or none: <why no point qualified>.
|
|
89
|
+
|
|
90
|
+
**Key takeaways:**
|
|
91
|
+
- <one to three reusable lessons>
|
|
92
|
+
|
|
93
|
+
**Proofs read:** implementer <surface/command>, tester <surface/command>.
|
|
94
|
+
|
|
95
|
+
**Production check:** <the command or user action that will show the change working in production>
|
|
96
|
+
**Carried by:** <the deploy or restart that carries the merge there>
|
|
97
|
+
**Run by:** <the agent or role your system prompt's deployment instructions name; when none, the person to ask>
|
|
98
|
+
|
|
99
|
+
<!-- legion: {"session":"<session-id>","phase":"retro"} -->
|
|
100
|
+
EOF
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The merge's close hands you the production check's first look in this session; the daemon
|
|
104
|
+
wakes a later look at a deploy only after you report `pending`
|
|
105
|
+
(`skill://legion-worker/references/merge-gate.md#the-production-check-after-the-close`).
|
|
106
|
+
8. **Complete** with the `legion` tool's `handoff_complete`, its summary two sentences for the
|
|
107
|
+
architect. It reports your workspace's `@-`, so push first. In the workspace retro changes only
|
|
108
|
+
`docs/solutions/` and removes only `.legion/<issue>/`; outside it, it writes only step 5's
|
|
109
|
+
`mktemp -d` directory and the PR body. It sets no GitHub or Dispatch label: Legion keeps phase
|
|
110
|
+
state in the daemon, not in labels.
|
|
111
|
+
|
|
112
|
+
## Before you complete
|
|
113
|
+
|
|
114
|
+
- Before the push, `jj -R "$LEGION_WORKSPACE" diff --from "legion/${LEGION_ISSUE:?}@origin" --to @- --name-only`
|
|
115
|
+
lists only `docs/solutions/` and `.legion/<issue>/` paths. It covers your commits; READY checks
|
|
116
|
+
the approved head the review round recorded, which `read_record` does not show.
|
|
117
|
+
- `jj -R "$LEGION_WORKSPACE" file list -r @- "root:.legion/${LEGION_ISSUE:?}"` prints nothing.
|
|
118
|
+
- Each body line you added or changed that says work was done names work your commits did.
|
|
119
|
+
- `gh pr view <n> -R <owner>/<repo> --json headRefOid -q .headRefOid` is your `@-`, and the
|
|
120
|
+
Dispatch message is posted.
|