Example apps for the Livepeer network. An app is a container you build and put on the network: a normal HTTP or WebSocket service that exposes your endpoints. Orchestrators host and run your app via the live runner, and clients call it through the orchestrator using the livepeer-gateway Python SDK.
Live runners are not on go-livepeer main yet and currently live on the ja/live-runner branch. Until it merges, both the orchestrator image and the SDK come from that branch.
Important
SSE streaming (used by the vllm example) depends on gateway PR #25, which is not yet merged. Until it lands, streaming is only available from the SDK's rs/live-runner-streaming branch, not ja/live-runner.
| Example | Transport | Registration |
|---|---|---|
hello-world |
HTTP (JSON request/response) | dynamic |
vllm |
HTTP (OpenAI API, via a local gateway) | static |
More will follow. Each example is self-contained and runs both offchain (free, no wallet) and on-chain (paid); see its README for the commands.
- Dynamic — the app self-registers with the orchestrator via the SDK (
register_runner) and sends heartbeats; the orchestrator drops it when heartbeats stop. Best for apps that come and go. (hello-worldis dynamic.) - Static — the orchestrator is configured with the app's URL in a
runners.jsonand polls a health endpoint; the app needs no SDK. Best for fixed, long-running deployments.
-
Docker for the end-to-end demos. They use the
livepeer/go-livepeer:ja-live-runnerimage, so there is nothing to build. -
Python 3.12+ and
uvfor the client. -
The
livepeer-gatewaySDK from theja/live-runnerbranch (not yet on PyPI):pip install "git+https://github.com/livepeer/livepeer-python-gateway@ja/live-runner"
Each example is runnable on its own, but the orchestrator and signer services are defined once at the repo root and pulled into each example with Docker Compose extends, so examples don't duplicate them:
compose.orchestrator.yml— the offchain orchestrator (-useLiveRunners).compose.onchain.yml— adds a remote signer and re-points the orchestrator on-chain.
On-chain runs add a remote signer that holds the payer wallet and mints probabilistic micropayment tickets; the orchestrator (recipient) redeems the winning ones. The setup is shared across examples:
- Wallets live outside this repo. Point
*_KEYSTORE_DIRat go-livepeer keystore directories by absolute path; they are mounted read-only. Only the address and password come from.env, and the private keys never enter the repo. .envis per example and gitignored. Copy the example's.env.exampleand fill in the RPC, network, keystore paths, accounts, and pricing. It holds the keystore password, so it is never committed.- Pricing is in USD, converted to wei on-chain via the price feed. The app advertises
PRICE_PER_UNIT(whole-number USD) perPIXELS_PER_UNIT; keepPIXELS_PER_UNITsmall, because large values shrink the per-unit price below 1 wei and it floors to 0 (free). The signer accepts up toMAX_PRICE_PER_UNIT. - Payments are probabilistic. A call mints tickets that win with some probability; only winning tickets are redeemed on-chain. With default settings you will rarely see a redemption on a short run — that is expected.
Before running a client, confirm the orchestrator actually advertises your runner with the expected price by calling /discovery directly:
curl -sk https://localhost:8935/discovery | jqEach entry lists its runners with an app, version, capacity, and price_info (price_per_unit / pixels_per_unit in WEI). Check that your app appears and that the price matches what you configured — a price_per_unit of 0 means it floored to free (see the PIXELS_PER_UNIT note above).
- Apps bind to
127.0.0.1by default (safe for local runs). In a container the compose files pass--host=0.0.0.0so the orchestrator can reach the app. - Orchestrators serve a self-signed TLS cert; the SDK skips verification.