# repo-mailbox Renamed from `coord` in v0.3.0. The plugin/repo is `repo-mailbox`; the CLI (`coord-send.sh`, `coord-inbox.sh`, `coord-done.sh`), the mailbox root (`~/.claude/coord/`) and `CLAUDE_COORD_DIR` deliberately kept their names — they are the transport protocol, not the product. ## Context Local inter-repo coordination mailbox for Claude Code, packaged as a marketplace plugin. Three components, one boundary: - **Engine (`scripts/*.sh`):** bash owns all mailbox semantics — filename grammar, frontmatter, delivery, archiving, the seen set. `coord-send.sh` writes, `coord-inbox.sh` reads (formatted for context injection), `coord-done.sh` archives, `coord-count.sh` counts without delivering, `coord-sweep.sh` closes the aged FYI backlog machine-wide. Everything is pinned by `coord-selftest.sh` (257 checks, throwaway mailbox via `CLAUDE_COORD_DIR`). **`ktg-plugin-marketplace` is a RETIRED `--to` address (operator decision 2026-08-15), rejected rather than redirected.** It is a polyrepo directory, not a git repo, so `basename(git toplevel)` can never resolve to it and no session was ever able to hold that identity naturally - mail for it belongs to `catalog` instead. A silent redirect was considered and declined: it delivers mail somewhere the sender does not believe it landed, which is the same misdelivery defect this closes a second time (2 messages sat undelivered 2 days on this exact misaddressing before `catalog`'s H4 count caught 6 more). Rejection fails loud at the sender, at the moment the mistake is made. Only `--to` is retired, not `--from` - the defect was mail *arriving* there, never mail claiming to *originate* there. **`coord-send --reply-to` asserts "marked handled" against GROUND TRUTH, and the exit code alone is NOT that ground truth.** The line used to print unconditionally with `coord-done`'s output discarded (`>/dev/null 2>&1`), so the one line a session relies on to close a reply debt was false at the moment it was printed — measured with a stub `coord-done` exiting 1: original still in the inbox, no `archive/`, exit 0, "marked handled". Every reply this repo sent had to be verified by hand afterwards, which is what a false success in the TRANSPORT costs. The check is `exit 0` **and** the original no longer being at `$COORD/$FROM/inbox/$REPLYTO`, because `coord-done` exits 0 when it archives nothing (an unknown name is idempotently fine by its own contract), so a nonzero-exit test still certifies a message that never moved. The path is recomputed rather than reusing `$REPLY_ORIG`, which resolves to the inbox OR the archive — replying to an already-archived original moves nothing and must not warn. Failure is exit **1**, a new status: the reply WAS delivered and re-sending would duplicate it, so 2 stays the nothing-was-written status it has always been. Selftest section 34 pins all four cases (fails outright / exits 0 without moving / real happy path / archive-path reply). **`--to` is the one line-oriented field that is REFUSED rather than sanitized, and the asymmetry with `--from`/`--subject` is the whole point.** A target name is also the destination DIRECTORY name (`$COORD/$TO/inbox`, and `$COORD/$TO/orders` in `coord-order-send.sh`), so collapsing a control character to a space the way `sanitize_field` does everywhere else would deliver the message to a mailbox the sender never named - the same misdelivery the retired `ktg-plugin-marketplace` address is rejected rather than redirected to avoid. Both corruptions were measured on the live engine before the guard existed, each with exit 0 and a "delivered" line: a newline lands its payload INSIDE the frontmatter block, above the `reply-expected: yes` the engine itself wrote, so `coord-count` reads `owed=0` and the debt the engine declared is silenced (defeating its own rule that only the frontmatter block may speak - the injected line IS in the block); a tab makes `coord-count` print FIVE tab-separated fields where its contract is four, so a consumer reads the mailbox name as the part before the tab and its pending count as the part after. `board.sh` consumes that TSV. The guard sits AFTER reply-mode resolution because `--reply-to` takes the target from the original's `from:` line - untrusted cross-repo input this repo did not write, and the one target name nobody typed. The denominator was measured rather than assumed: two scripts build a directory from a caller-supplied name, and `coord-order-send.sh` had the identical defect, where it costs more - an order filed under a name no session can hold is exactly the silent evaporation the ownership chain exists to prevent, while `board.sh`'s ORDRE column counts the INTENDED repo's queue and stays 0 with nothing reporting a failure. The read-side `--repo` arguments were checked and left alone: they resolve an EXISTING directory, so a control character there finds nothing and writes nothing. Both selftests carry the mandatory known-positive controls - an ordinary name still delivers, and so does a dot-prefixed one, since `coord-send.sh`'s own guard comment protects dot names as real repos (`basename` of a git toplevel under a hidden directory). **`coord-sweep.sh` is the only path that closes a message with no human in the loop, and every constraint on it follows from that.** It may close exactly one mechanically decidable class - `reply-expected: no`, older than the grace window - because a message that owes a reply can only be answered by a session in the repo that owes it. Dry-run is the default, inverted from the rest of the engine, since this is the one script that destroys pending state. It closes through `coord-done.sh --repo` rather than moving files, so the archive layout and the `_broadcast` refusal stay in one place. And it logs every closure with sender and subject, because directed messages have no seen-tracking: the sweep genuinely cannot tell "seen and ignored" from "never delivered", so a notice can be closed unread and the log is the only record that it existed. Widening the class, defaulting to `--write`, or dropping the log each independently turn this from a bounded cleanup into silent data loss. **Order 20260902T113745Z-1254925290 (WP5, 2026-09-02, amended by the operator 2026-09-03): the sweep was CORRECT AND UNREACHABLE, and the fix is a schedule, not a mechanism.** It 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, of which **23 were pure notices** being re-injected at every session start in repos nobody had opened. The order asked for a mechanism and named two candidates; the measurement chose neither, and the session returned it saying so. Bulk-ack for pure notices *was already built* - this script - so building the order's candidate B 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, not reduced them. `launchd/com.ktg.repo-mailbox-sweep.plist` is the entire 0.33.0 change. **Invocation was the gap.** **The 14-day window is written OUT in the plist, never left to the script's default.** It is a policy constant the operator chose on a measured distribution (30d -> 0 messages, 14d -> 7, 7d -> 13), of the same class as the STATE.md line limit - so a later change to `DAYS=14` in the script must not silently change what an unattended nightly job closes across every other mailbox on this machine. (A hard count belongs in the dated measurement doc, not here: it was 52 with an `inbox/` on 2026-09-03 and 53 a day later.) The agent runs at **05:30**, clear of the 06:00 briefing agent, because the briefing scans the same mailbox this mutates; selftest section 38 asserts the two hours differ. It does **not** change the briefing's DEBT figure - since 0.22.0 that is read from `coord-count.sh`'s `owed` column, and this sweep closes only messages that owe nothing, so the debt listing is byte-identical before and after. What moves is the raw pending count (the table's `INN` column, `--brief`'s FYI-only naming, and the volume injected at every session start). The first cut of this paragraph claimed the sweep made the briefing report "the debt that remains" - an overclaim, caught in review, and recorded here because it is the kind of plausible sentence that survives a reread. **`launchctl list` proves an agent is LOADED, never that it is RIGHT, and a wrong program path is the one defect in this repo that nothing catches at runtime** - the agent simply never runs, in silence, with no output to be wrong and no exit status to read. Two separate things close it, and neither substitutes for the other: `launchctl start