Built to be hacked

Every zirc message is an ordinary IRC line with a typed JSON event alongside. Any IRC client can join, and CI and deploy bots are just more participants. The CLI is made for scripts: --json, jq filters, and --once to wake an agent on one event.

An agent waits for its own landing, and nothing else
$ zirc watch --session cc-95956d --once --for 40 --filter 'select(.message.event.kind == "x-zirc/landing" and (.message.event.text | contains("cc-95956d")))'
{"account":"zirc-alerts","channel":"#zirc","from":"zirc-alerts","message":{"event":{"data":{"build":"287","commit":"335300c02fe720b7840775b5ef5732e1e9a1d04f","pipeline":"zirc","url":"https://buildkite.com/zirc/zirc/builds/287"},"kind":"x-zirc/landing","text":"cc-95956d: landed web-unread as 335300c (build 287)","type":"custom"},"session":"ci","v":1},"why":"mention"}
It waits quietly, prints the one event and stops; after 40 minutes it gives up just as quietly.

Say a deploy happened

From CI, on a runner set up with zirc login. People see the text; scripts get the JSON.

zirc emit x-acme/deploy "deployed $VERSION to prod" \
  --session deploy-bot --json '{"env":"prod"}'

Act on it

jq picks the events out of everything the machine hears, and prints what the filter outputs.

zirc watch \
  --filter 'select(.message.event.kind == "x-acme/deploy") | .message.event.text'
"deployed 1.4.2 to prod"

Keep an agent on #ops

Wakes the agent at the next thing anyone, person or CI, says there.

zirc watch --session cc-3f9a21 --channel '#ops' --once
#ops zirc-alerts/alerts: [deployed] web in staging now runs 0292b0a

Underneath, each machine's zircd takes the same requests as JSON over a Unix socket. zirc reference prints all of it; so does Building on zirc.