@sjawhar/opencode-legion-envoy 6.4.2 → 6.5.1

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.
@@ -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
- ```ts
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
- ```ts
24
- dispatch_ask({
25
- issue: "DSP-42",
26
- question:
27
- "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.",
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
- ```ts
37
- dispatch_edit_ask({
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
- `dispatch_read` of the ask lists every earlier answer. Act on the newest answer.
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 `dispatch_edit_ask` writes the
53
- block along with the row, so the edit stands and the document reads the same. It changes only the fields you name: pass `urgency`
54
- alone and the question's own wording, formatting, links and comment anchors are untouched. Pass `question` or `options` and that part
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 `dispatch_doc_edit` works too and is the way to change anything else about it, including adding formatting to a question.
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
- ```ts
66
- dispatch_resolve_ask({
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. `dispatch_doc_edit` refuses deleting the block of an open ask; a block removed another way, by a
76
- 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
77
- 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
78
- `dispatch_comment` (mutually exclusive with `reply_to`).
79
- A review comment you opened has its own closer, `dispatch_resolve_comment` — see
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 `dispatch_comment({ reply_to_ask })`, or reword the question itself with `dispatch_edit_ask` when the wording
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
- (`turn` omitted, or `turn: "human"`) hands the turn to the human: the ask returns to their `Waiting on you`. When you are not done
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
- `turn: "agent"`: the note lands in the thread, the ask stays under `Waiting on agents`, and the human is not told to act. Use
92
- `turn: "agent"` for every progress note and `turn: "human"` (the default) only when you need them. A human's reply always hands the
93
- turn to you. The result names the state (`ask now waiting on agent` / `human`), the delivered `comment.created` carries it as
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
- `dispatch_comment({ reply_to_ask })` — plus any session a human adds from the ask card. The ask's answer, edits, resolution, and
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 tool result says so (`You follow this ask: its answer and replies reach you directly.`) and carries `details.follows.ask`;
102
- the host tells you once per ask. Leave a thread you no longer need, or rejoin one, with:
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
- ```ts
105
- dispatch_follow({ ask, action: "follow" | "unfollow" })
84
+ ```bash
85
+ dispatch follow --ask <id> --action unfollow # or --action follow
106
86
  ```
107
87
 
108
- `ask` is the full ask id or a `dispatch://KEY/ask/<id>` reference; `dispatch_follow`, `dispatch_edit_ask`, and
109
- `dispatch_resolve_ask` also take an 8+ hex prefix that is unique among your own open asks, and refuse anything shorter by naming
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
 
@@ -1,16 +1,19 @@
1
1
  # Editing a document
2
2
 
3
- Every document a Dispatch tool writes — an issue's spec, a project document — is edited in place
4
- with `dispatch_doc_edit`, never re-uploaded. "The Spec" in `skill://dispatch` sends you here for
5
- the tool's shape, how to target the text you mean, what each operation costs a block, and how to
3
+ Every document Dispatch holds — an issue's spec, a project document — is edited in place
4
+ with `dispatch doc-edit`, never re-uploaded. "The Spec" in `skill://dispatch` sends you here for
5
+ the command's shape, how to target the text you mean, what each operation costs a block, and how to
6
6
  reject a stale edit.
7
7
 
8
- ```ts
9
- dispatch_doc_edit({ issue?, project?, artifact, ops, precondition?, summary? })
8
+ ```bash
9
+ dispatch doc-edit --issue <KEY> --artifact spec --summary '<names the version>' --ops-json-file - <<'EOF'
10
+ [{"op": "replace", "find": "old sentence", "with": "new sentence"}]
11
+ EOF
10
12
  ```
11
- It returns issue or project-document owner details plus `applied`, optional `version`, `changed`,
12
- `unchanged_ops`, `lost_ops`, and the document token this edit produced, rendered as a
13
- `Document token: <token>` line. `ops` is an array of this exact `EditOp` shape:
13
+ `--project` replaces `--issue` for a project document, and `--precondition-json` guards against a
14
+ stale edit (below). It prints whether the edit applied, the version it wrote, which operations
15
+ changed nothing (`unchanged_ops`) or were lost to a concurrent change (`lost_ops`), and the document
16
+ token this edit produced, as a `Document token: <token>` line. The ops are a JSON array of this exact `EditOp` shape:
14
17
 
15
18
  ```ts
16
19
  type EditOp = {
@@ -28,8 +31,8 @@ type EditOp = {
28
31
  };
29
32
  ```
30
33
 
31
- An operation takes only these keys. A key it does not declare is refused before the call leaves
32
- your process, naming the operation and its keys, because every key but `op` is optional: a
34
+ An operation takes only these keys. A key it does not declare is refused before the command sends
35
+ anything, naming the operation and its keys, because every key but `op` is optional: a
33
36
  misspelled `with` would otherwise be dropped and the `replace` would delete the text you meant to
34
37
  rewrite.
35
38
 
@@ -93,7 +96,7 @@ paragraph is stored `\---`, not a rule, so to add a rule, `insert` it beside the
93
96
  `***`). A CR LF or a lone carriage return in any text you write - an insert's markdown, a `with` in text or in code,
94
97
  a suggestion, an upload or a spec - is stored as a line feed, as the browser editor reads both. Use zero-based
95
98
  `occurrence` for a
96
- repeated target; re-read a missing or ambiguous target before retrying. Pass `summary` to name the version when recording a decision.
99
+ repeated target; re-read a missing or ambiguous target before retrying. Pass `--summary` to name the version when recording a decision.
97
100
 
98
101
  **Rewriting several paragraphs is one `replace` per paragraph, then a read-back.** `replace` is inline:
99
102
  each `with` is the new text of one paragraph, and outside a code block a `with` that forms two paragraphs is
@@ -131,17 +134,17 @@ the old block's place is it a `delete` of the old block and then an `insert` of
131
134
  block before or after it. The delete is what costs the id (below); a typed block keeps its id when the insert
132
135
  carries it, which works only in that order, because an insert carrying an id the document still holds is refused.
133
136
  The tools refuse a `delete` or `retype` that would take out an `ask` block whose ask is still open, delete-then-insert included:
134
- reword it with `replace`, relocate it with `move`, or change its question, options, urgency or `multiple` with `dispatch_edit_ask` if you asked it. A single
137
+ reword it with `replace`, relocate it with `move`, or change its question, options, urgency or `multiple` with `dispatch edit-ask` if you asked it. A single
135
138
  batch that moves an open block out of a container and then deletes the container is refused; make them two calls (the check reads
136
139
  the document as it stood before the batch).
137
140
  Then read the document back with
138
- `dispatch_doc_read` and read the passage and its neighbours, not a grep for the words you added: an empty
141
+ `dispatch doc-read` and read the passage and its neighbours, not a grep for the words you added: an empty
139
142
  `with` deletes the matched text on purpose, so a `replace` whose `with` you meant to fill
140
143
  empties that paragraph — the block and its id stay, holding nothing — and only a read shows what the document now says.
141
144
 
142
145
  A batch that leaves the document's semantic identity unchanged — including its inline anchor marks, so an edit that only orphans a
143
146
  comment or ask anchor still mints its version — mints no version, named or not: the response carries
144
- `changed: false` with `unchanged_ops` naming each operation that did nothing, and the tool result says nothing changed. A `summary`
147
+ `changed: false` with `unchanged_ops` naming each operation that did nothing, and the output says nothing changed. A `--summary`
145
148
  does not force a version for such a batch; `POST /api/v1/artifacts/<id>/versions`, which names the current state on purpose, still does.
146
149
 
147
150
  A `delete` whose `find` is a block's entire text removes the block itself — the bullet, paragraph, or heading, not just its words — and
@@ -165,11 +168,11 @@ whose anchor lies inside the moved block, or a delete that would leave a typed b
165
168
  `INVALID_OP` naming the field and the rule.
166
169
 
167
170
  `GET /api/v1/artifacts/<artifact UUID>/blocks` includes a full-state `token` on every block, including
168
- inline marks. To reject a stale edit, pass `precondition` with exactly one of
169
- `{ document: "<document token>" }` or
170
- `{ blocks: [{ id: "<block id>", token: "<block token>" }] }`. A document token comes from
171
- `dispatch_doc_read` or from the previous `dispatch_doc_edit`, whose result carries the token its
172
- own edit produced: a run of guarded edits passes each result's token to the next one and reads the
171
+ inline marks. To reject a stale edit, pass `--precondition-json` with exactly one of
172
+ `{"document": "<document token>"}` or
173
+ `{"blocks": [{"id": "<block id>", "token": "<block token>"}]}`. A document token comes from
174
+ `dispatch doc-read` or from the previous `dispatch doc-edit`, whose output carries the token its
175
+ own edit produced: a run of guarded edits passes each output's token to the next one and reads the
173
176
  document once, not once per edit. The server resolves the whole batch before
174
177
  mutation: a block guard must cover every content block it changes, or Dispatch returns
175
178
  `400 INVALID_PRECONDITION` without applying anything. Use a document token for insert and move because they
@@ -197,6 +200,6 @@ an existing paragraph is the question that should become a decision.
197
200
 
198
201
  An ask block has two ids: the block id, shown as `:::ask{#<id> …}` in the rendered document and
199
202
  taken bare by `move`/`delete` in `block` (the `block:<id>` form is only for `before`/`after`
200
- anchors), and the ask id, which `dispatch_open_asks`, the dashboard's ask links (`/asks/<id>`,
201
- `?ask=`), `dispatch_read` and `dispatch_comment({ reply_to_ask })` use. They differ;
203
+ anchors), and the ask id, which `dispatch open-asks`, the dashboard's ask links (`/asks/<id>`,
204
+ `?ask=`), `dispatch read` and `dispatch comment --reply-to-ask` use. They differ;
202
205
  `dispatch://KEY/ask/<block-id>` answers `not found`.
@@ -15,7 +15,7 @@ Dispatch writes its fences that way. An unclosed typed block at document level i
15
15
  opening line that continues a paragraph instead of standing on its own (indented four or more
16
16
  columns under the paragraph's text) is refused, naming the line's number and text - `INVALID_OP` on an edit's `markdown` or `with`, `INVALID_MARKDOWN` on any other write - since it
17
17
  would be stored as the paragraph's text; start the block on its own line. An opening written inside
18
- a line is stored as text, and `dispatch_issue` and `dispatch_artifact` quote it back as a
18
+ a line is stored as text, and `dispatch issue` and `dispatch artifact` quote it back as a
19
19
  typed-block opening that is text, not a block. For
20
20
  a new typed block, omit `#block-id`; Dispatch mints it. When editing an existing typed block, retain
21
21
  its id and every rendered attribute. Never copy an existing block's id into new markdown: an id
@@ -24,9 +24,9 @@ outside the text it replaces is refused naming the id: `INVALID_OP` for an inser
24
24
  `INVALID_MARKDOWN` for any other write. To rewrite such a block whole, `delete` it and then
25
25
  `insert` the new one carrying its id, anchored on the block before or after it, in that order and
26
26
  in one batch: an insert carrying an id the document still holds is refused. An `ask` block whose ask
27
- is still open cannot be rewritten that way: the tools refuse the `delete`, so reword it with
27
+ is still open cannot be rewritten that way: `dispatch doc-edit` refuses the `delete`, so reword it with
28
28
  `replace`, relocate it with `move`, or change its question, options, urgency or `multiple` with
29
- `dispatch_edit_ask` if you asked it ([Editing a document](skill://dispatch/references/document-edits.md)).
29
+ `dispatch edit-ask` if you asked it ([Editing a document](skill://dispatch/references/document-edits.md)).
30
30
 
31
31
  Use only the type names, content rule, attributes, and enum values returned by the schema. Values are
32
32
  quoted: `:::callout{kind="warning" title="Risk"}`. Do not write Pandoc-style `::: {.callout}`, leaf
@@ -55,67 +55,67 @@ unknown cost before production while keeping today's release possible.
55
55
  ```
56
56
 
57
57
  When a human answers a decision written as an ask block, the answer lives on that ask. Use
58
- `dispatch_resolve_ask` when the decision is resolved without a human response, or preserve the
58
+ `dispatch resolve-ask` when the decision is resolved without a human response, or preserve the
59
59
  human's answer; never rewrite the question into its answer or blank its options. An edit that leaves
60
60
  an ask block without a question or with a blank option is rejected with `INVALID_ASK_BLOCK`.
61
61
 
62
- When `dispatch_issue` or `dispatch_artifact` answers `This spec holds no ask blocks …`, read it as a
62
+ When `dispatch issue` or `dispatch artifact` answers `This spec holds no ask blocks …`, read it as a
63
63
  question: either no decision is needed and you say nothing, or you forgot to make it a block. When
64
64
  it answers `… typed-block openings in this document are text, not blocks`, the quoted openings are
65
65
  blocks stored as prose (inside a line, or a paste with something before every line): fix the markdown
66
66
  and upload again; a mention on purpose belongs in code. Neither answer sees a spec wrapped whole in a
67
67
  code fence (take the fence off), a malformed opening inside a line (`::ask{`, `:::ask {`: an ask opens
68
- only as `:::ask{…}` on a line of its own), or any `dispatch_doc_edit`: after an edit that writes an
69
- ask, `dispatch_doc_read` the section and check it renders as `:::ask{#<id> …}` on its own line.
68
+ only as `:::ask{…}` on a line of its own), or any `dispatch doc-edit`: after an edit that writes an
69
+ ask, `dispatch doc-read` the section and check it renders as `:::ask{#<id> …}` on its own line.
70
70
 
71
71
  ## Comments and suggestions
72
72
 
73
- Add feedback with:
73
+ Add feedback with `dispatch comment` (`dispatch comment --help` lists its flags):
74
74
 
75
- ```ts
76
- dispatch_comment({ issue?, project?, artifact?, ref?, quote?, occurrence?, body, reply_to?, reply_to_ask?, turn? })
75
+ ```bash
76
+ dispatch comment --issue <KEY> --artifact spec --quote '<the passage>' --body '<the question or note>'
77
77
  ```
78
78
 
79
- It returns issue or project-document owner details plus `comment`; a `reply_to_ask` reply also returns `ask` and `follows: { ask }`,
80
- because replying to an ask makes you one of its followers (see [Following](skill://dispatch/references/asks.md)).
81
- `ref` names the owner (an issue or project-document reference) in place of `issue`/`project`.
82
- `quote` requires `artifact`; its anchor is pinned to the containing block while retaining the quote
83
- for display. Omit both for a floating issue comment. A reply (`reply_to`/`reply_to_ask`) takes no
84
- `quote`; it belongs to its parent's anchor. Reply to any comment in a thread; the server keeps
79
+ It prints the comment's id; a `--reply-to-ask` reply also makes you one of the ask's followers
80
+ (see [Following](skill://dispatch/references/asks.md)).
81
+ `--ref` names the owner (an issue or project-document reference) in place of `--issue`/`--project`.
82
+ `--quote` requires `--artifact`; its anchor is pinned to the containing block while retaining the quote
83
+ for display. Omit both for a floating issue comment. A reply (`--reply-to`/`--reply-to-ask`) takes no
84
+ `--quote`; it belongs to its parent's anchor. Reply to any comment in a thread; the server keeps
85
85
  threads flat. A reply to a resolved thread reopens it, except a decided suggestion's: a reply joins
86
- that thread and the suggestion stays accepted or rejected. Use `reply_to_ask` to reply directly under a
87
- question asked with `dispatch_ask`; `turn` (only with `reply_to_ask`) says who holds the turn after
86
+ that thread and the suggestion stays accepted or rejected. Use `--reply-to-ask` to reply directly under a
87
+ question asked with `dispatch ask`; `--turn` (only with `--reply-to-ask`) says who holds the turn after
88
88
  the reply — `agent` for a progress note that keeps the ask waiting on you, `human` (the default) when
89
89
  the human needs to act; see "Asking" in `skill://dispatch`. Comments are edited only by their author from the
90
90
  dashboard. A delivered `comment.created` event carries the comment `id`; reply to it with
91
- `dispatch_comment({ reply_to: <id> })`.
91
+ `dispatch comment --reply-to <id>`.
92
92
 
93
93
  Resolve your own review comment once you have addressed it:
94
94
 
95
- ```ts
96
- dispatch_resolve_comment({ comment })
95
+ ```bash
96
+ dispatch resolve-comment --comment <id>
97
97
  ```
98
98
 
99
- `comment` is the comment id, or a `dispatch://KEY/comment/<id>` or `dispatch://PROJECT/artifact/<slug>/comment/<id>` reference (an
100
- 8+ character id prefix is resolved against the owner's comments). It returns the owner details plus `comment`, and takes no reason —
101
- say what you did in a `reply_to` first if the thread needs it. The server lets any session or human resolve any open comment, so
99
+ `--comment` is the comment id, or a `dispatch://KEY/comment/<id>` or `dispatch://PROJECT/artifact/<slug>/comment/<id>` reference (an
100
+ 8+ character id prefix is resolved against the owner's comments). It takes no reason —
101
+ say what you did in a `--reply-to` first if the thread needs it. The server lets any session or human resolve any open comment, so
102
102
  resolve only threads you opened or were asked to close; reopening a resolved thread is human-only (from the dashboard), though your
103
103
  reply to it reopens it - except a decided suggestion's, which your reply joins and leaves accepted or rejected. A reply to a pending
104
- suggestion whose text an edit removed lands as well. Asks are closed with `dispatch_resolve_ask` instead.
104
+ suggestion whose text an edit removed lands as well. Asks are closed with `dispatch resolve-ask` instead.
105
105
 
106
- An exact replacement for document text is a suggestion (`dispatch_suggest`), never a comment; a
106
+ An exact replacement for document text is a suggestion (`dispatch suggest`), never a comment; a
107
107
  comment is for a question or a note the human answers in words. A human accepts a suggestion with
108
108
  one click and cannot accept a comment, so propose the replacement instead of describing it:
109
109
 
110
- ```ts
111
- dispatch_suggest({ issue?, project?, artifact, ref?, quote, replace_with, body?, occurrence? })
110
+ ```bash
111
+ dispatch suggest --issue <KEY> --artifact spec --quote '<exact text>' --replace-with '<replacement>'
112
112
  ```
113
113
 
114
- It returns issue or project-document owner details plus `comment`. A human accepts or rejects a suggestion.
115
- Errors: `TARGET_AMBIGUOUS` (add `occurrence`), `TARGET_NOT_FOUND` (re-read first), `INVALID_ANCHOR`/`ANCHOR_MISSING`/`ANCHOR_ORPHANED`
114
+ It prints the suggestion's id; `--body` adds a note and `--occurrence` picks a repeated quote. A human accepts or rejects a suggestion.
115
+ Errors: `TARGET_AMBIGUOUS` (add `--occurrence`), `TARGET_NOT_FOUND` (re-read first), `INVALID_ANCHOR`/`ANCHOR_MISSING`/`ANCHOR_ORPHANED`
116
116
  (bad, unwritten, or stale quote), `INVALID_MARKDOWN`/`DOC_SCHEMA` (malformed content), `CAP_EXCEEDED`, `ISSUE_CLOSED`.
117
117
  Suggest only what the quoted block can hold. The accept, not the suggestion, checks that: an
118
- accept whose `replace_with` would break an ask block that was readable before it is refused with
118
+ accept whose replacement would break an ask block that was readable before it is refused with
119
119
  `INVALID_ASK_BLOCK` - a question given a code block, text after an ask's options, a second option
120
120
  list, or an emptied question; one that names an id the document holds outside the text it
121
121
  replaces, an ask under a held id included, with `INVALID_MARKDOWN`; and one no part of the
@@ -127,51 +127,54 @@ stays open until someone rejects or replaces it.
127
127
 
128
128
  Attach an image, diagram, or local file with:
129
129
 
130
- ```ts
131
- dispatch_artifact({ issue?, project?, name, path, summary? })
130
+ ```bash
131
+ dispatch artifact --issue <KEY> --name diagram.png --path ./diagram.png
132
132
  ```
133
133
 
134
- Or, when the text is already in the call, post a Markdown document directly:
134
+ Or, when the text is already at hand, post a Markdown document directly:
135
135
 
136
- ```ts
137
- dispatch_artifact({ issue?, project?, name: "load-test-results.md", content: "# Load test\n..." })
136
+ ```bash
137
+ dispatch artifact --issue <KEY> --name load-test-results.md --content-file - <<'EOF'
138
+ # Load test
139
+ ...
140
+ EOF
138
141
  ```
139
142
 
140
- Exactly one of `issue` and `project` is required. A project upload creates an unlinked project document; it must not include `artifact`.
141
- Exactly one of `path` and `content` is required. It returns issue or project-document owner details plus `artifact` and `version`.
142
- Uploading the same `name` creates its next version — so uploading `spec.md` **replaces the issue's own specification**
143
- with your text. Never do that: the spec is edited in place with `dispatch_doc_edit` (see [Editing a document](skill://dispatch/references/document-edits.md)). Address an existing
144
- artifact by the slug shown in the upload result or by its filename, and a project document by its artifact id, slug, or filename; the
143
+ Exactly one of `--issue` and `--project` is required. A project upload creates an unlinked project document; it takes no `--artifact`.
144
+ Exactly one of `--path` and `--content` is required. It prints the document's slug and version.
145
+ Uploading the same `--name` creates its next version — so uploading `spec.md` **replaces the issue's own specification**
146
+ with your text. Never do that: the spec is edited in place with `dispatch doc-edit` (see [Editing a document](skill://dispatch/references/document-edits.md)). Address an existing
147
+ artifact by the slug the upload printed or by its filename, and a project document by its artifact id, slug, or filename; the
145
148
  slug also arrives on `artifact.created` events. Dispatch suffixes a slug two documents would share, so one document's
146
149
  filename can be another's slug (`plan v2` takes `plan-v2`, then a document named `plan-v2` takes `plan-v2-2`): a bare
147
- `artifact` that names both is refused with each one's id, while a `dispatch://` reference's document part is always the slug.
150
+ `--artifact` that names both is refused with each one's id, while a `dispatch://` reference's document part is always the slug.
148
151
 
149
- A picture meant to be seen inline in a message, comment or ask is not uploaded with `dispatch_artifact`: pass its local
150
- path in that tool's `images` (PNG, JPEG, GIF or WebP by its bytes, at most 25 MiB each). Each is uploaded to the issue (a
152
+ A picture meant to be seen inline in a message, comment or ask is not uploaded with `dispatch artifact`: pass its local
153
+ path with that command's `--image`, once per picture (PNG, JPEG, GIF or WebP by its bytes, at most 25 MiB each). Each is uploaded to the issue (a
151
154
  project document's project; for a reply to a direct message, your own conversation) and appended after a blank line as
152
155
  one `![<file name>](dispatch://<owner>/artifact/<slug>@vN)` line, about 60 characters that count toward the body or
153
- question cap; a call the lines would carry over the cap is refused with the count before anything uploads, and again,
156
+ question cap; a command the lines would carry over the cap is refused with the count before anything uploads, and again,
154
157
  with nothing posted, in the rare case where Dispatch gives an upload a longer address than that (a later version of a
155
158
  name the owner already holds, or a slug another file took first). The `@vN` pins the version the upload made (the same
156
159
  file name again makes the next version). A plain `dispatch://KEY/artifact/<slug>` reference to an image stays a link
157
160
  with a thumbnail.
158
161
 
159
- `dispatch_read` hands you the pictures the messages, asks and comments it shows embed, newest first, at most 8 and
160
- 10 MiB per read, and its `Pictures:` section names each one shown, in order, and the rest by reference for
161
- `dispatch_doc_read`, which shows one picture (at most 3,750,000 bytes, the 5 MB of base64 a model provider takes; a
162
- larger one or an SVG is described). A picture in a
162
+ `dispatch read` writes the pictures the messages, asks and comments it shows embed to files, newest first, at most 8 and
163
+ 10 MiB per read, prints a `- picture: <path>` line for each, and its `Pictures:` section names each one shown, in order, and the rest by reference for
164
+ `dispatch doc-read`, which shows one picture (at most 3,750,000 bytes, the 5 MB of base64 a model provider takes; a
165
+ larger one or an SVG is described). Open each written file with your file-read tool. A picture in a
163
166
  conversation on the Agents page belongs to that conversation, `dispatch://agent/<session id>/artifact/<slug>@vN`, and
164
- `dispatch_doc_read` reads it by that reference alone. On Oh My Pi an Inbox delivery carries its pictures the same way; in
167
+ `dispatch doc-read` reads it by that reference alone. On Oh My Pi an Inbox delivery carries its pictures as images; in
165
168
  Claude Code it stays text with the reference.
166
169
 
167
170
  A session is shown each picture once. A later read or delivery that embeds a picture you were already shown names it in
168
171
  `Pictures:` as `shown earlier this session` and sends no bytes, since every request carries the session's whole history
169
- and a model provider refuses one over 32 MB; `dispatch_doc_read` always shows the picture, so ask it for one you need
172
+ and a model provider refuses one over 32 MB; `dispatch doc-read` always shows the picture, so ask it for one you need
170
173
  again, after compaction too.
171
174
 
172
175
  Documents are CommonMark. A bare `<https://example.com|text>` is a CommonMark autolink and is normalised: the angle brackets are
173
176
  dropped and the URL keeps `|text`. A backslash-escaped `\<https://example.com|text>` displays as `<https://example.com|text>` in the
174
- document but comes back re-escaped (`\<`) from `dispatch_doc_read`. A Slack mrkdwn draft, or any other payload that is not Markdown,
177
+ document but comes back re-escaped (`\<`) from `dispatch doc-read`. A Slack mrkdwn draft, or any other payload that is not Markdown,
175
178
  still belongs inside a fenced code block, where it survives verbatim both ways.
176
179
 
177
180
  A table cell ends at every `|` not written `\|`, inside inline code and links too, so write
@@ -184,27 +187,27 @@ of bare table rows `TABLE_WIDTH`, which names the cell counts only.
184
187
 
185
188
  ## Approval requests
186
189
 
187
- ```
188
- dispatch_request_approval({ issue?, project?, artifact?, summary })
190
+ ```bash
191
+ dispatch request-approval --issue <KEY> --summary '<what the human is approving>'
189
192
  ```
190
193
 
191
- The call opens an approval ask with the options `Approve` and `Request changes`, its question
192
- "Approve spec.md (version N)?" followed by `summary`, where N is the document's latest version. It
194
+ The command opens an approval ask with the options `Approve` and `Request changes`, its question
195
+ "Approve spec.md (version N)?" followed by the summary, where N is the document's latest version. It
193
196
  is refused, with nothing sent, while that version holds a decision block open, and the refusal
194
- names each block and its ask. An answer or a `dispatch_resolve_ask` closes the ask at once but
197
+ names each block and its ask. An answer or a `dispatch resolve-ask` closes the ask at once but
195
198
  reaches a version only when the document settles, about two seconds later, or with your next
196
- `dispatch_doc_edit`: fold the answer into the text (or, for a waiver, write the human's decision
199
+ `dispatch doc-edit`: fold the answer into the text (or, for a waiver, write the human's decision
197
200
  in) before you request. A block written in the last few seconds counts as open before Dispatch has
198
201
  opened its ask. A document holds one open request. A new version moves it to that version, keeping
199
202
  its thread and summary, and leaves it waiting on you, as a human's reply in its thread does; a move
200
- your own edit made sends you no event, and `dispatch_read` and `dispatch_doc_read` show it as
201
- `Approval: awaiting, waiting on agent`. Call again when "Approval of a spec" in `skill://dispatch`
202
- allows: that hands the same request back to the human, reworded first when `summary` is new. Your
203
- own reply in its thread hands it back too, with no call and the summary it already holds, unless
204
- you post it with `reply_to_ask` and `turn: "agent"` (`reply_to` carries no turn, so its reply takes
203
+ your own edit made sends you no event, and `dispatch read` and `dispatch doc-read` show it as
204
+ `Approval: awaiting, waiting on agent`. Run it again when "Approval of a spec" in `skill://dispatch`
205
+ allows: that hands the same request back to the human, reworded first when `--summary` is new. Your
206
+ own reply in its thread hands it back too, with no command and the summary it already holds, unless
207
+ you post it with `--reply-to-ask` and `--turn agent` (`--reply-to` carries no turn, so its reply takes
205
208
  the default, `human`) or a new version has moved the request since your last
206
- `dispatch_request_approval`. While it waits on the human, a call with the same `summary` changes
207
- nothing, and one with a different `summary` is refused, since it would rewrite the card they are
209
+ `dispatch request-approval`. While it waits on the human, the same `--summary` changes
210
+ nothing, and a different `--summary` is refused, since it would rewrite the card they are
208
211
  reading. The answer reaches you as `artifact.approved` or `artifact.changes_requested` with the
209
212
  pinned `version` and closes the request, so the next call opens a new one; `changes_requested`
210
213
  carries the reason, which is your next piece of work. Those reads show the document's approval
@@ -213,18 +216,18 @@ state; `stale` means it was approved and then edited.
213
216
  ## A document that is reloading
214
217
 
215
218
  These calls can answer `DOC_SERVICE_UNAVAILABLE` (HTTP 503), because each writes a document inside its
216
- transaction: `dispatch_doc_edit`; `dispatch_ask` and `dispatch_comment` on a quote; a `dispatch_comment` reply
217
- in a thread whose first comment is anchored; `dispatch_suggest`; `dispatch_resolve_comment` on an anchored
218
- comment; `dispatch_artifact` replacing a document that already exists; and, on an ask that lives in a `:::ask`
219
- block, `dispatch_edit_ask` and `dispatch_resolve_ask`, which write that block. Creating an issue with a spec,
220
- uploading a new document, `dispatch_request_approval` and `dispatch_message` never answer it, and neither do
221
- `dispatch_edit_ask` and `dispatch_resolve_ask` on an ask that has no block. It means that document's live room
219
+ transaction: `dispatch doc-edit`; `dispatch ask` and `dispatch comment` on a quote; a `dispatch comment` reply
220
+ in a thread whose first comment is anchored; `dispatch suggest`; `dispatch resolve-comment` on an anchored
221
+ comment; `dispatch artifact` replacing a document that already exists; and, on an ask that lives in a `:::ask`
222
+ block, `dispatch edit-ask` and `dispatch resolve-ask`, which write that block. Creating an issue with a spec,
223
+ uploading a new document, `dispatch request-approval` and `dispatch message` never answer it, and neither do
224
+ `dispatch edit-ask` and `dispatch resolve-ask` on an ask that has no block. It means that document's live room
222
225
  failed and is reloading from its durable copy, so the server refused rather than wait for it; your call wrote
223
226
  nothing and the document is intact. Nothing retries it for you: the Dispatch client hands a 503 straight back.
224
227
  Wait a few seconds and make the same call again. A second refusal in a row is worth telling your human about,
225
228
  with the document's reference.
226
229
 
227
- `dispatch_doc_read` can answer it too, though it writes nothing: a read never opens a live room, and waits out
230
+ `dispatch doc-read` can answer it too, though it writes nothing: a read never opens a live room, and waits out
228
231
  a room that is reloading, so it is refused only when the document's durable copy cannot be read or decoded.
229
232
  Retry it the same way.
230
233