repo-mailbox/skills/dispatch/SKILL.md
Kjell Tore Guttormsen 165385be5f chore(release): 0.26.0
The done-guard (d16a3f5) landed after 0.25.0 was already tagged and published
on 95ac710, with the catalog ref pinned to it (catalog 01161f0). Moving a
published tag would swap content under a name consumers may already have
fetched, so the guard gets its own release instead.

Version bumped in all seven places: plugin.json, package.json, the README
badge, and the coord-send / board / route / dispatch skill frontmatters.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P4LMWBQGmufmBU6UdvJZ2E
2026-08-16 22:19:08 +02:00

8.4 KiB

name description version
dispatch Turn "start a session in repo X, on order Y, at cost Z" into a complete, verified startup command — the prompt written to a file, the model and effort derived from the rubric, and the output form chosen by whether the target repo already has a terminal pane. Use whenever work is being handed to a session in another repo, or to this repo's own next session: "dispatch a session in repo X", "start a session there with this order", "give me the startup command for repo Y", "hand this work to <repo>", "write the plan file for that session", "open a tab for X with this task", "how do I launch the next session on this". Also triggers on Norwegian phrasings: "dispatch en økt i repo X", "start en økt der med denne ordren", "gi meg oppstartskommandoen for Y", "send arbeidet til <repo>", "skriv planfila for den økten", "åpne en tab for X med denne oppgaven", "hvordan starter jeg neste økt på dette". Trigger even when no tool is named — producing a runnable startup command for another session IS this skill. Not for choosing WHICH repo deserves the next session (that is `board`), not for scoring model and effort alone (that is `route`), and not for sending a message to another repo (that is `coord-send`). 0.26.0

dispatch — hand a session a task it can actually start on

A dispatch is one line the operator pastes and one file that line reads. Both halves are easy to get wrong in ways that look right: a command with no prompt in it, a plan file the driver silently discards, a --no-go that does not stop what everyone assumed it stopped. All three were measured on 2026-08-16 — four separate misfires in one day, by two different repos — and this skill exists so they are not re-derived a fifth time.

You produce the command. You never run it. Starting a session in another repo spends the operator's quota and takes an action inside a repo this session does not own. Hand back the finished command and stop.

The engine

BOARD="${CLAUDE_PLUGIN_ROOT}/scripts/board.sh"

"$BOARD" --dispatch --repo <name> \
         --prompt-file <absolute path> \
         --target-pane <yes|no> \
         --path <known|partial|undetermined> \
         --verification <strong|weak|none> \
         --reversibility <cheap|costly|one-way> \
         --scope <local|multi-file|cross-cutting> \
         --rationale "why these four scores"

It writes nothing and prints one block. Exit 2 means it refused — read stderr and fix the call; every refusal is a case where a command would have been wrong rather than merely imperfect.

It is board.sh and not a script of its own because the block format (tab=/repo=/dir=/command=/paste=) has exactly one generator. Two emitters of one file format is the drift defect this repo's CLAUDE.md warns about.

The four steps, in order

1. Write the prompt file

The order goes in a file, in plain prose, and the file is what the session actually receives:

mkdir -p "$HOME/.claude/dispatch"
PF="$HOME/.claude/dispatch/<repo>-$(date -u +%Y%m%dT%H%M%SZ).prompt"

Runtime scratch, not repo content — but it must survive until the operator pastes the line, so never write it to a directory that gets cleaned between sessions. The path must be absolute and shell-clean (letters, digits, /, ., _, -); --dispatch refuses anything else, because the path is expanded inside the command while the contents are not.

Write the whole order: the concrete task, which discipline applies (Iron Law, TDD, which file the test goes in), and what must not be triggered. A prompt that says only "continue" forces the receiving session to guess its task out of STATE.md, which is the thing handing over a prompt is supposed to prevent.

Norwegian prose, æøå, quotes, $ and backticks are all fine in the file. That is measured, not assumed: "$(cat file)" hands the bytes to the session as one argv element with no re-evaluation. The ASCII rule applies to shell and hook code, not to a prompt travelling through argv.

2. Measure whether the target already has a pane

morning --probe-panes | grep "<absolute dir of the target repo>"

A hit means --target-pane yes. Measure it; never assume it. This is the one input --dispatch refuses to default, for the same reason route.sh refuses to default --last-effort: it is a fact about the world, and guessing it produces a dispatch that verifies green and opens nothing.

Two facts about this measurement, both verified 2026-08-16 against the installed morning:

  • --probe-panes works from a Claude session, without a tty. It cannot identify the anchor pane, but the DIR column — the part you need — is there.
  • A session dispatching its own next session is always --target-pane yes. That is not a special case for one repo; it is what self-dispatch is, and it is where all four of the day's misfires landed.

3. Score the four traits and call --dispatch

Scoring is judgement and it is yours; the model, effort and advisor flag are a lookup and are route.sh's. Score the task the dispatched session will do, using the route skill's trait table.

--dispatch deliberately takes no --model/--effort. --advisor opus is a property of the rubric row — two rows share a model/effort pair while differing on it, and the CLI accepts a wrong advisor silently — so a dispatch that took the model directly would have no honest source for that flag. If the right call is a Fable row, the rubric cannot produce it: write that command by hand, and say in the handover that it is a recorded override, running without an advisor.

4. Verify, then hand it over

--target-pane no (plan-file form). Write the whole output to a file and dry-run it:

"$BOARD" --dispatch ... > "$HOME/.claude/dispatch/<repo>-<ts>.plan"
morning --plan-file "$HOME/.claude/dispatch/<repo>-<ts>.plan" --dry-run

Expect opening: 1 of 1. Then hand back:

morning --plan-file <path to the plan file> --no-go

Know what that dry-run does not prove. It proves the block parses and yields a command. It does not answer the pane question: run from a Claude session there is no tty, so morning reports window: unknown ... assuming an empty window and plan_drop_open never fires. A gate built on the dry-run would pass the self-dispatch case every single time — the one case it would exist to catch. Step 2 is the measurement; this is a parse check.

--target-pane yes (paste-only form). There is no plan file, deliberately: morning's plan_drop_open (morning:1788) drops a block whose repo already has a pane. Hand back the paste= line, and say it goes in the existing tab after /exit. Never prefix it with cd — one repo per terminal tab, and the operator is already standing in that one. morning --relaunch bypasses the filter but opens a second tab beside the existing one, which is rarely wanted.

Three things that must reach the operator

Say these in the handover, not only in the plan file. Each was a real correction, not a hypothetical:

  1. The command carries the prompt in argv. claude --model X --effort Y on its own is not a dispatch; it is a session waiting for someone to tell it what to do. Delivered bare twice on 2026-08-16, corrected by the operator with "gi meg alltid komplette oppstartskommandoer for nye sesjoner".
  2. --no-go does not make the session wait. It suppresses only the follow-up Go message — morning:806 is exact: "--no-go says nothing is typed once the startup command is in". The startup command, prompt and all, is typed regardless, so the dispatched session starts working on its own. An operator decision was once taken on the opposite premise and had to be corrected before the run.
  3. Which form you produced, and why. "Plan file, because <repo> has no pane" or "paste line, because <repo> already has one and a plan block for it would be dropped". The form is a consequence of a measurement, and the operator should be able to see the measurement.

Where a dispatch is not enough

The prompt file is scratch: it carries the order to one session and nothing records it afterwards. When the receiving repo needs a durable record of the order — something its next session will still see after this one is gone — send it a coord-send message as well. The dispatch starts the session; the mailbox is what makes the order survive it.