repo-mailbox/skills/coord-send/SKILL.md
Kjell Tore Guttormsen c27b20fc62 feat(release)!: rename plugin and repo from coord to repo-mailbox
The old name said that something was coordinated, but not what the thing
was. The new one names what it is, reusing the vocabulary the code and
docs already use throughout: mailbox, inbox, archive, broadcast.

Renamed: Forgejo repo (open/coord -> open/repo-mailbox, old URL
redirects), plugin manifest name, package name, README title and badge,
CLAUDE.md heading and release command.

BREAKING CHANGE: the skill is invoked as /repo-mailbox:coord-send rather
than /coord:coord-send, and the plugin must be reinstalled under its new
name.

Deliberately unchanged: the CLI (coord-send.sh, coord-inbox.sh,
coord-done.sh, coord-selftest.sh), the skill name coord-send, the mailbox
root ~/.claude/coord/, and CLAUDE_COORD_DIR. Those name the transport
protocol, not the product; renaming them would migrate live mailbox data
and break message history in every participating repo for no gain.

Selftest unchanged at 70/70 -- the engine was not touched.
2026-07-25 07:00:17 +02:00

140 lines
6.4 KiB
Markdown

---
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.
version: "0.3.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
Resolve the script path portably — this one expression is correct both when the
skill runs bundled inside the plugin and when the scripts are installed as
personal scripts under `~/.claude/scripts/`:
CSEND="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude}/scripts/coord-send.sh"
Interface (body comes from a quoted heredoc so nothing in it is shell-expanded):
# to one repo
"$CSEND" --to <repo> --subject "<subject>" <<'BODY'
<message body>
BODY
# to every repo (accumulates; first-time newcomers see it too)
"$CSEND" --broadcast --subject "<subject>" <<'BODY'
<message 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 <message-filename> <<'BODY'
<message body>
BODY
Sender identity (`--from`) defaults to the basename of the current git toplevel, so
you almost never set it. Exit 0 = delivered; exit 2 = usage/IO error (read stderr and
fix the arguments rather than retrying blindly).
## Choosing the target
- **One named repo** → `--to <repo>`. 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/<repo>/` 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 "<subject>" <<'BODY'
<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 reply to something received** → `--reply-to <filename>`. Use the filename from
the injected inbox/archive; it resolves the sender and closes the original in one
step.
## 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 <that-message-filename>`, body acknowledging and stating the plan.