@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,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: legion-worker
|
|
3
|
+
description: Use when dispatched as an architect, plan, implement, test, or review phase worker in a Legion issue workspace.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Legion Phase Worker
|
|
7
|
+
|
|
8
|
+
You are one phase in a shared issue workspace, not a dispatcher or pipeline coordinator. The
|
|
9
|
+
architect owns the tree; phases use the same jj workspace sequentially. Complete the phase
|
|
10
|
+
assigned in the prompt, return its structured output to the architect, and leave the durable
|
|
11
|
+
copy that the next phase can trust.
|
|
12
|
+
|
|
13
|
+
## Identity, scope, and role
|
|
14
|
+
|
|
15
|
+
The dispatch supplies the issue, phase, daemon-minted role token, workspace, and task
|
|
16
|
+
`outputSchema`. At startup, claim that role with `envoy_role_set`; never construct a role
|
|
17
|
+
token from an issue name. A claim survives parking, and a revived or re-created worker claims
|
|
18
|
+
its own role again.
|
|
19
|
+
|
|
20
|
+
Read the current issue and its acceptance criteria before changing the workspace. Work only
|
|
21
|
+
on this phase's artifact. You may use ordinary scouts, reviewers, and oracle subagents for
|
|
22
|
+
phase work; never spawn legion-role workers. Escalate a product, scope, cross-phase, or
|
|
23
|
+
lifecycle decision to the owning architect through hub, with the verified facts and the
|
|
24
|
+
decision needed. For a durable question that needs Sami directly, you may use the raw
|
|
25
|
+
`dispatch` MCP tool yourself; replies return to your own session.
|
|
26
|
+
|
|
27
|
+
## Workspace and handoff precedence
|
|
28
|
+
|
|
29
|
+
The `workspace` attribute in your `<legion-spawn>` block is the authoritative issue
|
|
30
|
+
workspace. Before reading repository files or handoffs, you **MUST** bind to that exact
|
|
31
|
+
path with:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cd -- "<workspace>" && jj -R "<workspace>" status
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Never rely on the inherited cwd. Every later repository shell command **MUST** begin
|
|
38
|
+
`cd -- "<workspace>" &&`; every jj command **MUST** use `-R "<workspace>"`; and native
|
|
39
|
+
filesystem tool paths **MUST** be absolute under that workspace. Do not create an isolated
|
|
40
|
+
worktree, change the workspace topology, or mix another issue's work into it. Concurrent
|
|
41
|
+
issues have disjoint workspaces; phases for this issue are sequential.
|
|
42
|
+
|
|
43
|
+
On every start, and especially after revival or re-creation, read the issue and then the
|
|
44
|
+
committed predecessor handoffs in lifecycle order from `<workspace>/.legion/`:
|
|
45
|
+
|
|
46
|
+
1. `architect.json`
|
|
47
|
+
2. `plan.json`
|
|
48
|
+
3. `implement.json`
|
|
49
|
+
4. `test.json`
|
|
50
|
+
5. `review.json`
|
|
51
|
+
|
|
52
|
+
Read only files that precede the assigned phase. The live path returns JSON matching the task
|
|
53
|
+
`outputSchema` directly to the architect. The durable path uses the **same schema** in
|
|
54
|
+
`<workspace>/.legion/<phase>.json`. If a committed handoff conflicts with memory or a prior
|
|
55
|
+
transcript, the committed file wins: it is the copy that survived.
|
|
56
|
+
|
|
57
|
+
## jj Safety Rules
|
|
58
|
+
|
|
59
|
+
- **Always `jj -R "<workspace>" new` to create isolated commits.** Never
|
|
60
|
+
`jj -R "<workspace>" edit @-` to go back to a parent — this changes what `@` points to
|
|
61
|
+
and makes `jj abandon` dangerous.
|
|
62
|
+
- **Never `jj -R "<workspace>" abandon`.** If a mistake would require abandoning work,
|
|
63
|
+
stop and send the owning architect the `jj -R "<workspace>" log` evidence.
|
|
64
|
+
- **Before pushing, check ancestry:** `jj -R "<workspace>" log -r 'ancestors(@, 5)'` —
|
|
65
|
+
verify only your issue's commits are in the chain, not unrelated work.
|
|
66
|
+
|
|
67
|
+
**Shared operation safety:** Never run `jj op restore` in a Legion workspace. It rewrites the
|
|
68
|
+
shared operation log. If a mistake reaches that point, stop and send the owning architect the
|
|
69
|
+
`jj -R "<workspace>" log` evidence; recover only through the approved, path-scoped workflow.
|
|
70
|
+
|
|
71
|
+
## Phase work
|
|
72
|
+
|
|
73
|
+
Follow the repository's normal engineering workflow and the assigned issue's acceptance criteria.
|
|
74
|
+
The dispatch output schema defines the phase artifact and completion evidence. Do not replace
|
|
75
|
+
architect-owned decomposition, gate discipline, scheduling, or human communication with labels
|
|
76
|
+
or a local status model.
|
|
77
|
+
|
|
78
|
+
Commit attribution is automatic: the Legion extension exports a `JJ_CONFIG` overlay at root
|
|
79
|
+
bootstrap, so every jj commit made in the session family carries an `Omp-Session: <root-session-id>`
|
|
80
|
+
trailer with no action from you. Do not add attribution trailers by hand.
|
|
81
|
+
|
|
82
|
+
The jj configuration already supplies the phase worker's plus-addressed author and committer
|
|
83
|
+
identity. Do not override Git identity configuration. The worker session receives the
|
|
84
|
+
credential capability it needs; invoke GitHub through the credential helper:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
legion gh -- <gh args…>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## GitHub comment attribution
|
|
91
|
+
|
|
92
|
+
Append this exact structured footer to **every** GitHub issue comment, pull-request comment,
|
|
93
|
+
and review that this phase posts. It preserves session provenance on the artifact itself so
|
|
94
|
+
work stays attributable to the session that produced it:
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<!-- legion: {"session":"<session-id>","phase":"<phase>"} -->
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
For example:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
legion gh -- issue comment <issue-number> \
|
|
104
|
+
--body $'Verification complete.\n\n<!-- legion: {"session":"<session-id>","phase":"<phase>"} -->' \
|
|
105
|
+
--repo <owner>/<repo>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Implementer push and pull request
|
|
109
|
+
|
|
110
|
+
Only the implementer creates the issue bookmark, pushes it, and opens the pull request. After
|
|
111
|
+
its implementation commit and verification, it uses this exact branch name and push procedure:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cd -- "<workspace>" && \
|
|
115
|
+
jj -R "<workspace>" bookmark set legion/issue-<n> && \
|
|
116
|
+
jj -R "<workspace>" git push --bookmark legion/issue-<n> --allow-new
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The provisioned issue workspace configures `credential.helper` with the daemon's absolute
|
|
120
|
+
credential command, so `jj -R "<workspace>" git push` authenticates transparently through the
|
|
121
|
+
same session capability. Never handle a token.
|
|
122
|
+
|
|
123
|
+
Then create the pull request with the `github` tool's `pr_create` operation. The credential
|
|
124
|
+
helper and `legion gh` provide the GitHub identity; never export, fetch, or replace a token.
|
|
125
|
+
Other phases advance the existing branch rather than creating a replacement bookmark or PR.
|
|
126
|
+
|
|
127
|
+
## Completion gate: handoff write, verification, and persistence
|
|
128
|
+
|
|
129
|
+
The durable handoff uses the phase-specific fields from the task's `outputSchema` only.
|
|
130
|
+
`--data` must not include `schemaVersion`, `phase`, or `completed`: the CLI generates that
|
|
131
|
+
envelope. Return the **full** schema through the task's structured output, including the
|
|
132
|
+
generated envelope fields.
|
|
133
|
+
|
|
134
|
+
Write the phase-specific handoff:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
cd -- "<workspace>" && \
|
|
138
|
+
legion handoff write --phase <p> --data '<JSON object of phase-specific fields only>'
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Then verify the durable artifact exists:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
test -f "<workspace>/.legion/<phase>.json"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Then commit that exact handoff file onto the issue branch:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
cd -- "<workspace>" && \
|
|
151
|
+
jj -R "<workspace>" split -m "<phase>: record handoff" .legion/<phase>.json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
If the issue bookmark exists locally, advance it and push it with the provisioned credential
|
|
155
|
+
helper. `--allow-new` also publishes the locally provisioned bookmark on its first push:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
cd -- "<workspace>" && \
|
|
159
|
+
jj -R "<workspace>" bookmark set legion/issue-<n> && \
|
|
160
|
+
jj -R "<workspace>" git push --bookmark legion/issue-<n> --allow-new
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Do not report phase completion until the write, existence check, and handoff commit succeed;
|
|
164
|
+
when an issue branch exists, its push is also required. This is the committed copy the next
|
|
165
|
+
phase reads after revival. The reviewer later removes `.legion/` as its final commit; phase
|
|
166
|
+
workers do not remove it.
|
|
167
|
+
|
|
168
|
+
## Completion and escalation
|
|
169
|
+
|
|
170
|
+
Return the same schema as the durable handoff through the task's structured output. Do not add
|
|
171
|
+
pipeline labels, run a controller loop, or notify a controller with an invented completion
|
|
172
|
+
protocol. A direct worker delivery belongs to its role; overseers receive only derived
|
|
173
|
+
verdicts.
|
|
174
|
+
|
|
175
|
+
When blocked on lifecycle, scope, or cross-phase matters, send the owning architect a concise
|
|
176
|
+
hub message: issue, phase, verified observation, what you tried, and the decision required.
|
|
177
|
+
Reach for `dispatch` yourself only for a standalone human question outside that coordination.
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Repository Configuration (.legion/config.yml)
|
|
2
|
+
|
|
3
|
+
Workers load repository-specific configuration from `.legion/config.yml` at the workspace root. This file allows teams to customize Legion behavior per repository without modifying workflows.
|
|
4
|
+
|
|
5
|
+
## Schema Overview
|
|
6
|
+
|
|
7
|
+
The config file is YAML with the following top-level sections:
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
merge:
|
|
11
|
+
require_smoke_test: boolean
|
|
12
|
+
require_reporter_approval: boolean
|
|
13
|
+
auto_merge_allowed: boolean
|
|
14
|
+
|
|
15
|
+
testing:
|
|
16
|
+
require_specific_task: boolean
|
|
17
|
+
require_taiga_evidence: boolean
|
|
18
|
+
|
|
19
|
+
notifications:
|
|
20
|
+
slack_channel: string
|
|
21
|
+
ping_reporter_on_pr: boolean
|
|
22
|
+
|
|
23
|
+
skills:
|
|
24
|
+
required:
|
|
25
|
+
- skill_name_1
|
|
26
|
+
- skill_name_2
|
|
27
|
+
|
|
28
|
+
phases:
|
|
29
|
+
architect:
|
|
30
|
+
# Phase-specific overrides (same keys as top-level)
|
|
31
|
+
plan:
|
|
32
|
+
# Phase-specific overrides
|
|
33
|
+
implement:
|
|
34
|
+
# Phase-specific overrides
|
|
35
|
+
test:
|
|
36
|
+
# Phase-specific overrides
|
|
37
|
+
review:
|
|
38
|
+
# Phase-specific overrides
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Field Reference
|
|
42
|
+
|
|
43
|
+
### merge
|
|
44
|
+
|
|
45
|
+
Controls merge behavior and approval gates.
|
|
46
|
+
|
|
47
|
+
| Field | Type | Default | Description |
|
|
48
|
+
|-------|------|---------|-------------|
|
|
49
|
+
| `require_smoke_test` | boolean | `false` | If `true`, merge workflow requires evidence of smoke testing before auto-merge |
|
|
50
|
+
| `require_reporter_approval` | boolean | `false` | If `true`, merge workflow requires explicit reporter approval before merging |
|
|
51
|
+
| `auto_merge_allowed` | boolean | `false` | If `true`, merge workflow may auto-merge PRs that pass all gates |
|
|
52
|
+
|
|
53
|
+
### testing
|
|
54
|
+
|
|
55
|
+
Controls test requirements and evidence gates.
|
|
56
|
+
|
|
57
|
+
| Field | Type | Default | Description |
|
|
58
|
+
|-------|------|---------|-------------|
|
|
59
|
+
| `require_specific_task` | boolean | `false` | If `true`, test workflow requires evidence of specific task testing (not just unit tests) |
|
|
60
|
+
| `require_taiga_evidence` | boolean | `false` | If `true`, test workflow requires Taiga evidence (e.g., screenshots, logs) attached to the issue |
|
|
61
|
+
|
|
62
|
+
### notifications
|
|
63
|
+
|
|
64
|
+
Controls notifications and pings.
|
|
65
|
+
|
|
66
|
+
| Field | Type | Default | Description |
|
|
67
|
+
|-------|------|---------|-------------|
|
|
68
|
+
| `slack_channel` | string | `null` | Slack channel ID (e.g., `#eng-legion`) where implementation status updates are posted. If set and `slack-bot` skill is available, implement workflow posts PR URL and CI state |
|
|
69
|
+
| `ping_reporter_on_pr` | boolean | `false` | If `true`, notify the issue reporter when a PR is created |
|
|
70
|
+
|
|
71
|
+
### skills
|
|
72
|
+
|
|
73
|
+
Specifies skills that should be invoked for all phases.
|
|
74
|
+
|
|
75
|
+
| Field | Type | Default | Description |
|
|
76
|
+
|-------|------|---------|-------------|
|
|
77
|
+
| `required` | string[] | `[]` | List of skill names to invoke in addition to plan handoff `requiredSkills` and independently discovered skills. Additive with other skill sources |
|
|
78
|
+
|
|
79
|
+
### phases
|
|
80
|
+
|
|
81
|
+
Phase-specific overrides. Each phase (`architect`, `plan`, `implement`, `test`, `review`) can override any top-level key.
|
|
82
|
+
|
|
83
|
+
**Merge behavior:** Phase-specific values override top-level values. For example:
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
merge:
|
|
87
|
+
require_reporter_approval: false
|
|
88
|
+
|
|
89
|
+
phases:
|
|
90
|
+
implement:
|
|
91
|
+
merge:
|
|
92
|
+
require_reporter_approval: true # Override for implement phase only
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Recognized Keys
|
|
96
|
+
|
|
97
|
+
Workers recognize the following keys (case-sensitive):
|
|
98
|
+
|
|
99
|
+
- `merge.require_smoke_test`
|
|
100
|
+
- `merge.require_reporter_approval`
|
|
101
|
+
- `merge.auto_merge_allowed`
|
|
102
|
+
- `testing.require_specific_task`
|
|
103
|
+
- `testing.require_taiga_evidence`
|
|
104
|
+
- `notifications.slack_channel`
|
|
105
|
+
- `notifications.ping_reporter_on_pr`
|
|
106
|
+
- `skills.required`
|
|
107
|
+
- `phases.<mode>.*` (any of the above keys under a phase)
|
|
108
|
+
|
|
109
|
+
Unknown keys are silently ignored. Malformed YAML causes the config to be skipped (fallback to defaults).
|
|
110
|
+
|
|
111
|
+
## Worker Behavior
|
|
112
|
+
|
|
113
|
+
### Loading
|
|
114
|
+
|
|
115
|
+
Each workflow loads config at startup:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
if [ -f .legion/config.yml ]; then cat .legion/config.yml; fi
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
If the file is missing or malformed, workers proceed with defaults (no error).
|
|
122
|
+
|
|
123
|
+
### Parsing
|
|
124
|
+
|
|
125
|
+
Workers parse recognized keys and echo them for auditability:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Repo config constraints from .legion/config.yml:
|
|
129
|
+
- merge.require_reporter_approval: true
|
|
130
|
+
- testing.require_specific_task: true
|
|
131
|
+
- skills.required: [test-driven-development, verification-before-completion]
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Application
|
|
135
|
+
|
|
136
|
+
Config values are applied to shape workflow behavior:
|
|
137
|
+
|
|
138
|
+
- **Plan phase:** Config constraints inform the plan preamble (e.g., "reporter approval required before merge")
|
|
139
|
+
- **Implement phase:** Config-required skills are invoked additively with plan handoff skills
|
|
140
|
+
- **Test phase:** Config gates (e.g., `require_specific_task`) are enforced
|
|
141
|
+
- **Review phase:** Config-required skills are invoked additively
|
|
142
|
+
- **Merge phase:** Config gates (e.g., `require_reporter_approval`) are enforced
|
|
143
|
+
|
|
144
|
+
## Example Configuration
|
|
145
|
+
|
|
146
|
+
### Minimal (all defaults)
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
# Empty file or omitted entirely
|
|
150
|
+
# All defaults apply
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Strict Testing
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
testing:
|
|
157
|
+
require_specific_task: true
|
|
158
|
+
require_taiga_evidence: true
|
|
159
|
+
|
|
160
|
+
skills:
|
|
161
|
+
required:
|
|
162
|
+
- test-driven-development
|
|
163
|
+
- verification-before-completion
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Slack Notifications + Approval Gate
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
notifications:
|
|
170
|
+
slack_channel: "#eng-legion"
|
|
171
|
+
ping_reporter_on_pr: true
|
|
172
|
+
|
|
173
|
+
merge:
|
|
174
|
+
require_reporter_approval: true
|
|
175
|
+
require_smoke_test: true
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Phase-Specific Overrides
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
# Default: no approval required
|
|
182
|
+
merge:
|
|
183
|
+
require_reporter_approval: false
|
|
184
|
+
|
|
185
|
+
# But for implement phase, require approval
|
|
186
|
+
phases:
|
|
187
|
+
implement:
|
|
188
|
+
merge:
|
|
189
|
+
require_reporter_approval: true
|
|
190
|
+
|
|
191
|
+
# And require specific task testing only in test phase
|
|
192
|
+
phases:
|
|
193
|
+
test:
|
|
194
|
+
testing:
|
|
195
|
+
require_specific_task: true
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Full Example
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
merge:
|
|
202
|
+
require_smoke_test: true
|
|
203
|
+
require_reporter_approval: false
|
|
204
|
+
auto_merge_allowed: false
|
|
205
|
+
|
|
206
|
+
testing:
|
|
207
|
+
require_specific_task: true
|
|
208
|
+
require_taiga_evidence: false
|
|
209
|
+
|
|
210
|
+
notifications:
|
|
211
|
+
slack_channel: "#eng-legion"
|
|
212
|
+
ping_reporter_on_pr: true
|
|
213
|
+
|
|
214
|
+
skills:
|
|
215
|
+
required:
|
|
216
|
+
- test-driven-development
|
|
217
|
+
- verification-before-completion
|
|
218
|
+
|
|
219
|
+
phases:
|
|
220
|
+
plan:
|
|
221
|
+
skills:
|
|
222
|
+
required:
|
|
223
|
+
- brainstorming
|
|
224
|
+
implement:
|
|
225
|
+
merge:
|
|
226
|
+
require_reporter_approval: true
|
|
227
|
+
test:
|
|
228
|
+
testing:
|
|
229
|
+
require_taiga_evidence: true
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Defaults
|
|
233
|
+
|
|
234
|
+
If a key is not specified in `.legion/config.yml`, the following defaults apply:
|
|
235
|
+
|
|
236
|
+
```yaml
|
|
237
|
+
merge:
|
|
238
|
+
require_smoke_test: false
|
|
239
|
+
require_reporter_approval: false
|
|
240
|
+
auto_merge_allowed: false
|
|
241
|
+
|
|
242
|
+
testing:
|
|
243
|
+
require_specific_task: false
|
|
244
|
+
require_taiga_evidence: false
|
|
245
|
+
|
|
246
|
+
notifications:
|
|
247
|
+
slack_channel: null
|
|
248
|
+
ping_reporter_on_pr: false
|
|
249
|
+
|
|
250
|
+
skills:
|
|
251
|
+
required: []
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Notes
|
|
255
|
+
|
|
256
|
+
- **Additive skills:** Config-required skills are additive with plan handoff `requiredSkills` and independently discovered skills. All sources are combined.
|
|
257
|
+
- **Phase overrides:** Phase-specific values completely override top-level values for that phase. Partial overrides are not merged.
|
|
258
|
+
- **Missing file:** If `.legion/config.yml` is missing or malformed, workers proceed with defaults (no error).
|
|
259
|
+
- **Auditability:** Workers echo recognized keys and effective values at the start of each phase for transparency.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Knowledge Injection Algorithm
|
|
2
|
+
|
|
3
|
+
Canonical algorithm for injecting relevant learnings from `docs/solutions/` before phase-specific work begins. All worker workflows reference this file for the injection procedure; each workflow specifies its own keyword sources.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Before starting main work, each phase checks the learnings index for applicable prior knowledge. This surfaces patterns, pitfalls, and institutional knowledge that previous workers documented.
|
|
8
|
+
|
|
9
|
+
**Injection must never block work.** If any step fails (missing index, invalid JSON, missing files, empty handoff data), skip silently and proceed with the phase's main work.
|
|
10
|
+
|
|
11
|
+
## Algorithm
|
|
12
|
+
|
|
13
|
+
### 1. Read the Index
|
|
14
|
+
|
|
15
|
+
Assemble the index by reading all per-entry JSON files in `docs/solutions/.index/`:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Read and merge all entry files in .index/ directory
|
|
19
|
+
for f in docs/solutions/.index/*.json; do
|
|
20
|
+
[ -f "$f" ] && cat "$f"
|
|
21
|
+
done
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Each file has the format `{ "version": 1, "entries": { "key": ["learning-path", ...] } }`. Merge all `entries` maps together, deduplicating learning paths per key.
|
|
25
|
+
|
|
26
|
+
If the `.index/` directory doesn't exist or contains no valid JSON files, skip injection entirely — proceed to the phase's main work.
|
|
27
|
+
|
|
28
|
+
### 2. Extract Keywords
|
|
29
|
+
|
|
30
|
+
Collect keywords from the phase-specific sources (defined in each workflow file). The extraction algorithm:
|
|
31
|
+
|
|
32
|
+
1. **Collect raw text** from the specified keyword sources (see the calling workflow's keyword source table)
|
|
33
|
+
2. **Tokenize**: split on whitespace, `/`, `-`, `_`, and camelCase boundaries
|
|
34
|
+
3. **Normalize**: lowercase all tokens
|
|
35
|
+
4. **Filter**: remove tokens < 3 chars and common stopwords (the, and, for, with, this, that, from, into, when, will, should, would, could, also, been, have, each, etc.)
|
|
36
|
+
5. **Deduplicate** tokens
|
|
37
|
+
6. **Extract full path segments**: e.g., `packages/daemon/src/state` — keep as-is for path matching in addition to individual tokens
|
|
38
|
+
|
|
39
|
+
Also look for references to:
|
|
40
|
+
- Source path segments (e.g., `packages/daemon/src/state/`, `serve-manager`)
|
|
41
|
+
- Module names (e.g., "daemon", "controller", "worker", "state")
|
|
42
|
+
- Component names (e.g., "serve-manager", "decision", "fetch")
|
|
43
|
+
- Feature areas (e.g., "skills", "linear", "github", "review", "retro")
|
|
44
|
+
- Integration concerns (e.g., "PR", "labels", "MCP")
|
|
45
|
+
- Domain concepts and error keywords from the context
|
|
46
|
+
|
|
47
|
+
### 3. Match Keywords Against Index
|
|
48
|
+
|
|
49
|
+
Use two matching modes against the keys in `.index`:
|
|
50
|
+
|
|
51
|
+
- **Path matching**: For each key that does NOT start with `tag:`, check if any extracted keyword appears as a substring of the key (case-insensitive). Collect all matched learning file paths.
|
|
52
|
+
- **Tag matching**: For each key that starts with `tag:`, extract the tag name (e.g., `tag:race-condition` → `race-condition`). Check if any extracted keyword matches the tag name (case-insensitive). Collect matched learning file paths.
|
|
53
|
+
|
|
54
|
+
### 4. Deduplicate and Rank
|
|
55
|
+
|
|
56
|
+
- Remove duplicates (same file matched via multiple keys)
|
|
57
|
+
- **Status filter**: For each candidate, read its YAML front matter `status` field. Exclude any file with `status: superseded`. If the file doesn't exist or has no front matter, include it (graceful degradation).
|
|
58
|
+
- **Primary rank: tag overlap** — For each remaining candidate, read its `tags` front matter field. Count how many of its tags appear in the extracted keywords (case-insensitive). Higher overlap = higher rank.
|
|
59
|
+
- **Secondary rank: key specificity** — Learnings matched via longer/more-specific keys rank higher (e.g., a match on `packages/daemon/src/state` outranks a match on `packages/daemon`)
|
|
60
|
+
- **Tertiary rank: match count** — Number of distinct key matches (more matches = more relevant)
|
|
61
|
+
- **Cap at 3 learnings maximum**
|
|
62
|
+
|
|
63
|
+
### 5. Read Matched Learnings
|
|
64
|
+
|
|
65
|
+
For each matched learning file (from `docs/solutions/<path>`):
|
|
66
|
+
|
|
67
|
+
1. Read YAML front matter: extract `title` and `tags` fields
|
|
68
|
+
2. Skip past front matter (`---` blocks) and headings, take the first paragraph of prose (typically the Problem or Overview section)
|
|
69
|
+
3. Prepend structured header: `[{title} | tags: {comma-separated tags}]`
|
|
70
|
+
4. Truncate entire output (header + prose) to **350 characters**
|
|
71
|
+
|
|
72
|
+
**If a matched file doesn't exist on disk:** Skip that entry silently (stale index entry from a file rename). Do not error.
|
|
73
|
+
|
|
74
|
+
### 6. Output Injected Learnings
|
|
75
|
+
|
|
76
|
+
Output the injected learnings visibly in the session before proceeding with the phase's main work:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
## Relevant Learnings (from docs/solutions/)
|
|
80
|
+
|
|
81
|
+
1. [docs/solutions/<path>]: [{title} | tags: {tag1}, {tag2}] <prose excerpt> (350 chars max total)
|
|
82
|
+
2. [docs/solutions/<path>]: [{title} | tags: {tag1}, {tag2}] <prose excerpt>
|
|
83
|
+
3. [docs/solutions/<path>]: [{title} | tags: {tag1}, {tag2}] <prose excerpt>
|
|
84
|
+
|
|
85
|
+
(Review these for patterns and pitfalls relevant to this phase's work.)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**If no matches found:** Output "No relevant learnings found." and proceed. Do NOT add an empty section.
|
|
89
|
+
|
|
90
|
+
**Canonical identifiers:** All references to learnings use their `docs/solutions/` relative file path (e.g., `daemon/controller-lifecycle-separation.md`). These paths are the stable IDs used for injection, handoff tracking, and future aggregation. Never use titles or truncated text as identifiers.
|
|
91
|
+
|
|
92
|
+
## Fallback Behavior
|
|
93
|
+
|
|
94
|
+
When a keyword source is unavailable (missing handoff data, empty fields, missing phase data), silently fall back to the next available source as defined in the calling workflow's fallback rules. Never error on missing data.
|
|
95
|
+
|
|
96
|
+
## Integration with Handoffs
|
|
97
|
+
|
|
98
|
+
If the phase writes handoff data, include a `learningsInjected` field listing the `docs/solutions/` relative paths of all injected learnings. This enables downstream phases to see what knowledge was available and supports future aggregation.
|
|
@@ -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.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Strategy: Systematic Rename
|
|
2
|
+
|
|
3
|
+
When a repo, package, or URL is renamed across a codebase.
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
1. **Scope by file type** — grep all text-bearing extensions, not just the obvious ones:
|
|
8
|
+
- Source code (`.ts`, `.js`, `.py`, `.sh`) — functional, must update
|
|
9
|
+
- CI/CD configs (`.yml`, `.yaml`) — functional, must update
|
|
10
|
+
- Documentation (`.md`) — correctness, should update
|
|
11
|
+
- Config files (`.json`, `.toml`) — check but may be immutable
|
|
12
|
+
|
|
13
|
+
2. **Classify matches as mutable vs immutable** — historical records (transcripts, test snapshots, progress logs) must NOT be modified. Changing them falsifies history.
|
|
14
|
+
|
|
15
|
+
3. **Check comments for semantic context** — a comment mentioning the old name may still be correct in intent. Update the name but preserve the reasoning.
|
|
16
|
+
|
|
17
|
+
4. **Verify with grep before AND after** — capture pre-edit state as a baseline for comparison.
|
|
18
|
+
|
|
19
|
+
5. **Use `jj diff --git`** for verification — plain `jj diff` without color concatenates old/new text confusingly (e.g., `old-nameNEW-name` without color codes).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: linear
|
|
3
|
+
description: Manage Linear issues. Use when working with tasks, tickets, bugs, or Linear.
|
|
4
|
+
mcp:
|
|
5
|
+
linear:
|
|
6
|
+
command: npx
|
|
7
|
+
args: ["-y", "github:obra/streamlinear"]
|
|
8
|
+
env:
|
|
9
|
+
LINEAR_API_TOKEN: ${LINEAR_API_TOKEN}
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Linear (Stream Linear)
|
|
13
|
+
|
|
14
|
+
Single-tool MCP with action dispatch. All operations go through `linear_linear`.
|
|
15
|
+
|
|
16
|
+
## Actions
|
|
17
|
+
|
|
18
|
+
### Search Issues
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
linear_linear(action="search") # Your active issues
|
|
22
|
+
linear_linear(action="search", query="auth bug") # Text search
|
|
23
|
+
linear_linear(action="search", query={state: "In Progress"}) # Filter
|
|
24
|
+
linear_linear(action="search", query={team: "ENG", assignee: "me"})
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Get Issue Details
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
linear_linear(action="get", id="ABC-123") # By short ID
|
|
31
|
+
linear_linear(action="get", id="https://linear.app/...") # By URL
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Returns: title, description, status, labels, comments, attachments.
|
|
35
|
+
|
|
36
|
+
### Update Issue
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
linear_linear(action="update", id="ABC-123", state="Done")
|
|
40
|
+
linear_linear(action="update", id="ABC-123", priority=1)
|
|
41
|
+
linear_linear(action="update", id="ABC-123", assignee="me")
|
|
42
|
+
linear_linear(action="update", id="ABC-123", labels=["legion-backlog", "existing-label"])
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Labels array replaces all labels.** Fetch current labels first, then append.
|
|
46
|
+
|
|
47
|
+
### Comment on Issue
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
linear_linear(action="comment", id="ABC-123", body="Fixed in commit abc123")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Create Issue
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
linear_linear(action="create", title="Bug: Login fails", team="ENG")
|
|
57
|
+
linear_linear(action="create", title="Bug", team="ENG", body="Details", priority=2)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Raw GraphQL
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
linear_linear(action="graphql", graphql="query { viewer { name } }")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Help
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
linear_linear(action="help")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Reference
|
|
73
|
+
|
|
74
|
+
- Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low
|
|
75
|
+
- State matching is fuzzy: "done" → "Done", "in prog" → "In Progress"
|
|
76
|
+
- IDs accept: `ABC-123`, Linear URLs, or UUIDs
|