dispatch-card · git:20261104.1566e4b · 2026-11-04 · sha256 cf40a62264734420
dispatch-card git:20261104.1566e4bA
Immutable. This exact content never changes and is served at /api/v1/blob/cf40a62264734420.
--- name: dispatch-card description: "Use when sending work to another repo, or a side branch of this one, as a new Orca card while this session keeps going — \"별도 세션으로 진행해줘\", \"현재 세션은 두고 ~\", \"~ repo 에 작업 지시해줘\", \"dispatch to another repository\". Not the next ticket (handoff-ticket), subagents." --- # Orca dispatch Pack what the new session needs to know into a brief, create the card in the target repo, confirm it started, come back to your own work. ## 0. Dispatch or handoff — and is it even this skill The user's phrasing decides it. **"위임하고 너는 X 계속해"** — "~에 위임하고 너는 손 떼", "위임해서 진행시키고 너는 원래 작업 진행해줘", "기존 작업 하면서 ~도 진행해줘" — is dispatch: this session has its own work after the instruction. **"끝났으니 다음"** — "작업 끝나면 다음 티켓", "남은 것 진행해줘" — is `handoff-ticket`. "병렬로" alone usually means handoff or a sub-agent; it is dispatch only when this session keeps working. "서브에이전트로" is the Agent tool. | | dispatch-card | handoff-ticket | |---|---|---| | This session | keeps going | finishes and closes | | Target repo | another repo, or a side branch of this one | this repo | | Input | a brief you write (§2) | a ticket, `/goal <TICKET>` | | Relationship | parent → child card, both alive | successor card, this one gone | This skill never calls `end-session` — dispatching is the reason this session stays alive. If the target is this repo and this session is done, stop here and follow `handoff-ticket` instead. Target is another repo → always this skill, whatever the phrasing; handoff never crosses repos. The reverse does not hold — same repo is still dispatch when this session keeps working. Where the work goes is a separate question, and only one answer is this skill: - "서브에이전트로", "sub-agent 로 진행해두고" → the Agent tool, in this session. Not this skill. - A new Orca card / worktree, in this repo or another → this skill. - Several tickets supervised to a finish line, with this session as the lead that lands their PRs → `orchestrate`. Not this skill. "병렬로" by itself says nothing about which: most of the time it is same-repo, ticket-based parallel work (handoff) or sub-agents. Read the rest of the sentence. ## 1. Resolve the target repo ```bash orca repo list # <id> <name> <path> orca repo add --path <path> --json # only when the repo is not listed ``` The selector for §3 is `name:<name>` from that list. Register first, then create — a `--repo` pointing at an unknown repo does not fall back to anything useful. A repo you have been working in from a plain shell is not automatically an Orca repo; check the list before assuming it is. ## 2. Write the brief This is the whole point of the skill. The new session knows nothing about repo A — not what you did there, not why this task exists, not where the outputs are. Default: one note in the notes store (`use-notes`; its rules file says where it goes), and a `--prompt` of `/goal <the goal and its done, one sentence>. 브리프: <note path>` plus a three-line summary. The `/goal` keeps the card working until the goal holds, and the first prompt is the only place an approval reaches it: the card's auto-mode classifier treats a later message from another session as not the human's, so an approval sent afterwards is refused. The brief has: - **Background** — what happened in repo A and why this work follows from it. - **Sources** — links, not summaries: repo, PR, commit, note paths the target session reads itself. - **Deliverable and done** — the exact output and what makes it complete. - **Do not** — repo A is off limits; anything else the target must leave alone, written in the brief's `FORBIDDEN` row after its marked section. `skills-sync card` (§3) writes `orchestrate` `references/brief.md` FORBIDDEN (through "run it again.", the refused-act paragraph included) into that row between `<!-- FORBIDDEN:begin -->` and `<!-- FORBIDDEN:end -->`, replacing an older copy, so the card never gets a stale one; lines outside the markers stay yours. A card gets these rules from no other place: an inline `--prompt` card with no brief file pastes the paragraph itself, by its first and last words, not by line numbers. - **Approved** — an `APPROVED:` row: the acts the human already approved for this work, each with their words and the date (merge, deploy, restarting an app, a settings or language change, an upgrade). Written as a row, it reaches the first prompt (§3); a heading or bullet does not. The card decides inside them with the recommended default and reports what it chose; it does not ask. - **Human only** — what stays the human's: permission dialogs, logins, payments, document submissions, and any irreversible or outward act not under Approved. The card puts these to the human in one batched message and keeps doing the rest. - **Questions** — only for a brief that reports to `run:<id>` and goes out as a `/goal` card (§3 says which): one line telling the card how to ask what Approved leaves open. Orca refuses `ask` and `--type escalation` from a session with no Dispatch, so the card sends `orca orchestration send --to run:<id> --type question --subject … --body …`; a status wakes no inbox wait and stays off the dashboard's Needs you. The answer is the `reply` to it: a `status` message whose `thread_id` is the question's id, read with `orca orchestration check --wait --types status --timeout-ms 1800000` once nothing else can move, again after each empty wait. A card that coordinates a Run of its own (a lead) gets the reply in that Run's inbox: read it in the one inbox wait it already runs (`orch wait` or `orch inbox`, the line with `thread=<question id>`), never in a second check loop beside it. To look again, `check --all` and match `thread_id`; never a list you sort or cut yourself (a card sorting by a field the rows do not have, `createdAt` for `created_at`, missed two replies). A supervised worker needs no such line: its preamble's `ask` does this. - **Model calls** — one line: "다른 모델 호출(서브에이전트, API)은 필요할 때만 하고, 모델은 그때 고른다. 무엇을 왜 불렀는지는 마지막 보고에 적는다". Never name a model in the brief: the card reads a named model as an order and calls it whether or not the task needs it. The calls go in the final report because nobody reads an unattended card's chat before a call. - **Target repo rules** — one line: "그 repo의 CLAUDE.md와 스킬을 확인하고 적용하라". Never paste its CLAUDE.md or skills into the brief; that session reads them itself. - **Close** — one line: "`CLOSE`: 완료 기준을 채우고 결과를 적으면 `end-session` §8대로 같은 턴에 스스로 닫는다". Without it the card idles after its last report and nobody closes it. `KEEP` instead only when this session will reuse the card. The line goes in `--prompt` itself, written out, wherever the rest of the brief lives: the plugin's guard hook refuses an `orca worktree create --prompt` without `CLOSE` or `KEEP`. `skills-sync card` (§3) copies it from the brief file for you. A card that will run a project for this session through cards of its own (a lead) gets `orchestrate` `references/brief.md` "Lead" instead of the list above, and its `--prompt` also carries the `MODE`, `ROLE: lead <slug>`, `INBOX`, `DELEGATE`, `PREDICATE`, `MERGE`, `TASKS` and `GATE` lines; the hook refuses a lead's prompt (a `MODE` line or a `<project>: lead` head) that lacks `MODE`, `ROLE`, `DELEGATE` or `PREDICATE`. The `ROLE` line binds the lead role to the card's session, so the reorient hook reminds it of its program on every prompt. It stands in for `claude --agent agent-skills:lead`: `orca worktree create --agent` takes an Orca agent id, not CLI flags. Without these lines a lead reports done and waits for an order that never comes. Exceptions. A task that fits in three or four lines goes inline in `--prompt` after `/goal`, no note; the Approved and `CLOSE` lines still go in. Product backlog goes through `write-ticket` first and the prompt becomes `/goal <TICKET>`, with the Approved line after the ticket ID. Feedback the user gives on work a card is already doing goes by §3's rule for a card already on the task: feedback that changes the work is a new ticket and a new card, never an addition to the running card's brief. So is a wider approval: when a card stops on an act its first prompt did not approve, start a new `/goal` card whose Approved line carries it; do not send the approval by message, and do not do the act yourself. ## 3. Create the card Same command and conventions as `handoff-ticket` §3. What differs: ```bash orca worktree ps # a card already on this task? the first rule below # the brief is a file holding a `/goal <goal>` line and its APPROVED, CLOSE or KEEP (and a lead's) rows skills-sync card <brief file> \ --repo name:<repo> \ --name "<target>-<topic>" \ --display-name "<ID or target> <short title>" \ --comment "<brief path>" \ --reference "<ticket URL, or a Jira key>" # one per ticket; omit when there is none # --role verify|review for a second card on the same ticket that checks, not implements (default impl) ``` The helper starts `skills-sync close-setup <path> --agent <handle>` in the background itself: the setup terminal stays a shell after its script, so `terminal wait --for exit` never fires. Its log (the output's `card.close_setup.log`) ends in `result: failed` when the agent sits on a trust or permission dialog or shows no start; read it before §4, and trust a path as in `orchestrate` references/top-level.md "Starting a worker". - A card already on the task (the same PR, branch or ticket). With `--reference`, `skills-sync card` stops on a live card of the same repo, reference and `--role` (exit 2, the cards listed); `--supersede` starts the new one anyway and sends the old one the line below, logged and recorded. If it only needs to be told something, send that to it (`skills-sync nudge <handle> "<message>"`, logged with `orch sent add`; never `SendMessage`, which is not the user's word) and create no card. If the work needs a different implementation, ask it for a state summary (done, left, branch and PR), put that summary in the new card's brief, and in the turn you create the new card tell the old one `superseded by <new card>: stop and close by end-session §8` and drop the questions it left waiting (`orchestrate` "Stay answerable"). Without the summary the new card redoes or undoes finished work; left open, the old card waits on a question about work the new card already did. - Which card it makes. A brief whose REPORT or PARENT line sends to `run:<id>` is work this session waits on: from a session bound to that Run (`orca orchestration run-current`; bind one as in `orchestrate` references/top-level.md "Your Run"), or itself a dispatched worker on it (a lead started as one; `orch doctor` says which), `skills-sync card` starts it as a supervised worker with `orca orchestration worker-start --worktree new-child` (your worktree becomes its Orca parent; `new-top-level` with `--no-parent`). It is then a Dispatch: its escalation, `ask` and `worker_done` reach your Run, and Orca watches it for a prompt only a human can answer. Its spec is the composed prompt without the leading `/goal` (Orca delivers a spec as the task after its own preamble). Everything else is a `/goal` card from `orca worktree create`: a brief with no Run report (fire-and-forget), a lead's brief while Orca's Nested worker depth is below 3 (the lead's workers' helpers would not fit; the helper prints the setting to change), or `--card`. A Run brief from a session bound to no Run, or to another Run than the brief's `run:<id>`, creates nothing (exit 6): bind the brief's Run (`orca orchestration run-use --id <id>`), fix the brief's Run, or pass `--card` for a `/goal` card on purpose. The printed output ends in a `card` object: `kind` (worker or card), `path`, `handle`, `run`, `parent`. - A brief that sends to a `term_…` handle, in any line, is refused (exit 2): the handle dies with its terminal, so a report sent after a restart is refused (`terminal_not_found`), and until then it is only stored. Write `orca orchestration send --to run:<your run id>`. - `--reference` links the ticket in Orca (the card's `linkedItems`), so `orca reference find <ticket>` finds the card and `orca linear attach --current` works from it: on create for a `/goal` card, by `orca reference add` on the new card right after the start for a worker. Linear and GitHub take the full URL; a bare key is read as Jira. - `skills-sync card` writes the brief's `/goal` line (plus the brief's path, unless the line names one), PROGRAM, APPROVED, lead and CLOSE or KEEP rows into `--prompt` itself, logs a `/goal` card with `orch sent add` (a worker's spec is its Orca Task, which the Sent page reads), sets the display name and prints Orca's create output. A row is a line outside a ``` fence that starts with its key and a colon (`CLOSE: …`), or the Lead template's wide gap; a `## Close` heading is not one. The brief is a local file: a note only the notes store reaches is copied to one first. The guard hook checks that file as the helper does, but only for a plain `skills-sync card` call: a wrapper (`env …`, `bash -c`, running `scripts/card.py` itself) skips its lead-starts-lead test, since the hook is a guardrail, not a sandbox. The auto-mode classifier sees only the command and its path, and the helper is not auto-allowed. Never pass `--prompt "$(cat <brief>)"`: the hook reads only the command text, so it refuses that card even when the file holds the lines. A nonzero exit is a failing check, not a refusal: 2 names the missing line (add it to the brief), 3 is the pressure gate's reason (wait as it says, then run the same command), 4 is Orca's create or `worker-start` error, with Orca's whole receipt on stderr (Orca can fail a launch whose outcome it could not confirm: follow the receipt's recovery commands, and for a `worker-start` the `request-show` line the helper prints, before running it again; `completed` or `pending` there means it took or may still take effect, and `absent` is no proof that nothing started, so check `orca worktree ps` and `orca orchestration worker-list` too; a 4 for a refused parent or depth lists the choices instead, and nothing was created), 5 means the card exists but its link, log or name failed (do that step by hand; do not create it again), 6 means nothing was created because the Run or the parent did not check out (pick one of the printed choices, never `--no-parent` or `--card` just to get past it). The `term_` refusal is a 2. An inline brief with no file goes straight to `orca worktree create --prompt`, its lines written out. - `--repo` is required. Omitted, Orca infers the current worktree's repo and the card lands in the wrong place. - `--name` is `<target>-<topic>`, e.g. `blog-launch-post`. A ticket-backed card uses the ticket ID in its display name: `"ENG-123 <short title>"`. - The parent is this terminal's own worktree by default: the helper looks it up (`orca terminal show --terminal $ORCA_TERMINAL_HANDLE --json`, `result.terminal.worktreeId`) and passes `--parent-worktree id:<it>`; no handle or no answer creates nothing (exit 6). Name another parent only as `id:<worktree id>`, never `path:` (refused: Orca workspaces sharing a path resolve to the repo's main worktree). `--no-parent` only for work with no relation to this session. - Omit `--base-branch`; the target repo's default base is the right one. ## 4. Confirm the start, then go back to work A worker (`card.kind` worker) needs no start check: `worker-start` exits 0 only once Orca saw it ready. Read it with `orca orchestration worker-show --dispatch <id>` and `worker-read --dispatch <id> --source auto` (a worker may have no terminal, and terminal verbs refuse such a handle), talk to it with `orca orchestration send --to dispatch:<id>`, and wait for its `worker_done` in your inbox wait (`orch inbox --wait`, or `orch wait` in a program). `orch watch-cards` judges its prompts from Orca's `agentWait`. A `/goal` card (`card.kind` card): ```bash orca terminal wait --terminal <card.handle> --for tui-idle --timeout-ms 60000 orca terminal read --terminal <handle> --screen orch watch-cards --card <handle> # under run_in_background: STARTED, ENDED, CLOSED, or STUCK on a lost login, a prompt or no /goal ``` Take the handle only from the `card.handle` field of the output (Orca's `launch.outcome.handle`, or `agentTerminalHandle` on an older Orca), never from a loose `term_…` match: the brief or its context can quote another handle (your own among them), and a `/goal` or nudge sent to the first match lands on the sending session. Before any send, check that the handle is not your own (`$ORCA_TERMINAL_HANDLE`). Once. Read that the agent picked up the brief, report the worktree path, branch and handle, and return to what this session was doing. The `--card` check reports about four minutes later, since a card can lose its login a few turns in; on `STUCK`, read its screen, and for a lost login or a missing `/goal` start a new card on the same brief and supersede this one (§3, first rule). `ENDED` and `CLOSED` are a card that finished or stopped inside the window: read its report or screen first, and start it again only when that shows the work is not done. The card's Orca parent is how this session finds the card again when it ends (`end-session` §3); a `--no-parent` card goes in the worklog instead. Results are fire-and-forget by default: do not loop on `tui-idle`, do not block repo A on repo B. Only when the user says "결과 받아와": tell the target session in the brief to append its result to the brief note, and read the note when this session actually needs it.