coord-sweep.sh shipped in 0.10.0 and had never run once against the real mailbox. Measured 2026-09-03 with a denominator (docs/2026-09-03-coordination- debt-measurement.md): 55 mailbox directories, 52 with an inbox/, 27 pending directed messages - 23 of them pure notices, re-injected at every session start in repos nobody had opened. The script was correct and unreachable. WP5 (order 20260902T113745Z-1254925290) asked for a mechanism and named two candidates. The measurement chose neither, and the first session returned the order saying so: bulk-ack for pure notices was already built - it is this script - so the second candidate would have been two copies of one policy, and the broadcast class converges on its own (reading sets seen), with 34 of 263 unread pairs belonging to two mailboxes no session can hold, so a TTL would have closed those rather than reduced them. The operator then chose the window and authorized the schedule. launchd/com.ktg.repo-mailbox-sweep.plist runs --write --days 14 daily at 05:30. That is the entire behavioural change. The window is written out in the plist rather than inherited from the script's default: it is a policy constant chosen on a measured distribution (30d -> 0 messages, 14d -> 7, 7d -> 13), so a later change to DAYS=14 must not silently change what an unattended job closes across 51 other repos. It runs BEFORE the 06:00 briefing agent, which scans the same mailbox this mutates, so the morning briefing reports the debt that remains rather than counting notices being closed underneath it. coord-selftest.sh section 38 pins the launchd templates (242 -> 257 checks). A wrong program path is the one defect here that nothing catches at runtime: the agent loads cleanly and then silently never runs, with no output to be wrong and no exit status to read. launchctl list proves an agent is LOADED, never that it is RIGHT. The section covers every plist in launchd/, not only the new one - the plist grammar gets one reader rather than one per agent - while board-selftest.sh section 9 keeps owning brief-nightly.sh's behaviour. Each plist must name a script that exists here, carry a Label matching its filename, keep its __CHECKOUT__/__HOME__ placeholders (public mirror), and never point into the version-pinned plugin cache. The cache assertion runs on the extracted path, never the whole file - caught by the check itself on its first run: the brief plist's header explains in prose why it does not point at the cache, and a file-wide grep read that explanation as the defect it warns about, the same shape as prose saying status=done triggering the board's done-guard. Four controls present; mutation- verified against the real file, where a one-letter typo (coord-sweeep.sh) turns exactly that check red. XML well-formedness is deliberately not checked: plutil is not coreutils, and malformed XML already fails loudly at launchctl load - the opposite of the silent failure this section exists for. Also fixes the README selftest-checks badge, stale at 529 since 0.25.0; the real total is 868 (257 + 368 + 73 + 116 + 54). Suites: coord 257, board 368, route 73, orders 116, guard 54. npm test 11/11. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
219 lines
11 KiB
Markdown
219 lines
11 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. 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.33.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 <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
|
|
|
|
# retire one of THIS repo's own broadcasts (no subject, no body)
|
|
"$CSEND" --retract <broadcast-filename>
|
|
|
|
# a notice that needs no answer (any of the forms above)
|
|
"$CSEND" --to <repo> --subject "<subject>" --fyi <<'BODY'
|
|
<message 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 <repo>` 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 <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 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 <filename>`. 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 <broadcast-filename>` 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 <old-sender>` 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: <filename> ---` 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 <that-message-filename>`, 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 <that-filename>`
|
|
(adding `--from <old-sender>` if this repo has been renamed since). Report that
|
|
repos which already received it are unaffected.
|