Donkey-push: a BYOC live capability that carries audio to Swarm — looking for a second Orchestrator to run it

I’ve been running a live audio pipeline on Livepeer BYOC for the last week, and it’s at the point where another Orchestrator could run the capability.

The shape: a publisher (a phone, or a box) sends live audio to an Orchestrator; the capability there transcribes it with whisper and pushes [ the audio, the captions and the playlists ] into Swarm; listeners play it in a browser straight out of Swarm via an in-browser node, captions and all. The Orchestrator is paid per second in PM tickets. Nobody in the middle holds the publisher’s key.

In one picture

Black arrows carry media; red dashed arrows carry the publisher’s signatures. The publisher is the only box with a key. The Orchestrator carries; Swarm stores; the browser is its own Swarm node.

Where to look first

Two things to try before reading any further:

  1. Listen. Open https://chrisradio.eth.limo/ in Brave or Chrome. That page is a weeb-3 build (GitHub - lat-murmeldjur/weeb-3: Weebery · GitHub) served out of Swarm behind an ENS name: the browser joins Swarm as a light node in WASM, follows the station’s pointer feed to the current broadcast, reads the playlists and the chunks itself, and hls.js plays them with captions in sync. No gateway, no CDN, no server of mine anywhere in the path — when the phone is on air, that is the phone talking to an Orchestrator and nothing else. weeb-3 is what makes the listener side of this real; without it “on Swarm” still means “behind somebody’s gateway”.

  2. Publish. The Android app (Radicle Explorer) is the publisher: microphone in, ten-second segments out to an Orchestrator running donkey-push, tickets, stamps and feed updates all signed on the phone with the publisher’s own key. Point it at your Orchestrator and the audio comes out of the page above.

Why “donkey”

A donkey carries what it’s given and owns none of it. You pay it for the carrying. That’s the whole contract of this capability: it carries chunks to Swarm on the publisher’s stamps, and it cannot write anything on its own account. It’s the Swarm donkey, not the Trojan horse: it helps you distribute the value, and nobody jumps out and kills everyone.

Segments and chunks are different things

The publisher cuts the audio into HLS segments, ten seconds each, and sends those to the Orchestrator. The capability splits each segment into 4 KB Swarm chunks (a ten-second segment is about 25 of them), asks the publisher over the session to stamp each chunk, and pushes them. The publisher then signs the updated playlist as a Swarm feed update. So the Orchestrator sees segments; Swarm sees chunks; the publisher signs both the stamps and the playlists.

What the Operator runs

One container, podman pull registry.hobcroft.org/donkey-push:0.2.0 (the registry itself is served from Swarm), registered with go-livepeer as a static live runner via -liveRunnerConfig runners.json. It listens on loopback; the publisher only ever talks to your Orchestrator. Price is yours to set, per hour of audio. You need -ticketEV raised — at the stock 8 gwei a session can’t be funded, since clients cap at 100 tickets per payment. The README with the exact steps is in the spine repo: Radicle Explorer (capability/README.md).

One caveat, tracked in go-livepeer #4077 (Remote signer: live session pays once and is then released for insufficient balance · Issue #4077 · livepeer/go-livepeer · GitHub): the stock Orchestrator releases every live session on a single missed 3-second health poll, and a container answering a few hundred milliseconds late is enough to trigger it. A one-file patch that waits for three consecutive misses is at GitHub - chrishobcroft/go-livepeer at health-poll-threshold · GitHub; my Orchestrator runs it.

What the capability does not hold

No postage batch, no BZZ, no chequebook, no key of the publisher’s — and no chain access at all: no Gnosis endpoint, no Arbitrum endpoint. The only process on the Operator’s box that touches a chain is go-livepeer itself, for the tickets. Every chunk the capability pushes carries a stamp the publisher signed during the session, and every playlist it pushes is a feed update the publisher signed. If the container disappears mid-stream, the publisher reconnects to a fresh session and carries on.

Captions

faster-whisper tiny.en (int8, two threads): about 4.5x realtime on a 2 vCPU VPS, which is what my Orchestrator is. base.en is baked in too and is one environment variable away. Larger models aren’t in this image — it’s deliberately offline for HuggingFace, since a network-reachable model load measured 1080 seconds — so small, medium or large-v3 mean a rebuilt image with the weights baked. An Operator with a GPU could absolutely offer that (large-v3 runs at 16x realtime on a 4060 Ti), advertised in runners.json at its own price; that’s a build target, not something that exists today.

What the publisher runs

Either a Python publisher on a box — built on Josh’s livepeer-python-gateway (GitHub - j0sh/livepeer-python-gateway: Python Livepeer Gateway SDK · GitHub), which is where the live-runner client protocol lives — or an Android app (API 21+, no native code) that speaks the same protocol in Kotlin. The app holds the publisher’s key — you import your existing gateway keystore file — and signs the PM tickets and the Swarm stamps and feed updates on the phone. Payments are plain HTTP against the Orchestrator’s 402 challenge: no gRPC, no remote signer. Code: Radicle Explorer. The Swarm side needs a postage volume owned by the same key — BZZ on Gnosis, one transaction through the volume registry (GitHub - shtukaresearch/swarm-volume-registry: Onchain volume lifecycle management for Swarm · GitHub). That’s the one genuinely new thing for a Livepeer person, and it’s also the point: the publisher’s key pays for both the transport and the storage.

Where it stands

Publishing from a box has run for days at a time on my Orchestrator (sessions of 5h19m, 13h30m and 30h21m; captions in sync in Brave throughout). Publishing from a Pixel 8 passed a decoy-gated listening test on 14 Sep. Capacity is one broadcast per runner at the moment. Audio only, by design.

If you’d like to try it: run the capability, tell me the Orchestrator, and I’ll publish into it from the phone before you set up a key of your own.

2 Likes

Hi Chris,

I’ve been tracking your work with Donkey-push and the way you’re bridging Livepeer BYOC and Swarm. I really resonate with the “Donkey” philosophy—providing the infrastructure for transport without claiming ownership of the asset. That’s exactly the line we’re drawing with the Creative Platform.

I’m building out professional rails for sovereign artists to own their IP and distribution end-to-end. I want to deploy an Orchestrator to support my creative stable and move this from a concept to a production environment.

I’ve got a Lenovo workstation with an NVIDIA RTX 3060 Ti, and I want to leverage that to run the

large-v3

Whisper model. My goal is to provide institutional-grade, high-fidelity captions for the artists on my platform.

A few things I want to lock down as I set up the environment:

  1. GPU Optimization: For the 3060 Ti, do you have a specific build or container image you recommend for the
large-v3

weights to keep performance optimal in real-time?
2. Payment Rails: I’m integrating a custom token economy (CRTV AI) for my members. I’m looking for the best way to handle the 402 payment challenge so we can bridge our token logic with the PM ticket system.
3. Downstream Integration: The ultimate vision is to pipe these sovereign audio assets into a larger AI suite I’m building called Creative Pixels for automated visual generation and broadcasting. Have you seen any effective patterns for downstreaming Swarm chunks into other AI agents?

I’m ready to get a node live and add some real capacity to the network. Let me know the best way to coordinate the setup.

Best,

G2

Thanks, and please do run it. A second operator is exactly what I’m after.

The part I’d most like you to see is what happens to the output. donkey-push pushes everything it makes (the audio, the captions and the playlist) straight into Swarm, stamped with the publisher’s own key and paid for by the publisher. Your orchestrator does the work and gets paid per second, but it holds nothing of theirs: no key, no storage, no copy it has to keep. The broadcast belongs to the publisher, lives on Swarm under their key, and keeps playing wherever they take it next. For a creator platform, that’s the interesting bit: your creators own their broadcasts outright, and nobody in the middle can take them down.

That also answers your agents question. Because it’s all public on Swarm, your Creative Pixels agents can read a broadcast the same way any listener does, with nothing to wire up on the orchestrator.

On the GPU: today donkey-push carries one broadcast per runner and captions it on the CPU with a small Whisper model (tiny.en by default, or base.en), and two cores keep up with one stream. Many concurrent streams is where a GPU becomes necessary. That isn’t in the image yet, and a 3060 Ti is exactly where I’d want to try it once you have one stream running.

Payment is ETH through PM tickets, from the publisher’s own key, like any other Livepeer job. The capability itself never handles payment, so there’s no place in it for another token.

To start, pull registry.hobcroft.org/donkey-push:0.3.0 and follow the first post. Tell me when it’s registered and I’ll publish into it.