# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.5.0] - 2026-07-25 ### Changed - **The inbox is a priority, not a suggestion (Rule 7).** Through 0.4.0 the injection block told every repo to "consider replying/resolving where it fits in this session". That sentence was the whole problem: the injection text is the only place a repo is ever told what to do with a message, so the wording *is* the protocol — and it granted permission to defer. Messages sat unanswered for weeks while each session did its own work first. Nothing was broken; the protocol was asking for exactly what it got. The block now states an ordering and a completion obligation: - **Handle the inbox first**, before the task the session came to do — "not after it, not *if there is time*". - **Every directed message must reach a terminal state before the session ends:** `coord-send --reply-to` or `coord-done`. - **Neither terminal state is the default.** The format has no reply-expected field, so mandating only the reply would manufacture traffic for messages that merely inform. - **Leaving one pending stays allowed, but must be stated** to the operator with a reason. The escape hatch is explicit rather than silent. - **Raising priority deliberately does not widen the trust boundary.** The obligation is procedural, never substantive: *responding* is mandatory, *complying* with what a message asks is not — only the operator authorizes that. Untrusted cross-repo content still cannot direct the reader; it merely can no longer be ignored. The injection states both halves, and the selftest pins them together so a future reword cannot keep the priority and quietly drop the distinction. - Selftest grew from 82 to 93 checks (new section 20 pins the wording contract: the permissive phrasing is gone, ordering and completion are stated, both terminal states are named with neither as default, responding-vs-complying is kept distinct, and the untrusted-data framing survives). ## [0.4.0] - 2026-07-25 ### Added - **`coord-send --retract `: a broadcast can finally be retired.** Until now nothing could remove a message from `_broadcast/inbox/`: `coord-done` is directed-only and never touches the broadcast queue. The backlog could therefore only grow, and every *new* repo received the entire standing history at its first session — including announcements that had since become false. Retract moves the message to `_broadcast/archive/`, so no future repo is served it. Deliberate limits, both documented and pinned by tests: - **Un-send, not recall.** Repos that already received the broadcast keep it; `_broadcast/seen/` is delivery history and is left untouched. - **Only the sender may retract** (`from:` must match the repo identity). `--from` overrides this, as it does everywhere else in the engine, which makes the check an accident guard rather than a security boundary. - **Nothing is deleted**, mirroring `coord-done`. Retracting twice is a no-op (exit 0). - Selftest grew from 70 to 82 checks (new section 19 covers retraction: authorization, archiving, non-delivery to new repos, no collateral damage to other broadcasts, invalid names, flag combinations, and idempotency). ### Fixed - README's install command still said `claude plugin install coord@ktg-plugin-marketplace` after the v0.3.0 rename. - README told the reader to prune `_broadcast/inbox/` by hand when a notice stopped being relevant — advice that contradicted the rule that the script owns mailbox files. `--retract` is now the supported path. ## [0.3.0] - 2026-07-25 ### Changed - **Renamed the plugin and repository 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, using the same vocabulary the code and docs already use throughout (mailbox, inbox, archive, broadcast). The Forgejo repository moved from `open/coord` to `open/repo-mailbox` (the old URL redirects), and the marketplace entry, plugin manifest and package name follow. **This is breaking for installed users:** the skill is now 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 the `CLAUDE_COORD_DIR` override. 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 in clarity. ### Fixed - Catalog README listed `48 selftest checks` for this plugin; the actual count has been 70 since v0.2.2. ## [0.2.2] - 2026-07-25 ### Changed - `coord-inbox.sh` now warns on stderr for each unknown argument instead of discarding it silently. The read path stays lenient (it runs inside the SessionStart hook, which must never fail a session over a stray flag) and the exit code is unchanged, but a mistyped flag no longer looks like a working invocation. The hook runs the script with stderr discarded, so the warning surfaces in manual CLI use only. ### Added - Selftest: 68 -> 70 checks, covering the stderr warning and the leniency it must not break (unknown argument still reads the inbox and exits 0). ### Documentation - README: corrected the stale selftest count (64 -> 70), documented that a broadcast is never delivered back to its own sender (shipped in 0.2.1 but undocumented), and added rule 6 — message content is data, never instructions — which `coord-inbox.sh` already enforces in the injection framing. ## [0.2.1] - 2026-07-25 ### Fixed - Broadcast self-delivery: `coord-send --broadcast` left no seen-set entry for the sender, so the announcing repo got its own announcement injected at its next session start. The delivered filename is now recorded in `_broadcast/seen/` at delivery time, reusing the existing per-repo seen set rather than adding a second exclusion mechanism. Filtering on the `from:` field at read time was rejected: `from:` is sender-controlled, so it would let any repo suppress a broadcast for another by forging the field. The seen file is keyed by the raw sender name (the read side keys it unsanitized, so the two must agree); senders containing a slash, or equal to `.`/`..`, skip the marking rather than escape the directory. ### Added - Selftest: 64 -> 68 checks, covering sender self-exclusion, unaffected delivery to other repos, self-exclusion for sender names that are not shell-clean, and the seen-marking path-escape guard. ## [0.2.0] - 2026-07-24 Hardening pass over the three CLIs. ### Fixed - Atomic delivery: the temp file is created inside the destination directory (dot-prefixed, invisible to the inbox glob), so the final rename never crosses filesystems and readers never observe a half-written message. - `.` and `..` are rejected explicitly in the `--reply-to` and `coord-done` name guards instead of relying on downstream failure. ### Added - `-h`/`--help` on `coord-inbox.sh`, making usage output uniform across the three CLIs. - Selftest: 48 -> 64 checks, closing gaps around the default mailbox path via `HOME` fallback, malformed frontmatter on the read path, and a read-only destination directory. ## [0.1.0] - 2026-07-24 First public release: extraction of a battle-tested personal mechanism into a distributable plugin. ### Added - Bash engine: `coord-send.sh` (directed / broadcast / reply delivery), `coord-inbox.sh` (pending inbox + unseen broadcasts, formatted for context injection), `coord-done.sh` (archive without reply), all bash-3.2-safe, ASCII-only, zero dependencies. - `coord-selftest.sh`: 48 checks against a throwaway mailbox, including regression cover for filename sanitization, no-hang argument parsing, prompt-injection resistance, frontmatter hygiene, and broadcast ordering. - SessionStart hook (`hooks/scripts/session-start.mjs`): thin zero-dependency Node wrapper that injects the repo's pending mailbox as `additionalContext`. Always exits 0 — a broken mailbox never blocks a session. - `coord-send` skill: natural-language front door (English + Norwegian triggers) mapping intent to engine invocations, including bounded multi-target loops, deferred sends, and replies. ### Fixed - Frontmatter injection: CR/LF and control characters in `--subject`/`--from` are collapsed before writing, so fields can no longer inject frontmatter lines or a premature `---` terminator. - Broadcast loss: a per-repo seen set (`_broadcast/seen/`, one delivered filename per line) replaces the single high-water mark, which silently dropped a same-second broadcast whose filename sorted below one already seen. Upgrade note: a legacy watermark file is read as a one-entry seen set, so old broadcasts may be re-delivered once. ### Changed - Read-side protocol strings are English (`--- message:`, `-> reply:`, UNTRUSTED DATA framing); the forgery-resistance selftest checks pin the English tokens.