@sjawhar/pi-envoy 8.4.0 → 8.5.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 +38 -31
- package/bin/dispatch +6 -0
- package/dist/dispatch.js +18648 -0
- package/dist/envoy.js +580 -2656
- package/dist/skills/dispatch/SKILL.md +85 -97
- package/dist/skills/dispatch/references/api.md +4 -4
- package/dist/skills/dispatch/references/asks.md +34 -54
- package/dist/skills/dispatch/references/document-edits.md +24 -21
- package/dist/skills/dispatch/references/documents.md +75 -72
- package/dist/skills/dispatch/references/examples.md +37 -67
- package/dist/skills/dispatch/references/issues.md +48 -48
- package/dist/skills/dispatch/references/messages.md +18 -25
- package/dist/skills/dispatch/references/reading.md +10 -10
- package/dist/skills/dispatch-brainstorming/SKILL.md +19 -15
- package/dist/skills/dispatch-first/SKILL.md +7 -7
- package/dist/skills/envoy/SKILL.md +3 -2
- package/package.json +6 -5
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dispatch
|
|
3
|
-
description: "Use before posting a message, a status update, or a periodic status update; before asking a question that references another message, artifact, or eval; before asking a design question or brainstorming a change; and when asking the human a question, updating the spec, commenting on a document, attaching an artifact, or
|
|
3
|
+
description: "Use before posting a message, a status update, or a periodic status update; before asking a question that references another message, artifact, or eval; before asking a design question or brainstorming a change; and when asking the human a question, updating the spec, commenting on a document, attaching an artifact, or running a dispatch command."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Dispatch
|
|
7
7
|
|
|
8
8
|
Dispatch is your issue's or project document's living spec, asks, comments, and artifacts — a high-signal record for the humans who
|
|
9
9
|
decide, never a log of your work. The transcript is your scratch pad; progress and status stay there. Anything meant for a human
|
|
10
|
-
goes through
|
|
10
|
+
goes through the `dispatch` command, which runs in your shell: `dispatch --help` lists the commands, and `dispatch <command> --help`
|
|
11
|
+
each one's flags and an example. A field is a flag (`--issue LEGION-3`); long text goes on stdin with `--<field>-file -` and a
|
|
12
|
+
quoted here-document (`<<'EOF'` … `EOF`), and an object or list field takes JSON (`--ops-json`). What it prints is the result; it
|
|
13
|
+
exits 0 when it wrote or read, 1 when Dispatch refused, and 2 on a usage error.
|
|
11
14
|
|
|
12
15
|
The server enforces high signal: an ask question is at most 800 characters with at most eight options; comment and message bodies are at
|
|
13
16
|
most 2,000 characters; a markdown document is at most 1 MiB and any other file at most 25 MiB. It refuses over-limit input with the number
|
|
14
|
-
to trim (`question is 50 characters over the 800-character limit (850/800)`); it never truncates it. A
|
|
15
|
-
refused once, every problem listed (
|
|
16
|
-
longer exist.
|
|
17
|
+
to trim (`question is 50 characters over the 800-character limit (850/800)`); it never truncates it. A command with several problems is
|
|
18
|
+
refused once, every problem listed (`dispatch <command> was not called: N problems`), so one corrected call lands.
|
|
17
19
|
|
|
18
20
|
## Where the detail lives
|
|
19
21
|
|
|
@@ -23,14 +25,14 @@ after `skill://dispatch/` is relative to this skill's base directory.
|
|
|
23
25
|
|
|
24
26
|
| When you are about to | Read |
|
|
25
27
|
| --- | --- |
|
|
26
|
-
|
|
|
28
|
+
| run `dispatch doc-edit`: rewrite a paragraph, insert or move a block, change a table's cells, rows or columns | [Editing a document](skill://dispatch/references/document-edits.md) |
|
|
27
29
|
| write a typed block (an `:::ask`, a callout), comment on or suggest a change to a document, upload an artifact, or retry after `DOC_SERVICE_UNAVAILABLE` | [Documents](skill://dispatch/references/documents.md) |
|
|
28
30
|
| choose your next issue, claim one, move its status or priority, reorder a board, or audit a project's backlog | [Working an issue](skill://dispatch/references/issues.md) |
|
|
29
31
|
| find who answers an ask, edit, retract or resolve one, reply with the turn, or follow a thread | [Asks after they open](skill://dispatch/references/asks.md) |
|
|
30
32
|
| catch up after a restart, trace what cites a node, or write a `dispatch://` reference | [Reading back](skill://dispatch/references/reading.md) |
|
|
31
33
|
| answer a BTW, Aside or Steer frame, or a message from the Agents page | [Targeted and direct messages](skill://dispatch/references/messages.md) |
|
|
32
34
|
| see a worked ask, a reply that names its mechanism, a message not to send, and where a draft goes | [Before and after](skill://dispatch/references/examples.md) |
|
|
33
|
-
| set up a token, or call a route the
|
|
35
|
+
| set up a token, or call a route the commands do not cover | [Authentication and the HTTP API](skill://dispatch/references/api.md) |
|
|
34
36
|
|
|
35
37
|
## Design changes are brainstormed here
|
|
36
38
|
|
|
@@ -47,7 +49,7 @@ not share this session's vocabulary, and is often on a phone. Write for that per
|
|
|
47
49
|
- Plain English, full sentences, one idea per sentence. Never repo shorthand or nouns you coined:
|
|
48
50
|
not "fix 8c", "READY-target", "PR B", "spec@v3", "the pair", "the packet" — say what the thing is.
|
|
49
51
|
- A real name is not a coined noun: name a product, a tool and its operation
|
|
50
|
-
(`
|
|
52
|
+
(`dispatch request-approval`), an event type (`artifact.approved`), a route, a setting or a
|
|
51
53
|
status exactly, and say how it works in a clause ("the daemon opens the gate when Dispatch emits
|
|
52
54
|
`artifact.approved` for that document at that version"), never with a vague verb such as
|
|
53
55
|
"notice", "accept", "tell" or "pick up" ([before and after](skill://dispatch/references/examples.md#naming-the-mechanism)).
|
|
@@ -82,7 +84,7 @@ a new version that keeps the human's own text, never a second "spec" artifact be
|
|
|
82
84
|
says. Because it is an ask, it reaches the human's Inbox, and the answer lands next to its context.
|
|
83
85
|
- **A settled point records the person's own words and the date**, quoted, so no reader mistakes
|
|
84
86
|
it for your inference; an answer that is only a chosen option is recorded in the form
|
|
85
|
-
`<name> chose "Commit author" on the question below (<date>)`, naming them from `
|
|
87
|
+
`<name> chose "Commit author" on the question below (<date>)`, naming them from `dispatch whoami`
|
|
86
88
|
or the conversation, or "the person" when the token names no owner — never a name you were not
|
|
87
89
|
given. A point you inferred says so, with the reasoning — a security concern, a restriction, or
|
|
88
90
|
a cost nobody measured is exactly this, not a settled constraint; during a live brainstorming
|
|
@@ -117,20 +119,20 @@ A decision a human must make is an `:::ask` block at the end of the section that
|
|
|
117
119
|
shaped as [Writing for the human](#writing-for-the-human) says for a question, with what
|
|
118
120
|
constrains the answer split into measured, known and unknown. It asks how to solve the problem,
|
|
119
121
|
never whether to apply a change already chosen. Never gather decisions into a list, at the top,
|
|
120
|
-
at the bottom or in an "open questions" section, and never ask one as a standalone `
|
|
122
|
+
at the bottom or in an "open questions" section, and never ask one as a standalone `dispatch ask`
|
|
121
123
|
that points at the spec.
|
|
122
124
|
|
|
123
125
|
The block is what reaches the human's Inbox. A question phrased as prose in the spec reaches
|
|
124
126
|
nobody. A spec with no ask blocks is fine only when the issue genuinely needs no human decision.
|
|
125
|
-
What `
|
|
127
|
+
What `dispatch issue` and `dispatch artifact` answer about a spec's blocks, and how to check an edit
|
|
126
128
|
wrote one, is in [Typed blocks](skill://dispatch/references/documents.md#typed-blocks).
|
|
127
129
|
|
|
128
130
|
**Wrong:** a **Decisions needed** list at the top of the spec with three bullets.
|
|
129
131
|
**Right:** each decision an `:::ask{#slug}` block at the end of the design section that discusses
|
|
130
132
|
it, with 2–4 options, a recommendation, and surrounding prose that explains the trade-off.
|
|
131
133
|
|
|
132
|
-
A spec that already has the pile is repaired with `move`, not rewritten: `
|
|
133
|
-
|
|
134
|
+
A spec that already has the pile is repaired with `move`, not rewritten: `dispatch doc-edit` with
|
|
135
|
+
`--ops-json '[{"op":"move","block":"<block-uuid>","after":"<the last sentence of the section that discusses it>"}]'` relocates
|
|
134
136
|
the block and keeps its ask, its answer and its followers; the context paragraphs that were lifted
|
|
135
137
|
out of Design move the same way, and the emptied section is deleted. An ask block has two ids that
|
|
136
138
|
differ; [Editing a document](skill://dispatch/references/document-edits.md) says which.
|
|
@@ -140,38 +142,32 @@ See [Typed blocks](#typed-blocks) for the syntax and [Before you ask](#before-yo
|
|
|
140
142
|
|
|
141
143
|
## Your owner
|
|
142
144
|
|
|
143
|
-
Every session works on an issue or project document. Legion pre-fills
|
|
145
|
+
Every session works on an issue or project document. Legion pre-fills `--issue` from `LEGION_ISSUE`: use a native issue key such as
|
|
144
146
|
`LEGION-3`, an external `owner/repo#n` reference, or a bare positive number (resolved against the cwd repository). Otherwise pass
|
|
145
|
-
exactly one owner to every owner-scoped
|
|
147
|
+
exactly one owner to every owner-scoped command: `--issue` for an issue, or `--project` and `--artifact` for an unlinked project document (see
|
|
146
148
|
[Reference forms](skill://dispatch/references/reading.md) for the resulting ref shape). An external issue reference addresses the existing Dispatch issue linked to
|
|
147
|
-
that GitHub issue or pull request. Only `
|
|
148
|
-
`
|
|
149
|
+
that GitHub issue or pull request. Only `dispatch issue` with `--external` creates a native issue; if no issue is linked, run
|
|
150
|
+
`dispatch issue --external owner/repo#n --project <project> --title '<title>'` before addressing it.
|
|
149
151
|
|
|
150
|
-
Create an issue for newly tracked work with
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```
|
|
154
|
-
`labels` are optional initial labels: Dispatch trims them, preserves their case, and removes case-insensitive duplicates. `priority` is yours on creation too — see [Priority is yours to set](skill://dispatch/references/issues.md). Set `assignee` (the email of a person who has signed in to Dispatch) only when the human said who owns the work; otherwise the default above applies, so a child inherits its parent's assignee. It returns
|
|
155
|
-
`details` `{ issue }`; creating an issue does not subscribe you to it (see [Following](#following)). Use `dispatch_issue` only to create an issue; never use it to park a question. When `spec` is supplied,
|
|
152
|
+
Create an issue for newly tracked work with `dispatch issue --project <KEY> --title '<title>'` (`dispatch issue --help` lists `--parent`, `--spec-file`, `--label`, `--priority` and the rest).
|
|
153
|
+
Labels are optional: Dispatch trims them, preserves their case, and removes case-insensitive duplicates. `--priority` is yours on creation too — see [Priority is yours to set](skill://dispatch/references/issues.md). Set `--assignee` (the email of a person who has signed in to Dispatch) only when the human said who owns the work; otherwise the default above applies, so a child inherits its parent's assignee. It prints
|
|
154
|
+
the new key; creating an issue does not subscribe you to it (see [Following](#following)). Use `dispatch issue` only to create an issue; never use it to park a question. When you pass a spec,
|
|
156
155
|
follow [Writing a spec](#writing-a-spec).
|
|
157
156
|
|
|
158
157
|
## Search first
|
|
159
158
|
|
|
160
159
|
`skill://dispatch-first`, which every session with Dispatch carries, says how to search before
|
|
161
160
|
you plan, start a design document, file an issue, ask, post a finding or start work, and what to
|
|
162
|
-
do with each hit. What it leaves out:
|
|
163
|
-
```ts
|
|
164
|
-
dispatch_search({ query, project?, limit?, offset? })
|
|
165
|
-
```
|
|
161
|
+
do with each hit. What it leaves out (`dispatch search --help` has `--project`, `--limit` and `--offset`):
|
|
166
162
|
Websearch syntax applies: `"merge queue"`, `-daemon`, `OR`. Issues, documents, asks, comments, and messages rank separately; the
|
|
167
163
|
merged page orders each kind's best in turn — issue, document, ask, comment, message — and a bare issue key ranks first. Each
|
|
168
164
|
kind's list also merges a query embedding's meaning match with keyword hits (LEGION-549): a paraphrase with no shared word can
|
|
169
|
-
still match; without an embedder, it says so and ranks by keyword alone. A page holds
|
|
165
|
+
still match; without an embedder, it says so and ranks by keyword alone. A page holds `--limit` hits (20 default, 50 max); the first
|
|
170
166
|
line gives the total (`showing 1-20 of 312`); see [Search paging](skill://dispatch/references/issues.md#search-paging) for more.
|
|
171
167
|
Queries over 1,000 characters are refused: use the few words `skill://dispatch-first` names, never a pasted passage. Issue hits
|
|
172
168
|
start with the issue key; document hits start with `dispatch://PROJECT/artifact/<slug>`, then the link. Cite the hit (`dispatch://KEY` or the doc ref) or say "no prior issue".
|
|
173
169
|
|
|
174
|
-
`
|
|
170
|
+
`dispatch issue` refuses a title that near-duplicates an issue in the same project and prints the candidates (`POSSIBLE_DUPLICATE`). Read them; reference the existing issue, or run it again with `--force` when it is genuinely new work.
|
|
175
171
|
The check compares title words only (shared stemmed terms), never meaning: "four tests that fail a
|
|
176
172
|
merge" pairs with "four CI gates that cannot fail a merge". So when you force past a candidate, give
|
|
177
173
|
the new issue a title that names what differs where you can, and open its spec with the
|
|
@@ -189,9 +185,9 @@ is the tell.
|
|
|
189
185
|
|
|
190
186
|
Before you start implementing an issue, claim it, and release the claim when you stop: finished,
|
|
191
187
|
handing over, or moving to something else. Closing the issue releases it for you.
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
```bash
|
|
189
|
+
dispatch claim --issue LEGION-234 # I am implementing this
|
|
190
|
+
dispatch claim --issue LEGION-234 --release # I have stopped; it is free
|
|
195
191
|
```
|
|
196
192
|
A claim is intent to implement: reading, commenting, asking, or gating a pull request claims
|
|
197
193
|
nothing. `409 ISSUE_CLAIMED` means someone else holds the issue; never work it in parallel. What
|
|
@@ -201,10 +197,10 @@ each refusal means, and when a claim is yours to take, is in
|
|
|
201
197
|
## Issue status is yours to move
|
|
202
198
|
|
|
203
199
|
Claiming and moving the status are two actions, and you do both: when you start,
|
|
204
|
-
`
|
|
200
|
+
`dispatch claim --issue <KEY>` and `dispatch issue-update --issue <KEY> --status in_progress`. Outside
|
|
205
201
|
Legion the session doing the work moves its issue and the children it owns: `in_progress` when
|
|
206
202
|
implementation starts, `testing` while the change is proven on a production-like surface,
|
|
207
|
-
`needs_review` when its pull request waits on the merge queue, and `done`, with a
|
|
203
|
+
`needs_review` when its pull request waits on the merge queue, and `done`, with a `--reason`, once
|
|
208
204
|
the change has been driven in production. Never write the status of an issue that carries the
|
|
209
205
|
`legion` label, or of any issue under one: the Legion daemon writes those. Closing, clearing a
|
|
210
206
|
field, and choosing your next issue are in [Working an issue](skill://dispatch/references/issues.md).
|
|
@@ -216,11 +212,11 @@ block in that document ([Decision blocks](#decision-blocks)), whatever phase the
|
|
|
216
212
|
whether or not the document was approved: a block in an approved document makes the approval
|
|
217
213
|
stale, which is right. A Legion phase worker sends such a decision to its architect, which writes
|
|
218
214
|
the block (`skill://legion-worker`). A to-do or permission only a human can give, or a decision
|
|
219
|
-
with no document to live in, is a `
|
|
215
|
+
with no document to live in, is a `dispatch ask`. The gates below apply to both.
|
|
220
216
|
|
|
221
217
|
### Before you ask
|
|
222
218
|
|
|
223
|
-
Every `
|
|
219
|
+
Every `dispatch ask` passes four gates first:
|
|
224
220
|
|
|
225
221
|
1. **Does it need his authority, taste, or risk appetite?** This is the bar for a decision
|
|
226
222
|
written as an `:::ask` block in context ([Decision blocks](#decision-blocks)). Technical
|
|
@@ -228,7 +224,7 @@ Every `dispatch_ask` passes four gates first:
|
|
|
228
224
|
internals are your lane's to decide where the work happens, in the plan or the code, not in the
|
|
229
225
|
spec. A contract between two lanes is settled by those two lanes over Envoy, and you open no ask
|
|
230
226
|
for it. A halt condition (a change to IAM, deletion or exposure of production data, anything
|
|
231
|
-
that reaches a customer) passes this gate: it is your own `
|
|
227
|
+
that reaches a customer) passes this gate: it is your own `dispatch ask` to the human on your own
|
|
232
228
|
issue.
|
|
233
229
|
2. **Is there genuine uncertainty, and have you measured what you can?** If there is none, it is
|
|
234
230
|
a plan you execute. The one legitimate ask without uncertainty is permission for an action
|
|
@@ -245,7 +241,7 @@ Every `dispatch_ask` passes four gates first:
|
|
|
245
241
|
Report what the measurement could **not** establish, with its own control: "I found no
|
|
246
242
|
evidence" and "there is no evidence to find" read alike and mean opposite things, and a
|
|
247
243
|
control that shares the query's blind spot proves neither. Before you say you are waiting on
|
|
248
|
-
him, run `
|
|
244
|
+
him, run `dispatch open-asks` (below) — and the test for a new ask is not whether you asked on
|
|
249
245
|
this issue before, but whether it asks him to re-report something he has already answered.
|
|
250
246
|
3. **Can someone who has not read the code answer it on a phone?** Write it as
|
|
251
247
|
[Writing for the human](#writing-for-the-human) says — who can do what today and what changes
|
|
@@ -268,35 +264,27 @@ Every `dispatch_ask` passes four gates first:
|
|
|
268
264
|
Nobody audits or retracts another session's asks: passing every gate, and carrying the content
|
|
269
265
|
instead of pointing at another message in prose (below), is the asking session's own check.
|
|
270
266
|
|
|
271
|
-
Open a standalone ask with:
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
artifact?,
|
|
277
|
-
ref?,
|
|
278
|
-
question,
|
|
279
|
-
options?: { label, description? }[],
|
|
280
|
-
multiple?,
|
|
281
|
-
urgency?,
|
|
282
|
-
anchor?: { artifact, quote, occurrence? },
|
|
283
|
-
})
|
|
267
|
+
Open a standalone ask with `dispatch ask` (`dispatch ask --help` lists its flags), one `--option` per choice:
|
|
268
|
+
```bash
|
|
269
|
+
dispatch ask --issue <KEY> --question-file - --option 'Label: what it costs' --option 'Other: what it costs' <<'EOF'
|
|
270
|
+
<the problem, what constrains the answer, and your recommendation with its reason>
|
|
271
|
+
EOF
|
|
284
272
|
```
|
|
285
|
-
It
|
|
273
|
+
It prints the ask's id; you follow the ask you opened (see [Following](#following)).
|
|
286
274
|
|
|
287
|
-
References belong in the question text;
|
|
275
|
+
References belong in the question text; `--ref` is sugar that appends its `dispatch://` value to the question as a rendered link.
|
|
288
276
|
|
|
289
277
|
An ask is read on a phone by someone who has not read the code. Write its question and options as
|
|
290
278
|
[Writing for the human](#writing-for-the-human) says, and apply its phone test before posting.
|
|
291
279
|
Never lead a question with a file path, line number, sequence number, document version or role token: its own text explains the problem.
|
|
292
|
-
Evidence below it may cite one where the reader checks it, or anchor the ask to the passage with
|
|
280
|
+
Evidence below it may cite one where the reader checks it, or anchor the ask to the passage with `--anchor-json '{"artifact":"spec","quote":"…"}'`; an optional `occurrence` is zero-based and selects a repeated quote.
|
|
293
281
|
A quote anchor is pinned to its lowest complete
|
|
294
282
|
containing block while retaining its quote as display text, so rewording the passage keeps it
|
|
295
283
|
attached; a quote spanning top-level blocks, and existing anchors without a block, stay readable
|
|
296
284
|
against their original document version if their quote disappears.
|
|
297
285
|
|
|
298
286
|
An ask must be answerable from its own text and its anchor alone. Anchor a to-do about a document
|
|
299
|
-
passage with
|
|
287
|
+
passage with `--anchor-json`. Follow up on an ask or comment with `dispatch comment`; cite anything else
|
|
300
288
|
with a `dispatch://` reference (see [References](#references)). Never write "see above", "the
|
|
301
289
|
message above", or "as attached".
|
|
302
290
|
|
|
@@ -321,20 +309,20 @@ they must read to decide belongs in the spec in the first place — see [Artifac
|
|
|
321
309
|
|
|
322
310
|
### When you need a human
|
|
323
311
|
|
|
324
|
-
Before saying you are waiting for human input,
|
|
312
|
+
Before saying you are waiting for human input, run `dispatch open-asks`. With no flags it lists this session's active asks across open issues and project documents, including whether the human or agent owes the next reply. With `dispatch open-asks --project <KEY>` it lists every open ask in that project — on its issues and on its documents, whoever authored them — which is how you see what a whole project is waiting on rather than just your own asks.
|
|
325
313
|
|
|
326
314
|
**Unsettled product shape needs a decision before implementation.** When a page, navigation entry, table key, customer-scoping rule, or persisted sidecar would set product shape that the human has not already settled, write a decision block in the document that records the work before the first implementation commit; in a Legion tree the architect writes it, and a phase worker sends the decision to its architect. A lane's schema decision or a contract two lanes agree does not settle product shape. This does not turn a user-specified decision or routine implementation into an approval request. A control or behaviour the human asked for in words is settled by those words, together with every choice inside it that his words do not make (where it sits, its defaults, …
|
|
327
315
|
|
|
328
316
|
**Anything you are blocked on a human for is visible in Dispatch.** An agent waits on a human only
|
|
329
317
|
through an open ask. A to-do, permission, credential or grant renewal, setting only they can
|
|
330
|
-
change, review click, or conflict between two of their own rules is a `
|
|
318
|
+
change, review click, or conflict between two of their own rules is a `dispatch ask` the moment you
|
|
331
319
|
know. Start with the problem and why it matters, then the constraints, options and their costs, and
|
|
332
320
|
your recommendation. For an action only the human can perform, state what it changes and risks;
|
|
333
321
|
never make the action itself the question (a design decision is a decision block, as above). Never
|
|
334
322
|
write a human to-do only into a spec, a comment reply, a message, or a pull-request body: nothing
|
|
335
323
|
in those paths reaches the human's Inbox, and a human who is not reading the document does not
|
|
336
324
|
know they are the blocker. Before asking, try to remove the step: a value already on the machine, a
|
|
337
|
-
permission you already hold, an API that replaces the click. One ask per item,
|
|
325
|
+
permission you already hold, an API that replaces the click. One ask per item, `--urgency high`
|
|
338
326
|
when work is stopped on it; while it is open, keep working on everything that is not.
|
|
339
327
|
|
|
340
328
|
Once an ask is open (who answers it, handing a human a to-do, editing, retracting or resolving it,
|
|
@@ -345,32 +333,32 @@ answering a clarification, whose turn a reply gives, an answer the human changes
|
|
|
345
333
|
|
|
346
334
|
Attach every architectural issue to the components it changes. Attach the root before decomposing it: children inherit the root's effective attachment unless they deliberately set their own, so one root attachment classifies the whole tree.
|
|
347
335
|
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
336
|
+
```bash
|
|
337
|
+
dispatch issue --project CORE --title '...' --components-json '{"mode":"explicit","ids":["dispatch-server","web"]}'
|
|
338
|
+
dispatch issue-update --issue CORE-12 --components-json '{"mode":"explicit","ids":["web"]}' # its own set, replacing what it inherited
|
|
339
|
+
dispatch issue-update --issue CORE-13 --components-json '{"mode":"none","reason":"hiring, not code"}'
|
|
340
|
+
dispatch issue-update --issue CORE-14 --components-json '{"mode":"inherit"}' # back to the parent chain's attachment
|
|
353
341
|
```
|
|
354
342
|
|
|
355
|
-
No
|
|
343
|
+
No `dispatch` command lists component ids. Read the configured model with `GET /api/v1/projects/{key}/architecture` and use each non-external `components[].id`; when its source repository is your checkout, those ids are the file names under `.dispatch/architecture/` (`web.md` → `web`). An id absent from the model, or an `external` component, is refused with `COMPONENTS_INPUT`.
|
|
356
344
|
|
|
357
|
-
Use `mode:
|
|
345
|
+
Use `"mode":"none"` with a concrete reason only when the work is genuinely non-architectural (for example hiring, process, or operations work). A closed issue can be classified without reopening. Change code and its architecture description (`.dispatch/architecture/<id>.md`) in the same review. When the model you read is behind your checkout, `dispatch architecture-sync` imports it now ([Syncing a project's architecture model](skill://dispatch/references/issues.md)).
|
|
358
346
|
|
|
359
347
|
## Close what you opened
|
|
360
348
|
|
|
361
349
|
An ask you opened is yours until it is answered or you resolve it. When the answer arrives some
|
|
362
350
|
other way — the human said it live, a later comment settled it, or the question became moot because the
|
|
363
|
-
design moved — resolve it yourself with `
|
|
351
|
+
design moved — resolve it yourself with `dispatch resolve-ask` in the same turn you learn that.
|
|
364
352
|
Never leave it for the human to clear.
|
|
365
353
|
|
|
366
354
|
Every later write on the issue answers `You still have an open ask on …` and names it. Treat that
|
|
367
355
|
as the checklist: if it is still needed, leave it; if it was answered elsewhere, resolve it with
|
|
368
356
|
the resolving fact as the reason. Before posting a new ask, inspect your open ones. If the new ask
|
|
369
|
-
supersedes one, retract the old one with `
|
|
357
|
+
supersedes one, retract the old one with `dispatch resolve-ask --kind retracted` in the same
|
|
370
358
|
turn.
|
|
371
359
|
|
|
372
360
|
See [Following](#following) for why you receive what happens to asks you open and
|
|
373
|
-
[What comes back](skill://dispatch/references/reading.md) for finding them again with `
|
|
361
|
+
[What comes back](skill://dispatch/references/reading.md) for finding them again with `dispatch open-asks`.
|
|
374
362
|
|
|
375
363
|
## Approval of a spec
|
|
376
364
|
|
|
@@ -387,40 +375,38 @@ hold (`skill://legion-architect`).
|
|
|
387
375
|
When all three hold, request it in the pass that finishes the spec: a design waiting with nothing in
|
|
388
376
|
the human's Inbox waits on nobody. When a human asks for approval while a block is open, do not
|
|
389
377
|
request it and do not hold it silently: name each open block and ask them to answer it or waive
|
|
390
|
-
it. For a waiver, close the block with `
|
|
391
|
-
|
|
392
|
-
`
|
|
378
|
+
it. For a waiver, close the block with `dispatch resolve-ask --kind resolved` (their words as
|
|
379
|
+
`--reason`), then write their decision into the text in their words and request.
|
|
380
|
+
`dispatch request-approval` refuses while any block is open.
|
|
393
381
|
|
|
394
382
|
An approval request carries nothing new: a point the human has not agreed to gets its own decision
|
|
395
383
|
block first, with your recommendation, or, when it is a choice you can make yourself
|
|
396
384
|
([Before you ask](#before-you-ask), gate 1) and the human will not want a say in it, comes out of
|
|
397
385
|
the spec and is made where the work happens; an inference you cannot defend in a decision block
|
|
398
|
-
comes out of the spec.
|
|
386
|
+
comes out of the spec. `--summary` says in one to three sentences what the human is approving and
|
|
399
387
|
nothing else: no commentary on itself or on the conversation, and no open question. The Inbox
|
|
400
388
|
shows it after "Approve spec.md (version N)?". Never write "Approve" options into an ordinary
|
|
401
|
-
`
|
|
389
|
+
`dispatch ask`; only humans approve. The call, its result and its answer:
|
|
402
390
|
[Approval requests](skill://dispatch/references/documents.md#approval-requests).
|
|
403
391
|
|
|
404
392
|
## The Spec
|
|
405
393
|
|
|
406
394
|
The spec holds the design and the decisions that shaped it, written as [Writing a spec](#writing-a-spec)
|
|
407
395
|
says, which also lists what it never carries. It changes when the conversation changes it, and
|
|
408
|
-
every version that records a decision is named with `
|
|
396
|
+
every version that records a decision is named with `dispatch doc-edit --summary`.
|
|
409
397
|
|
|
410
|
-
Read the current document before changing it
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
```
|
|
415
|
-
It returns live or versioned markdown with open marks. A live read ends with a document token; `issue` with an omitted
|
|
416
|
-
`artifact` reads the issue specification; a project needs `artifact`; and a `dispatch://PROJECT/artifact/<document-ref>`
|
|
398
|
+
Read the current document before changing it with `dispatch doc-read` (`--issue`, or `--project`
|
|
399
|
+
and `--artifact`, an optional `--version`, or `--ref`).
|
|
400
|
+
It prints live or versioned markdown with open marks. A live read ends with a document token; `--issue` with no
|
|
401
|
+
`--artifact` reads the issue specification; a project needs `--artifact`; and a `dispatch://PROJECT/artifact/<document-ref>`
|
|
417
402
|
ref supplies both, where `document-ref` is the slug (an id or a filename resolves when no document has that slug). A file
|
|
418
|
-
`
|
|
419
|
-
A picture (PNG, JPEG, GIF or WebP under 3,750,000 bytes, 5 MB of base64)
|
|
420
|
-
|
|
421
|
-
|
|
403
|
+
`dispatch artifact` uploaded reads its text at the latest or named version, or a description when it is not UTF-8 text.
|
|
404
|
+
A picture (PNG, JPEG, GIF or WebP under 3,750,000 bytes, 5 MB of base64) is written to a file, and the command prints a
|
|
405
|
+
`- picture: <path>` line with its type and size: open it with your file-read tool. That includes
|
|
406
|
+
`dispatch://agent/<session id>/artifact/<slug>@vN`, one a person sent you on the Agents page. A session is shown each picture once,
|
|
407
|
+
since the provider refuses a request over 32 MB: later reads and deliveries name it, and `dispatch doc-read` shows it again (after compaction too).
|
|
422
408
|
|
|
423
|
-
Editing one is [Editing a document](skill://dispatch/references/document-edits.md): the shape of `
|
|
409
|
+
Editing one is [Editing a document](skill://dispatch/references/document-edits.md): the shape of `dispatch doc-edit`,
|
|
424
410
|
how to quote the text you mean, one `replace` per paragraph, preconditions against a stale edit, and
|
|
425
411
|
what each operation costs a block's id and its anchors.
|
|
426
412
|
|
|
@@ -435,12 +421,12 @@ as [Documents](skill://dispatch/references/documents.md) says.
|
|
|
435
421
|
a summary — goes in the spec as a section: the spec is the one document they open. A separate
|
|
436
422
|
artifact is for a real file: something sent as-is, a long report, a binary, a screenshot.
|
|
437
423
|
|
|
438
|
-
When you do upload one, the spec links it as `dispatch://KEY/artifact/<slug>` (the
|
|
439
|
-
upload
|
|
424
|
+
When you do upload one, the spec links it as `dispatch://KEY/artifact/<slug>` (the slug the
|
|
425
|
+
upload prints; it renders as a link) at the place the reader needs it, and the ask that needs the
|
|
440
426
|
decision carries the same reference. A heading or a sentence naming the filename is not a
|
|
441
427
|
reference.
|
|
442
428
|
|
|
443
|
-
Uploading one (`
|
|
429
|
+
Uploading one (`dispatch artifact`, its slugs, versions and Markdown rules) is in
|
|
444
430
|
[Documents](skill://dispatch/references/documents.md).
|
|
445
431
|
|
|
446
432
|
## Structure over stream
|
|
@@ -454,12 +440,12 @@ Dispatch is a structured workspace, never a message stream. The structure IS the
|
|
|
454
440
|
document, or an artifact on the issue it belongs to.
|
|
455
441
|
- **Content lives in documents; decisions live in asks; messages only announce.** A draft the
|
|
456
442
|
human must read goes in the issue's spec (see [Artifacts](#artifacts)), which the dashboard renders with versions and margins; the
|
|
457
|
-
ask that needs their word references it (
|
|
443
|
+
ask that needs their word references it (`--ref`, or the `dispatch://` link inline) instead of
|
|
458
444
|
restating it. A message never carries a body a human has to scroll.
|
|
459
445
|
- **Never split one deliverable across a message + an ask that points at it.** Ask the question
|
|
460
446
|
with the document reference in the question text; the reader lands on the content in one click.
|
|
461
447
|
|
|
462
|
-
The
|
|
448
|
+
The command answers your third consecutive message on an issue with no human reply with
|
|
463
449
|
`You've sent N messages …`. That is the ledger pattern being named; stop and either wait or ask
|
|
464
450
|
once.
|
|
465
451
|
|
|
@@ -470,15 +456,17 @@ change a human must know about now: a deliverable landed. Nothing else — no pr
|
|
|
470
456
|
"starting X", no "still working", no restating the spec, no status on a timer. Your transcript is where work is narrated; the
|
|
471
457
|
pull request is where it is summarised. One message that a human reads beats ten that train them to skip you.
|
|
472
458
|
|
|
473
|
-
```
|
|
474
|
-
|
|
459
|
+
```bash
|
|
460
|
+
dispatch message --issue <KEY> --body-file - <<'EOF'
|
|
461
|
+
<what landed, with its link>
|
|
462
|
+
EOF
|
|
475
463
|
```
|
|
476
464
|
|
|
477
|
-
|
|
478
|
-
(a decision block, or `
|
|
465
|
+
The body is capped at 2,000 characters. A message is not a decision
|
|
466
|
+
(a decision block, or `dispatch ask` for a human to-do) or document feedback (`dispatch comment`), and it does not wake anyone unless the issue is routed.
|
|
479
467
|
|
|
480
|
-
**Pictures.** To show a screenshot inline, pass its path
|
|
481
|
-
`
|
|
468
|
+
**Pictures.** To show a screenshot inline, pass its path with `--image` (`dispatch message`, `dispatch comment`, `dispatch ask`);
|
|
469
|
+
`dispatch read` writes the pictures what it shows embeds to files and prints their paths. Both are in [Documents](skill://dispatch/references/documents.md), "Artifacts".
|
|
482
470
|
|
|
483
471
|
A BTW, Aside or Steer frame, or a message from the Agents page, is answered as
|
|
484
472
|
[Targeted and direct messages](skill://dispatch/references/messages.md) says.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Authentication and the HTTP API
|
|
2
2
|
|
|
3
|
-
`skill://dispatch` sends you here when you set up a Dispatch token, or need a route the
|
|
4
|
-
not cover.
|
|
3
|
+
`skill://dispatch` sends you here when you set up a Dispatch token, or need a route the `dispatch`
|
|
4
|
+
commands do not cover.
|
|
5
5
|
|
|
6
6
|
## Agent authentication
|
|
7
7
|
|
|
@@ -19,7 +19,7 @@ is the callback registered on the sign-in pool's app client
|
|
|
19
19
|
|
|
20
20
|
### Finding a route
|
|
21
21
|
|
|
22
|
-
The
|
|
22
|
+
The `dispatch` commands cover the everyday surface. For anything else, ask the server: `GET /api/v1` (no
|
|
23
23
|
credential) returns every route as `{method, path, auth, description}` sorted by path — `auth`
|
|
24
24
|
is `public`, `any` (a human or a bearer), `human` (a bearer gets `403 HUMAN_ONLY`), or `bearer`.
|
|
25
25
|
A path Dispatch does not serve under `/api` or `/v1` answers
|
|
@@ -33,7 +33,7 @@ every issue your filters match. Walking the pages with the next `offset` is exac
|
|
|
33
33
|
listing does not change: an issue that enters or leaves what the filters match, or whose status or
|
|
34
34
|
rank changes, between two reads shifts rows across a page boundary, and one issue comes back twice
|
|
35
35
|
and another never, even when you stop at `total`. The unpaged array is the only exact set one read
|
|
36
|
-
gives. `cursor` is `400 INVALID_QUERY`. `
|
|
36
|
+
gives. `cursor` is `400 INVALID_QUERY`. `dispatch issues` pages for you.
|
|
37
37
|
The event logs page with `after` or `before` and `limit`, and `GET /api/v1/search` takes a `limit`
|
|
38
38
|
of at most 50 and has no next page. Every other route answers without paging and ignores a paging
|
|
39
39
|
parameter.
|
|
@@ -7,11 +7,8 @@ thread. Whether to ask at all, and how to write the question, is "Before you ask
|
|
|
7
7
|
|
|
8
8
|
## Who answers an ask
|
|
9
9
|
|
|
10
|
-
An ask goes to the issue's assignee: their Inbox opens on **Mine**, which lists asks on the issues they hold plus an Unassigned band; an ask on an unassigned issue waits in that band for someone to take it. Find out who Dispatch takes you for with
|
|
11
|
-
|
|
12
|
-
dispatch_whoami({})
|
|
13
|
-
```
|
|
14
|
-
It returns `details` `{ session, owner, service }`: `owner` is the lowercase email of the person whose personal token you run under, or `null` under the shared token or a verified service token, in which case `service` is that token's subject (`system:serviceaccount:<namespace>:<name>`, `null` otherwise) and every write you make is rendered `(as <namespace>/<name>)` — the namespace is kept because every namespace has a `default` service account, and a subject that is not a Kubernetes one is shown whole. An issue you create without `assignee` goes to your owner; with no owner it inherits its parent's assignee, or stays unassigned without a parent. If an issue you are asking on is unassigned and the answer matters, assign it to your owner (`PATCH /api/v1/issues/{key}` with `{"assignee": "<email>"}`; any authenticated caller may reassign, and an email nobody has signed in with is refused with `ASSIGNEE_NOT_ALLOWED`) or name in the question who should answer it. Never reassign an issue a human holds to get an answer faster: that is the human's call.
|
|
10
|
+
An ask goes to the issue's assignee: their Inbox opens on **Mine**, which lists asks on the issues they hold plus an Unassigned band; an ask on an unassigned issue waits in that band for someone to take it. Find out who Dispatch takes you for with `dispatch whoami`.
|
|
11
|
+
It prints whom the session acts for: the lowercase email of the person whose personal token you run under, or, under the shared token or a verified service token, that it has no owner — naming the service as `<namespace>/<name>` for a service token (`system:serviceaccount:<namespace>:<name>`), which is also how every write you make is rendered (`(as <namespace>/<name>)`) — the namespace is kept because every namespace has a `default` service account, and a subject that is not a Kubernetes one is shown whole. An issue you create without `--assignee` goes to your owner; with no owner it inherits its parent's assignee, or stays unassigned without a parent. If an issue you are asking on is unassigned and the answer matters, assign it to your owner (`PATCH /api/v1/issues/{key}` with `{"assignee": "<email>"}`; any authenticated caller may reassign, and an email nobody has signed in with is refused with `ASSIGNEE_NOT_ALLOWED`) or name in the question who should answer it. Never reassign an issue a human holds to get an answer faster: that is the human's call.
|
|
15
12
|
|
|
16
13
|
## Handing a human a to-do, editing, resolving, and replying
|
|
17
14
|
|
|
@@ -20,41 +17,28 @@ A to-do handed to a human still follows the question and options contract that `
|
|
|
20
17
|
answer. There is no fixed vocabulary and the server treats no label specially.
|
|
21
18
|
If an outcome needs a reason, say so in that option's description, and the human's free-text answer
|
|
22
19
|
carries it:
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
options: [
|
|
29
|
-
{ label: "Deploy the verified fix", description: "Restores the fix but can expose a deployment problem." },
|
|
30
|
-
{ label: "Hold the deploy", description: "Avoids a production change now but leaves production without the fix." },
|
|
31
|
-
],
|
|
32
|
-
})
|
|
20
|
+
```bash
|
|
21
|
+
dispatch ask --issue DSP-42 \
|
|
22
|
+
--question 'The verified fix remains unavailable in production because deployment is pending. Deploying changes production and could expose a deployment problem. How should we proceed? Recommendation: deploy the verified fix now because it restores the intended behavior.' \
|
|
23
|
+
--option 'Deploy the verified fix: Restores the fix but can expose a deployment problem.' \
|
|
24
|
+
--option 'Hold the deploy: Avoids a production change now but leaves production without the fix.'
|
|
33
25
|
```
|
|
34
26
|
|
|
35
|
-
Correct or refine an open ask in place instead of opening a second question
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ask,
|
|
39
|
-
question?,
|
|
40
|
-
options?: { label, description? }[],
|
|
41
|
-
multiple?,
|
|
42
|
-
urgency?,
|
|
43
|
-
})
|
|
44
|
-
```
|
|
45
|
-
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
|
|
27
|
+
Correct or refine an open ask in place instead of opening a second question, with
|
|
28
|
+
`dispatch edit-ask --ask <id>` and any of `--question`, `--option` (repeated), `--multiple` and `--urgency`.
|
|
29
|
+
At least one of them is required. Use this only while the same decision remains open: it keeps the prior text in the event
|
|
46
30
|
log and invalidates any answer draft against the prior `edited_at` revision, so the human sees the new wording and explicitly reconfirms.
|
|
47
31
|
An answered or resolved ask cannot be edited. If the decision is moot or superseded, retract the old ask and open a new one.
|
|
48
32
|
A human can change an answer they gave. The change arrives as another `ask.answered` frame whose
|
|
49
33
|
`previous_answer` names the answer it replaced, through the same route the first answer took, and
|
|
50
|
-
`
|
|
34
|
+
`dispatch read --ref dispatch://KEY/ask/<id>` lists every earlier answer. Act on the newest answer.
|
|
51
35
|
|
|
52
|
-
An ask that lives as an `ask` block in a document keeps its question and options in the block, and `
|
|
53
|
-
block along with the row, so the edit stands and the document reads the same. It changes only the fields you name: pass
|
|
54
|
-
alone and the question's own wording, formatting, links and comment anchors are untouched. Pass
|
|
36
|
+
An ask that lives as an `ask` block in a document keeps its question and options in the block, and `dispatch edit-ask` writes the
|
|
37
|
+
block along with the row, so the edit stands and the document reads the same. It changes only the fields you name: pass `--urgency`
|
|
38
|
+
alone and the question's own wording, formatting, links and comment anchors are untouched. Pass `--question` or `--option` and that part
|
|
55
39
|
is rewritten, so anchors inside the text you replaced move as they would for any document edit. Either way it is a document edit: it
|
|
56
40
|
writes a new version, which on a spec awaiting approval closes the design gate until the new version is approved. Editing the block
|
|
57
|
-
with `
|
|
41
|
+
with `dispatch doc-edit` works too and is the way to change anything else about it, including adding formatting to a question.
|
|
58
42
|
Re-sending a field unchanged rewrites nothing, so retrying the whole ask is safe.
|
|
59
43
|
Text the block cannot carry back unchanged is refused outright, naming the field and writing nothing - an option label containing
|
|
60
44
|
`": "`, the separator between a label and its description, is one example of text that cannot survive the round trip. Blank lines separate paragraphs;
|
|
@@ -62,51 +46,47 @@ a single newline is kept as a line break.
|
|
|
62
46
|
|
|
63
47
|
An ask stays open until a human answers, unless its question no longer needs that answer. Retract a moot or superseded question, or
|
|
64
48
|
self-resolve one after finding the answer:
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
ask,
|
|
68
|
-
kind: "retracted",
|
|
69
|
-
reason: "A newer ask supersedes this question.",
|
|
70
|
-
})
|
|
49
|
+
```bash
|
|
50
|
+
dispatch resolve-ask --ask <id> --kind retracted --reason 'A newer ask supersedes this question.'
|
|
71
51
|
```
|
|
72
52
|
Use `retracted` when the question is obsolete and `resolved` when you found the answer. Include the reason because the question remains
|
|
73
53
|
in its Conversation card and reply thread; a reason beginning `removed from the document in version` is refused, because that is how a
|
|
74
54
|
retraction the document's own settlement wrote is recognised. Resolving a block ask records it in the block too, so it stays resolved
|
|
75
|
-
however the document moves afterwards. `
|
|
76
|
-
whole-document `
|
|
77
|
-
resolved. A human may reply to an open or answered ask; so may you, e.g. after finding the answer — use `
|
|
78
|
-
`
|
|
79
|
-
A review comment you opened has its own closer, `
|
|
55
|
+
however the document moves afterwards. `dispatch doc-edit` refuses deleting the block of an open ask; a block removed another way, by a
|
|
56
|
+
whole-document `dispatch artifact` replace or by a person in the browser, closes its ask, and putting the block back reopens it. Resolution is not an answer: it never records a human decision, and an answered ask cannot be
|
|
57
|
+
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
|
|
58
|
+
`dispatch comment` (mutually exclusive with `--reply-to`).
|
|
59
|
+
A review comment you opened has its own closer, `dispatch resolve-comment` — see
|
|
80
60
|
[Comments and suggestions](skill://dispatch/references/documents.md).
|
|
81
61
|
|
|
82
62
|
A human answers or asks back from the same field; a question-shaped free-text answer is offered as a clarification first. A human
|
|
83
63
|
reply while your ask is still open (the delivered `comment.created` carries `ask_state: open`) is a request for clarification, not
|
|
84
64
|
an answer: the human did not understand the question or needs more before choosing. The ask now waits on you in their Inbox. Answer
|
|
85
|
-
in the same thread with `
|
|
65
|
+
in the same thread with `dispatch comment --reply-to-ask <id>`, or reword the question itself with `dispatch edit-ask` when the wording
|
|
86
66
|
was the problem; either puts the ask back in front of them. Do not open a second ask.
|
|
87
67
|
|
|
88
68
|
Every reply to an open ask says whose turn it is next, and the Inbox files the ask by that, not by who spoke last. Your plain reply
|
|
89
|
-
(
|
|
69
|
+
(`--turn` omitted, or `--turn human`) hands the turn to the human: the ask returns to their `Waiting on you`. When you are not done
|
|
90
70
|
yet — "dispatched two auditors, back with results", "checking the release branch, back shortly", any working-on-it note — reply with
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
turn to you. The
|
|
71
|
+
`--turn agent`: the note lands in the thread, the ask stays under `Waiting on agents`, and the human is not told to act. Use
|
|
72
|
+
`--turn agent` for every progress note and `--turn human` (the default) only when you need them. A human's reply always hands the
|
|
73
|
+
turn to you. The output names the state (`ask now waiting on agent` / `human`), the delivered `comment.created` carries it as
|
|
94
74
|
`ask_waiting_on`, and every ask read carries it as `waiting_on`.
|
|
95
75
|
|
|
96
76
|
## Following
|
|
97
77
|
|
|
98
78
|
An ask has followers: every session that wrote to it — the session that opened it and every session that replied with
|
|
99
|
-
`
|
|
79
|
+
`dispatch comment --reply-to-ask` — plus any session a human adds from the ask card. The ask's answer, edits, resolution, and
|
|
100
80
|
every reply on it reach each follower's own agent topic directly, whether or not the writer was a human and whatever the issue's
|
|
101
|
-
route. The
|
|
102
|
-
|
|
81
|
+
route. The output says so (`You follow this ask: its answer and replies reach you directly.`) once per ask.
|
|
82
|
+
Leave a thread you no longer need, or rejoin one, with:
|
|
103
83
|
|
|
104
|
-
```
|
|
105
|
-
|
|
84
|
+
```bash
|
|
85
|
+
dispatch follow --ask <id> --action unfollow # or --action follow
|
|
106
86
|
```
|
|
107
87
|
|
|
108
|
-
|
|
109
|
-
`
|
|
88
|
+
`--ask` is the full ask id or a `dispatch://KEY/ask/<id>` reference; `dispatch follow`, `dispatch edit-ask`, and
|
|
89
|
+
`dispatch resolve-ask` also take an 8+ hex prefix that is unique among your own open asks, and refuse anything shorter by naming
|
|
110
90
|
those asks. A human may also remove you from the ask card; either way you are
|
|
111
91
|
told with an `ask.follower_removed` notice, and a human adding you arrives as `ask.follower_added`.
|
|
112
92
|
|