An OpenAI-compatible inference gateway and SaaS shell built on top of the Livepeer network and the livepeer-network-modules framework.
This repository is both:
- a working application
- a reference implementation / demo of how to build against Livepeer
network capabilities through the LOC — Livepeer Open Clearinghouse
HTTP API and the broker wire surface from
livepeer-network-modules
The core idea is simple: keep the OpenAI client surface familiar, but route work through Livepeer's capability marketplace. The LOC owns route selection and payment minting; the gateway opens a job per request and forwards it to the broker the LOC picks.
Agents should start at AGENTS.md. Humans can use this README as the main overview.
This repo contains:
gateway/: one TypeScript Fastify service that hosts:- the OpenAI-compatible
/v1/*API - a waitlist / verify / approve / API-key shell
- portal and admin backend routes
- production serving for
web/site,web/portal, andweb/admin - a typed HTTP client for the LOC clearinghouse
- the OpenAI-compatible
web/site/: zero-build Lit marketing and waitlist siteweb/portal/: zero-build Lit user portal with account, keys, health, playground, and usageweb/admin/: zero-build Lit admin with waitlist, users, usage, health, and registry diagnostics
This repo holds no chain keys and never talks to the chain directly. It
delegates route selection and payment minting to the LOC — Livepeer
Open Clearinghouse (https://loc.cloudspe.com by default), reached
over HTTPS with an X-API-Key header.
This project demonstrates a practical application architecture for the Livepeer network:
- discover capabilities from the LOC clearinghouse
- open a job per request — the LOC selects a route AND mints the payment envelope in one call
- forward OpenAI-shaped requests to the broker the LOC returns
- settle actual usage afterwards so the LOC refunds the unused part of each estimate
- preserve enough job / route metadata for auditing and debugging
It is intentionally opinionated:
- clearinghouse-mediated only
- no daemon sidecars, no local chain keys
- no static overlay routing
- no local hardcoded model catalog
- no local fallback broker path
This repo follows an agent-first harness model:
- the repository is the system of record
- plans live in the repo
- architecture is documented as executable invariants, not tribal lore
- the codebase is designed to be navigable by both humans and coding agents
The working style is:
- humans provide intent, constraints, and approval
- agents inspect the current repo state, make changes, run checks, and keep the work grounded in checked-in artifacts
- docs, code, and deployment surfaces are expected to move together
Relevant references:
flowchart LR
SDK[OpenAI SDK or client] -->|/v1/*| GW[gateway]
SiteUser[Visitor] -->|/api/*| GW
PortalUser[Approved user] -->|/portal/* + /v1/*| GW
AdminUser[Operator] -->|/admin/*| GW
SITE[web/site] -->|served by gateway| GW
PORTAL[web/portal] -->|served by gateway| GW
ADMIN[web/admin] -->|served by gateway| GW
GW --> DB[(Postgres)]
GW -->|jobs + settle| LOC[LOC clearinghouse]
GW --> BROKER[capability-broker]
BROKER --> WORKER[capability worker]
GW --> EMAIL[Resend]
LOC --> CHAIN[(EVM chain<br/>route selection + PM tickets)]
flowchart TD
A[Client request] --> B[Bearer or session auth]
B --> C[Open reservation]
C --> D[Open LOC job: route + payment envelope]
D --> F[Dispatch to broker with Livepeer-Payment]
F --> G[Capability worker executes]
G --> H[Gateway returns response]
H --> I[Commit or refund reservation + enqueue settle intent]
I --> K[Background settler reports actual units to LOC]
K --> J[Portal and admin can inspect usage]
sequenceDiagram
participant C as Client
participant G as Gateway
participant DB as Postgres
participant L as LOC clearinghouse
participant B as Broker
C->>G: POST /v1/*
G->>DB: validate key + open usage_reservations row
G->>L: POST /v1/jobs {capability, offering, estimated_units}
L-->>G: {job_id, broker_url, mode, payment_envelope, ...}
G->>B: forward request + Livepeer-Payment header
B-->>G: response or stream
G->>DB: commit or refund reservation + enqueue settle intent
G-->>C: OpenAI-shaped response
Note over G,L: background settler later POSTs<br/>/v1/jobs/{id}/settle {actual_units, outcome}
erDiagram
WAITLIST ||--o{ API_KEYS : owns
API_KEYS ||--o{ SESSIONS : issues
API_KEYS ||--o{ USAGE_RESERVATIONS : logs
WAITLIST {
uuid id PK
text email
text name
text status
timestamptz email_verified_at
timestamptz approved_at
timestamptz created_at
}
API_KEYS {
uuid id PK
uuid waitlist_id FK
text key_prefix
text key_hash
timestamptz created_at
timestamptz last_used_at
timestamptz revoked_at
}
SESSIONS {
uuid id PK
uuid api_key_id FK
text session_hash
timestamptz expires_at
timestamptz revoked_at
timestamptz created_at
}
USAGE_RESERVATIONS {
uuid id PK
uuid api_key_id FK
uuid work_id
text capability
text model
text selected_capability
text selected_offering
text broker_url
text eth_address
text quote_id
text quote_version
text state
bigint estimated_work_units
bigint committed_work_units
integer status_code
integer latency_ms
timestamptz created_at
timestamptz resolved_at
}
MODELS {
text model_id PK
text capability
text interaction_mode
text provider
boolean active
timestamptz snapshot_at
}
| Path | Purpose |
|---|---|
| gateway/ | TypeScript backend, routing, auth, usage tracking, LOC client |
| web/site/ | Marketing site and waitlist signup |
| web/portal/ | User portal and playground |
| web/admin/ | Operator/admin UI |
| docs/ | Design docs, product specs, exec plans |
The gateway is the center of the system. It:
- exposes OpenAI-compatible endpoints
- validates API keys and portal/admin credentials
- opens, commits, and refunds usage reservations
- opens a LOC job per request (the LOC selects the route AND mints the payment envelope)
- forwards requests to the broker the LOC returns
- settles actual usage back to the LOC via a durable background task
- stores a cached public model catalog in Postgres
The three web/ apps are zero-build Lit SPAs:
site: onboarding and verificationportal: user-facing account, keys, network health, playground, and usageadmin: waitlist management, user inspection, usage, network health, and LOC / catalog diagnostics
There are two distinct paths:
- hot-path routing:
request-time
POST /v1/jobsto the LOC, which returns a single route plus its payment envelope - catalog/debug path:
background refresh from the LOC
GET /v1/capabilitiesinto themodelstable for/v1/modelsand diagnostics
That split is intentional. Request routing must go through the LOC so selection and payment stay consistent. Public catalog reads must stay cheap and cacheable.
The model id is the LOC offering id. /v1/models rows are built from
the LOC capability catalog; the gateway no longer maps user-facing
aliases onto internal offering keys. Display metadata (name,
description, provider, category) is populated only by operator
overrides — it is not catalog-sourced.
Current v1 surface:
POST /v1/chat/completionsPOST /v1/embeddingsPOST /v1/images/generationsPOST /v1/audio/speechPOST /v1/audio/transcriptionsPOST /v1/rerankGET /v1/models
The runtime is env-driven. See .env.example for the full manifest.
The main groups are:
BASE_URLPUBLIC_SITE_URLPUBLIC_PORTAL_URLALLOWED_ORIGINSLOG_LEVELGATEWAY_HOST_PORT
POSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORD
ADMIN_TOKENAPI_KEY_HASH_PEPPERIP_HASH_PEPPERMETRICS_TOKENSESSION_TTL_HOURS
RESEND_API_KEYRESEND_BASE_URLFROM_EMAIL
LOC_BASE_URL(defaulthttps://loc.cloudspe.com)LOC_API_KEY(required — sent asX-API-Key)LOC_TIMEOUT_MSLOC_SETTLE_INTERVAL_MS(background settler cadence, default 15s)LOC_SETTLE_MAX_ATTEMPTS(per-job settle retries, default 20)LOC_JOB_RETRIES(job-open retries on 429/5xx/mode-mismatch, default 2)
REGISTRY_REFRESH_INTERVAL_MSV1_RATE_LIMIT_PER_MINUTEV1_RATE_LIMIT_BURST
pnpm install
make buildpnpm -F @livepeer-modules-openai/gateway lint
pnpm -F @livepeer-modules-openai/gateway testdocker compose build gatewayThis is the shortest path to getting the stack up locally.
git clone <repo-url> livepeer-modules-openai
cd livepeer-modules-openai
pnpm installcp .env.example .envFill at least:
ADMIN_TOKENAPI_KEY_HASH_PEPPERIP_HASH_PEPPERLOC_API_KEY
The gateway holds no chain keys. For a working /v1/* stack it needs a
reachable LOC clearinghouse and an LOC_API_KEY whose account holds a
credit balance. There is no local resolver / payer daemon to run.
docker compose up -d --buildCheck health:
curl http://localhost:4001/healthOne command:
make webOr individually:
cd web/site && node dev-server.js
cd web/portal && node dev-server.js
cd web/admin && node dev-server.jsDefault local ports:
- gateway-served site:
http://localhost:4001 - gateway-served portal:
http://localhost:4001/portal/ - gateway-served admin:
http://localhost:4001/admin/ - optional split dev servers:
http://localhost:3000,http://localhost:3001,http://localhost:3002
Convenience targets:
make site-uimake portal-uimake admin-ui
curl http://localhost:4001/v1/modelsImportant:
/v1/modelscan return503 models_cache_unavailablebriefly while the first catalog refresh has not landed yet/v1/modelscan return503 models_cache_staleif the cached model snapshot is older than the allowed age
make smoke- migrations run automatically at gateway boot
- the portal and admin use their own session/token auth surfaces
- the playground uses the real
/v1/*endpoints - speech voice options are derived from published model metadata when a speech model advertises them
make loc-smokeopens a 1-unit job and settles 0 against the live LOC- admin and portal health are intentionally different:
- portal: concise user-facing availability
- admin: operator-facing capability, LOC, and catalog diagnostics
For production deployment, use DEPLOYMENT.md.
The important operational constraints are:
- the LOC must be reachable and
LOC_API_KEYvalid before serving/v1/* - the LOC account must hold enough credit balance for the estimate charged at job issuance
- the DB migrations must run before serving traffic
- the background settler must keep up so refunds aren't delayed
- public
/v1/modelsdepends on a fresh LOC-backed cache
The repo is in decent shape, but the following additions would still add value:
- a focused operator runbook for common failures:
- stale model cache
- LOC reachable but no offerings for a capability
- LOC job-open failures / insufficient credit balance
- settle backlog growing (refunds delayed)
- broker failures vs LOC mode mismatches
- a capability-by-capability product matrix:
- request shape
- interaction mode
- work unit
- expected model metadata
- known caveats
- a glossary for:
- capability
- offering
- model id
- LOC job / work id
- payment envelope
- settle intent
- a troubleshooting page for local development:
- LOC API key / reachability
- empty
/v1/models - stale cache responses
- portal/admin auth issues
- example OpenAI SDK snippets for:
- chat
- streaming chat
- embeddings
- speech
- transcription
- rerank