aboutsummaryrefslogtreecommitdiff
path: root/.ai/workflows/broadcast.org
blob: 1be07d28f167ee08da9a188026317d8d6430f185 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#+TITLE: 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. Say a thing once instead of hand-walking 20+ projects.

Two modes share the same fan-out plumbing and differ only in what the message carries and what the receiver does with it:

- *Announcement* — a tooling, capability, or rule change every project's agent should know about. Maintainer-facing.
- *Situational* — a life or work event in Craig's world (travel, a visitor, a birth or death, quitting a job, a move) that should reach every project's agent so none is missing context. Craig says it once; each agent folds it into its own work on its own judgment.

The mode picks the message template (Compose) and the receiving contract. Everything else — discovery, scope confirmation, fan-out, reporting — is shared.

* When to Use This Workflow

*Announcement triggers:*
- "broadcast this to every project"
- "notify every project about <thing>"
- "fan out this announcement"
- "let every project know X is available"

Automatic announcement triggers:
- *New machine-global capability landed.* A new script in =~/.local/bin/=, a new MCP server, a new tool (e.g. =signal-cli=). Projects need to know it's available.
- *Shared rule or protocol change* in =claude-rules/= or =claude-templates/.ai/= that materially changes how every project's agent should behave.
- *Deprecation notice* — a script, workflow, or rule going away; give every project a chance to migrate.

*Situational triggers:*
- "broadcast the <event> to all projects" (e.g. "broadcast the travel to all projects")
- "broadcast that <situation>"
- "let every project know I'll be <away / out / unreachable> ..."

Situational mode is user-driven only — never automatic. Craig decides an event is worth every project knowing.

* When NOT to Use This Workflow

- *Project-specific work.* A handoff for one project goes through =inbox-send= directly, not broadcast.
- *Routine status updates.* The session log and todo.org cover routine work.
- *Bulk noise.* Every broadcast adds N inbox files across the fleet. Use sparingly. Ask whether projects actually need to know.
- *Every commit.* Most commits are project-internal hygiene the other projects don't care about. Cross-project workflow updates already 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 or *hold* the context. The startup rsync carries the bits; the broadcast carries the *attention*, and attention is the costly resource.

* Cadence Guideline

Broadcasts are event-level, not commit-level. A reasonable cadence is one to four per month. Each broadcast costs N inbox processings across the fleet (currently ~23 targets), so daily broadcasts mean daily noise and train projects to ignore the 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.

Situational broadcasts are naturally rare (a real life or work event), so the same restraint applies without much effort — but don't withhold one that genuinely bears on how the agents should act.

* The Fan-Out (shared by both modes)

** Phase A — Discover targets

#+begin_src bash
python3 .ai/scripts/broadcast.py --list
#+end_src

The helper scans =~/code/=, =~/projects/=, =~/.emacs.d= for any directory containing =.ai/protocols.org=. Prints basename and full path of each, sender-excluded (the current project never receives its own broadcast).

** Phase B — Compose the message

Pick the mode, write the body to =/tmp/broadcast-<topic>.org= using that mode's template (below), then continue to Phase C. The mode templates are the only place the two modes diverge.

** Phase C — Confirm scope with Craig

Surface the discovered project list and the message inline. Both modes confirm before fan-out — it reaches many inboxes and a situational message goes out under Craig's situation, so the content gets one approval first.

#+begin_example
Broadcast scope (<mode>):
- Target projects: <N> (list)
- Message: <2-line summary>
- <Action required / Receiving contract>: <one line>

1. Send to all <N> targets (recommended)
2. Exclude specific projects (name them)
3. Cancel — message stays at /tmp/broadcast-<topic>.org
#+end_example

** Phase D — Fan out

#+begin_src bash
python3 .ai/scripts/broadcast.py \
    --file /tmp/broadcast-<topic>.org \
    [--exclude project1 --exclude project2 ...]
#+end_src

The helper iterates targets, runs =inbox-send.py <target> --file <broadcast>= per target, and captures success/failure per project. The =from-<sender>= prefix in each 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). Surface any failures — a partial broadcast is the failure mode you'll never notice otherwise.

** Phase F — Cleanup

Delete =/tmp/broadcast-<topic>.org=. The content lives in each target's inbox now.

* Mode A — Announcement

A tooling, capability, or rule change. Write the body to =/tmp/broadcast-<topic>.org= with this structure — rigid on purpose, so every project's next session scans 20+ broadcasts in seconds:

#+begin_example
,#+TITLE: <one-line summary>
,#+DATE: YYYY-MM-DD
,#+SOURCE: <sender project name>

,* What's new

<two to five sentences: the capability, rule, or change.>

,* How to use it

<two to five lines: the concrete invocation, command, or path. Code in =#+begin_src= blocks. No prose walls.>

,* Why this matters / when to use

<two to four sentences: the rationale and the discrimination rule for when the new thing applies vs. when existing alternatives suffice.>

,* Action required

<one of:>
- =FYI=, no action required (most broadcasts)
- =Update workflow X= to reference the new capability
- =Deprecate workflow Y= by date Z
#+end_example

* Mode B — Situational

A life or work event Craig wants every project to know. The point is to beat the silo problem: Craig forgets to mention something during a conversation with one project, but it actually bears on how that project works and on the agent's decisions or ideas. Broadcast once, and every agent already knows by the time he's chatting with them.

** Composing principle

- *No per-project tailoring.* The broadcasting agent does NOT figure out how the event is relevant to each project. One general message goes to all. Each receiving agent decides relevance to its own current tasks.
- *General, not comprehensive.* Communicate a good amount of detail, but don't try to be exhaustive for a complex situation. Enough that an agent unfamiliar with it gets the picture and knows the shape of what changed. The receiving agent can ask Craig follow-up questions after startup.
- *Gather, then ask for gaps.* Pull the salient facts from the current session and project. Ask Craig only for the few you don't have (the concrete ones an agent would need — dates, who, where, what's changing).

Write the body to =/tmp/broadcast-<topic>.org= with this structure:

#+begin_example
,#+TITLE: Broadcast: <one-line situation>
,#+DATE: YYYY-MM-DD
,#+SOURCE: <sender project name>

,* What's happening

<A general but substantive summary: what the event is, who/what/where, any
dates or duration, what's changing. General, not comprehensive.>

,* For the receiving agent

This is situational context Craig wanted every project to have — said once and
broadcast, not a task and not tailored to this project.

- Decide for yourself whether and how it bears on this project's work and your
  suggestions. He is not prescribing actions; you judge relevance.
- Record it so it persists: add it to this project's =notes.org= Active
  Reminders. Time-box it with an end date if the situation has one (a return
  date, a departure date); otherwise hold it as standing context until it is no
  longer relevant.
- Surface it at the next startup and raise it if it touches current work.
- Ask Craig any follow-up questions then — this message is deliberately general.
#+end_example

The "For the receiving agent" block is fixed text — it travels with every situational broadcast so the message is self-describing. A receiving project's =process-inbox= reads it and acts on those instructions without needing any special-casing; the value gate accepts it as situational awareness that improves how the project works.

** Receiving behavior (what a project does with an incoming situational broadcast)

When =process-inbox= encounters a =Broadcast:= item, the disposition is *record-and-hold*, not file-as-task:

1. Add a dated entry to =notes.org= Active Reminders capturing the situation and its end date (if any).
2. If the event bears on an open task, note the connection in that task's body.
3. Surface it at the next startup; retire it once its end date passes or it stops being relevant.

* Common Mistakes

1. *Broadcasting project-specific work.* Each broadcast costs N inbox files across the fleet. Routine handoffs go through =inbox-send= directly.
2. *Per-project tailoring in situational mode.* The broadcasting agent does not analyze relevance per project — that's the receiving agent's job. One general message, full stop.
3. *Over-engineering the situational summary.* General, not comprehensive. The receiver asks follow-ups; don't stall trying to anticipate every project's needs.
4. *Skipping the announcement structure.* Free-form announcements force every recipient to parse them differently. Use the rigid headings.
5. *Sender-includes-itself.* The discovery helper excludes the sender automatically. Don't override it — broadcasting to your own inbox creates a self-reply loop.
6. *Forgetting Phase E.* A broadcast that partially succeeded is the failure mode you'll never notice. Always check the per-target results.
7. *Announcement without an "Action required" line, or situational without the "For the receiving agent" block.* Each mode's recipients need to know what the message is for.

* Living Document

If the discovery roots change (a new top-level directory for AI projects), update =broadcast.py='s =SEARCH_ROOTS=. If the per-broadcast structure proves too rigid or too loose, tune the mode templates. If recipient projects complain about broadcast noise, the rule is "broadcast less," not "structure broadcasts harder." If situational broadcasts start needing per-project routing, that's a sign the silo is better solved by the shared org-roam KB than by fan-out — revisit before adding routing logic here.