Post-Completion — manual, NOT automated. This is the only path that cannot be unit-tested: it needs a real interactive Claude Code session and a human-attended terminal to observe an idle session actually waking. The wire schema itself is fully covered by automated tests (see
internal/channel/channel_test.go) against the DOCUMENTED schema inCHANNELS_SCHEMA.md; this checklist verifies the live behaviour end-to-end. Running it is the final go/no-go for the cc adapter.
- A broker reachable from this machine, running as a managed long-lived
service (NOT per-session). Note its
ws://host:port, bearer token, and HMAC secret (provisioned out-of-band). peerbusbinary built (make build).- A second peer to send from — use the generic adapter
(
peerbus adapter --adapter=generic) wired into any agent, or a throwaway test client. - Claude Code v2.1.80+ (channels research preview;
--dangerously-load-development-channelsavailable).
In the project where the Claude session will run:
{
"mcpServers": {
"peerbus": {
"command": "/abs/path/to/peerbus",
"args": ["adapter", "--adapter=cc"],
"env": {
"PEERBUS_URL": "ws://BROKER_HOST:PORT",
"PEERBUS_TOKEN": "THE_BEARER_TOKEN",
"PEERBUS_HMAC_SECRET": "THE_SHARED_SECRET"
}
}
}
}(Use the env/flag names the binary actually reads — confirm against
cmd/peerbus.) Leave the peer name unset to exercise
auto-registration; the adapter mints cc-<hostname>-<pid>-<rand> (see
channel.UniqueName).
From a real, human-attended terminal:
claude --dangerously-load-development-channels server:peerbusConfirm at startup that Claude Code loaded the channel (no capability
error). The adapter advertises
capabilities.experimental["claude/channel"]={} and tools={}; Claude Code
registers the notification listener and discovers bus.send,
bus.broadcast, bus.peers.
Do not type anything. Wait until the session is idle (no active turn).
Using the generic adapter / test client registered under a different name,
send a direct message addressed to the cc adapter's peer name (read it from
the cc adapter's stderr log line, or call bus.peers from the second peer):
bus.send to=<cc-adapter-peer-name> body={"text":"ping from peer 2"}
Expected: the idle Claude session wakes and a new turn is created
containing a <channel> XML block, e.g.:
<channel source="peer-bus" from="<peer-2-name>" msg_id="<id>">
ping from peer 2
</channel>contentis the message body as text.metabecomes<channel>attributes:from,source(the envelopesource,peer-bus),msg_id.
If the session does NOT wake: verify the broker delivered the frame (broker
audit log), that the adapter registered (its stderr), and that
channelsEnabled org policy is not blocking (CHANNELS_SCHEMA.md §6 —
silently dropped if disabled).
In the woken Claude session, have Claude call bus.send back to peer 2:
bus.send to=<peer-2-name> body={"text":"pong from claude"}
Confirm peer 2 receives pong from claude. This proves the two-way path:
push-wake in, ordinary MCP tool call out (no special reply notification, no
turn/correlation id — CHANNELS_SCHEMA.md §4).
From peer 2, bus.broadcast a message. A broadcast from a different peer
now wakes the cc session exactly like a direct message: the broker delivers
the sender's verbatim signed envelope (to:"*", original id, original
HMAC) and the per-recipient routing/ack identity rides on the
wire.Deliver.delivery_key field, OUTSIDE the HMAC canonical subset — so the
copy verifies end-to-end and produces a notifications/claude/channel push.
The session is NOT woken by its OWN broadcast copy (sender exclusion: the
broker never fans a broadcast back to its sender). Direct and broadcast are
now both verified end-to-end push-wake paths.
(Historical note: an earlier broker rewrote the signed id/to per recipient,
which broke broadcast HMAC and forced a log-and-skip. That has been fixed —
the broker no longer mutates the signed envelope; the parity test
TestParity_BroadcastFanOutSenderExcluded now hard-asserts real delivery +
end-to-end verification.)
- Channel loaded with no capability error.
- Idle session woke on the direct message (turn created,
<channel>block with correct content +from/source/msg_idattributes). - Claude's
bus.sendreached peer 2. - No orphaned adapter process after the session exits (lifecycle bound to stdio — kill the Claude session, confirm the adapter exits).