Events β notify, mailbox, bus
The events facade β a session mailbox by default, a local event broker behind it.
bro comms notify writes through one events facade β mailbox by default,
or the local broker when "connectors": { "events": "bus" } selects it.
The notify connector's postTool probe drains drops into session
context, so a watcher, fixer, or convoy worker reaches a live session
mid-turn instead of the recipient burning tokens in a wait loop.
The mailbox itself is plain files β no broker, no config, no daemon β
and bro review watch --notify writes there directly (a raw dropMailbox
tmp+rename), bypassing the facade: connectors.events routes bro comms notify writes only, never watch drops.
The mailbox β bro comms notify
One atomic drop (tmp+rename) per event into
<git-common-dir>/bro/notify/ inside a repo β shared across linked
worktrees via the common git dir β or the XDG state dir
($XDG_STATE_HOME, default ~/.local/state) outside one.
| Command | What it does |
|---|---|
bro comms notify <text> | Drop one event β delivered to every session's next postTool probe |
bro comms notify -- <text> | Verbatim text β needed when it contains option-looking words like --help |
bro comms notify --to <agentId|sessionId|orchestrator> <text> | Addressed drop for exactly one consumer β orchestrator names the session owning agents; absent means broadcast |
--kind note|info|ask|result|block | A label, never a grant β a block or ask carries no approval or scope with it |
--in-reply-to <ref> | The drop, bead, or step this answers |
--key <k> | Coalesce β a pending same-key drop from this source is superseded by the newer one |
Delivery is pull-based: a drop never wakes a sleeping session β it lands in context on the next tool call. Broadcast drops stay for every session until the drop TTL reaps them; addressed drops expire on read (single-consumer). Each drop should be self-contained β the drain renders it verbatim.
The broker β bro comms bus
A local event broker in @broject/core β topics, filters, seq cursors.
status deliberately exits 0 when the broker is down: nobody started
one is a normal state, not a fault.
| Command | What it does |
|---|---|
bro comms bus serve [--json] | Run the broker (SIGINT/SIGTERM to stop) |
bro comms bus publish --topic T --kind K [--key K] [--source S] [--to ADDR] [--cause C] [--ref R] [--payload JSON] [--json] | Publish one event and exit β connect, write, close. --to addresses one recipient (orchestrator works here too); absent means broadcast |
bro comms bus subscribe [--topic T]β¦ [--kind K]β¦ [--to ADDR] [--since N] [--json] | Stream matching events until interrupted; --since N replays from a seq cursor β a cursor outside the window reports a gap |
bro comms bus status [--json] | Liveness and counters |
GitHub webhooks β github:*
bro fleet serve ingests GitHub webhook deliveries and publishes them as bus
topics: POST /api/v1/webhooks/github maps each verified delivery to
github:<event> (github:pull_request, github:check_run, β¦) with the
payload action as kind and pr-<n>/sha-<head> as key. The
X-Hub-Signature-256 HMAC is the auth β no session token β and the
route is armed only while BRO_GITHUB_WEBHOOK_SECRET is set; unset it
answers 503, a bad signature 401. When the secret IS set, bro fleet serve
also starts the repo's broker in-process β the two commands below are
the whole local-dev receiver:
gh extension install cli/gh-webhook # once
BRO_GITHUB_WEBHOOK_SECRET=dev bro fleet serve --port 8791
gh webhook forward --repo=org/repo \
--events=pull_request,pull_request_review,check_run,check_suite,issue_comment \
--url=http://127.0.0.1:8791/api/v1/webhooks/github --secret=devHosted mode is the same route behind a tunnel or reverse proxy pointed at a repo webhook or GitHub App β the signature check survives the public Host a tunnel forwards with.
bro review act wait subscribes to github:* and polls early when a matching
event lands β a check completing wakes the wait instead of sitting out
the interval. Broker down means plain timer polling: the webhook path
is an accelerator over the default, never a requirement.
Policy
- Write, don't wait. A finished worker, a watcher that saw a transition, a fixer that needs attention β drop the event and get on with it; never poll the parent.
- Once per session, not once total. The mailbox is broadcast with a
per-session
.seencursor β a drop reaches every live session exactly once. bro review watch --notifydrops the initial snapshot and gate transitions into the mailbox β see Fleet & supervision.