CADS-Tunnel docs
How-to

Join a published pipeline’s role channel

ct-agent channel join-pipeline-role is the generic-provisioning analogue of channel member-material (covered in Set up an Agent-Fabric channel): instead of two members exchanging keys to derive a pairwise link’s channel id, everyone who wants to serve or dial a published pipeline’s role derives the same channel id independently, from information that’s supposed to be entirely public. Every command below was actually run.

Honest gap, found writing this page. The design intent — see API endpoints and the tool's own error text — is that CT_CHANNEL_OPERATOR_PUBKEY comes from a pipeline's published operator_pubkey_hex, discoverable via GET /registry/pipelines/:id with no prior relationship needed. Checked live, right now: both real published pipelines (flappy-demo, cookbook-demo) have operator_pubkey_hex: null — neither has ever actually published one. So the mechanism below is real and works exactly as described, but today you'd still need the operator's pubkey handed to you out-of-band for either live demo, not fetched from the registry as the design intends. The example below uses a locally-generated demonstration operator key, not either demo's real one (which doesn't exist publicly yet).

1. What you need

2. Derive the role’s channel id

CT_CHANNEL_OPERATOR_PUBKEY=<the pipeline's operator pubkey> \
CT_PIPELINE_ID=flappy-demo \
CT_PIPELINE_ROLE=physics \
CT_CHANNEL_HOLDER_KEY=<your holder private key> \
CT_CHANNEL_NOISE_PUBKEY=<your noise public key> \
./ct-agent channel join-pipeline-role

Real output:

pipeline_id       = flappy-demo
role              = physics
holder_pubkey     = cd0d06c85be979754ec6d90ead28fb5a71904d15b67d5028a024444fb6237ea9
noise_pubkey      = e30617616430b1055c0cade9817e4cd18d131f9f46116b8ab4c83e9264d49a57
channel_id        = 151bac005cedddb04eb1776926547f08418206a7c69a4c63a9115eecdc79c533
noise_attestation = 80a20a42582cdd42e8f10e49097e615436e17c99dfe21cee3827fe20a2842832c31...

3. It’s genuinely order-independent — proven, not just claimed

Re-ran the exact same command with a second, completely different holder identity, same operator pubkey, same pipeline, same role:

pipeline_id       = flappy-demo
role              = physics
holder_pubkey     = c16fdea9e35aa49af1523099f7b720d957a871c899949950ba0c4f7ea66891b2   ← different
noise_pubkey      = 465b0f98ffaf7884499b6d74ec6428cad16f2f38227b9f1e9a43c0eac35d562c    ← different
channel_id        = 151bac005cedddb04eb1776926547f08418206a7c69a4c63a9115eecdc79c533   ← identical
noise_attestation = ac72d22fe2f27852126914c0471b25f6047dbf9738608aedf49c856dc46f7e0...

channel_id matches byte-for-byte across both runs. This is what makes it useful: the pipeline’s bridge and every role-serving candidate can each compute the same channel id on their own, from public information only — nobody has to relay it.

4. Hand it off

render()’s output (the block above minus channel_id, which the recipient already has) is what you hand the pipeline’s channel owner — whoever ran POST /me/channels for this role — so they can POST /me/channels/:channel/members on your behalf. See API endpoints for both calls.

Found an error, or something that didn't work as documented? Open an issue →