@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.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/skills/envoy/SKILL.md +47 -286
  3. package/skills/envoy/references/check-settlement.md +62 -0
  4. package/skills/envoy/references/deliveries.md +62 -0
  5. package/skills/envoy/references/legion.md +12 -0
  6. package/skills/envoy/references/roles.md +10 -0
  7. package/skills/envoy/references/sources.md +41 -0
  8. package/skills/legion-architect/SKILL.md +41 -419
  9. package/skills/legion-architect/references/acceptance.md +153 -0
  10. package/skills/legion-architect/references/decomposition.md +77 -0
  11. package/skills/legion-architect/references/design-gate.md +148 -0
  12. package/skills/legion-architect/references/wake-routing.md +11 -6
  13. package/skills/legion-controller/SKILL.md +96 -469
  14. package/skills/legion-controller/references/admission.md +7 -6
  15. package/skills/legion-controller/references/backlog-stewardship.md +32 -27
  16. package/skills/legion-controller/references/daily-report.md +72 -0
  17. package/skills/legion-controller/references/escalation.md +37 -0
  18. package/skills/legion-controller/references/finding-asks.md +32 -14
  19. package/skills/legion-controller/references/session.md +98 -0
  20. package/skills/legion-controller/references/slack-mentions.md +10 -9
  21. package/skills/legion-controller/references/triage.md +81 -0
  22. package/skills/legion-controller/references/wakes.md +90 -0
  23. package/skills/legion-oracle/SKILL.md +26 -57
  24. package/skills/legion-retro/SKILL.md +116 -240
  25. package/skills/legion-retro/references/learnings.md +58 -0
  26. package/skills/legion-retro/references/pr-body-content.md +78 -0
  27. package/skills/legion-worker/SKILL.md +40 -462
  28. package/skills/legion-worker/references/conflicts-and-rewrites.md +2 -2
  29. package/skills/legion-worker/references/default-branch-check.md +16 -0
  30. package/skills/legion-worker/references/findings.md +2 -2
  31. package/skills/legion-worker/references/pr-body.md +1 -1
  32. package/skills/legion-worker/references/review-threads.md +1 -1
  33. package/skills/legion-worker/references/tools.md +7 -11
  34. package/skills/thermonuclear-code-quality/SKILL.md +34 -82
  35. 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: Research institutional knowledge before escalating questions to users. Check docs/solutions/ and codebase patterns before asking humans.
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
- Research institutional knowledge before escalating questions to users.
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
- ## Core Principle
10
+ ## When to research instead of asking
11
11
 
12
- **Check docs/solutions/ first.** This codebase captures learnings from past work.
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
- ## When to Use
15
+ ## Research steps
15
16
 
16
- ```dot
17
- digraph oracle_decision {
18
- "About to ask user a question?" [shape=diamond];
19
- "Is it a preference/requirement?" [shape=diamond];
20
- "Might be documented?" [shape=diamond];
21
- "Ask user directly" [shape=box];
22
- "Use oracle" [shape=box];
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
- "About to ask user a question?" -> "Is it a preference/requirement?" [label="yes"];
25
- "About to ask user a question?" -> "Ask user directly" [label="no - not asking"];
26
- "Is it a preference/requirement?" -> "Ask user directly" [label="yes"];
27
- "Is it a preference/requirement?" -> "Might be documented?" [label="no"];
28
- "Might be documented?" -> "Use oracle" [label="yes"];
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` then `read` over `docs/solutions/` (front-matter `tags`, then the body) | [question]'s keywords |
49
- | 2. Codebase patterns | `task(agent="scout")`; `task(agent="oracle")` when judgment across many files is needed | Find how [module] handles [topic] |
50
- | 3. Framework docs | `read` the library's documentation URL | [library] [topic] |
51
- | 4. External practices | `web_search`, then `read` the primary source | Current best practices for [topic] |
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 relying on a step 1 hit, also search `docs/solutions/` for its path
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
- **Found:** Answer with source (file:line or URL)
62
-
63
- **Not found:** "Checked docs/solutions/ and codebase - no relevant learnings found" → search externally OR escalate to user
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 an issue has passed review and its parked implementer is revived for the mandatory pre-merge Legion retrospective.
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 Retro
7
-
8
- Retro is mandatory for every issue that passed review. The daemon starts the implementer on it
9
- once the reviewer approves, so the person with implementation context performs the retrospective,
10
- and the skill obtains a separate fresh-eyes perspective. Retro runs before merge.
11
-
12
- The `scripts/e2e/` proofs this skill names are in sjawhar/legion, the Legion repository, which
13
- need not be the repository you are working in. `docs/solutions/` and `.legion/` are on the issue
14
- branch of the repository you are working in.
15
-
16
- ## Merge-gate ordering
17
-
18
- Follow this ordering exactly. It keeps the reviewed branch clean while preserving the
19
- retrospective's durable output.
20
-
21
- 1. Tester green and all code-review cycles finish.
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. The
24
- architect then accepts the issue (`accepting`) with `sign_off`, which starts this retro; one it
25
- sends back to `implementing` or `testing` instead runs those phases again first.
26
- 3. Run this retro (*Durable outputs*, below): its learnings under `docs/solutions/`, then one final
27
- commit removing `.legion/<issue>/`, pushed together, and the retro message on the Dispatch
28
- issue. Retro writes **no handoff**. The removal exists because a squash merge commits the head
29
- merged into the base, and nothing on the base reads a handoff; the handoffs stay on the issue
30
- branch below that commit.
31
- 4. The merger quotes retro's commits (`jj diff --from <approved-sha> --to <tip-sha> --summary`) in
32
- READY, and sends the READY packet with its completion, which refuses a head with anything above
33
- the approved head but those commits, or still carrying `.legion/<issue>/`; the daemon
34
- posts it on the Dispatch issue and publishes it to the project's merge-queue role when one is
35
- configured. On READY's acceptance the daemon submits the merge, and it lands under the
36
- repository's rules: its required reviews and checks, and its merge queue when it enables one.
37
- 5. That merge closes the issue: the daemon writes `done`, and the implementer — not the reviewer or
38
- merger — is handed the production check in its live session, as work after the close: the agent
39
- that developed the change is responsible for testing it in production, once production carries
40
- the merge. The record is the pull request's `Production:` line and one pull-request comment,
41
- naming what was driven, how, what was observed, the merge commit and what woke the look; nothing
42
- is written on the closed issue, since Dispatch refuses it. A defect the check finds is a
43
- `dispatch ask` on the controller's report issue, never an issue the implementer files
44
- (`skill://legion-worker/references/merge-gate.md`, *The production check after the close*).
45
-
46
- Retro's commits sit above the reviewer's approved head and the approval stands: commits that change
47
- only `docs/solutions/`, and the one that removes `.legion/<issue>/`, do not void it, and the tree
48
- goes from retro to the merger — never back to the tester or reviewer. A conflict merge pushed above
49
- the approved head with no review round after it brings the base's paths above that head, so READY
50
- refuses it (`READY_UNREVIEWED_CHANGE`) and the reviewer reviews the new head as a new round; one the
51
- conflict procedure sends back through `implementing` is confirmed before READY. Any round after
52
- retro (a conflict round, a round a red CI sends back, a re-review) writes `.legion/<issue>/` again,
53
- and every approval, through the architect's acceptance, moves the issue to retro once more: each retro ends with the removal again, or
54
- READY is refused.
55
-
56
- Do not start retro before step 2 or skip it because the change seems mechanical; the merger's
57
- `READY` comes only after step 3. The design gate is not a substitute for review and retro.
58
-
59
- ## Two perspectives
60
-
61
- 1. Re-read the issue, its acceptance criteria, the PR, test evidence, and review evidence.
62
- Confirm the PR carries both proofs: the implementer's own `E2E (implementer)` line and the tester's `E2E (tester)` line,
63
- each naming a production-like surface (the daemon's real-process tests and the live proofs under `scripts/e2e/`; a live check at the operator's next daemon restart, recorded on the PR; a sandbox repository, a devN
64
- stack, staging, or a local stack with real migrations), a command or run id, an observation, a head
65
- SHA, and a negative control. If either is missing, or links only a unit suite, the retro's first
66
- durable learning is that gap and the issue goes back — to the implementer for its own proof, to the
67
- tester for the tester's — before `READY`.
68
- Do not rebase or create a new branch; work on the existing issue branch.
69
- 2. Spawn one fresh-eyes subagent. Give it the issue and PR, ask it to inspect the diff and
70
- return concrete reusable learnings, and require it to return analysis rather than edit files.
71
- 3. Independently record the implementer's perspective: surprising constraints, difficult
72
- decisions, failed approaches, and reusable patterns.
73
- 4. Integrate the two perspectives. The implementer owns the final judgment: reject generic or
74
- context-free suggestions and preserve only learning that will help a future worker.
75
-
76
- ## Durable outputs
77
-
78
- Before your turn's first commit, run `jj -R "$LEGION_WORKSPACE" log -r @ --no-graph -T 'empty'`.
79
- When it prints `true`, run `jj -R "$LEGION_WORKSPACE" new @-`; otherwise `@` holds only your own
80
- resumed edits, so run `jj -R "$LEGION_WORKSPACE" new`. Never `jj describe` or `jj split` the
81
- working-copy commit you found at the turn's start; `skill://legion-worker` explains the
82
- shared-workspace authorship rule.
83
-
84
- Write the integrated learning as one or more discoverable documents under `docs/solutions/`.
85
- Organize by reusable topic rather than by pull request, but never edit a document you did not
86
- write this retro — not its frontmatter, not its body. Two trees' retros can land within the same
87
- hour, and an in-place edit (another `related_issues` entry, a sharpened sentence, a `status`
88
- flip) conflicts with any other tree's edit to the same lines of the same file. Search
89
- `docs/solutions/` for the topic first; before relying on a hit, also search `docs/solutions/` for
90
- its path (`docs/solutions/<its-path>`): a hit in another file's front matter under its
91
- `supersedes:` key (on that line, or as an item of the list below it) supersedes the one you found,
92
- and a line `Extends docs/solutions/<its-path>` extends it. Legion runs no pass that reconciles
93
- these links, so a newer file is discoverable only by following them. Then write a new file of
94
- your own, named `docs/solutions/<category>/<slug>-<LEGION_ISSUE>.md` so two trees never choose
95
- the same path:
96
-
97
- - **A fresh topic:** state the rule in a few imperative lines; the incident goes in an Evidence
98
- section below, never in the rule.
99
- - **A topic an existing document already covers:** underneath its own H1 heading, the first line
100
- reads `Extends docs/solutions/<existing-path>.md.`; the rule states only the delta.
101
- - **A topic an existing document states wrongly:** frontmatter adds
102
- `supersedes: docs/solutions/<existing-path>.md`, or, for several, a `supersedes:` list with one
103
- `- docs/solutions/<existing-path>.md` item each; the first line under the H1 says why. Leave
104
- the old file's frontmatter and body untouched: Legion runs no pass that reconciles it, so the
105
- `supersedes:` link is the only thing that makes the correction discoverable from the old file.
106
-
107
- Each document uses this front matter:
108
-
109
- ```yaml
110
- ---
111
- title: "Descriptive title matching the H1"
112
- category: subdirectory-name
113
- tags:
114
- - searchable-topic
115
- date: YYYY-MM-DD
116
- status: active
117
- module: affected-module
118
- related_issues:
119
- - "LEGION-123" # the Dispatch issue
120
- - "owner/repo#456" # the pull request
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.