@sjawhar/opencode-legion-envoy 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/dispatch-mcp-shim.js +0 -6
- package/dist/src/server.js +40 -38
- package/package.json +6 -4
- package/skills/AGENTS.md +38 -0
- package/skills/envoy/SKILL.md +396 -0
- package/skills/github/SKILL.md +203 -0
- package/skills/legion-architect/SKILL.md +201 -0
- package/skills/legion-controller/SKILL.md +136 -0
- package/skills/legion-oracle/SKILL.md +63 -0
- package/skills/legion-retro/SKILL.md +87 -0
- package/skills/legion-worker/SKILL.md +177 -0
- package/skills/legion-worker/references/config.md +259 -0
- package/skills/legion-worker/references/knowledge-injection.md +98 -0
- package/skills/legion-worker/resources/strategies/cleanup-deletion.md +22 -0
- package/skills/legion-worker/resources/strategies/systematic-rename.md +19 -0
- package/skills/linear/SKILL.md +76 -0
- package/src/server.ts +30 -2
- package/src/dispatch-subscribe.ts +0 -52
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github
|
|
3
|
+
description: Manage GitHub issues via Projects V2. Use when LEGION_ISSUE_BACKEND=github.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub (gh CLI)
|
|
7
|
+
|
|
8
|
+
Direct CLI operations via `gh`. No embedded MCP — all commands are shell invocations.
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
Requires `gh` CLI installed and authenticated:
|
|
13
|
+
```bash
|
|
14
|
+
gh auth login
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Operations
|
|
18
|
+
|
|
19
|
+
### Search/List Issues (via project)
|
|
20
|
+
|
|
21
|
+
List all items in a GitHub Project V2:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gh project item-list $PROJECT_NUM --owner $OWNER --format json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Parameters:**
|
|
28
|
+
- `$PROJECT_NUM`: Project number (from `LEGION_ID` format: `owner/project-number`)
|
|
29
|
+
- `$OWNER`: Repository owner
|
|
30
|
+
- `--format json`: Returns structured data for parsing
|
|
31
|
+
|
|
32
|
+
**Example:**
|
|
33
|
+
```bash
|
|
34
|
+
gh project item-list 42 --owner acme --format json | jq '.items[] | {id, title, status}'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Get Issue Details
|
|
38
|
+
|
|
39
|
+
Fetch full issue metadata:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
gh issue view $ISSUE_NUMBER --json title,body,labels,comments,state -R $OWNER/$REPO
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Parameters:**
|
|
46
|
+
- `$ISSUE_NUMBER`: Issue number (e.g., `123`)
|
|
47
|
+
- `-R $OWNER/$REPO`: Repository (required for multi-repo support)
|
|
48
|
+
- `--json`: Fields to return (title, body, labels, comments, state, etc.)
|
|
49
|
+
|
|
50
|
+
**Example:**
|
|
51
|
+
```bash
|
|
52
|
+
gh issue view 123 --json title,body,labels,state -R acme/backend
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Update Status (Projects V2 — GraphQL)
|
|
56
|
+
|
|
57
|
+
Update issue status in a GitHub Project V2. Requires field and option IDs from project schema:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
gh api graphql -f query='mutation {
|
|
61
|
+
updateProjectV2ItemFieldValue(input: {
|
|
62
|
+
projectId: "$PROJECT_ID"
|
|
63
|
+
itemId: "$ITEM_ID"
|
|
64
|
+
fieldId: "$STATUS_FIELD_ID"
|
|
65
|
+
value: { singleSelectOptionId: "$OPTION_ID" }
|
|
66
|
+
}) { projectV2Item { id } }
|
|
67
|
+
}'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Parameters:**
|
|
71
|
+
- `$PROJECT_ID`: GraphQL ID of the project (not the number)
|
|
72
|
+
- `$ITEM_ID`: GraphQL ID of the issue in the project
|
|
73
|
+
- `$STATUS_FIELD_ID`: GraphQL ID of the Status field
|
|
74
|
+
- `$OPTION_ID`: GraphQL ID of the status option (e.g., "In Progress", "Done")
|
|
75
|
+
|
|
76
|
+
**Note:** Field and option IDs must be resolved from the project schema. The controller caches these after first query.
|
|
77
|
+
|
|
78
|
+
**Resolve IDs (one-time):**
|
|
79
|
+
```bash
|
|
80
|
+
gh api graphql -f query='query {
|
|
81
|
+
repository(owner: "$OWNER", name: "$REPO") {
|
|
82
|
+
projectV2(number: $PROJECT_NUM) {
|
|
83
|
+
fields(first: 20) {
|
|
84
|
+
nodes {
|
|
85
|
+
... on ProjectV2SingleSelectField {
|
|
86
|
+
id
|
|
87
|
+
name
|
|
88
|
+
options { id name }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}'
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Add Label
|
|
98
|
+
|
|
99
|
+
Add a label to an issue (additive — does not remove existing labels):
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
gh issue edit $ISSUE_NUMBER --add-label "needs-approval" -R $OWNER/$REPO
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Parameters:**
|
|
106
|
+
- `$ISSUE_NUMBER`: Issue number
|
|
107
|
+
- `--add-label`: Label to add (can be used multiple times)
|
|
108
|
+
- `-R $OWNER/$REPO`: Repository
|
|
109
|
+
|
|
110
|
+
**Example:**
|
|
111
|
+
```bash
|
|
112
|
+
gh issue edit 123 --add-label "needs-approval" -R acme/backend
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Remove Label
|
|
116
|
+
|
|
117
|
+
Remove a label from an issue:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
gh issue edit $ISSUE_NUMBER --remove-label "needs-approval" -R $OWNER/$REPO
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Parameters:**
|
|
124
|
+
- `$ISSUE_NUMBER`: Issue number
|
|
125
|
+
- `--remove-label`: Label to remove (can be used multiple times)
|
|
126
|
+
- `-R $OWNER/$REPO`: Repository
|
|
127
|
+
|
|
128
|
+
**Example:**
|
|
129
|
+
```bash
|
|
130
|
+
gh issue edit 123 --remove-label "legion-backlog" -R acme/backend
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Comment on Issue
|
|
134
|
+
|
|
135
|
+
Add a comment to an issue:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
gh issue comment $ISSUE_NUMBER --body "Fixed in commit abc123" -R $OWNER/$REPO
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Parameters:**
|
|
142
|
+
- `$ISSUE_NUMBER`: Issue number
|
|
143
|
+
- `--body`: Comment text (supports Markdown)
|
|
144
|
+
- `-R $OWNER/$REPO`: Repository
|
|
145
|
+
|
|
146
|
+
**Example:**
|
|
147
|
+
```bash
|
|
148
|
+
gh issue comment 123 --body "Implemented in PR #456" -R acme/backend
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Create Issue
|
|
152
|
+
|
|
153
|
+
Create a new issue:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
gh issue create --title "Bug: Login fails" --body "Details" -R $OWNER/$REPO
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Parameters:**
|
|
160
|
+
- `--title`: Issue title (required)
|
|
161
|
+
- `--body`: Issue description (optional, supports Markdown)
|
|
162
|
+
- `-R $OWNER/$REPO`: Repository
|
|
163
|
+
|
|
164
|
+
**Example:**
|
|
165
|
+
```bash
|
|
166
|
+
gh issue create --title "Feature: Add dark mode" --body "User request from #789" -R acme/backend
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Key Differences from Linear
|
|
170
|
+
|
|
171
|
+
| Aspect | Linear | GitHub |
|
|
172
|
+
|--------|--------|--------|
|
|
173
|
+
| **Labels** | Replace all (read-modify-write) | Additive (`--add-label`, `--remove-label`) |
|
|
174
|
+
| **Status** | Direct field update | Projects V2 GraphQL mutation |
|
|
175
|
+
| **PR Association** | Attachment field | Native (issue ↔ PR link) |
|
|
176
|
+
| **API** | MCP tool dispatch | Direct `gh` CLI |
|
|
177
|
+
| **Multi-repo** | Single team | `-R owner/repo` per command |
|
|
178
|
+
|
|
179
|
+
## Important Notes
|
|
180
|
+
|
|
181
|
+
- **Always specify `-R $OWNER/$REPO`** for multi-repo project support
|
|
182
|
+
- **Labels are additive**: Use `--add-label` and `--remove-label` separately (unlike Linear which replaces all)
|
|
183
|
+
- **Status updates require Projects V2 GraphQL** — not just issue labels
|
|
184
|
+
- **PR association is automatic** — GitHub links issues and PRs natively
|
|
185
|
+
- **`$OWNER` and `$REPO` come from `LEGION_ID`** (format: `owner/project-number`)
|
|
186
|
+
- **Field/option IDs must be cached** by the controller after first resolution
|
|
187
|
+
|
|
188
|
+
## Error Handling
|
|
189
|
+
|
|
190
|
+
Common errors and solutions:
|
|
191
|
+
|
|
192
|
+
| Error | Cause | Solution |
|
|
193
|
+
|-------|-------|----------|
|
|
194
|
+
| `Could not resolve to a Repository` | Wrong `-R` format | Use `-R owner/repo` (not `owner-repo`) |
|
|
195
|
+
| `Could not resolve to an Issue` | Issue doesn't exist | Verify issue number is correct |
|
|
196
|
+
| `GraphQL error: Field not found` | Wrong field ID | Re-resolve field IDs from project schema |
|
|
197
|
+
| `Not authenticated` | `gh` not logged in | Run `gh auth login` |
|
|
198
|
+
|
|
199
|
+
## Reference
|
|
200
|
+
|
|
201
|
+
- **Project number**: Visible in GitHub UI (e.g., `https://github.com/orgs/acme/projects/42` → `42`)
|
|
202
|
+
- **Issue number**: Visible in URL (e.g., `https://github.com/acme/backend/issues/123` → `123`)
|
|
203
|
+
- **GraphQL IDs**: Base64-encoded, returned by GraphQL queries (not human-readable)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: legion-architect
|
|
3
|
+
description: Own a Legion root or child issue through event-driven decomposition, waves, gates, integration, retro, sign-off, and close.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Legion Architect
|
|
7
|
+
|
|
8
|
+
You are the owning architect for one issue tree. The tree can start with no children or
|
|
9
|
+
with human-created children; either way you own its complete outcome. Work from delivered
|
|
10
|
+
wakes and current artifacts. Do not perform code work yourself and do not rely on a
|
|
11
|
+
separate coordinator to finish necessary work.
|
|
12
|
+
|
|
13
|
+
## Tool and ownership boundaries
|
|
14
|
+
|
|
15
|
+
- Use the `legion` tool for lifecycle writes. Its issue key format is
|
|
16
|
+
`owner/repo#number`.
|
|
17
|
+
- Use `task` for every Legion role spawn and `hub` to direct or revive a known phase
|
|
18
|
+
worker. Phase workers escalate lifecycle, scope, and cross-phase matters inward to you
|
|
19
|
+
through hub. Any role may use `dispatch` directly for a standalone human question;
|
|
20
|
+
replies return to the asking session.
|
|
21
|
+
- The runtime, not you, appends a machine `<legion-spawn>` block. Each Legion `task`
|
|
22
|
+
text must start with `Legion-Issue: <owner/repo#n>` on its first line.
|
|
23
|
+
- Use only the live label vocabulary: `needs-approval`, `human-approved`,
|
|
24
|
+
`legion-child`, and `legion-backlog`. Do not attempt to apply a label whose ownership
|
|
25
|
+
belongs to the controller or Sami.
|
|
26
|
+
- Deferring necessary work is failure. The sole valid deferral is a new child issue you
|
|
27
|
+
create and continue to own. Re-file a genuinely independent child through the
|
|
28
|
+
controller rather than treating it as an abandoned dependency.
|
|
29
|
+
|
|
30
|
+
## 1. Decompose or adopt
|
|
31
|
+
|
|
32
|
+
Inspect the root issue, acceptance criteria, existing children, and current handoffs.
|
|
33
|
+
|
|
34
|
+
- **Existing children:** adopt them. Do not replace or re-decompose human-created work.
|
|
35
|
+
Put every adopted child into the initial wave. **You MUST call**
|
|
36
|
+
`legion({ op: "wave_release", children: ["owner/repo#41", "owner/repo#42"] })`
|
|
37
|
+
**before any `task` spawn for an adopted child.** Until release, the daemon holds that
|
|
38
|
+
child's role activity. Then spawn each child's in-process `legion-architect` owner.
|
|
39
|
+
- **No children:** choose a single-issue tree only when its acceptance criteria can be
|
|
40
|
+
completed and integrated as one unit. Otherwise create complete child issues with:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
legion({
|
|
44
|
+
op: "issue_create",
|
|
45
|
+
title: "<child outcome>",
|
|
46
|
+
body: "<acceptance criteria, scope, and context>",
|
|
47
|
+
labels: []
|
|
48
|
+
})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The daemon establishes the sub-issue relationship and the `legion-child` label. Keep
|
|
52
|
+
the returned issue keys in ordered waves; a child is inert until released.
|
|
53
|
+
|
|
54
|
+
Write one root specification containing the accepted scope, adoption/decomposition,
|
|
55
|
+
waves, acceptance criteria, and integration test. When the config-armed root design gate
|
|
56
|
+
applies, run this exact sequence **before any Legion-role spawn**, including a
|
|
57
|
+
sub-architect:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
legion({ op: "post_spec", issue: "<root issue>", body: "<root specification>" })
|
|
61
|
+
legion({ op: "label_add", issue: "<root issue>", label: "needs-approval" })
|
|
62
|
+
dispatch({
|
|
63
|
+
parent: "<root issue>",
|
|
64
|
+
subject: "Legion design approval requested",
|
|
65
|
+
body: "<summary, specification, and requested decision>"
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then park. Do not release a wave or spawn a Legion role until a later delivered wake
|
|
70
|
+
shows `human-approved` on the root. You never add that label yourself. Approval covers
|
|
71
|
+
the entire tree: later waves, re-scopes, and integration-failure children do not repeat
|
|
72
|
+
this sequence.
|
|
73
|
+
|
|
74
|
+
## 2. Children in flight
|
|
75
|
+
|
|
76
|
+
Release only the next useful wave, then give its owners their work. A release is an
|
|
77
|
+
explicit lifecycle write:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
legion({ op: "wave_release", children: ["owner/repo#41", "owner/repo#42"] })
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
After release, spawn each relevant owner with an issue-prefixed task; for example:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
task({
|
|
87
|
+
agent: "legion-architect",
|
|
88
|
+
task: "Legion-Issue: owner/repo#41\nOwn this child through its lifecycle and report its evidence."
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Do not add a `<legion-spawn>` block. Keep the child agent IDs and session identifiers
|
|
93
|
+
returned by `task`, because retro and adjustment use those live sessions. Park while
|
|
94
|
+
children are in flight. On each child closure, re-scope open work, close obsolete work
|
|
95
|
+
with a reason, and release the next wave only when it now makes sense. There is no
|
|
96
|
+
inter-child dependency mechanism to encode.
|
|
97
|
+
|
|
98
|
+
## 3. Children complete
|
|
99
|
+
|
|
100
|
+
Treat `children-complete` as the edge into the end-game, not as a reason to close the
|
|
101
|
+
parent. Launch one **fresh** `legion-tester` for the parent, scoped to the parent's own
|
|
102
|
+
acceptance criteria and current `main` integration surface:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
task({
|
|
106
|
+
agent: "legion-tester",
|
|
107
|
+
task: "Legion-Issue: owner/repo#40\nFreshly verify this parent issue against its acceptance criteria on current main; return reproducible integration evidence."
|
|
108
|
+
})
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If that tester finds a failure, create and release a new corrective child wave, then
|
|
112
|
+
return to children-in-flight. Do not downgrade the parent criterion or silently carry the
|
|
113
|
+
failure forward.
|
|
114
|
+
|
|
115
|
+
## 4. Integration verification
|
|
116
|
+
|
|
117
|
+
Read the fresh tester's evidence, not merely a child PR's check status. The parent test
|
|
118
|
+
is successful only when every parent acceptance criterion has evidence against current
|
|
119
|
+
main. Route a failed criterion into a corrective child wave; route a passing result to
|
|
120
|
+
review and the merge-gate sequence.
|
|
121
|
+
|
|
122
|
+
## 5. Retro
|
|
123
|
+
|
|
124
|
+
Retro is mandatory for every issue that passed review, before merge. Revive the parked
|
|
125
|
+
implementer that owns the reviewed work through `hub`, naming the skill in the message:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
hub({
|
|
129
|
+
op: "send",
|
|
130
|
+
to: "<implementer agent identifier>",
|
|
131
|
+
message: "Run the legion-retro skill now. Capture durable learnings and post the issue comment; do not create a .legion handoff file."
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Wait for the revived implementer to report its durable retro result. Retro output is
|
|
136
|
+
`docs/solutions/` plus an issue comment; it must not create a `.legion` file or change
|
|
137
|
+
the reviewer-approved head after cleanup.
|
|
138
|
+
|
|
139
|
+
## 6. Architect sign-off and final merge gate
|
|
140
|
+
|
|
141
|
+
Sign off only when scope is fully met, integration evidence is current, corrective work
|
|
142
|
+
is complete, review is clean, retro completed, and no necessary work was silently
|
|
143
|
+
deferred. Make the sign-off comment explicit about that evidence.
|
|
144
|
+
|
|
145
|
+
When the config-armed final merge gate applies, preserve this order exactly:
|
|
146
|
+
|
|
147
|
+
1. tester green and review cycles complete;
|
|
148
|
+
2. reviewer pushes the `.legion/` deletion as its final commit and approves that head;
|
|
149
|
+
3. retro completes without dirtying the branch;
|
|
150
|
+
4. enter the Sami-approval step by calling
|
|
151
|
+
`legion({ op: "merge_gate", pr: <pull request number> })`. The daemon performs one
|
|
152
|
+
current GitHub review read against the pinned head. If it returns `approved: true`, the
|
|
153
|
+
approval already satisfies the gate and you immediately continue to the merger; do not
|
|
154
|
+
wait for a new wake. If it returns `approved: false`, request or retain Sami approval
|
|
155
|
+
and park for a later `pr-ready` wake. Do not poll or retry this check;
|
|
156
|
+
5. `legion-merger` verifies the approved head and squash-merges without pushing.
|
|
157
|
+
|
|
158
|
+
If anything changes the approved head, return to review; do not ask the merger to merge
|
|
159
|
+
an obsolete approval.
|
|
160
|
+
|
|
161
|
+
## 7. Close
|
|
162
|
+
|
|
163
|
+
After the merge result and sign-off are recorded, close this issue through the Legion
|
|
164
|
+
write surface and include the sign-off comment:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
legion({
|
|
168
|
+
op: "issue_close",
|
|
169
|
+
issue: "owner/repo#40",
|
|
170
|
+
comment: "<sign-off: scope, integration evidence, review, retro, Sami approval, and merge>"
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Closing a child supplies the closure event to its parent. Do not close a parent until the
|
|
175
|
+
entire end-game sequence has completed.
|
|
176
|
+
|
|
177
|
+
## Wake routing
|
|
178
|
+
|
|
179
|
+
Handle one delivered wake by verifying the relevant live artifact and then performing the
|
|
180
|
+
corresponding lifecycle procedure.
|
|
181
|
+
|
|
182
|
+
| Wake | Procedure |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| `child-closed` | Read the child completion and remaining open children. Re-scope or close obsolete open work; release an appropriate next wave, or await `children-complete`. |
|
|
185
|
+
| `children-complete` | Execute steps 3–4: fresh parent integration verification; failures become a new child wave, success advances to review and retro. |
|
|
186
|
+
| `child-reopened` | Treat the completion edge as reset. Reassess the reopened child and return the tree to children-in-flight; do not continue an already-started end-game. |
|
|
187
|
+
| `pr-ready` | Verify the live PR head, green status, and review state. Continue the review/retro/Sami/merger order only for that current head. |
|
|
188
|
+
| `pr-blocked` | Read the failed CI evidence and recovery attempts. Assign a focused implementer or corrective child, then return it through testing and review; do not treat the blocked PR as final. |
|
|
189
|
+
| `pr-closed-unmerged` | Decide from current scope whether to reopen the work, send a fresh implementer, or cancel it with a reason. Delegate the repository action to the responsible phase worker and keep ownership. |
|
|
190
|
+
| `issue-comment` | Interpret the comment in the issue's design context. Answer it, adjust the plan, or relay it through `hub` to the responsible worker; scope and product decisions remain with you. |
|
|
191
|
+
| `catchup-overseer` | Verify its gates, child counts, and PR verdicts against current artifacts, then resume the applicable numbered lifecycle step. It is a current-state snapshot, not a raw-event replay. |
|
|
192
|
+
| `revive-worker` | The extension has revived the backed worker. Do not create a duplicate; direct the restored worker through `hub` if action is needed and rely on its committed handoff over recollection. |
|
|
193
|
+
| `reopened` | Reopen the root lifecycle: inspect the reason and current artifacts, reassess scope and children, and resume at the first applicable numbered step. |
|
|
194
|
+
|
|
195
|
+
## Escalation judgment
|
|
196
|
+
|
|
197
|
+
Controller-actionable matters are exactly re-filing a genuinely independent child,
|
|
198
|
+
capacity, and cross-tree conflict. Use the Legion escalation operation for those. Handle
|
|
199
|
+
everything else in the tree, or use `dispatch` for a human question; workers may reach
|
|
200
|
+
Sami directly with `dispatch` the same way. Do not create a wait loop for any wake
|
|
201
|
+
source.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: legion-controller
|
|
3
|
+
description: Use when handling Legion controller wakes for root-issue triage, backlog admission, architect escalation, resync healing, human interaction, or gate approval.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Legion Controller
|
|
7
|
+
|
|
8
|
+
The controller is the one persistent, wake-driven session for a Legion project. It makes
|
|
9
|
+
triage, escalation, and human-interaction judgments; it never does phase-worker work or
|
|
10
|
+
routes raw events into an architect.
|
|
11
|
+
|
|
12
|
+
## Start and claim the controller role
|
|
13
|
+
|
|
14
|
+
The Legion extension claims `legion-<project>-controller` and registers controller readiness
|
|
15
|
+
with the daemon during session startup. Do not handle a wake unless that startup succeeded.
|
|
16
|
+
|
|
17
|
+
For an interactive takeover, start OMP with `LEGION_CONTROLLER_SECRET` and
|
|
18
|
+
`LEGION_DAEMON_URL` in its environment, then run:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
/legion-claim-controller
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The command resolves the project from daemon state, claims the Envoy role for the current
|
|
25
|
+
session, and posts readiness before controller commands can act. It retains the environment
|
|
26
|
+
capability for `legion admit`, `legion approve`, and `legion backlog`. Never pass a secret as a
|
|
27
|
+
command argument or copy it into a transcript.
|
|
28
|
+
|
|
29
|
+
This handshake lets the daemon redeliver held controller work. It does not turn the controller
|
|
30
|
+
into a state holder: daemon state and GitHub artifacts remain authoritative.
|
|
31
|
+
|
|
32
|
+
## Turn discipline
|
|
33
|
+
|
|
34
|
+
- **Direct user message always first.** If this turn includes a direct user message, answer
|
|
35
|
+
it before handling every other wake.
|
|
36
|
+
- **One wake = one turn.** Handle exactly the wake's implication, then end the turn. Never
|
|
37
|
+
poll, idle-loop, or wait for another event.
|
|
38
|
+
- **Wakes are advisory.** Before any side effect, verify the current daemon state and the
|
|
39
|
+
relevant GitHub artifact. A stale or duplicate wake may cost a read, never a wrong action.
|
|
40
|
+
- **Controller state is disposable.** Do not reconstruct or preserve local controller
|
|
41
|
+
bookkeeping between turns.
|
|
42
|
+
|
|
43
|
+
## Wake routing table
|
|
44
|
+
|
|
45
|
+
| Wake | Content | Controller action |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| New issue added to the project board (webhook: issue opened / project item added; resync heals misses) | issue ref + triage context (incl. pre-existing children) | Triage: spawn root process via daemon admission, or park in the daemon-state backlog |
|
|
48
|
+
| Backlog eligibility | slot freed / priority change | Reconsider parked items; deliberately-backlogged issues carry a marker so resync doesn't re-flag them |
|
|
49
|
+
| Architect escalation (controller-actionable only: re-file a child as a root issue, capacity, cross-tree conflicts) | request + context | Judge and act; issue-scoped human Q&A goes through `dispatch` from the owning architect, not here |
|
|
50
|
+
| Resync report | artifact-driven anomaly list (zero-owner trees, erroring issues) | Verify against fresh state, then dispatch/heal |
|
|
51
|
+
| Mention | Slack/GitHub @mention text | Answer, or route to the owning issue's architect role |
|
|
52
|
+
| Approval interpretation | ambiguous human comment on a gated issue | Decide whether it's an approval; if so, apply `human-approved` via the daemon |
|
|
53
|
+
| Direct user message | — | Always first |
|
|
54
|
+
|
|
55
|
+
## New issue triage
|
|
56
|
+
|
|
57
|
+
1. Read `legion state --json`, then inspect the reported GitHub issue with `gh issue view`.
|
|
58
|
+
Verify the issue is on this project board, is eligible for a root process, and whether it
|
|
59
|
+
has pre-existing children. GitHub and daemon state, not the wake text, decide triage.
|
|
60
|
+
2. If it should run now, admit the root issue:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
legion admit <issue>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
3. If it should deliberately wait, record a durable reason instead of leaving it unowned:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
legion backlog <issue> --marker <reason>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The marker is required: it distinguishes intentional backlog from a missed wake during
|
|
73
|
+
resync. Do not triage a system-created child as a root issue.
|
|
74
|
+
|
|
75
|
+
## Backlog eligibility
|
|
76
|
+
|
|
77
|
+
When a slot frees or priority changes, use `legion state --json` and the current issue
|
|
78
|
+
artifact to reconsider marked backlog entries. Admit the selected root with `legion admit
|
|
79
|
+
<issue>`. Keep an item backlogged only with a current, explicit marker; changing the marker
|
|
80
|
+
is a deliberate controller decision, not a no-op.
|
|
81
|
+
|
|
82
|
+
## Architect escalation
|
|
83
|
+
|
|
84
|
+
Only decide controller-actionable escalations: re-filing independent work, capacity, and
|
|
85
|
+
cross-tree conflicts. Issue-scoped human Q&A goes through `dispatch` from the owning
|
|
86
|
+
architect, not the controller.
|
|
87
|
+
|
|
88
|
+
For an independence judgment, verify the child and its parent against GitHub and current
|
|
89
|
+
daemon state. If the work belongs in an independent root:
|
|
90
|
+
|
|
91
|
+
1. File a **fresh root issue** with `gh`, carrying the necessary context.
|
|
92
|
+
2. Close the child and leave a pointer to the new root issue.
|
|
93
|
+
3. Admit or deliberately backlog the new root through the normal triage procedure.
|
|
94
|
+
|
|
95
|
+
Never promote a child in place. Resolve capacity and cross-tree conflicts from verified
|
|
96
|
+
state, routing design decisions back to the owning architect when they are not controller
|
|
97
|
+
judgments.
|
|
98
|
+
|
|
99
|
+
## Resync report
|
|
100
|
+
|
|
101
|
+
Treat a resync report as an anomaly list, not an instruction. For every zero-owner tree or
|
|
102
|
+
erroring issue it names, verify `legion state --json` and the current GitHub artifact first.
|
|
103
|
+
Then heal the verified condition: admit an eligible root, restore a deliberately backlogged
|
|
104
|
+
marker, or use the applicable daemon control path. Do not act on erroring or stale entries
|
|
105
|
+
until their source artifact explains the anomaly.
|
|
106
|
+
|
|
107
|
+
## Mentions
|
|
108
|
+
|
|
109
|
+
Read the mention and its artifact. Answer it when it asks the controller for triage or
|
|
110
|
+
human-facing information. Otherwise resolve the authoritative owning architect role and
|
|
111
|
+
route the verified context with `envoy_publish`. Do not route raw event traffic or invent a
|
|
112
|
+
role token from a partial issue reference.
|
|
113
|
+
|
|
114
|
+
## Approval interpretation
|
|
115
|
+
|
|
116
|
+
For an ambiguous human comment on a gated issue, verify the current issue, gate state, and
|
|
117
|
+
comment's meaning. If it is Sami's approval, apply the daemon transition:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
legion approve <issue>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
This applies `human-approved` and clears `needs-approval` atomically. It is not a generic
|
|
124
|
+
label-edit operation. The design gate remains skill-enforced by the architect, and the
|
|
125
|
+
merge gate remains config-armed until Sami approves the final reviewed head.
|
|
126
|
+
|
|
127
|
+
## Label vocabulary
|
|
128
|
+
|
|
129
|
+
Use only the project labels below, with their stated ownership:
|
|
130
|
+
|
|
131
|
+
| Label | Applied by | Removed by | Meaning |
|
|
132
|
+
|---|---|---|---|
|
|
133
|
+
| `needs-approval` | architect | controller/Sami when applying `human-approved` | design gate armed, awaiting Sami |
|
|
134
|
+
| `human-approved` | Sami or controller | Sami | design gate open |
|
|
135
|
+
| `legion-child` | daemon | never | system-created child |
|
|
136
|
+
| `legion-backlog` | controller | controller | deliberately unowned root |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: legion-oracle
|
|
3
|
+
description: Research institutional knowledge before escalating questions to users. Check docs/solutions/ and codebase patterns before asking humans.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Legion Oracle
|
|
7
|
+
|
|
8
|
+
Research institutional knowledge before escalating questions to users.
|
|
9
|
+
|
|
10
|
+
## Core Principle
|
|
11
|
+
|
|
12
|
+
**Check docs/solutions/ first.** This codebase captures learnings from past work.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
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];
|
|
23
|
+
|
|
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
|
+
Run steps 1-2 first (parallel OK), then 3-4 if needed:
|
|
40
|
+
|
|
41
|
+
| Step | Tool | Query |
|
|
42
|
+
|------|------|-------|
|
|
43
|
+
| 1. Institutional learnings | `Task learnings-researcher` | Search docs/solutions/ for [question] |
|
|
44
|
+
| 2. Codebase patterns | `Task Explore` | Find how src/ handles [topic] |
|
|
45
|
+
| 3. Framework docs | Context7 MCP | resolve-library-id → query-docs |
|
|
46
|
+
| 4. External practices | `Task best-practices-researcher` or `WebSearch` | Current best practices for [topic] |
|
|
47
|
+
|
|
48
|
+
## Output
|
|
49
|
+
|
|
50
|
+
**Found:** Answer with source (file:line or URL)
|
|
51
|
+
|
|
52
|
+
**Not found:** "Checked docs/solutions/ and codebase - no relevant learnings found" → search externally OR escalate to user
|
|
53
|
+
|
|
54
|
+
## Example
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
/legion-oracle How should I handle GraphQL pagination?
|
|
58
|
+
|
|
59
|
+
[learnings-researcher] → No matches
|
|
60
|
+
[Explore] → Found src/legion/state/fetch.py uses cursor-based pagination
|
|
61
|
+
|
|
62
|
+
Answer: Use cursor-based pagination per src/legion/state/fetch.py:42
|
|
63
|
+
```
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
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.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Legion Retro
|
|
7
|
+
|
|
8
|
+
Retro is mandatory for every issue that passed review. The architect revives the parked
|
|
9
|
+
implementer so the person with implementation context performs the retrospective, and the
|
|
10
|
+
skill obtains a separate fresh-eyes perspective. Retro runs before merge.
|
|
11
|
+
|
|
12
|
+
## Merge-gate ordering
|
|
13
|
+
|
|
14
|
+
Follow this ordering exactly. It keeps the reviewed branch clean while preserving the
|
|
15
|
+
retrospective's durable output.
|
|
16
|
+
|
|
17
|
+
1. Tester green and all code-review cycles finish.
|
|
18
|
+
2. The reviewer removes `.legion/`, pushes that deletion as its final commit, then approves.
|
|
19
|
+
3. Run this retro: commit durable learnings to `docs/solutions/` and post the issue comment.
|
|
20
|
+
Retro writes **no `.legion` file**, so it never re-dirties the cleaned handoff tree.
|
|
21
|
+
4. Sami approves the final reviewed head.
|
|
22
|
+
5. The merger squash-merges and pushes nothing.
|
|
23
|
+
|
|
24
|
+
Do not start retro before step 2, skip it because the change seems mechanical, or merge before
|
|
25
|
+
steps 3 and 4. The design gate is not a substitute for this final merge gate.
|
|
26
|
+
|
|
27
|
+
## Two perspectives
|
|
28
|
+
|
|
29
|
+
1. Re-read the issue, its acceptance criteria, the PR, test evidence, and review evidence.
|
|
30
|
+
Do not rebase or create a new branch; work on the existing issue branch.
|
|
31
|
+
2. Spawn one fresh-eyes subagent. Give it the issue and PR, ask it to inspect the diff and
|
|
32
|
+
return concrete reusable learnings, and require it to return analysis rather than edit files.
|
|
33
|
+
3. Independently record the implementer's perspective: surprising constraints, difficult
|
|
34
|
+
decisions, failed approaches, and reusable patterns.
|
|
35
|
+
4. Integrate the two perspectives. The implementer owns the final judgment: reject generic or
|
|
36
|
+
context-free suggestions and preserve only learning that will help a future worker.
|
|
37
|
+
|
|
38
|
+
## Durable outputs
|
|
39
|
+
|
|
40
|
+
Write the integrated learning as one or more discoverable documents under `docs/solutions/`.
|
|
41
|
+
Organize by reusable topic rather than by pull request. Each document uses this front matter:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
---
|
|
45
|
+
title: "Descriptive title matching the H1"
|
|
46
|
+
category: subdirectory-name
|
|
47
|
+
tags:
|
|
48
|
+
- searchable-topic
|
|
49
|
+
date: YYYY-MM-DD
|
|
50
|
+
status: active
|
|
51
|
+
module: affected-module
|
|
52
|
+
related_issues:
|
|
53
|
+
- "owner/repo#123"
|
|
54
|
+
---
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Commit the documentation on the existing issue branch, advance its existing bookmark, and push
|
|
58
|
+
that branch. Do not create a replacement branch or bookmark. Then post an issue comment naming
|
|
59
|
+
the documents and the one-to-three most useful takeaways. The comment must carry this revived
|
|
60
|
+
implementer's structured attribution footer with `phase` set to `retro`:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
legion gh -- issue comment <issue-number> \
|
|
64
|
+
--body $'## Retro Complete
|
|
65
|
+
|
|
66
|
+
**Learnings documented in:**
|
|
67
|
+
- docs/solutions/<path>.md
|
|
68
|
+
|
|
69
|
+
**Key takeaways:**
|
|
70
|
+
- <reusable lesson>
|
|
71
|
+
|
|
72
|
+
<!-- legion: {"session":"<session-id>","phase":"retro"} -->' \
|
|
73
|
+
--repo <owner>/<repo>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The issue comment and `docs/solutions/` commit are the only retro outputs. Never write a
|
|
77
|
+
handoff, phase artifact, local feedback log, or completion label.
|
|
78
|
+
|
|
79
|
+
## Completion check
|
|
80
|
+
|
|
81
|
+
Before returning, verify all of the following:
|
|
82
|
+
|
|
83
|
+
- The reviewer cleanup commit remains below the retro documentation commit.
|
|
84
|
+
- The learning documents and issue comment both exist.
|
|
85
|
+
- No `.legion` file was created or modified by retro.
|
|
86
|
+
- The fresh-eyes analysis was considered alongside the implementer's context.
|
|
87
|
+
- Sami's approval and the merger remain subsequent steps, not work performed by retro.
|