--- name: coord-send description: >- Send an inter-repo coordination message through the local coord mailbox — a natural-language front door over the `coord-send` script. Use this whenever the user wants to notify, tell, message, ping, or coordinate with another repository (or all repositories) about work happening in the current repo: "send info to all repos", "tell repo-x the bug is fixed", "let repo Y and Z know", "broadcast that the spec changed", "reply to that coord message", or a deferred/conditional notice like "when the build is green, notify repo X". Also triggers on Norwegian phrasings: "send info til alle repo", "varsle repo X", "gi beskjed til Y og Z", "kringkast at …", "svar på coord-meldingen", "når Z er ferdig, varsle X". Trigger even when the user names a repo plus something to convey without saying "coord" explicitly — routing a message to another repo IS this skill. Also covers retiring a broadcast that has become wrong or obsolete: "retract that broadcast", "that announcement is outdated, pull it", "trekk tilbake kringkastingen", "den broadcasten er utdatert". version: "0.17.0" --- # coord-send — natural-language front door for inter-repo messages This skill turns a plain request ("tell repo X that Y happened") into the right `coord-send` invocation. The script is the engine; this skill is only the mapping from intent to arguments. It never edits mailbox files by hand — always go through the script, because the script owns the filename grammar, frontmatter, and delivery guarantees. ## Boundary — why messages are thin The mailbox is **transport, not state**. A coord message is a *notice*, not the source of truth. The durable record of any decision lives in the owning repo's state files / docs and its git history. So when you compose a body, write a self-contained heads-up and point at where the real record lives (a commit hash, a doc path) — don't try to make the message itself the canonical artifact. Coordination content is also private: it never belongs on a public surface. ## The engine CSEND="${CLAUDE_PLUGIN_ROOT}/scripts/coord-send.sh" There is no deployed copy anywhere else and no fallback path. A Bash tool call never has `CLAUDE_PLUGIN_ROOT` set as a real shell variable — only this skill's own rendering resolves the token — so a `${CLAUDE_PLUGIN_ROOT:-$HOME/.claude}` fallback silently won every time the line above was actually executed, routing through whatever happened to sit at `~/.claude/scripts/coord-send.sh` instead of the plugin's own bundled script. That path was never a legitimate parallel deployment — the operator invokes this skill only through its natural-language front door, never a personal terminal alias — so the file that sat there was a pure accident target with no owner keeping it current. It has been deleted. If this fails to resolve, the fix is this expression — never a restored fallback. Interface (body comes from a quoted heredoc so nothing in it is shell-expanded): # to one repo "$CSEND" --to --subject "" <<'BODY' BODY # to every repo (accumulates; first-time newcomers see it too) "$CSEND" --broadcast --subject "" <<'BODY' BODY # reply to a message this repo received (routes to the original sender and # marks the original handled; target + "Re: …" subject are inferred) "$CSEND" --reply-to <<'BODY' BODY # retire one of THIS repo's own broadcasts (no subject, no body) "$CSEND" --retract # a notice that needs no answer (any of the forms above) "$CSEND" --to --subject "" --fyi <<'BODY' BODY Sender identity (`--from`) defaults to the basename of the current git toplevel, so you almost never set it. Outside a git repo there is no default — the send refuses with exit 2 rather than naming itself after the working directory, so on a global surface (`~/repos`, `$HOME`) pass `--from ` and make the identity a choice. Exit 0 = delivered; exit 2 = usage/IO error (read stderr and fix the arguments rather than retrying blindly). ## Does it need an answer? (`--fyi`) Every message declares whether its sender expects a reply. **Omitting `--fyi` is the declaration that one is expected** — that is the default, and it is the safe one: a forgotten flag over-counts what the recipient owes, which is visible, while the opposite would create debt nobody ever sees. Pass `--fyi` when the message is genuinely a notice: "shipped 0.9.0", "the spec moved to docs/x.md", "your build is green again". Omit it when you are asking a question, requesting a decision, or handing over work — anything where silence would leave *you* blocked. Two things this flag is not: - **Not a way to lower the bar for the recipient.** Both terminal states stay open on every message: a `--fyi` message must still be closed with `coord-done`, and the recipient may still reply. The field says what *you* expect, and the receiving session is told in as many words that it is a declaration, not an instruction. - **Not available on a broadcast.** `--broadcast` always writes `reply-expected: no`, `--fyi` or not, because there is no reply path to a broadcast at all (`--reply-to` resolves inside the recipient's own mailbox). Passing it there is harmless and changes nothing. A reply is not a special case either: `--reply-to` without `--fyi` expects one back. When your reply closes the exchange — and it usually does — say so with `--fyi` rather than leaving the other repo an open item. ## Choosing the target - **One named repo** → `--to `. The repo name is its directory basename; use the name the user gave. No registration exists — sending to a new name just creates that repo's inbox, so a typo silently creates a dead mailbox. If unsure a name is real, check `~/repos/` or existing `~/.claude/coord//` before sending. - **Several named repos** ("X and Y") → loop `--to` once per repo with the same subject and body. There is no multi-target flag; the loop is the mechanism: for repo in repo-x repo-y; do "$CSEND" --to "$repo" --subject "" <<'BODY' BODY done - **All repos** → `--broadcast`. Prefer this only when the notice genuinely concerns everyone, because broadcasts accumulate and every future first-time repo sees the standing backlog. For a bounded, known set, loop `--to` instead so unrelated future repos don't inherit it. A broadcast that later turns out wrong can be retired with `--retract` (see below), but only for repos that have not received it yet. - **A reply to something received** → `--reply-to `. Use the filename from the injected inbox/archive; it resolves the sender and closes the original in one step. ## Retracting a broadcast When a broadcast has become wrong or obsolete, retire it — don't send a correction and leave the original standing, because every future first-time repo would receive both. `--retract ` archives it out of the delivery queue. Three things to be honest about when you report it: - **It is un-send, not recall.** Repos that already received the broadcast keep it. Retraction only stops delivery to repos that haven't seen it yet. If the old news actively misleads someone who already got it, a correcting broadcast is still needed — retraction alone does not reach them. - **Only the sender may retract.** The `from:` field must match this repo's identity. If the announcing repo has since been renamed, its old identity no longer resolves, so pass `--from ` explicitly (read the sender off the file). Say that you did. - **Nothing is deleted.** The message moves to `_broadcast/archive/`. Never remove a mailbox file by hand — the script owns the filename grammar and delivery guarantees. Find the filename in `~/.claude/coord/_broadcast/inbox/` (or from the injected `--- broadcast: ---` line) rather than guessing it. ## Composing the message Derive a short, specific `--subject` from the intent if the user didn't give one ("ingest bug fixed", not "update"). In the body, state what happened, what the recipient should know or do, and a pointer to the durable record (commit hash, doc path). Keep it to the point — this is a notice, not a report. Match the repo's language convention for message content; keep it sober and factual. ## Deferred and conditional sends "When Z is done, notify X" means: do **not** send now. Hold the intent — the target, subject, and body — and continue the work. The moment condition Z is satisfied *in this session*, fire the send. This works because you carry the intent across turns within a session. Be honest about the limit: a skill cannot persist intent across sessions. If the session is ending and the condition still hasn't been met, surface the pending message to the user so it isn't silently lost — don't imply it will fire later on its own. ## After sending Report what actually happened: the target(s), the subject, and the delivered filename(s) from the script's stdout. If a send failed (exit 2), say so with the stderr reason rather than claiming success. Delivery reaches the recipient at *their* next session start (the receive side is a hook), so tell the user it's queued, not that the other repo has seen it. ## Examples **Example 1 — single repo, composed body** Input: "tell repo-x the ingest bug is fixed, it was commit abc1234" Action: `--to repo-x --subject "ingest bug fixed"`, body naming the fix and pointing at commit abc1234 and the owning doc. **Example 2 — broadcast** Input: "let all the repos know the shared spec grew a new validation rule" Action: `--broadcast --subject "spec: new validation rule"`, body summarizing the change and pointing at the spec's owning repo. **Example 3 — bounded multi-target** Input: "gi beskjed til repo-x og repo-y om at gaten er re-pinnet" Action: loop `--to repo-x` then `--to repo-y`, same subject "shared gate re-pinned". **Example 4 — deferred** Input: "når testene er grønne, varsle repo-y" Action: keep working; once the test run passes this session, send `--to repo-y` with the green result. If the session ends first, surface the pending notice to the user. **Example 5 — reply** Input: "svar på coord-meldingen fra repo-x at vi tar det" Action: `--reply-to `, body acknowledging and stating the plan. **Example 6 — retract** Input: "den gamle kringkastingen om plugin-navnet er utdatert, trekk den" Action: locate the file in `_broadcast/inbox/`, then `--retract ` (adding `--from ` if this repo has been renamed since). Report that repos which already received it are unaffected.