Skip to content

Pipeline SDK — tracking issue #8

@rickstaa

Description

@rickstaa

Outcome

Developers go from "I have a Python ML model" to a discoverable BYOC
capability on Livepeer in under 5 minutes — surfaced in the
developer dashboard
ready for any caller to invoke.

The Pipeline SDK is the authoring surface that makes that possible:
write a Python class, get a containerised, BYOC-compatible,
schema-described capability.

Spec: pipeline-sdk.md

What we're building

A FastAPI + Pydantic-native authoring SDK delivered as a staircase
of small, shippable commits. Each step yields a working SDK that's
strictly more capable than the previous one. Status updated as work
lands.

Roadmap

  • C1Pipeline base + serve() + hello-world BYOC E2E
  • C2setup() lifecycle + HuggingFace sentiment example
  • C3 — FastAPI HTTP layer (/health, /predict, /docs, /openapi.json)
  • C4 — Pydantic BaseModel for inputs/outputs via signature introspection (/docs shows real fields instead of additionalProp1)
  • C5 — Image upscale example (binary I/O via Pydantic Base64Bytes)
  • C6/health state machine (LOADING / OK / ERROR / IDLE) matching go-livepeer's HealthCheck wire format
  • C7 — SSE auto-detection from generator predict() + LLM chat example
  • C8LivePipeline for trickle transport (real-time video)
  • C9livepeer push CLI + livepeer.yaml manifest
  • C10 — Schema as Docker image label (org.livepeer.pipeline.schema)
  • C11 — Agent-friendly docs (AGENTS.md, expanded Pipeline docstring, examples/runner/_template/) so AI tooling and new contributors can scaffold pipelines without parsing the whole codebase
  • C12 — Migrate to monorepo with PEP 420 namespace packages: split into livepeer-runner (authoring SDK), livepeer-client (caller-side BYOC), livepeer-trickle (shared transport). User-facing imports become livepeer.runner.*, livepeer.client.*, livepeer.trickle.*. See Architecture: monorepo + namespace packages below for rationale and layout.

Architecture: monorepo + namespace packages

The repo will be reorganized into a uv workspace publishing three
distributions under a shared livepeer.* namespace.

Why monorepo (vs separate repos)

  • One team owns all packages — no cross-team coordination overhead
  • Atomic refactors across packages (BYOC contract changes touch both runner and client)
  • Shared transport code (livepeer.trickle) becomes a workspace dep, not a publish-and-depend dance
  • Future users of the client will also deploy pipelines — single resolution surface for pip install livepeer-runner livepeer-client
  • Single repo for issues, PRs, CI

Why namespace packages (vs flat package or extras)

  • Coherent user-facing identity: livepeer.runner, livepeer.client, livepeer.trickle
  • Modular install: pipeline authors install only livepeer-runner, callers only livepeer-client
  • Industry-standard pattern (Apache Airflow airflow.providers.*, Google Cloud SDK google.cloud.*, Azure SDK azure.*)
  • Future packages join the namespace cleanly (livepeer.cli, livepeer.adapters.cog, etc.)
  • Hides the multi-package detail from users — they see one namespace

Layout

livepeer-python/                          # Repo (rename from livepeer-python-gateway)
├── pyproject.toml                         # uv workspace root
├── uv.lock                                # Single lockfile, all packages
├── packages/
│   ├── livepeer-runner/
│   │   ├── pyproject.toml                 # publishes "livepeer-runner"
│   │   ├── src/livepeer/runner/           # PEP 420: no __init__.py at livepeer/
│   │   │   ├── __init__.py
│   │   │   ├── pipeline.py
│   │   │   └── serve.py
│   │   └── examples/
│   ├── livepeer-client/
│   │   ├── pyproject.toml                 # publishes "livepeer-client"
│   │   └── src/livepeer/client/
│   └── livepeer-trickle/
│       ├── pyproject.toml                 # publishes "livepeer-trickle"
│       └── src/livepeer/trickle/
└── README.md

Critical convention

No __init__.py at src/livepeer/ — that empty directory IS the
namespace marker (PEP 420 implicit namespace package). Each
livepeer/X/__init__.py is a regular package. Adding an __init__.py
at the namespace level breaks cross-distribution discovery and has
historically bitten Airflow contributors. Add a CI check.

Tooling

  • uv workspaces — one lockfile, workspace-aware deps, per-package builds via uv build --package <name>
  • PyPI — three independent packages, can version sync or independent
  • CI — single GitHub Actions workflow with path filtering for per-package test/build/publish
  • Migration cost — ~1-2 days mechanical work (file moves, import updates, pyproject splits, CI adjustments)

Migration strategy

Clean break, no compatibility shim — the SDK is pre-1.0 and not yet
widely consumed externally. Coordinate with the in-flight fork to
contribute back upstream rather than maintain divergence.

Framework adapters (deferred — build on demand)

Migration paths for users from existing ML frameworks. Each ships as
its own pip package with its own foreign dep, isolated from core SDK.
Build only when a real migration ask shows up.

  • livepeer-gateway-cog — wraps cog.BasePredictor
  • livepeer-gateway-fal — wraps fal.App
  • livepeer-gateway-modal — wraps Modal @app.function
  • livepeer-gateway-bentoml — wraps @bentoml.service

Future protocol work (cross-team, gated on C9 + upstream go-livepeer)

Cross-cutting changes to BYOC capability identity that span the SDK,
go-livepeer, and the spec. Tracked here so the SDK side is captured;
implementation lands once C9 (livepeer push) provides the publish
hook and upstream protocol changes are agreed.

  • Capability identity via OCI digest — replace free-form
    capability names with content-hashed references like
    byoc/<repo>@sha256:<digest>. Aligns BYOC with Replicate's
    reproducibility model: orchestrators advertise the digest, gateway
    pins it, callers always invoke against an exact build. SDK side:
    livepeer push captures the digest at publish time and bakes it
    into the manifest. Upstream side: orchestrator registration +
    gateway routing + OrchestratorInfo carry the digest.
  • Cosign / Sigstore signing of capability digests — optional
    layer on top of digest pinning. Publisher signs the digest, gateway
    verifies signature against publisher's key. Same security property
    as a Livepeer-specific PKI but identity lives in standard registry
    / Sigstore tooling.
  • Name:version aliases over digest-pinned wire — Replicate-
    style mutable names (byoc/text-reverser:v2) that resolve to a
    digest at lookup time. Wire protocol always pins the digest;
    aliases are a UX layer for humans and dashboards.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions