@sjawhar/claude-envoy 0.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/.claude-plugin/plugin.json +6 -0
  2. package/.mcp.json +11 -0
  3. package/.omp-plugin/plugin.json +6 -0
  4. package/AGENTS.md +343 -0
  5. package/README.md +639 -0
  6. package/bin/dispatch +6 -0
  7. package/bin/envoy-channel.ts +9 -0
  8. package/bin/envoy-send.ts +33 -0
  9. package/dist/THIRD_PARTY_NOTICES +816 -0
  10. package/dist/dispatch.js +27707 -0
  11. package/dist/envoy-channel.js +57695 -0
  12. package/dist/session-hook.js +26328 -0
  13. package/dist/session-title-hook.js +116 -0
  14. package/hooks/hooks.json +60 -0
  15. package/hooks/session-hook.ts +512 -0
  16. package/hooks/session-title-hook.ts +46 -0
  17. package/legion/.claude-plugin/plugin.json +4 -0
  18. package/legion/agents/deep-worker.md +68 -0
  19. package/legion/agents/oracle.md +35 -0
  20. package/legion/agents/plan-gap-analyst.md +65 -0
  21. package/legion/agents/plan-reviewer.md +104 -0
  22. package/legion/agents/thermonuclear-code-quality.md +30 -0
  23. package/legion/agents/thermonuclear-deep-review.md +30 -0
  24. package/legion/hooks/hooks.json +89 -0
  25. package/legion/skills/ce-simplify-code/LICENSE +21 -0
  26. package/legion/skills/ce-simplify-code/SKILL.md +66 -0
  27. package/legion/skills/ce-simplify-code/references/personas/code-quality-reviewer.md +17 -0
  28. package/legion/skills/ce-simplify-code/references/personas/code-reuse-reviewer.md +7 -0
  29. package/legion/skills/ce-simplify-code/references/personas/efficiency-reviewer.md +11 -0
  30. package/legion/skills/leading-a-work-stream/SKILL.md +96 -0
  31. package/legion/skills/leading-a-work-stream/references/daily-plan.md +8 -0
  32. package/legion/skills/leading-a-work-stream/references/decision-rights.md +6 -0
  33. package/legion/skills/leading-a-work-stream/references/direction-and-coaching.md +13 -0
  34. package/legion/skills/leading-a-work-stream/references/dispatch-upkeep.md +8 -0
  35. package/legion/skills/leading-a-work-stream/references/sources.md +9 -0
  36. package/legion/skills/leading-a-work-stream/references/speed-tick.md +44 -0
  37. package/legion/skills/leading-a-work-stream/references/user-quotes.md +7 -0
  38. package/legion/skills/legion-architect/SKILL.md +86 -0
  39. package/legion/skills/legion-architect/references/acceptance.md +208 -0
  40. package/legion/skills/legion-architect/references/decomposition.md +129 -0
  41. package/legion/skills/legion-architect/references/design-gate.md +206 -0
  42. package/legion/skills/legion-architect/references/merge-notices.md +91 -0
  43. package/legion/skills/legion-architect/references/wake-routing.md +41 -0
  44. package/legion/skills/legion-controller/SKILL.md +151 -0
  45. package/legion/skills/legion-controller/references/admission.md +22 -0
  46. package/legion/skills/legion-controller/references/backlog-stewardship.md +101 -0
  47. package/legion/skills/legion-controller/references/daily-report.md +75 -0
  48. package/legion/skills/legion-controller/references/escalation.md +82 -0
  49. package/legion/skills/legion-controller/references/finding-asks.md +181 -0
  50. package/legion/skills/legion-controller/references/parked-decisions.md +198 -0
  51. package/legion/skills/legion-controller/references/session.md +100 -0
  52. package/legion/skills/legion-controller/references/slack-mentions.md +154 -0
  53. package/legion/skills/legion-controller/references/triage.md +96 -0
  54. package/legion/skills/legion-controller/references/wakes.md +132 -0
  55. package/legion/skills/legion-oracle/SKILL.md +48 -0
  56. package/legion/skills/legion-retro/SKILL.md +112 -0
  57. package/legion/skills/legion-retro/references/learnings.md +60 -0
  58. package/legion/skills/legion-retro/references/pr-body-content.md +56 -0
  59. package/legion/skills/legion-worker/SKILL.md +69 -0
  60. package/legion/skills/legion-worker/references/cleanup-deletion.md +22 -0
  61. package/legion/skills/legion-worker/references/conflicts-and-rewrites.md +164 -0
  62. package/legion/skills/legion-worker/references/default-branch-check.md +53 -0
  63. package/legion/skills/legion-worker/references/findings.md +199 -0
  64. package/legion/skills/legion-worker/references/merge-gate.md +353 -0
  65. package/legion/skills/legion-worker/references/pr-body.md +218 -0
  66. package/legion/skills/legion-worker/references/review-threads.md +77 -0
  67. package/legion/skills/legion-worker/references/systematic-rename.md +19 -0
  68. package/legion/skills/legion-worker/references/tools.md +708 -0
  69. package/legion/skills/thermonuclear-code-quality/LICENSE +21 -0
  70. package/legion/skills/thermonuclear-code-quality/SKILL.md +60 -0
  71. package/legion/skills/thermonuclear-deep-review/LICENSE +21 -0
  72. package/legion/skills/thermonuclear-deep-review/SKILL.md +80 -0
  73. package/package.json +49 -1
  74. package/scripts/build-inputs.txt +84 -0
  75. package/scripts/build.ts +415 -0
  76. package/scripts/check-packed-skills.sh +50 -0
  77. package/scripts/pack-skills.sh +146 -0
  78. package/scripts/smoke-channel.sh +178 -0
  79. package/scripts/smoke-clear-rebind.sh +164 -0
  80. package/scripts/smoke-session-title.sh +245 -0
  81. package/scripts/verify-build.sh +88 -0
  82. package/skills/agent-secrets/SKILL.md +180 -0
  83. package/skills/asd-ste100/LICENSE +21 -0
  84. package/skills/asd-ste100/SKILL.md +140 -0
  85. package/skills/asd-ste100/examples/before-after.md +92 -0
  86. package/skills/asd-ste100/references/writing-rules.md +59 -0
  87. package/skills/dispatch/SKILL.md +89 -0
  88. package/skills/dispatch-first/SKILL.md +46 -0
  89. package/skills/dispatch-writing-specs/SKILL.md +80 -0
  90. package/skills/envoy/SKILL.md +82 -0
  91. package/skills/envoy/references/check-settlement.md +62 -0
  92. package/skills/envoy/references/deliveries.md +67 -0
  93. package/skills/envoy/references/legion.md +14 -0
  94. package/skills/envoy/references/roles.md +12 -0
  95. package/skills/envoy/references/sources.md +41 -0
  96. package/skills/outside-message/SKILL.md +111 -0
  97. package/skills/plain-words/SKILL.md +88 -0
  98. package/src/channel-forwarder.ts +262 -0
  99. package/src/claude-channel.ts +705 -0
  100. package/src/claude-session.ts +38 -0
  101. package/src/envoy-channel-server.ts +2115 -0
  102. package/src/envoy-client.ts +26 -0
  103. package/src/envoy-off.ts +62 -0
  104. package/src/legion-claim.ts +211 -0
  105. package/src/legion-inbox.ts +110 -0
  106. package/src/legion-phase-hook.ts +554 -0
  107. package/src/legion-tool.ts +69 -0
  108. package/src/replay-state.ts +97 -0
  109. package/src/send-arguments.ts +13 -0
  110. package/src/session-identity.ts +165 -0
  111. package/src/session-state.ts +142 -0
  112. package/src/session-title.ts +251 -0
  113. package/src/subscription-topics.ts +16 -0
@@ -0,0 +1,132 @@
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, when no person set that label (a
13
+ session's label, yours included). The daemon sends it when a session creates the issue with the
14
+ label, and on each later change while it stays in `triage`, the change that adds the label
15
+ included. Triage the root as `skill://legion-controller/references/triage.md` says. A person's
16
+ label on a `triage` root wakes nobody: the root is queued by the daemon (its own `todo` write). A
17
+ person's approval of a parked (`backlog` or `icebox`) labelled root's spec is queued by the daemon
18
+ the same way and wakes nobody.
19
+
20
+ ## `slot-free on <KEY>` (`{kind: "slot-free"}`)
21
+
22
+ The daemon released `<KEY>`'s slot and no waiting root took it: its tree finished or left the
23
+ workflow, or the root returned the slot to wait on a person (`awaiting_person`, which also sends
24
+ its own `awaiting-person` wake). Name the free slots; take nothing.
25
+
26
+ ## `todo on <KEY>` (`{kind: "todo"}`)
27
+
28
+ `<KEY>`, an issue nobody handed to Legion, changed while in `todo` and a slot stood free; the
29
+ daemon waits half a minute and folds that window's events into one wake. Take nothing: it is not
30
+ Legion's.
31
+
32
+ ## `tick on <PROJECT>` (`{kind: "tick", openCapabilities?, blocked?}`)
33
+
34
+ The daemon's periodic wake, a minute after it starts and then every
35
+ `controller_wake_interval_seconds` (an hour by default), whatever the slots. Run the skill's every-turn
36
+ steps, then the parked-root walk (`skill://legion-controller/references/parked-decisions.md#the-walk`).
37
+
38
+ `openCapabilities`, when present, names the open capability rows; `read_state`'s `capabilities`
39
+ gives each one's `detail`. A deployment row (the secrets broker, model fallback, a role's CPU and
40
+ memory limits, the pool's capacity at boot) has a `configLine`, the `legion.yaml` line
41
+ (`capabilities.decided.<name>`) that would record a decision. A live row (`subagents`,
42
+ `web-search`, `mcp`, `repository-extensions`, `dispatch-envoy-tools`, `github`) is a running
43
+ session's failed check: its `detail` names the session (pod or pane), role, issue and fact, and it
44
+ has no `configLine`. The next daily report names each row still open; take no other action,
45
+ because the operator closes or decides a deployment row, and the operator or the issue's architect
46
+ fixes a live row's session.
47
+
48
+ `blocked`, when present, is `[{issue, blockedBy}, …]`: every root and child Legion is waiting to
49
+ start behind an unfinished Dispatch issue, each with the issues it waits on. `read_state` shows the
50
+ same list under `admission.blocked`, and `legion state` prints it as `blocked on Dispatch links:`.
51
+ The wait ends when each blocker reaches `done` (a person's close, or the blocker's own merge) or its
52
+ link is taken off (by a person or the tree's architect): name the waits in the day's report and
53
+ take nothing for them.
54
+
55
+ ## `unslotted on <KEY>` (`{kind: "unslotted", reason}`)
56
+
57
+ Either a root that waited for a slot was moved from `todo` to the status `reason` names, by a
58
+ person or by another session, or a root waiting on a person (`awaiting_person`) could not be
59
+ resumed — its `legion` label is gone, or a person or a session outside its tree took its Dispatch
60
+ claim. Either way the daemon took it out of the workflow (`phase: done`) and starts nothing for it;
61
+ `reason` says which. Re-admit nothing, because the move was someone else's; `dispatch read` shows
62
+ who claims it now. Tell the person in your summary: "<KEY> left Legion's workflow: <reason as the
63
+ wake gives it>; `todo` with the `legion` label queues it again". Other admission states:
64
+ `skill://legion-controller/references/admission.md`.
65
+
66
+ ## `awaiting-person on <KEY>` (`{kind: "awaiting-person", reason}`)
67
+
68
+ A root whose architect asked a person a question, or handed its spec to a person for approval, and
69
+ now waits only on them: the daemon returned its slot while the architect stays live to read the
70
+ person's comments and replies. Read `issues.<KEY>.waitingOn`. Do not park it or start anything, and
71
+ take nothing for the slot it returned: it is no reason to label or admit an issue ([Free
72
+ slots](skill://legion-controller/SKILL.md#free-slots)). The person's answer puts it at the front of
73
+ `admission.waiting` by itself, and the next free slot delivers its task. A lost label or a foreign
74
+ Dispatch claim sends the separate `unslotted` wake.
75
+
76
+ ## `parked-decision on <KEY>` (`{kind: "parked-decision", decision, root, ref, actor, version?, reason?}`)
77
+
78
+ A person's spec decision, or answer, resolution or reply on an ask, on a tree Legion is not
79
+ running, which nobody inside the tree heard. The payload names the decision, the tree's `root`,
80
+ the decision's Dispatch `ref`, the person (`actor`), and a spec decision's `version` and a changes
81
+ request's `reason`. Decide it as `skill://legion-controller/references/parked-decisions.md#deciding`
82
+ says.
83
+
84
+ ## `held on <KEY>` (`{kind: "held", phase, role?, reason?}`)
85
+
86
+ Check that the issue's `phase` is `held`. Without `reason`, a phase worker's launches or prompts
87
+ ran out, and the tree's architect decides whether to retry or escalate: do nothing. With
88
+ `reason: "escalated"` (`issues.<KEY>.holdReason` is `escalated`), the architect handed it to you:
89
+ handle it as an escalation (`skill://legion-controller/references/escalation.md`). A held issue
90
+ with no `holdReason` while its tree lingers (the time after its root closes when a reopen resumes
91
+ it) or is closed waits for the tree's re-admission and needs nothing from you.
92
+
93
+ When an escalated hold's cause is not gone, park the tree: `set_status` the root to `backlog`,
94
+ then, in the same turn, post one comment on the root (`dispatch comment --issue <root>
95
+ --body-file -`) whose first line is `Parked by Legion while it waits on: <the hold's cause>`, the
96
+ cause being what you found the held phase waits on (the payload's `phase` and `role`, and the held
97
+ issue's `dispatch read`). That mark is what makes the park Legion's own hold
98
+ (`skill://legion-controller/references/parked-decisions.md#deciding`, step 2). Set the root back to
99
+ `todo` only when you checked that the hold's cause is gone, a person asks, or a person's decision
100
+ after the park gives its work a next step (that reference's step 4), because `todo` re-admits it
101
+ as a new generation: a new run of the tree that starts again from its architect.
102
+
103
+ ## `worker-died on <KEY>` (`role: "architect"`)
104
+
105
+ The tree's architect ran out of launches or prompts, and the daemon relaunches nothing. Every other
106
+ notice of the tree goes to that architect, so nobody inside the tree can act. Check that
107
+ `issues.<KEY>.architect.state` is `failed`. When the root's `phase` is `done`, the tree is already
108
+ parked: do nothing (a failed architect reads `failed` until the tree closes). Otherwise look for
109
+ the cause: an open `capabilities` row whose `detail` names the architect's session, or the
110
+ architect's last message on the root issue. When you find none, or it is gone, re-admit the tree
111
+ (`set_status` the root to `backlog`, then to `todo`: a new generation whose architect starts with
112
+ fresh budgets). When it stays, park the tree (`set_status` the root to `backlog`) and say why on
113
+ the issue, because a relaunch would fail the same way.
114
+
115
+ ## `update-stalled on <KEY>` (`{kind: "update-stalled", reason, update}`)
116
+
117
+ An update round over the issue's pod, or over one claim's own process, is not finishing. Handle
118
+ it as `skill://legion-controller/references/escalation.md#an-update-round-that-is-not-finishing-update-stalled`
119
+ says.
120
+
121
+ ## GitHub mentions
122
+
123
+ Read the mention and its artifact. Answer a mention that asks you for triage or for information
124
+ that `read_state` or Dispatch holds.
125
+ Send any other to the owning architect: find its role in `read_state` and `envoy_publish` the
126
+ mention's URL, its text and the issue key you checked. Never build a role token from a partial
127
+ issue reference, because a wrong token reaches nobody.
128
+
129
+ A person who asks how to let a root past its design gate approves the root's spec document in
130
+ Dispatch: the `Approve` control in the document's header, or the approval question the architect's
131
+ request opened in the Inbox. No operator command opens a gate; a project that wants no gate sets
132
+ `gates.design: off` in `legion.yaml`.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: legion-oracle
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
+ ---
5
+
6
+ # Legion Oracle
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
+ ## When to research instead of asking
11
+
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.
14
+
15
+ ## Research steps
16
+
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 no session holds the role, the publish
23
+ answers that Envoy kept the question for the session that claims the role next, which is handed it
24
+ once within the hour. Nobody can answer you now, so put that kept answer in your output and
25
+ research at once rather than wait for it.
26
+
27
+ Run steps 1 and 2, in parallel if you choose, since neither needs the other's result. Run step 3
28
+ when the question names a library, and step 4 when it asks for general practice, each only when
29
+ steps 1 and 2 give no `file:line` source for some part of the question. Use only `read`, `grep`,
30
+ `web_search`, the `envoy_publish` above, and `task` with `scout` or `oracle`: the daemon's boot
31
+ gate checks that the agents Legion's prompts name exist, and no other. A `task` runs as a job of
32
+ its own, so `wait` for its result — two dispatched together are two results to wait for — and
33
+ answer from what came back, never from the dispatch.
34
+
35
+ | Step | Tool | Query |
36
+ |------|------|-------|
37
+ | 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 |
38
+ | 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] |
39
+ | 3. Framework docs | `web_search`, then `read` the library's official docs page | [library] docs [topic] |
40
+ | 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] |
41
+
42
+ 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.
43
+
44
+ ## Output
45
+
46
+ - Found: the answer with its source (`file:line` or a URL), so the reader can check it.
47
+ - Partly found: each part found with its source, then each part not found.
48
+ - 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.
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: legion-retro
3
+ description: "Use when the Legion daemon starts you, the implementer, on `Phase: retro` after the architect accepted the reviewed head."
4
+ ---
5
+
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-6 even when the change looks mechanical; each gives its reason.
14
+
15
+ Retro commits nothing and pushes nothing: every handoff is a record on the Dispatch issue, no
16
+ commit carries one, and what the work taught is a `dispatch comment` on the issue, for the skill
17
+ librarian to read. `docs/solutions/` stays as history, and no role writes there.
18
+ The head the merger names is the head the reviewer approved.
19
+
20
+ ## What READY refuses
21
+
22
+ - **A change after the approved head** (`READY_UNREVIEWED_CHANGE`): the
23
+ daemon diffs the reviewer's approved head against the head on GitHub, and the issue goes back to
24
+ the reviewer for another review. READY still lets through a commit that changes only
25
+ `docs/solutions/`, which no role writes any more, and a file under `.legion/` that GitHub lists
26
+ as removed: the commit `legion handoffs import` makes, never one of yours. Since retro commits
27
+ nothing, an ordinary head carries neither.
28
+ - `READY_UNREVIEWED_CHANGE` has more causes than a path outside retro's own. Every one of them
29
+ sends the head back to review and none is an error to retry; the complete list, with each
30
+ remedy, is the merger's own role prompt part.
31
+
32
+ Work on the existing issue branch: never rebase it onto another base, never make another branch or
33
+ bookmark, and push nothing, because READY reads this branch's head and a push of yours would void
34
+ the reviewer's approval.
35
+
36
+ ## When retro stops
37
+
38
+ When a step fails (the body cannot be computed, read or written, or Dispatch refuses a write), do
39
+ not call `handoff_complete`. Report it with `envoy_publish` to the architect's
40
+ topic in the `Legion addressing` line of your system prompt, with the command and its output. A
41
+ check with no current passing result goes back as step 1 says. The Dispatch message (step 5) is
42
+ for a finished retro only.
43
+
44
+ ## Steps
45
+
46
+ 1. **Read the evidence:** the issue, its checks (`dispatch results --issue <issue>`), the pull
47
+ request, and the tester's and reviewer's handoffs
48
+ (`dispatch handoff-read --issue <issue> --phase test`, then the review
49
+ at the version your task's `Handoff:` line names, `--phase review --version <n>`, the command
50
+ that line quotes). Every `before_merge` check of the issue carries a passing result that is
51
+ current at the approved head, the implementer's and the tester's alike, and the pull request
52
+ body's `Checks` block carries each of those lines. In
53
+ cybermonklabs/legion a surface may also be the daemon's real-process tests, a live proof under
54
+ `scripts/e2e/`, or a live check at the operator's next daemon restart recorded on the pull
55
+ request. When a check has no current passing result, or its only evidence is a unit suite,
56
+ call the `legion` tool's `request_backward_move` with `to: implementing` for the implementer's
57
+ result or `to: testing` for the tester's, its `reason` naming the check by its block id. When
58
+ retro runs again, that gap is your first learning.
59
+ 2. **Get a second reading**, because a reader without your context sees what you stopped seeing.
60
+ First list, in your session, the constraints the issue did not state, choices between two
61
+ working options, approaches you abandoned, and code another issue could reuse, so the second
62
+ answer does not set your list. Then run `task(agent="oracle")` (read-only) with the issue, the
63
+ pull request body and the diff in its brief, asking for reusable learnings, and `wait` for its
64
+ answer, since it runs as a job of its own. You decide which points to keep. Drop a point that
65
+ cites no file, symbol, quoted text or commit of this pull request.
66
+ 3. **Record the learnings.** Write each kept point you can state as a rule a worker on another
67
+ issue could follow as one `dispatch comment` on the issue, per
68
+ `skill://legion-retro/references/learnings.md`, which says what a point must carry for the
69
+ skill librarian to use it. When none qualifies, say so in that comment's place in step 5's
70
+ message and write no comment.
71
+ 4. **Update the PR body**, per `skill://legion-retro/references/pr-body-content.md`,
72
+ when the repository derives body lines from changed paths.
73
+ 5. **Post one Dispatch message on the issue**, the record of the retro that the architect reads.
74
+ No `gh issue` write: Legion issues live on Dispatch. The body is at most 32,000 characters,
75
+ Dispatch's message limit, and ends with your attribution footer:
76
+
77
+ ```bash
78
+ dispatch message --issue '<KEY>' --body-file - <<'EOF'
79
+ ## Retro Complete
80
+
81
+ **Learnings:** the comment of step 3 (`dispatch://<KEY>/comment/<id>`), or none: <why no point qualified>.
82
+
83
+ **Key takeaways:**
84
+ - <one to three reusable lessons>
85
+
86
+ **Results read:** implementer <check and result>, tester <check and result>.
87
+
88
+ **Production check:** <the command or user action that will show the change working in production>
89
+ **Carried by:** <the deploy or restart that carries the merge there>
90
+ **Run by:** <the agent or role your system prompt's deployment instructions name; when none, the person to ask>
91
+
92
+ <!-- legion: {"session":"<session-id>","phase":"retro"} -->
93
+ EOF
94
+ ```
95
+
96
+ The merge's close hands you the production check's first look in this session; the daemon
97
+ wakes a later look at a deploy only after you report `pending`
98
+ (`skill://legion-worker/references/merge-gate.md#the-production-check-after-the-close`).
99
+ 6. **Complete** with the `legion` tool's `handoff_complete`, its summary two sentences for the
100
+ architect. It reports the commit your workspace stands on, which is the head you found: retro
101
+ writes no handoff and makes no commit. In the workspace retro changes nothing; outside it, it
102
+ writes only step 4's `mktemp -d` directory, the PR body and the Dispatch comment and message.
103
+ It sets no GitHub or Dispatch label: Legion keeps phase state in the daemon, not in labels.
104
+
105
+ ## Before you complete
106
+
107
+ - `jj -R "$LEGION_WORKSPACE" diff --from "legion/${LEGION_ISSUE:?}@origin" --to @ --name-only`
108
+ lists nothing: retro leaves the workspace as it found it. READY checks the approved head the
109
+ review round recorded, which `read_record` does not show.
110
+ - Each body line you added or changed that says work was done names work this pull request did.
111
+ - The Dispatch comment and the Dispatch message are posted, and the pull request's head is the
112
+ head you found.
@@ -0,0 +1,60 @@
1
+ # Writing a retro learning as a Dispatch comment
2
+
3
+ Read this at step 3 of `skill://legion-retro`, when you write what the work taught. It is one
4
+ `dispatch comment` on the issue, and its reader is the skill librarian, who turns a point into a
5
+ rule in a skill, a role prompt or a repository guide. Retro commits nothing:
6
+ `docs/solutions/` stays as the history of the rules written before this, and no role writes there.
7
+
8
+ ## What a point must carry
9
+
10
+ Write each kept point as a rule a worker on another issue could follow, and give it:
11
+
12
+ - **The rule**, in a few imperative lines. State it in the present tense, about the work, never
13
+ about this pull request.
14
+ - **The evidence** below the rule: the file and symbol, or text quoted from the file, read at
15
+ the head you commit, and what went wrong before the rule. Never a line number: the next edit
16
+ above it moves it. Where the head no longer shows what your sentence says, quote the text and
17
+ name the commit you read it at. A reader takes a story as an instruction, so the story never
18
+ stands in the rule's place.
19
+ - **Where it belongs**: the skill, role prompt or guide a reader would look in — for example
20
+ `skills/legion-worker/references/tools.md` or `packages/daemon/internal/prompts/roles/tester.md`.
21
+ Name the file; the librarian decides whether to write it there.
22
+ - **What it replaces**, when an instruction the repository already carries is wrong: quote that
23
+ instruction and its path, so the librarian can find both.
24
+
25
+ Drop a point that cites no file, symbol, quoted text or commit of this pull request, and a
26
+ point that only restates what a skill already says.
27
+
28
+ ## Find what already covers the topic
29
+
30
+ 1. `dispatch search --query '<two or three words naming the topic>'` finds the issues and
31
+ comments that hold it, this project's retros included.
32
+ 2. Search `docs/solutions/` with the `grep` tool, case-insensitive, for the same words, and read
33
+ each hit's H1 and rule: a rule written before this change may already say it, or may say the
34
+ opposite, which is itself the point to report.
35
+ 3. Search the skills and role prompts the point would change (`skills/`,
36
+ `packages/daemon/internal/prompts/`). A rule one of them already states is no learning.
37
+
38
+ ## The comment
39
+
40
+ One comment holds every kept point, each under its own `###` heading, so the issue carries one
41
+ record of the retro rather than a thread of them:
42
+
43
+ ```bash
44
+ dispatch comment --issue '<KEY>' --body-file - <<'EOF'
45
+ ## Retro learnings
46
+
47
+ ### <the rule, in one line>
48
+
49
+ <the rule, a few imperative lines>
50
+
51
+ Evidence: <file and symbol, or text quoted from it, of this pull request, and what went wrong>.
52
+ Belongs in: <the skill, prompt or guide>.
53
+ Replaces: <the instruction and its path>, or nothing.
54
+
55
+ <!-- legion: {"session":"<session-id>","phase":"retro"} -->
56
+ EOF
57
+ ```
58
+
59
+ When no point qualifies, write no comment and say so in the retro message (step 5 of
60
+ `skill://legion-retro`).
@@ -0,0 +1,56 @@
1
+ # The PR body lines the changed paths require
2
+
3
+ Read this at step 4 of `skill://legion-retro`. A failure here stops retro as its
4
+ *When retro stops* section says.
5
+
6
+ ## Bring the body up to date before you complete
7
+
8
+ A repository can require body lines derived from the pull request's changed paths (for example one
9
+ checklist line when `src/**` changed and another when `docs/**` changed) and have a required check
10
+ read them from the body. The body approved earlier in the round may not account for every path the
11
+ pull request now changes, so that check fails at the head. The
12
+ merger reports a stale body rather than rewriting it, and GitHub will not merge a head whose
13
+ required check failed, so the merge waits.
14
+
15
+ `<owner>/<repo>` and `<n>` are the pull request's repository and number in every command below.
16
+
17
+ 1. Read your system prompt's deployment instructions, the repository's agent guide (`AGENTS.md`,
18
+ `CLAUDE.md`), its pull request template (`.github/pull_request_template.md` or
19
+ `.github/PULL_REQUEST_TEMPLATE/`), and the workflow under `.github/workflows/` that reads the
20
+ body, for lines they require per changed path. When they require none, there is nothing to do.
21
+ 2. List the paths the pull request changes at `<head>`, the approved head your task names:
22
+
23
+ ```bash
24
+ 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
25
+ ```
26
+
27
+ `@json` makes `base` a quoted jj string literal; never paste a branch name between quotes
28
+ yourself, because a name with a quote or revset character then breaks the command. For each
29
+ path pattern the step 1 sources name, write the line they require when a listed path matches
30
+ it. A line that says work was done names work this pull request did: retro commits nothing, so
31
+ a line whose work is undone is a finding for the architect, not work you do here.
32
+ 3. Make a directory outside `$LEGION_WORKSPACE` with `dir=$(mktemp -d)`, the one place you write
33
+ outside it: jj would commit a file inside it, and a fixed name in a shared `/tmp` can hold
34
+ another session's body. Save the live body as `$dir/before.md` (to restore on failure) and
35
+ `$dir/body.md` (to edit), and stop unless the read succeeded and is not empty:
36
+
37
+ ```bash
38
+ cd -- "$LEGION_WORKSPACE" && ( set -o pipefail && gh api repos/<owner>/<repo>/pulls/<n> --jq .body | tee "$dir/before.md" "$dir/body.md" ) && test -s "$dir/before.md"
39
+ ```
40
+
41
+ Without `pipefail` a failed read exits with `tee`'s status and leaves two empty files. The
42
+ parentheses keep `pipefail` to this line, since your shell persists and a later `cmd | head`
43
+ would exit 141 under it. In `$dir/body.md`, change only the lines the step 1 sources derive
44
+ from paths, adding a missing one where they place it. Leave every other line byte for byte,
45
+ the `Checks` block included.
46
+ 4. Write it back:
47
+
48
+ ```bash
49
+ cd -- "$LEGION_WORKSPACE" && gh api --method PATCH repos/<owner>/<repo>/pulls/<n> -F body=@"$dir/body.md"
50
+ ```
51
+
52
+ A body edit changes no commit, so the reviewer's approval stands, and a check that judges the
53
+ body runs again at once on the head as it is.
54
+
55
+ When the write back is refused, or the check it feeds fails, report it to the architect as *When
56
+ retro stops* says, with the command and its output.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: legion-worker
3
+ description: Use when dispatched as a per-process Legion phase worker — planner, implementer, tester, reviewer, or merger — booted from the daemon's LEGION_* environment.
4
+ ---
5
+
6
+ # Legion Phase Worker
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
+ You work one phase of one issue in a jj workspace every role of the issue shares; the architect owns the tree. Your role prompt gives the workspace binding, `gh`, the push, the handoff record, `handoff_complete` and how long your session stays; this skill adds the rest.
11
+
12
+ ## Every phase, in this order
13
+
14
+ 1. **Read first.** Read the issue, then each handoff before your phase with `dispatch handoff-read --issue <issue> --phase <word>`, in order: `plan`, `implement`, `test`, `review` (a phase with no handoff answers `HANDOFF_NOT_FOUND`). Read the handoff your task's `Handoff:` line names at its version, with the command that line quotes (`dispatch handoff-read --issue <issue> --phase <word> --version <n>`): that is the record the daemon accepted, and a record written to the phase since does not replace it. Where one disagrees with your memory or a transcript, the record wins: it is the copy that survived. At each later assignment read them again, your own included, since other phases may have recorded since. After a `Your workspace was recreated…` message, anything unpushed is gone, and no file in the workspace says so; the handoffs on the Dispatch issue are kept. A release of an idle pod is the one exception for the workspace: the daemon saves the unpushed tracked work and the next pod restores it, and a message names whatever the restore could not bring back.
15
+ 2. **Commit only your phase's work**, with `jj -R "$LEGION_WORKSPACE" split -m "<message>" <paths…>`, each commit holding only your phase's paths, so the next phase sees what you changed.
16
+ 3. **Put back what you copied in.** Before you write the handoff, run `jj -R "$LEGION_WORKSPACE" status` and remove or restore every file you copied or fetched in that is not your phase's work, such as another branch's test rig. With jj the working copy is the commit: the next role's first commit builds on what you left, and its push ships it.
17
+ 4. **Write the handoff** your role prompt names, with the `write` tool to `$TMPDIR/<issue>-<word>.json`, outside the workspace (jj snapshots every file in the workspace into the working-copy commit), then record it with `dispatch handoff-write --issue <issue> --phase <word> --body-file "$TMPDIR/<issue>-<word>.json"`. A handoff is never a commit, and no handoff carries the evidence: what you ran is a result you record against one of the issue's checks with `dispatch result`, and `skill://legion-worker/references/pr-body.md#what-a-result-is` defines a check and a result. To change a handoff already recorded, read it with `dispatch handoff-read`, edit the body, and record it whole again: each `dispatch handoff-write` adds a version, and `handoff_complete` reports the newest.
18
+ 5. **Push any work, then complete**, as the push section below says. `handoff_complete` is your only way to end a phase: add no label, keep no status of your own and run no loop of your own, since the daemon owns the issue's state and the architect its decomposition and gates.
19
+
20
+ ## Stop rules
21
+
22
+ - **A refused completion is information, not a retry loop.** Quote the answer verbatim to the architect, so "my work is lost" and "my work belongs to an ended run" read differently. `HANDOFF_STALE_GENERATION` (the issue is on a newer run: your turn began before the daemon's task for that run reached you, and the answer names that task when it is queued) or `HANDOFF_NO_RUN` (your claim holds no task): push nothing further, end the turn without completing, and tell the architect; if the task then arrives (none may: the new run's phase can be another claim's) and its work and handoff are already done, call `handoff_complete` again in that task's turn, and never redo the work or write a second handoff. `HANDOFF_STALE_ASSIGNMENT` (the issue left your phase and came back while your turn ran — a red sent the work back, and a later round returned it — so your work belongs to the assignment before the one the phase hands you now, and the answer names that task when it is queued): end the turn without completing and tell the architect, and report that work and that verdict no further. The phase was entered again, so the task it hands you now is work of its own — a testing assignment after a red is for the head the fix pushed, which your verdict on the head before it does not answer for: do that work at the head the task names, write a handoff of its own for it, and complete in its turn. `HANDOFF_NOT_CURRENT_PHASE`: the issue left your phase; report, never complete again. `HANDOFF_NO_PULL_REQUEST` (the implementer's completion found no open pull request on `legion/<KEY>`, and none recorded merged): open it and complete again at the same commit; when the answer names a closed pull request, the architect decides the phase: tell it, and open or reopen nothing until it answers. `HANDOFF_ALREADY_RECORDED`: the first answer stands, an acceptance or one of the refusals the daemon records (`HANDOFF_NOT_CURRENT_PHASE`, `READY_REQUIRED`, `HANDOFF_NOT_NEW`, and `HANDOFF_STALE_GENERATION` only when the issue moved during the call); if you did not see it, tell the architect. A refusal given before any fact is applied (`HANDOFF_STALE_GENERATION`, `HANDOFF_STALE_ASSIGNMENT`, `HANDOFF_NO_RUN`, `HANDOFF_NO_PULL_REQUEST`, the daemon's read of your handoff record and READY's checks of the head among them) records nothing, so the call that follows is applied rather than answered `HANDOFF_ALREADY_RECORDED`, where the remedy above says so. `HANDOFF_SESSION_MISMATCH` names a record another session wrote: read it, record it again from your session with `dispatch handoff-write`, and complete. A reminder is not a task: after an accepted completion, a second call is refused.
23
+ - **A turn that ends with your phase open is reminded**, at the end of every turn for as long as the phase stays open. Answer by completing, or with a WAITING line naming what you wait on, which buys a quiet wait; a turn that ends while background work of your own is still running buys the same quiet with no line at all, since that work wakes you when it finishes. A run of reminders that change nothing tells your architect. Under `runtime: kubernetes` that quiet wait also lets the daemon release your issue's pod, while background work of yours keeps the pod, because your session reports that work to the daemon.
24
+ - **A released pod is not a stop.** Under `runtime: kubernetes` the daemon releases your issue's pod once no role of it has a turn in progress or a turn due for ten minutes. Every role process of the pod ends, and the pod, its disk and its Sandbox are deleted. Your session, your phase, your place in it and the task you hold are all kept, and the daemon saves the workspace's unpushed commits and its working-copy change as a git bundle that the next pod restores before any role starts. A wake brings the pod back and resumes this session, so a release costs a pod start and nothing else. The daemon wakes you with a task, a notice, a phase start, a backward move, a phase-ended message, a production-check look or a slot resume. A message published to your role topic wakes you, and so does an Envoy direct message or a person's answer, comment or message that Dispatch routes to your session. A CI settlement that the daemon records for the head of your issue's pull request wakes you while your phase is open. A wait that raises none of those events wakes you at the backstop alone, 60 minutes after the release, and only while your phase is open: a Dispatch topic you subscribed to, CI of another repository, a deploy run and a Kubernetes Job are such waits, so name the wait in your WAITING line and expect that hour. A release keeps your unpushed tracked work, which is every commit no remote branch holds, your working-copy change and the local bookmarks that point at them. It keeps nothing else of the disk: `$TMPDIR`, every ignored file, every file larger than jj's `snapshot.max-new-file-size`, each role's home with its `local://` files, a test Postgres and the CodeGraph index all go with the pod. A named Oh My Pi `bash` service goes with the pod too, because it runs outside your session's job manager and your session reports nothing about it, so put work you must keep on the branch, in a tracked file or in Dispatch.
25
+ - **The workspace is read-only for you from the moment your phase ends**, whether you ended it by completing or a CI red took it back while your turn ran: no commit, no `jj new`, no edit to a tracked file, in the turn still running when the message reaches you and in every turn after it, until a new task names your phase. Nothing stops that turn for you, so stopping is yours to do: drop the work in hand and leave whatever you have uncommitted. The active phase owns the workspace, and your session is kept, until your issue leaves the workflow, to answer questions and to take your next assignment.
26
+ - **An update task comes before your own work.** The daemon sends one when it must replace the pod your issue's roles run in, and your role prompt carries the steps: push every commit you want kept to the issue branch, call the `legion` tool's `ready_for_update` with the round id that task names, and end the turn. The daemon takes your answer for that round alone and refuses one that names another, so read the id from the task you answer. If your `legion` tool has no `ready_for_update` operation, push, then end your last message with a line that starts with WAITING and names the round, then end the turn: the daemon reads that turn's end as your answer. It completes no phase and ends none. After you answer you wait: the pod's disk goes with the pod, and your process comes back on the new pod in this same session, where your workspace is built again from the issue's pushed branch.
27
+ - **Never start another Legion role**: the daemon starts every phase worker.
28
+ - **Never end your turn blocked on a decision someone else owns.** Send a product, scope, design, lifecycle or cross-phase decision to the owning architect as your role prompt says, with the issue, phase, verified observation, what you tried and the decision needed; a human-only to-do is a `dispatch ask`. Otherwise proceed: a phase that stops silently holds its issue until someone notices. Three waits stand rather than proceed, each with a WAITING line naming what it waits on: a planner on a decision the plan itself needs, because a plan completed around an open decision carries that gap into every later phase; a reviewer on a half of the round that has no review, which it neither approves nor reads in the agent's place (`skill://legion-worker/references/merge-gate.md`); and any pushing role whose second push still has not carried the pull request onto its commit, which waits rather than hand the next role a commit the pull request does not name (*Every role pushes its own commits*, below).
29
+ - **No surface reaches the changed path** is a report to the architect, never a reason to complete (`skill://legion-worker/references/pr-body.md#when-no-surface-reaches-the-changed-path`).
30
+ - **Asking another role**: if its topic answers 404, read its handoff with `dispatch handoff-read` instead.
31
+
32
+ ## References
33
+
34
+ Read each by its `skill://` link: a read by path stops at 300 lines.
35
+
36
+ | When | Read |
37
+ | --- | --- |
38
+ | You write or edit the PR body, record a result against a check, read another phase's results, or run the simplify pass | `skill://legion-worker/references/pr-body.md` |
39
+ | Before a push, to check your commits' App identity | `skill://legion-worker/references/default-branch-check.md` |
40
+ | You reply on, list or resolve review threads, or judge a bot's finding | `skill://legion-worker/references/review-threads.md` |
41
+ | A conflict, a need only the base meets, a retarget, a parent's last round, comparing heads after a forward merge, a push refused after the handoff import moved the branch, or rewriting a pushed commit | `skill://legion-worker/references/conflicts-and-rewrites.md` |
42
+ | You review or approve, build READY, or run the production check | `skill://legion-worker/references/merge-gate.md` |
43
+ | The issue renames a repository, package, or URL across the codebase | `skill://legion-worker/references/systematic-rename.md` |
44
+ | The issue deletes code, a command, or documentation | `skill://legion-worker/references/cleanup-deletion.md` |
45
+ | Before you read a shared database, a session store or another role's transcript among them; before you run a build or a test suite in your pod; you need a tool the image may not carry, before you install anything; before you measure Oh My Pi's binary; or a test fails in your pod or needs a database | `skill://legion-worker/references/tools.md` |
46
+ | A problem outside your issue, or a failed production check | `skill://legion-worker/references/findings.md` |
47
+ | Your text would reach a person outside the company: a comment, issue or pull request on a repository the company does not own, an email, a message to another project's maintainers | `skill://outside-message` |
48
+
49
+ ## Every role pushes its own commits
50
+
51
+ - Before a push, read `jj -R "$LEGION_WORKSPACE" log -r 'ancestors(@, 5)'` (earlier phases' commits in it are expected) and run the identity check (`skill://legion-worker/references/default-branch-check.md`). Add no attribution trailer: the pane's jj adds `Omp-Session:`.
52
+ - Only work is pushed: code, red tests, a forward merge, a rewrite, and the empty commit that carries the pull request onto the commit you pushed (the bullet below). No commit message carries a line or bracket keyword that stops GitHub's workflows (`[skip ci]` and its kin), since every head needs its own checks and a base that requires a check will not merge a head whose checks never ran. Retro pushes nothing: it records what the work taught with `dispatch comment` on the issue.
53
+ - **After a push, read the pull request's head and check that it is your commit.** A branch and a pull request are two objects on GitHub: the push moves the branch, and GitHub then moves the pull request onto the new commit, which is what starts its checks. Twice on 2026-11-05 it did not, and the newer commit got no checks while Legion read, tested and would have merged the older one. The step applies once the branch has an open pull request, whose number your task's `Pull request:` line names (`gh pr list --repo <the issue's repository> --head legion/<KEY> --state open --json number --jq '.[0].number'` when it names none): run `gh pr view <n> --repo <the issue's repository> --json headRefOid --jq .headRefOid` about ten seconds after your push, again about ten seconds later, and a last time about thirty seconds after that, with a read that gives the pushed commit ending the step there and only the last read deciding a mismatch, and compare each answer with the commit you pushed, which `jj -R "$LEGION_WORKSPACE" log -r legion/<KEY>@origin --no-graph -T commit_id` prints in the 40 characters `headRefOid` answers in. This read is of the pull request's own head and of no check, so the wait it makes is not a wait on CI (`skill://legion-worker/references/pr-body.md#never-waiting-on-ci`). When the last read still is not your commit, carry the pull request with a commit of its own, an empty one when your work is complete and an empty one just as much when `@` holds work of yours, since a push of a commit the branch already holds moves no ref; the push section of your role prompt gives the one `jj` recipe, which leaves `@` and everything in it where it is. A new head makes every result recorded at the old head older, so record each `before_merge` check again at the new head. When that second push does not carry the pull request either, tell your architect the commit you pushed, the head each read gave and the time of each, and end the turn with a WAITING line naming that answer rather than completing: a phase completed here hands the next role a commit the pull request does not name. The push you make to answer an update task is the exception: that task has you answer the daemon and end the turn at once, so make this read in your next turn, before your phase completes. The merger pushes nothing, so this step never falls to it; it reports a mismatch it sees to the architect.
54
+ - A push refused because `legion handoffs import` moved `legion/<KEY>@origin` (its commit's message is `chore(legion): <KEY>'s handoffs are on its Dispatch issue now`) is cured by `jj -R "$LEGION_WORKSPACE" git fetch`, a forward merge with `legion/<KEY>@origin`, and the push (`skill://legion-worker/references/conflicts-and-rewrites.md`, *After the handoff import moved the branch*): never a rewrite.
55
+ - A planner whose issue moved back from implementing starts on the remote tip, `jj -R "$LEGION_WORKSPACE" new legion/<KEY>@origin`, so a commit it makes never sits on the implementer's unpushed commits.
56
+
57
+ ## PR body, review, and the merge gate
58
+
59
+ - The implementer opens the pull request with the line `Dispatch: <KEY>` in its body, the daemon's link to the issue when the branch name is ambiguous. Later phases push to that branch and edit that pull request, never a new one.
60
+ - **No deferrals.** A finding that changes behaviour, hides an error, or breaks a gate is fixed in this pull request, and so is a wording nit or any clear fix in a file it touches: a later round costs a CI pass and a re-read of the whole change. The body's one `Fast-follow:` line reads "none", or names cleanup in files this pull request does not touch.
61
+ - **The reviewer fixes a prose-only finding itself** (wording, a count, a tense, a citation) in its own commit, pushed before its review. The exception is the round after a READY refusal. Code or behaviour goes back (`skill://legion-worker/references/merge-gate.md`).
62
+ - **The merge gate**, in order: the tester's evidence green → the reviewer's approval of the head → the architect's acceptance → retro → the merger's READY → the merge, which closes the issue → the implementer's production check, after the close. When the daemon accepts READY, it submits the merge of READY's head, unless the answer's note begins `MANUAL_MERGE_REQUIRED:`, where a person merges it; no role runs `gh pr merge`.
63
+ - Append `<!-- legion: {"session":"<session-id>","phase":"<phase>"} -->` to every pull-request comment and review you post: the daemon finds the session behind a review by it.
64
+ - Never write a GitHub issue, by `gh issue` or a non-GET `gh api` on `/issues` (post or edit a PR conversation comment with `gh pr comment`): Legion's issues live on Dispatch. Never run `gh config set` or `gh alias set`, and leave `GH_TOKEN`, `GITHUB_TOKEN` and `GH_HOST` empty: the daemon rewrites your gh directory in place, and a set variable outranks it.
65
+ - Before you report a resource unreachable, run the call through the secrets broker's client (`skill://agent-secrets`, which holds the form, the exit statuses and where a name comes from), and check `AWS_CONFIG_FILE` (read its profiles): a deployment can give your pod either. Your `task` subagents and background jobs inherit both, and your `gh` and `git`. Request a secret only to use it for your issue's work.
66
+
67
+ ## Deployment instructions
68
+
69
+ Deployment instructions in your prompt override this skill where they conflict, except four rules: no deferrals; bringing the base into the branch only on a real conflict, a need only the base meets, a retarget, or a parent's last round (`skill://legion-worker/references/conflicts-and-rewrites.md#reintegrating-the-base`); the implementer's own result for every `before_merge` check, on a production-like surface at the head that merges, an applied simplify head included (`skill://legion-worker/references/pr-body.md#what-a-result-is`, `skill://legion-worker/references/pr-body.md#the-rules-every-phases-evidence-follows`); and the implementer's production check after the close (`skill://legion-worker/references/merge-gate.md#the-production-check-after-the-close`).
@@ -0,0 +1,22 @@
1
+ # Strategy: Cleanup & Deletion PRs
2
+
3
+ When deleting deprecated code, stale docs, or consolidating references.
4
+
5
+ ## When deleting a CLI command, check all four:
6
+
7
+ 1. Implementation file(s)
8
+ 2. `package.json` / `pyproject.toml` script entry
9
+ 3. All project documentation references (AGENTS.md or equivalent — check command tables AND section headings)
10
+ 4. Wrapper scripts or CI jobs that invoke it
11
+
12
+ ## project doc headings are documentation too
13
+
14
+ When updating a command reference, grep for the section heading and update it in the same commit. Headings that reference specific paths (`## Foo (meta/bar/)`) go stale when paths change.
15
+
16
+ ## Deletion PRs should be almost entirely deletions
17
+
18
+ Resist opportunistic refactors. If the diff has significant additions, the scope has crept. The value of a cleanup PR is its tight, reviewable scope.
19
+
20
+ ## Complete the deletion chain
21
+
22
+ If a feature has implementation + CLI wrapper + package.json entry + docs, remove all of them together. Partial deletion leaves broken references.