@sjawhar/opencode-legion-envoy 0.41.1 → 0.41.2
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/src/server.js +14 -8
- package/package.json +1 -1
- package/skills/dispatch/SKILL.md +118 -134
- package/skills/legion-architect/SKILL.md +3 -0
- package/skills/legion-worker/SKILL.md +3 -1
package/dist/src/server.js
CHANGED
|
@@ -13566,14 +13566,16 @@ var IssueEventPayloadSchema = object({
|
|
|
13566
13566
|
route: string2().nullish()
|
|
13567
13567
|
});
|
|
13568
13568
|
var ArtifactCreatedEventPayloadSchema = object({
|
|
13569
|
-
artifact: object({ name: string2().optional() }).optional()
|
|
13569
|
+
artifact: object({ id: string2().optional(), slug: string2().optional(), name: string2().optional() }).optional()
|
|
13570
13570
|
});
|
|
13571
13571
|
var ArtifactVersionEventPayloadSchema = object({
|
|
13572
|
+
artifact_id: string2().optional(),
|
|
13572
13573
|
name: string2().optional(),
|
|
13573
13574
|
version: object({ number: number2().optional(), summary: string2().nullish() }).optional(),
|
|
13574
13575
|
diff: string2().optional()
|
|
13575
13576
|
});
|
|
13576
13577
|
var askEventPayloadFields = {
|
|
13578
|
+
id: string2().optional(),
|
|
13577
13579
|
opened_event_id: number2().int().positive(),
|
|
13578
13580
|
question: string2().optional(),
|
|
13579
13581
|
options: array(object({ label: string2().optional() })).nullish(),
|
|
@@ -13611,13 +13613,13 @@ var CommentEventPayloadSchema = object({
|
|
|
13611
13613
|
ask_question: string2().optional(),
|
|
13612
13614
|
anchor: object({ quote: string2().optional() }).nullish(),
|
|
13613
13615
|
suggestion: object({ replace_with: string2().optional() }).nullish(),
|
|
13614
|
-
author: object({ kind: string2(), id: string2()
|
|
13616
|
+
author: object({ kind: string2(), id: string2() }).optional(),
|
|
13615
13617
|
created_at: string2().optional()
|
|
13616
13618
|
});
|
|
13617
13619
|
var MessageEventPayloadSchema = object({
|
|
13618
13620
|
id: string2().optional(),
|
|
13619
13621
|
body: string2().optional(),
|
|
13620
|
-
author: object({ kind: string2(), id: string2()
|
|
13622
|
+
author: object({ kind: string2(), id: string2() }).optional()
|
|
13621
13623
|
});
|
|
13622
13624
|
var ChildStatusEventPayloadSchema = object({
|
|
13623
13625
|
child_key: string2().optional(),
|
|
@@ -13719,7 +13721,7 @@ var dispatchToolSpecs = [
|
|
|
13719
13721
|
},
|
|
13720
13722
|
{
|
|
13721
13723
|
name: "dispatch_ask",
|
|
13722
|
-
description: "Open a durable, answerable decision on an issue or project document. Do not use it for a status update or discussion; " +
|
|
13724
|
+
description: "Open a durable, answerable decision on an issue or project document. Do not use it for a status update or discussion; " + "use dispatch_message instead. Anchor a document question, thread reply_to/reply_to_ask, or cite a dispatch:// " + `reference \u2014 it must be answerable from its own text and anchor alone, never "see above". Question is at most 800 ` + `characters and has at most 8 options. ${OWNER_REFERENCE}`,
|
|
13723
13725
|
arguments: (z) => ({
|
|
13724
13726
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
13725
13727
|
project: z.string().describe("Project key owning the document.").optional(),
|
|
@@ -13800,7 +13802,7 @@ var dispatchToolSpecs = [
|
|
|
13800
13802
|
},
|
|
13801
13803
|
{
|
|
13802
13804
|
name: "dispatch_message",
|
|
13803
|
-
description: "Post a
|
|
13805
|
+
description: "Post a note to the issue's Conversation for humans: a status they should see now, or a reply to a human's message. " + "Not a progress ledger (the issue's progress.md artifact), a decision (dispatch_ask), or document feedback " + `(dispatch_comment). Body is at most 2,000 characters. ${ISSUE_REFERENCE}`,
|
|
13804
13806
|
arguments: (z) => ({
|
|
13805
13807
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
13806
13808
|
body: z.string({ max: 2000 }).describe("Update text, at most 2,000 characters.")
|
|
@@ -13808,7 +13810,7 @@ var dispatchToolSpecs = [
|
|
|
13808
13810
|
},
|
|
13809
13811
|
{
|
|
13810
13812
|
name: "dispatch_doc_edit",
|
|
13811
|
-
description: "Apply deterministic text edits to an issue or project document. Do not use it for review feedback or for reading; use " +
|
|
13813
|
+
description: "Apply deterministic text edits to an issue or project document. Do not use it for review feedback or for reading; use " + "dispatch_comment, dispatch_suggest, or dispatch_doc_read instead. The spec (or any document) holds requirements, " + `design, and decisions \u2014 record progress in the issue's progress.md artifact instead. ${OWNER_REFERENCE} ${SPEC_WRITING_GUIDANCE}`,
|
|
13812
13814
|
arguments: (z) => ({
|
|
13813
13815
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
13814
13816
|
project: z.string().describe("Project key owning the document.").optional(),
|
|
@@ -14988,8 +14990,12 @@ async function resolveArtifact(client, owner, artifactReference) {
|
|
|
14988
14990
|
} catch (error) {
|
|
14989
14991
|
if (!(error instanceof DispatchServiceError) || error.status !== 404)
|
|
14990
14992
|
throw error;
|
|
14991
|
-
const artifacts = await client.listProjectArtifacts(owner.project);
|
|
14992
|
-
const
|
|
14993
|
+
const artifacts = await client.listProjectArtifacts(owner.project, true);
|
|
14994
|
+
const matches = artifacts.filter((candidate) => candidate.name === artifactReference);
|
|
14995
|
+
if (matches.length > 1) {
|
|
14996
|
+
throw new Error(`artifact name ${artifactReference} is ambiguous in project ${owner.project}; ` + `${matches.length} documents share it \u2014 use its slug instead`);
|
|
14997
|
+
}
|
|
14998
|
+
const artifact = matches[0];
|
|
14993
14999
|
if (!artifact)
|
|
14994
15000
|
throw error;
|
|
14995
15001
|
return { owner, artifact };
|
package/package.json
CHANGED
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -5,17 +5,17 @@ description: "Use when asking Sami a question, updating the spec, commenting on
|
|
|
5
5
|
|
|
6
6
|
# Dispatch
|
|
7
7
|
|
|
8
|
-
Dispatch is your issue's or project document's living spec, asks, comments, and artifacts. The
|
|
9
|
-
|
|
8
|
+
Dispatch is your issue's or project document's living spec, asks, comments, and artifacts. The transcript is your scratch pad. Anything
|
|
9
|
+
meant for a human goes through a `dispatch_*` tool.
|
|
10
10
|
|
|
11
|
-
The server enforces high signal: an ask question is at most 800 characters with at most eight
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
The server enforces high signal: an ask question is at most 800 characters with at most eight options; comment and message bodies are at
|
|
12
|
+
most 2,000 characters; an artifact is at most 25 MiB. It refuses over-limit input; it never truncates it. GitHub threads and markers no
|
|
13
|
+
longer exist.
|
|
14
14
|
|
|
15
15
|
## Writing a spec
|
|
16
16
|
|
|
17
|
-
A spec is a decision record for the human who decides and the implementer who builds, not a
|
|
18
|
-
|
|
17
|
+
A spec is a decision record for the human who decides and the implementer who builds, not a transcript of your thinking. Use exactly
|
|
18
|
+
these document headings in this order.
|
|
19
19
|
|
|
20
20
|
| Section | Required content | Form |
|
|
21
21
|
| --- | --- | --- |
|
|
@@ -35,32 +35,23 @@ transcript of your thinking. Use exactly these document headings in this order.
|
|
|
35
35
|
- Do not hedge with “might” or “could consider.”
|
|
36
36
|
- Do not use TBD, TODO, or placeholders; an open item is a Decision needed.
|
|
37
37
|
- Keep each section to one screen; work that exceeds one screen per section is two specs.
|
|
38
|
-
- Update the spec in place as decisions land
|
|
39
|
-
|
|
40
|
-
### Self-review
|
|
41
|
-
|
|
42
|
-
- [ ] No placeholders remain.
|
|
43
|
-
- [ ] No sections conflict.
|
|
44
|
-
- [ ] The spec covers one implementation plan's worth of work.
|
|
45
|
-
- [ ] Every requirement has exactly one reading.
|
|
38
|
+
- Update the spec in place as decisions land: the spec is the record, comments are the discussion.
|
|
39
|
+
- Before sending it: no sections conflict, and every requirement has exactly one reading.
|
|
46
40
|
|
|
47
41
|
## Your owner
|
|
48
42
|
|
|
49
|
-
Every session works on an issue or project document. Legion pre-fills `issue` from
|
|
50
|
-
`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
`design-notes` identifies `dispatch://CORE/artifact/design-notes`. On first use, an external
|
|
55
|
-
issue reference creates its native issue in the project configured for that repository in
|
|
56
|
-
Dispatch Settings, then falls back to `DISPATCH_DEFAULT_PROJECT`.
|
|
43
|
+
Every session works on an issue or project document. Legion pre-fills `issue` from `LEGION_ISSUE`: use a native issue key such as
|
|
44
|
+
`LEGION-3`, an external `owner/repo#n` reference, or a bare positive number (resolved against the cwd repository). Otherwise pass
|
|
45
|
+
exactly one owner to every owner-scoped tool: `issue` for an issue, or `project` and `artifact` for an unlinked project document (see
|
|
46
|
+
[References](#references) for the resulting ref shape). On first use, an external issue reference creates its native issue in the
|
|
47
|
+
project configured for that repository in Dispatch Settings, then falls back to `DISPATCH_DEFAULT_PROJECT`.
|
|
57
48
|
|
|
58
49
|
Architects create newly tracked child work with:
|
|
59
50
|
```ts
|
|
60
51
|
dispatch_issue({ project, title, parent?, external?, spec?, force? })
|
|
61
52
|
```
|
|
62
|
-
It returns `details` `{ issue, topic }`. Use `dispatch_issue` only to create an issue; never use
|
|
63
|
-
|
|
53
|
+
It returns `details` `{ issue, topic }`. Use `dispatch_issue` only to create an issue; never use it to park a question. When `spec` is
|
|
54
|
+
supplied, follow [Writing a spec](#writing-a-spec).
|
|
64
55
|
|
|
65
56
|
## Search first
|
|
66
57
|
|
|
@@ -68,13 +59,12 @@ Before you create an issue or start a design document, search:
|
|
|
68
59
|
```ts
|
|
69
60
|
dispatch_search({ query, project?, limit? })
|
|
70
61
|
```
|
|
71
|
-
It returns every issue, document, comment, ask, and message that contains the words, with the
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
It returns every issue, document, comment, ask, and message that contains the words, with the issue key and a link. Cite the hit you
|
|
63
|
+
build on (`dispatch://KEY` or the document reference), or state "no prior issue" in the spec. Websearch syntax applies: `"merge queue"`,
|
|
64
|
+
`-daemon`, `OR`.
|
|
74
65
|
|
|
75
|
-
`dispatch_issue` refuses a title that near-duplicates an issue in the same project and returns
|
|
76
|
-
|
|
77
|
-
call with `force: true` when it is genuinely new work.
|
|
66
|
+
`dispatch_issue` refuses a title that near-duplicates an issue in the same project and returns the candidates (`POSSIBLE_DUPLICATE`).
|
|
67
|
+
Read them; reference the existing issue, or repeat the call with `force: true` when it is genuinely new work.
|
|
78
68
|
|
|
79
69
|
## Asking
|
|
80
70
|
|
|
@@ -91,14 +81,14 @@ dispatch_ask({
|
|
|
91
81
|
anchor?: { artifact, quote, occurrence? },
|
|
92
82
|
})
|
|
93
83
|
```
|
|
94
|
-
It returns `details` `{ issue, topic, ask }` for an issue or `{ project, artifact, document,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
84
|
+
It returns `details` `{ issue, topic, ask }` for an issue or `{ project, artifact, document, topic, ask }` for a project document.
|
|
85
|
+
Options are buttons: never enumerate choices in prose. Put the recommendation in `question`, and put each selectable choice in
|
|
86
|
+
`options`. Anchor a document question with `anchor: { artifact, quote, occurrence? }`; `occurrence` is zero-based and selects a repeated
|
|
87
|
+
quote, and an anchor whose quote later disappears becomes orphaned but stays readable against its original document version.
|
|
88
|
+
|
|
89
|
+
An ask must be answerable from its own text and its anchor alone. Anchor a question about a document passage with `anchor`; thread one
|
|
90
|
+
about a comment with `reply_to`; thread a follow-up on your own ask with `reply_to_ask`; cite anything else with a `dispatch://`
|
|
91
|
+
reference (see [References](#references)). Never write "see above", "the message above", or "as attached".
|
|
102
92
|
|
|
103
93
|
Correct or refine an open ask in place instead of opening a second question:
|
|
104
94
|
```ts
|
|
@@ -110,12 +100,11 @@ dispatch_edit_ask({
|
|
|
110
100
|
urgency?,
|
|
111
101
|
})
|
|
112
102
|
```
|
|
113
|
-
At least one field besides `ask` is required. Use this only while the same decision remains
|
|
114
|
-
|
|
115
|
-
If the decision is moot or superseded, retract the old ask and open a new one.
|
|
103
|
+
At least one field besides `ask` is required. Use this only while the same decision remains open: it keeps the prior text in the event
|
|
104
|
+
log. An answered or resolved ask cannot be edited. If the decision is moot or superseded, retract the old ask and open a new one.
|
|
116
105
|
|
|
117
|
-
An ask stays open until a human answers, unless its question no longer needs that answer. Retract a
|
|
118
|
-
|
|
106
|
+
An ask stays open until a human answers, unless its question no longer needs that answer. Retract a moot or superseded question, or
|
|
107
|
+
self-resolve one after finding the answer:
|
|
119
108
|
```ts
|
|
120
109
|
dispatch_resolve_ask({
|
|
121
110
|
ask,
|
|
@@ -123,32 +112,31 @@ dispatch_resolve_ask({
|
|
|
123
112
|
reason: "A newer ask supersedes this question.",
|
|
124
113
|
})
|
|
125
114
|
```
|
|
126
|
-
Use `retracted` when the question is obsolete and `resolved` when you found the answer. Include the
|
|
127
|
-
|
|
128
|
-
|
|
115
|
+
Use `retracted` when the question is obsolete and `resolved` when you found the answer. Include the reason because the question remains
|
|
116
|
+
in its Conversation card and reply thread. Resolution is not an answer: it never records a human decision, and an answered ask cannot be
|
|
117
|
+
resolved. A human may reply to an open or answered ask; so may you, e.g. after finding the answer — use `reply_to_ask` on
|
|
118
|
+
`dispatch_comment` (mutually exclusive with `reply_to`).
|
|
129
119
|
|
|
130
|
-
|
|
131
|
-
(the asker) can reply too — e.g. acknowledging a clarifying question, or following up after the
|
|
132
|
-
answer. Use `reply_to_ask` on `dispatch_comment` to reply under your own ask; it is mutually
|
|
133
|
-
exclusive with `reply_to`.
|
|
120
|
+
## The Spec
|
|
134
121
|
|
|
135
|
-
|
|
136
|
-
|
|
122
|
+
The spec holds requirements, design, acceptance, decisions, and rejected alternatives, structured per [Writing a spec](#writing-a-spec).
|
|
123
|
+
It changes only when a decision or requirement changes, and every version that records one is named with `summary`. Never write
|
|
124
|
+
progress, status, timestamps, an "Update HH:MMZ" section, a PR list, or handoff notes into the spec — that belongs in
|
|
125
|
+
[Progress](#progress) instead.
|
|
137
126
|
|
|
138
127
|
Read the current document before changing it:
|
|
139
128
|
|
|
140
129
|
```ts
|
|
141
130
|
dispatch_doc_read({ issue?, project?, artifact?, version?, ref? })
|
|
142
131
|
```
|
|
143
|
-
It returns live or versioned markdown with open marks. `issue` with an omitted `artifact`
|
|
144
|
-
|
|
145
|
-
`dispatch://PROJECT/artifact/<slug>` ref supplies both. Then write narrative with:
|
|
132
|
+
It returns live or versioned markdown with open marks. `issue` with an omitted `artifact` reads the issue specification; a project needs
|
|
133
|
+
`artifact`; and a `dispatch://PROJECT/artifact/<slug>` ref supplies both. Then write with:
|
|
146
134
|
|
|
147
135
|
```ts
|
|
148
136
|
dispatch_doc_edit({ issue?, project?, artifact, ops, summary? })
|
|
149
137
|
```
|
|
150
|
-
It returns issue or project-document owner details plus `applied`, optional `version`, and its
|
|
151
|
-
|
|
138
|
+
It returns issue or project-document owner details plus `applied`, optional `version`, and its write `topic`. `ops` is an array of this
|
|
139
|
+
exact `EditOp` shape:
|
|
152
140
|
|
|
153
141
|
```ts
|
|
154
142
|
type EditOp = {
|
|
@@ -162,23 +150,40 @@ type EditOp = {
|
|
|
162
150
|
};
|
|
163
151
|
```
|
|
164
152
|
|
|
165
|
-
Target `replace` and `delete` by the document's plain text: inline-code and link text match
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
span separate blocks into separate operations.
|
|
153
|
+
Target `replace` and `delete` by the document's plain text: inline-code and link text match without Markdown syntax, and a table-cell
|
|
154
|
+
anchor is its cell text. Quote code-block contents without their Markdown fences. A quote must stay within one textblock; split changes
|
|
155
|
+
that span separate blocks into separate operations.
|
|
169
156
|
|
|
170
|
-
`replace` requires `find` and `with`; `delete` requires `find`; `insert` requires `markdown`
|
|
171
|
-
|
|
172
|
-
`"
|
|
173
|
-
|
|
157
|
+
`replace` requires `find` and `with`; `delete` requires `find`; `insert` requires `markdown` and exactly one of `after` or `before`. An
|
|
158
|
+
insert anchor is a quote, `"start"`, `"end"`, or `"heading:Title"`. Ordinary inserts create a sibling block before or after the quote or
|
|
159
|
+
heading's enclosing document block; `"start"` and `"end"` select the document edges. At a table-cell quote, a body-row fragment (no
|
|
160
|
+
header or delimiter rows) extends that table before or after the matched row instead; short rows are padded, wider rows are rejected,
|
|
161
|
+
and deleting a cell's quoted text removes only that text.
|
|
174
162
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
163
|
+
Use `replace` for inline continuation. Use zero-based `occurrence` for a repeated target; re-read a missing or ambiguous target before
|
|
164
|
+
retrying. Pass `summary` to name the version when recording a decision.
|
|
165
|
+
|
|
166
|
+
## Progress
|
|
167
|
+
|
|
168
|
+
Every issue you work has one progress artifact, `progress.md` — for humans reading later and for your own successor after compaction. It
|
|
169
|
+
is never a wake signal.
|
|
170
|
+
|
|
171
|
+
Create it once, on first use:
|
|
172
|
+
```ts
|
|
173
|
+
dispatch_artifact({ issue, name: "progress.md", content: "### 2026-09-11 15:00Z - Started\n..." })
|
|
174
|
+
```
|
|
175
|
+
The server slugs `progress.md` to `progress-md`; address every later edit with that slug. Append — never edit or remove an earlier
|
|
176
|
+
entry:
|
|
177
|
+
```ts
|
|
178
|
+
dispatch_doc_edit({
|
|
179
|
+
issue,
|
|
180
|
+
artifact: "progress-md",
|
|
181
|
+
ops: [{ op: "insert", after: "end", markdown: "### 2026-09-11 16:10Z - Blocked\n..." }],
|
|
182
|
+
})
|
|
183
|
+
```
|
|
184
|
+
Newest entry last. Each entry is `### <UTC time> - <headline>` followed by 1-5 lines: what changed (cite `dispatch://` refs or PR
|
|
185
|
+
links), what is blocked and on whom, and what is next. `.legion/<phase>.json` is the durable machine handoff between phases;
|
|
186
|
+
`progress.md` is the human-readable narrative for the same work — keep both, never conflate one for the other.
|
|
182
187
|
|
|
183
188
|
## Comments and suggestions
|
|
184
189
|
|
|
@@ -188,14 +193,11 @@ Add feedback with:
|
|
|
188
193
|
dispatch_comment({ issue?, project?, artifact?, quote?, occurrence?, body, reply_to?, reply_to_ask? })
|
|
189
194
|
```
|
|
190
195
|
|
|
191
|
-
It returns issue or project-document owner details plus `comment` and, for writes, `topic`.
|
|
192
|
-
`
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
`
|
|
196
|
-
mutually exclusive. Comments are edited only by their author from the dashboard. A delivered
|
|
197
|
-
`comment.created` event carries the comment `id`; reply to it with
|
|
198
|
-
`dispatch_comment({ reply_to: <id> })`.
|
|
196
|
+
It returns issue or project-document owner details plus `comment` and, for writes, `topic`. `quote` requires `artifact`; omit both for a
|
|
197
|
+
floating issue comment. A reply (`reply_to`/`reply_to_ask`) takes no `quote`; it belongs to its parent's anchor. Use `reply_to` to
|
|
198
|
+
continue a comment thread at its root; a reply to a resolved thread reopens it. Use `reply_to_ask` to reply directly under a question
|
|
199
|
+
asked with `dispatch_ask`. Comments are edited only by their author from the dashboard. A delivered `comment.created` event carries the
|
|
200
|
+
comment `id`; reply to it with `dispatch_comment({ reply_to: <id> })`.
|
|
199
201
|
|
|
200
202
|
Propose an exact replacement instead of describing it:
|
|
201
203
|
|
|
@@ -203,15 +205,9 @@ Propose an exact replacement instead of describing it:
|
|
|
203
205
|
dispatch_suggest({ issue?, project?, artifact, quote, replace_with, body?, occurrence? })
|
|
204
206
|
```
|
|
205
207
|
|
|
206
|
-
It returns issue or project-document owner details plus `comment` and its write `topic`. A
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
before retrying. `INVALID_ANCHOR` requires exactly one nonempty anchor `quote` or `mark_id`;
|
|
210
|
-
`ANCHOR_MISSING` means a browser mark was not observed in the live tree, and
|
|
211
|
-
`ANCHOR_ORPHANED` means its marked text no longer exists. `INVALID_MARKDOWN` and `DOC_SCHEMA`
|
|
212
|
-
reject Markdown or a live tree outside the Proof schema. `INVALID_OP` names a malformed edit;
|
|
213
|
-
`CAP_EXCEEDED` never truncates; `ISSUE_CLOSED` rejects a write. `ACTOR_KIND` and `ROUTE_INVALID`
|
|
214
|
-
reject an invalid actor or route.
|
|
208
|
+
It returns issue or project-document owner details plus `comment` and its write `topic`. A human accepts or rejects a suggestion.
|
|
209
|
+
Errors: `TARGET_AMBIGUOUS` (add `occurrence`), `TARGET_NOT_FOUND` (re-read first), `INVALID_ANCHOR`/`ANCHOR_MISSING`/`ANCHOR_ORPHANED`
|
|
210
|
+
(bad, unwritten, or stale quote), `INVALID_MARKDOWN`/`DOC_SCHEMA` (malformed content), `CAP_EXCEEDED`, `ISSUE_CLOSED`.
|
|
215
211
|
|
|
216
212
|
## Artifacts
|
|
217
213
|
|
|
@@ -227,40 +223,37 @@ Or, when the text is already in the call, post a Markdown document directly:
|
|
|
227
223
|
dispatch_artifact({ issue?, project?, name: "spec.md", content: "# Design\n..." })
|
|
228
224
|
```
|
|
229
225
|
|
|
230
|
-
Exactly one of `issue` and `project` is required. A project upload creates an unlinked project
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
same `name` creates its next version. Use `content` when the text is already in the call.
|
|
235
|
-
Address an existing artifact by the slug shown in the upload result or by its filename.
|
|
226
|
+
Exactly one of `issue` and `project` is required. A project upload creates an unlinked project document; it must not include `artifact`.
|
|
227
|
+
Exactly one of `path` and `content` is required. It returns issue or project-document owner details plus `artifact`, `version`, and its
|
|
228
|
+
write `topic`. Uploading the same `name` creates its next version. Address an existing artifact by the slug shown in the upload result
|
|
229
|
+
or by its filename; the slug also arrives on `artifact.created` events.
|
|
236
230
|
|
|
237
231
|
## Messages
|
|
238
232
|
|
|
239
|
-
|
|
233
|
+
Post a note to the issue's Conversation for humans: a short status they should see now (a deploy landed, a blocker appeared), or a reply
|
|
234
|
+
to a human's message.
|
|
240
235
|
|
|
241
236
|
```ts
|
|
242
237
|
dispatch_message({ issue, body })
|
|
243
238
|
```
|
|
244
239
|
|
|
245
|
-
It returns `details` `{ issue, topic, message }`. `body` is capped at 2,000 characters.
|
|
246
|
-
|
|
240
|
+
It returns `details` `{ issue, topic, message }`. `body` is capped at 2,000 characters. It is not a progress ledger (`progress.md`), a
|
|
241
|
+
decision (`dispatch_ask`), or document feedback (`dispatch_comment`). Your message does not wake anyone unless the issue is routed.
|
|
247
242
|
|
|
248
243
|
## What comes back
|
|
249
244
|
|
|
250
|
-
A write result's `details.topic` subscribes the host to its owner. Issue writes use
|
|
251
|
-
`notifications.dispatch.
|
|
252
|
-
|
|
253
|
-
event; `notify` only controls agent wake and routed delivery. After a restart, catch up with:
|
|
245
|
+
A write result's `details.topic` subscribes the host to its owner. Issue writes use `notifications.dispatch.issue.<KEY>.>`;
|
|
246
|
+
project-document writes use `notifications.dispatch.document.<PROJECT>.<SLUG>.>`. The owner topic carries every Dispatch event; `notify`
|
|
247
|
+
only controls agent wake and routed delivery. After a restart, catch up with:
|
|
254
248
|
|
|
255
249
|
```ts
|
|
256
250
|
dispatch_read({ issue?, project?, artifact?, ref? })
|
|
257
251
|
```
|
|
258
252
|
|
|
259
|
-
With an issue ref, it returns the issue summary, open asks, references, and recent events with
|
|
260
|
-
`details` `{
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
reply chain. Reads do not subscribe; use `dispatch_doc_read` for document contents.
|
|
253
|
+
With an issue ref, it returns the issue summary, open asks, references, and recent events with `details` `{ issue }`. With a project
|
|
254
|
+
document owner or ref, it returns a document summary with `details` `{ project, document }`. With an ask ref, it returns that ask's
|
|
255
|
+
question, options, state, answer, and its reply thread. With a comment ref, it returns that comment and its quoted reply chain. Reads do
|
|
256
|
+
not subscribe; use `dispatch_doc_read` for document contents.
|
|
264
257
|
|
|
265
258
|
## References
|
|
266
259
|
|
|
@@ -277,6 +270,8 @@ dispatch://PROJECT/artifact/<slug>/ask/<id>
|
|
|
277
270
|
dispatch://PROJECT/artifact/<slug>/comment/<id>
|
|
278
271
|
```
|
|
279
272
|
|
|
273
|
+
A bare UUID or `KEY#seq` is not a reference; the `dispatch://` form is what Dispatch links and records.
|
|
274
|
+
|
|
280
275
|
## Before / after
|
|
281
276
|
|
|
282
277
|
Before — a wall of text hides the decision and makes the choices unclickable:
|
|
@@ -294,48 +289,37 @@ After — anchor the decision and make each option a button:
|
|
|
294
289
|
dispatch_ask({
|
|
295
290
|
issue: "LEGION-815",
|
|
296
291
|
question:
|
|
297
|
-
"Choose the release gate. Recommendation: ship after release-note review
|
|
292
|
+
"Choose the release gate. Recommendation: ship after release-note review, since the tested deployment is otherwise ready.",
|
|
298
293
|
options: [
|
|
299
|
-
{
|
|
300
|
-
|
|
301
|
-
description: "Keeps the tested release intact and publishes reviewed instructions.",
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
label: "Ship now",
|
|
305
|
-
description: "Meets the demo deadline; release notes follow separately.",
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
label: "Remove dashboard changes",
|
|
309
|
-
description: "Narrows the release but requires another deployment test.",
|
|
310
|
-
},
|
|
294
|
+
{ label: "Review notes, then ship", description: "Keeps the release intact and reviewed." },
|
|
295
|
+
{ label: "Ship now", description: "Meets the demo deadline; release notes follow later." },
|
|
311
296
|
],
|
|
312
297
|
urgency: "high",
|
|
313
|
-
anchor: {
|
|
314
|
-
artifact: "spec",
|
|
315
|
-
quote: "Release requires reviewed operator instructions before deployment.",
|
|
316
|
-
},
|
|
298
|
+
anchor: { artifact: "spec", quote: "Release requires reviewed operator instructions before deployment." },
|
|
317
299
|
})
|
|
318
300
|
```
|
|
319
301
|
|
|
320
|
-
Before — a
|
|
302
|
+
Before — progress typed once into a message, gone once compaction drops it from context:
|
|
321
303
|
|
|
322
|
-
```
|
|
323
|
-
|
|
304
|
+
```ts
|
|
305
|
+
dispatch_message({ issue: "LEGION-815", body: "Merged the release PR, moving to docs next." })
|
|
324
306
|
```
|
|
325
307
|
|
|
326
|
-
After —
|
|
308
|
+
After — append it to the progress artifact, where the record survives:
|
|
327
309
|
|
|
328
310
|
```ts
|
|
329
311
|
dispatch_doc_edit({
|
|
330
312
|
issue: "LEGION-815",
|
|
331
|
-
artifact: "
|
|
313
|
+
artifact: "progress-md",
|
|
332
314
|
ops: [
|
|
333
315
|
{
|
|
334
|
-
op: "
|
|
335
|
-
|
|
336
|
-
|
|
316
|
+
op: "insert",
|
|
317
|
+
after: "end",
|
|
318
|
+
markdown:
|
|
319
|
+
"### 2026-09-11 15:40Z - Release PR merged\n" +
|
|
320
|
+
"- dispatch://LEGION-815/artifact/spec stays unchanged; this is progress, not a decision.\n" +
|
|
321
|
+
"- Next: docs review.",
|
|
337
322
|
},
|
|
338
323
|
],
|
|
339
|
-
summary: "Recorded merged release",
|
|
340
324
|
})
|
|
341
325
|
```
|
|
@@ -71,6 +71,9 @@ exercise a criterion end to end, building that path is a child issue of this tre
|
|
|
71
71
|
inert until released.
|
|
72
72
|
|
|
73
73
|
Specifications written into Dispatch follow [`skills/dispatch`'s Writing a spec](../dispatch/SKILL.md#writing-a-spec).
|
|
74
|
+
Record ongoing status — wave releases, child closures, blockers — in the issue's `progress.md`
|
|
75
|
+
artifact (see [`skills/dispatch`'s Progress](../dispatch/SKILL.md#progress)), never in the spec
|
|
76
|
+
or a `dispatch_message`.
|
|
74
77
|
|
|
75
78
|
Write one root specification containing the accepted scope, adoption/decomposition,
|
|
76
79
|
waves, acceptance criteria, and integration test. When the config-armed root design gate
|
|
@@ -97,7 +97,9 @@ committed predecessor handoffs in lifecycle order from `$LEGION_WORKSPACE/.legio
|
|
|
97
97
|
Read only files that precede the assigned phase. There is no handoff schema (rejected
|
|
98
98
|
design — no schema validation runs anywhere in this pipeline): write the phase-specific
|
|
99
99
|
fields the next phase and the architect need, consistent with what predecessor phases
|
|
100
|
-
already wrote. The durable copy lives in `$LEGION_WORKSPACE/.legion/<phase>.json
|
|
100
|
+
already wrote. The durable copy lives in `$LEGION_WORKSPACE/.legion/<phase>.json` — the machine
|
|
101
|
+
handoff between phases, not a human-readable status; post that to the issue's `progress.md`
|
|
102
|
+
artifact instead (see [`skills/dispatch`'s Progress](../dispatch/SKILL.md#progress)). If a
|
|
101
103
|
committed handoff conflicts with memory or a prior transcript, the committed file wins: it
|
|
102
104
|
is the copy that survived.
|
|
103
105
|
|