#+TITLE: Cross-Project Broadcast Workflow #+AUTHOR: Craig Jennings & Claude #+DATE: 2026-05-29 * Overview Fan out a single message to every AI project's inbox in one operation. Discovers projects by fingerprint (any directory with =.ai/protocols.org=) and delivers via the existing =inbox-send.py= per-target. The point is announcing a new capability or shared change once, instead of hand-walking 20+ projects. * When to Use This Workflow User triggers: - "broadcast this to every project" - "notify every project about " - "fan out this announcement" - "let every project know X is available" Automatic invocation: - *New machine-global capability landed.* A new script in =~/.local/bin/=, a new MCP server registered, a new tool installed (e.g. =signal-cli=, =page-signal=). Projects need to know it's available so their agents can use it. - *Shared rule or protocol change.* When a change to =claude-rules/= or =claude-templates/.ai/= materially affects how every project's agent should behave, broadcast a heads-up so the next session of each project picks it up explicitly rather than discovering it on rsync. - *Deprecation notice.* When a script, workflow, or rule is going away, give every project a chance to migrate before the removal lands. * When NOT to Use This Workflow - *Project-specific work.* A handoff intended for one project goes through =inbox-send= directly, not broadcast. - *Routine status updates.* The session log and todo.org cover routine work. Broadcast is for capability- or rule-level changes. - *Bulk noise.* Every broadcast adds N inbox files. Use sparingly. Ask whether projects actually need to know. - *Every commit.* Most commits are project-internal hygiene (audit, intake, TODO updates) that the other projects don't care about. Even cross-project workflow updates rsync into every project's =.ai/= at next startup, so the capability lands without a broadcast. Broadcast only when projects need to *act* on the change (use a new tool, migrate before a deprecation, change their behavior per a new rule). Resist the urge to fan out a "here's what shipped today" digest. The startup rsync already carries the bits; the broadcast carries the *attention*, and attention is the costly resource. * Cadence Guideline Broadcasts are capability-and-rule-level events, not commit-level events. A reasonable cadence is one to four broadcasts per month, depending on what landed. Five reasons for the restraint: 1. Each broadcast costs N inbox processings across the fleet (currently ~23 targets). Daily broadcasts mean daily noise. 2. Most commits are project-internal. Other projects do not need to read about another project's TODO sweeps, audit passes, or hygiene work. 3. The startup rsync already does the capability work. Broadcasts add awareness, not availability. 4. Aggregation wins. One weekly "here's what shipped" digest beats ten per-commit pings on every dimension. Fewer inbox files, easier to skim, easier to defer reading. 5. Per-commit broadcasts train projects to ignore inbox. Then a real handoff gets missed. If a session ships several broadcastable changes, bundle them into one broadcast at session end rather than firing one per commit. * The Workflow ** Phase A — Discover targets Run the discovery helper: #+begin_src bash python3 .ai/scripts/cross-project-broadcast.py --list #+end_src The helper scans =~/code/=, =~/projects/=, =~/.emacs.d= for any directory containing =.ai/protocols.org=. Prints the basename and full path of each, in sender-excluded order (the current project never receives its own broadcast). ** Phase B — Compose the message Write the broadcast body to =/tmp/broadcast-.org=. Required structure: #+begin_example ,#+TITLE: ,#+DATE: YYYY-MM-DD ,#+SOURCE: ,* What's new ,* How to use it ,* Why this matters / when to use ,* Action required - =FYI=, no action required (most broadcasts) - =Update workflow X= to reference the new capability - =Deprecate workflow Y= by date Z #+end_example The structure is rigid on purpose. Every project's next session has to read 20+ broadcasts as efficiently as possible. The standard headings let the agent scan in seconds. ** Phase C — Confirm scope with the user Surface the discovered project list and the message inline. Ask: #+begin_example Broadcast scope: - Target projects: (list) - Message: <2-line summary> - Action required: 1. Send to all targets (recommended) 2. Exclude specific projects (name them) 3. Cancel — message stays at /tmp/broadcast-.org #+end_example ** Phase D — Fan out Run the broadcast helper with the composed message: #+begin_src bash python3 .ai/scripts/cross-project-broadcast.py \ --file /tmp/broadcast-.org \ [--exclude project1 --exclude project2 ...] #+end_src The helper iterates over targets, runs =inbox-send.py --file = per target, captures success/failure per project. The =from-= prefix in the resulting filename traces provenance. ** Phase E — Report Summarize the fan-out: - Total targets discovered - Sent successfully (count) - Failed (list with reason) - Excluded (list with reason) If any failures, surface them — silent failure on a broadcast means some projects never learn about the change. ** Phase F — Cleanup Delete =/tmp/broadcast-.org=. The content lives in each target's inbox now. * Common Mistakes 1. *Broadcasting project-specific work.* Each broadcast costs N inbox files across the fleet. Routine handoffs go through =inbox-send= directly. 2. *Skipping Phase B's structure.* Free-form broadcasts force every recipient to parse them differently. Use the rigid headings. 3. *Sender-includes-itself.* The discovery helper excludes the sender automatically. Don't override it — broadcasting to your own inbox creates a self-reply loop. 4. *Forgetting Phase E.* A broadcast that partially succeeded is the failure mode you'll never notice. Always check the per-target results. 5. *Broadcasting without an "Action required" line.* Recipients need to know whether this is FYI or whether their project has to do something. The line is non-optional. 6. *Using broadcast as a substitute for documentation.* Capability announcements should be paired with a rule or workflow update so the next-next session can rediscover the capability from canonical docs, not from a stale inbox file. * Living Document If the discovery roots change (a new top-level directory for AI projects), update =cross-project-broadcast.py='s =SEARCH_ROOTS=. If the per-broadcast structure proves too rigid or too loose, tune Phase B. If the recipient projects start complaining about broadcast noise, the rule is "broadcast less," not "structure broadcasts harder."