@sjawhar/pi-legion-envoy 0.29.0 → 0.30.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/README.md +2 -2
- package/dist/envoy.js +12 -8
- package/dist/legion.js +12 -8
- package/dist/skills/dispatch/SKILL.md +40 -7
- package/dist/skills/legion-architect/SKILL.md +3 -1
- package/dist/skills/legion-worker/SKILL.md +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,8 +121,8 @@ The shared contract supplies the model-facing schemas and descriptions. The
|
|
|
121
121
|
feedback, documents, artifacts, and status reads.
|
|
122
122
|
|
|
123
123
|
`dispatch_artifact` accepts exactly one upload source: a local `path`, or inline `content`.
|
|
124
|
-
For example, an architect can post
|
|
125
|
-
`{ issue, name: "spec.md", content: "# Design"
|
|
124
|
+
For example, an architect can post a specification directly with
|
|
125
|
+
`{ issue, name: "spec.md", content: "# Design" }`.
|
|
126
126
|
|
|
127
127
|
Lifecycle and scope decisions between Legion roles go through `envoy_publish` to the owning
|
|
128
128
|
architect's role topic; Dispatch is for durable questions to the human and the shared
|
package/dist/envoy.js
CHANGED
|
@@ -29700,6 +29700,16 @@ function dispatchToolSchema(spec, z, opts) {
|
|
|
29700
29700
|
return spec.validation === undefined ? z.object(shape, opts) : z.refineObject(shape, spec.validation.check, spec.validation.message, opts);
|
|
29701
29701
|
}
|
|
29702
29702
|
var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference; an external reference creates its native issue in the repository's dashboard-configured project or, failing that, the default project (DISPATCH_DEFAULT_PROJECT).";
|
|
29703
|
+
var SPEC_SECTIONS = [
|
|
29704
|
+
"Decisions needed",
|
|
29705
|
+
"Acceptance",
|
|
29706
|
+
"Requirements",
|
|
29707
|
+
"Design",
|
|
29708
|
+
"Errors",
|
|
29709
|
+
"Testing",
|
|
29710
|
+
"Rejected"
|
|
29711
|
+
];
|
|
29712
|
+
var SPEC_WRITING_GUIDANCE = `When writing a spec, use these sections in order: ${SPEC_SECTIONS.join(", ")}. ` + "Every line is a fact, decision, or risk; use tables over prose; see skills/dispatch Writing a spec.";
|
|
29703
29713
|
var ASK_URGENCIES = ["low", "med", "high", "blocking"];
|
|
29704
29714
|
var DOC_EDIT_OPS = ["replace", "delete", "insert"];
|
|
29705
29715
|
var dispatchToolSpecs = [
|
|
@@ -29711,7 +29721,7 @@ var dispatchToolSpecs = [
|
|
|
29711
29721
|
title: z.string().describe("Concise issue title."),
|
|
29712
29722
|
parent: z.string().describe("Optional parent issue.").optional(),
|
|
29713
29723
|
external: z.string().describe("Optional external issue reference.").optional(),
|
|
29714
|
-
spec: z.string().describe(
|
|
29724
|
+
spec: z.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_GUIDANCE}`).optional()
|
|
29715
29725
|
})
|
|
29716
29726
|
},
|
|
29717
29727
|
{
|
|
@@ -29777,7 +29787,7 @@ var dispatchToolSpecs = [
|
|
|
29777
29787
|
},
|
|
29778
29788
|
{
|
|
29779
29789
|
name: "dispatch_doc_edit",
|
|
29780
|
-
description: "Apply deterministic text edits to a document. Do not use it for review feedback or for reading; use " + `dispatch_comment, dispatch_suggest, or dispatch_doc_read instead. ${ISSUE_REFERENCE}`,
|
|
29790
|
+
description: "Apply deterministic text edits to a document. Do not use it for review feedback or for reading; use " + `dispatch_comment, dispatch_suggest, or dispatch_doc_read instead. ${ISSUE_REFERENCE} ${SPEC_WRITING_GUIDANCE}`,
|
|
29781
29791
|
arguments: (z) => ({
|
|
29782
29792
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
29783
29793
|
artifact: z.string().describe("Artifact slug or id for the document."),
|
|
@@ -29811,7 +29821,6 @@ var dispatchToolSpecs = [
|
|
|
29811
29821
|
name: z.string().describe("Artifact filename shown in Dispatch."),
|
|
29812
29822
|
path: z.string().describe("Local path to the file to upload.").optional(),
|
|
29813
29823
|
content: z.string().describe("Inline text to store as a Markdown document.").optional(),
|
|
29814
|
-
primary: z.boolean().describe("Make this document the issue primary artifact.").optional(),
|
|
29815
29824
|
summary: z.string().describe("Optional version summary.").optional()
|
|
29816
29825
|
}),
|
|
29817
29826
|
validation: {
|
|
@@ -31197,8 +31206,6 @@ class DispatchClient {
|
|
|
31197
31206
|
return this.#json("POST", artifactPath, input);
|
|
31198
31207
|
const form = new FormData;
|
|
31199
31208
|
form.set("name", input.name);
|
|
31200
|
-
if (input.primary !== undefined)
|
|
31201
|
-
form.set("primary", String(input.primary));
|
|
31202
31209
|
if (input.summary !== undefined)
|
|
31203
31210
|
form.set("summary", input.summary);
|
|
31204
31211
|
if (input.actor !== undefined)
|
|
@@ -31717,20 +31724,17 @@ Open anchored asks/comments: ${marks.join(", ")}`,
|
|
|
31717
31724
|
};
|
|
31718
31725
|
}
|
|
31719
31726
|
case "dispatch_artifact": {
|
|
31720
|
-
const primary = optionalBoolean(args, "primary");
|
|
31721
31727
|
const summary = optionalString(args, "summary");
|
|
31722
31728
|
const name = stringArg(args, "name");
|
|
31723
31729
|
const content = optionalString(args, "content");
|
|
31724
31730
|
const result = await client.artifact(issue(), content === undefined ? {
|
|
31725
31731
|
name,
|
|
31726
31732
|
file: Bun.file(resolvePath(input.cwd, stringArg(args, "path"))),
|
|
31727
|
-
...primary === undefined ? {} : { primary },
|
|
31728
31733
|
...summary === undefined ? {} : { summary },
|
|
31729
31734
|
actor
|
|
31730
31735
|
} : {
|
|
31731
31736
|
name,
|
|
31732
31737
|
content,
|
|
31733
|
-
...primary === undefined ? {} : { primary },
|
|
31734
31738
|
...summary === undefined ? {} : { summary },
|
|
31735
31739
|
actor
|
|
31736
31740
|
});
|
package/dist/legion.js
CHANGED
|
@@ -29698,6 +29698,16 @@ function dispatchToolSchema(spec, z, opts) {
|
|
|
29698
29698
|
return spec.validation === undefined ? z.object(shape, opts) : z.refineObject(shape, spec.validation.check, spec.validation.message, opts);
|
|
29699
29699
|
}
|
|
29700
29700
|
var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference; an external reference creates its native issue in the repository's dashboard-configured project or, failing that, the default project (DISPATCH_DEFAULT_PROJECT).";
|
|
29701
|
+
var SPEC_SECTIONS = [
|
|
29702
|
+
"Decisions needed",
|
|
29703
|
+
"Acceptance",
|
|
29704
|
+
"Requirements",
|
|
29705
|
+
"Design",
|
|
29706
|
+
"Errors",
|
|
29707
|
+
"Testing",
|
|
29708
|
+
"Rejected"
|
|
29709
|
+
];
|
|
29710
|
+
var SPEC_WRITING_GUIDANCE = `When writing a spec, use these sections in order: ${SPEC_SECTIONS.join(", ")}. ` + "Every line is a fact, decision, or risk; use tables over prose; see skills/dispatch Writing a spec.";
|
|
29701
29711
|
var ASK_URGENCIES = ["low", "med", "high", "blocking"];
|
|
29702
29712
|
var DOC_EDIT_OPS = ["replace", "delete", "insert"];
|
|
29703
29713
|
var dispatchToolSpecs = [
|
|
@@ -29709,7 +29719,7 @@ var dispatchToolSpecs = [
|
|
|
29709
29719
|
title: z.string().describe("Concise issue title."),
|
|
29710
29720
|
parent: z.string().describe("Optional parent issue.").optional(),
|
|
29711
29721
|
external: z.string().describe("Optional external issue reference.").optional(),
|
|
29712
|
-
spec: z.string().describe(
|
|
29722
|
+
spec: z.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_GUIDANCE}`).optional()
|
|
29713
29723
|
})
|
|
29714
29724
|
},
|
|
29715
29725
|
{
|
|
@@ -29775,7 +29785,7 @@ var dispatchToolSpecs = [
|
|
|
29775
29785
|
},
|
|
29776
29786
|
{
|
|
29777
29787
|
name: "dispatch_doc_edit",
|
|
29778
|
-
description: "Apply deterministic text edits to a document. Do not use it for review feedback or for reading; use " + `dispatch_comment, dispatch_suggest, or dispatch_doc_read instead. ${ISSUE_REFERENCE}`,
|
|
29788
|
+
description: "Apply deterministic text edits to a document. Do not use it for review feedback or for reading; use " + `dispatch_comment, dispatch_suggest, or dispatch_doc_read instead. ${ISSUE_REFERENCE} ${SPEC_WRITING_GUIDANCE}`,
|
|
29779
29789
|
arguments: (z) => ({
|
|
29780
29790
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
29781
29791
|
artifact: z.string().describe("Artifact slug or id for the document."),
|
|
@@ -29809,7 +29819,6 @@ var dispatchToolSpecs = [
|
|
|
29809
29819
|
name: z.string().describe("Artifact filename shown in Dispatch."),
|
|
29810
29820
|
path: z.string().describe("Local path to the file to upload.").optional(),
|
|
29811
29821
|
content: z.string().describe("Inline text to store as a Markdown document.").optional(),
|
|
29812
|
-
primary: z.boolean().describe("Make this document the issue primary artifact.").optional(),
|
|
29813
29822
|
summary: z.string().describe("Optional version summary.").optional()
|
|
29814
29823
|
}),
|
|
29815
29824
|
validation: {
|
|
@@ -31636,8 +31645,6 @@ class DispatchClient {
|
|
|
31636
31645
|
return this.#json("POST", artifactPath, input);
|
|
31637
31646
|
const form = new FormData;
|
|
31638
31647
|
form.set("name", input.name);
|
|
31639
|
-
if (input.primary !== undefined)
|
|
31640
|
-
form.set("primary", String(input.primary));
|
|
31641
31648
|
if (input.summary !== undefined)
|
|
31642
31649
|
form.set("summary", input.summary);
|
|
31643
31650
|
if (input.actor !== undefined)
|
|
@@ -32156,20 +32163,17 @@ Open anchored asks/comments: ${marks.join(", ")}`,
|
|
|
32156
32163
|
};
|
|
32157
32164
|
}
|
|
32158
32165
|
case "dispatch_artifact": {
|
|
32159
|
-
const primary = optionalBoolean(args, "primary");
|
|
32160
32166
|
const summary = optionalString(args, "summary");
|
|
32161
32167
|
const name = stringArg(args, "name");
|
|
32162
32168
|
const content = optionalString(args, "content");
|
|
32163
32169
|
const result = await client.artifact(issue(), content === undefined ? {
|
|
32164
32170
|
name,
|
|
32165
32171
|
file: Bun.file(resolvePath(input.cwd, stringArg(args, "path"))),
|
|
32166
|
-
...primary === undefined ? {} : { primary },
|
|
32167
32172
|
...summary === undefined ? {} : { summary },
|
|
32168
32173
|
actor
|
|
32169
32174
|
} : {
|
|
32170
32175
|
name,
|
|
32171
32176
|
content,
|
|
32172
|
-
...primary === undefined ? {} : { primary },
|
|
32173
32177
|
...summary === undefined ? {} : { summary },
|
|
32174
32178
|
actor
|
|
32175
32179
|
});
|
|
@@ -12,6 +12,38 @@ The server enforces high signal: an ask question is at most 800 characters with
|
|
|
12
12
|
options; comment and message bodies are at most 2,000 characters; an artifact is at most 25 MiB.
|
|
13
13
|
It refuses over-limit input; it never truncates it. GitHub threads and markers no longer exist.
|
|
14
14
|
|
|
15
|
+
## Writing a spec
|
|
16
|
+
|
|
17
|
+
A spec is a decision record for the human who decides and the implementer who builds, not a
|
|
18
|
+
transcript of your thinking. Use exactly these document headings in this order.
|
|
19
|
+
|
|
20
|
+
| Section | Required content | Form |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| **Decisions needed** | Only decisions requiring human authority, taste, or risk appetite. Each states one question, two or three options with tradeoffs, and a recommendation. Every item is an anchored `dispatch_ask`. Answered items move into Requirements with provenance, then leave this section. No other section asks the reader anything. Empty means `None.` | One decision per line; anchor each ask to that line. |
|
|
23
|
+
| **Acceptance** | Every outcome names its check and user-facing surface. An outcome without a verification method is not acceptance criteria. | Numbered lines; browser scenario, API call, or CLI command. |
|
|
24
|
+
| **Requirements** | Provenance is a verbatim human quote or `inferred: <reasoning>`; readers treat inferred requirements as hypotheses. Do not restate the prompt in prose. | `requirement \| provenance` table. |
|
|
25
|
+
| **Design** | State the files, components, routes, and data flow that change. | Facts, not narrative; diagrams only for genuine structure. |
|
|
26
|
+
| **Errors** | Name the behaviour for every error condition; never specify a silent fallback. | `condition \| behaviour` table. |
|
|
27
|
+
| **Testing** | Map every acceptance line to the proof that exercises it. | Suite or scenario. |
|
|
28
|
+
| **Rejected** | Record each considered alternative and why it was rejected so it is not proposed again. | One alternative per line. |
|
|
29
|
+
|
|
30
|
+
### Rules
|
|
31
|
+
|
|
32
|
+
- Every sentence is a fact, decision, or risk; delete the rest.
|
|
33
|
+
- Use tables over prose and keep one idea per line.
|
|
34
|
+
- Do not use Overview, Background, Introduction, Summary, or Conclusion sections.
|
|
35
|
+
- Do not hedge with “might” or “could consider.”
|
|
36
|
+
- Do not use TBD, TODO, or placeholders; an open item is a Decision needed.
|
|
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. The spec is the record; comments are the discussion.
|
|
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.
|
|
46
|
+
|
|
15
47
|
## Your issue
|
|
16
48
|
|
|
17
49
|
Every session works on an issue. Legion pre-fills `issue` from `LEGION_ISSUE`: use a native issue key
|
|
@@ -26,6 +58,7 @@ dispatch_issue({ project, title, parent?, external?, spec? })
|
|
|
26
58
|
```
|
|
27
59
|
It returns `details` `{ issue, topic }`. Use `dispatch_issue` only to create an issue; never use
|
|
28
60
|
it to park a question.
|
|
61
|
+
When `spec` is supplied, follow [Writing a spec](#writing-a-spec).
|
|
29
62
|
|
|
30
63
|
## Asking
|
|
31
64
|
|
|
@@ -65,6 +98,7 @@ answer. Use `reply_to_ask` on `dispatch_comment` to reply under your own ask; it
|
|
|
65
98
|
exclusive with `reply_to`.
|
|
66
99
|
|
|
67
100
|
## The spec is where narrative goes
|
|
101
|
+
Write and update the issue specification according to [Writing a spec](#writing-a-spec).
|
|
68
102
|
|
|
69
103
|
Read the current document before changing it:
|
|
70
104
|
|
|
@@ -72,7 +106,7 @@ Read the current document before changing it:
|
|
|
72
106
|
dispatch_doc_read({ issue?, artifact?, version?, ref? })
|
|
73
107
|
```
|
|
74
108
|
It returns live or versioned markdown with open marks and `details` `{ issue }`; omit `artifact`
|
|
75
|
-
with `issue` to read the
|
|
109
|
+
with `issue` to read the issue specification. Then write narrative with:
|
|
76
110
|
|
|
77
111
|
```ts
|
|
78
112
|
dispatch_doc_edit({ issue, artifact, ops, summary? })
|
|
@@ -119,27 +153,26 @@ dispatch_suggest({ issue, artifact, quote, replace_with, body?, occurrence? })
|
|
|
119
153
|
It returns `details` `{ issue, topic, comment }`. A human accepts or rejects a suggestion. On
|
|
120
154
|
`TARGET_AMBIGUOUS`, add zero-based `occurrence`. On `TARGET_NOT_FOUND`, re-read the document
|
|
121
155
|
before retrying. `INVALID_OP` names a malformed edit; `CAP_EXCEEDED` never truncates;
|
|
122
|
-
`ISSUE_CLOSED` rejects a write. `ACTOR_KIND
|
|
123
|
-
invalid actor, route, or primary artifact.
|
|
156
|
+
`ISSUE_CLOSED` rejects a write. `ACTOR_KIND` and `ROUTE_INVALID` reject an invalid actor or route.
|
|
124
157
|
|
|
125
158
|
## Artifacts
|
|
126
159
|
|
|
127
160
|
Attach an image, diagram, or local file with:
|
|
128
161
|
|
|
129
162
|
```ts
|
|
130
|
-
dispatch_artifact({ issue, name, path,
|
|
163
|
+
dispatch_artifact({ issue, name, path, summary? })
|
|
131
164
|
```
|
|
132
165
|
|
|
133
166
|
Or, when the text is already in the call, post a Markdown document directly:
|
|
134
167
|
|
|
135
168
|
```ts
|
|
136
|
-
dispatch_artifact({ issue, name: "spec.md", content: "# Design\n..."
|
|
169
|
+
dispatch_artifact({ issue, name: "spec.md", content: "# Design\n..." })
|
|
137
170
|
```
|
|
138
171
|
|
|
139
172
|
Exactly one of `path` and `content` is required. The inline form sends JSON with
|
|
140
173
|
`Content-Type: application/json`. It returns `details` `{ issue, topic, artifact, version }`.
|
|
141
|
-
Uploading the same `name` creates its next version. Use `content`
|
|
142
|
-
|
|
174
|
+
Uploading the same `name` creates its next version. Use `content` when the text is already in
|
|
175
|
+
the call.
|
|
143
176
|
|
|
144
177
|
## Messages
|
|
145
178
|
|
|
@@ -70,13 +70,15 @@ exercise a criterion end to end, building that path is a child issue of this tre
|
|
|
70
70
|
relationship from `parent`. Keep the returned issue keys in ordered waves; a child is
|
|
71
71
|
inert until released.
|
|
72
72
|
|
|
73
|
+
Specifications written into Dispatch follow [`skills/dispatch`'s Writing a spec](../dispatch/SKILL.md#writing-a-spec).
|
|
74
|
+
|
|
73
75
|
Write one root specification containing the accepted scope, adoption/decomposition,
|
|
74
76
|
waves, acceptance criteria, and integration test. When the config-armed root design gate
|
|
75
77
|
applies, run this exact sequence **before any Legion-role spawn**, including a
|
|
76
78
|
sub-architect:
|
|
77
79
|
|
|
78
80
|
```text
|
|
79
|
-
dispatch_artifact({ issue: "<root issue>", name: "spec.md", content: "<root specification>",
|
|
81
|
+
dispatch_artifact({ issue: "<root issue>", name: "spec.md", content: "<root specification>", summary: "<one-line summary>" })
|
|
80
82
|
askId = dispatch_ask({
|
|
81
83
|
issue: "<root issue>",
|
|
82
84
|
question: "<specification summary and the decision requested>",
|
|
@@ -118,6 +118,8 @@ path-scoped workflow.
|
|
|
118
118
|
|
|
119
119
|
## Phase work
|
|
120
120
|
|
|
121
|
+
Specifications written into Dispatch follow [`skills/dispatch`'s Writing a spec](../dispatch/SKILL.md#writing-a-spec).
|
|
122
|
+
|
|
121
123
|
Follow the repository's normal engineering workflow and the assigned issue's acceptance
|
|
122
124
|
criteria. Your phase's own charter and the predecessor handoffs you read define the phase
|
|
123
125
|
artifact and its completion evidence. Do not replace architect-owned decomposition, gate
|