Agentic video generation pipeline on Shelby Protocol. Trains style LoRAs on curated footage collections, generates text-to-video clips via an X402-gated inference API, and publishes all artifacts to Shelby on Aptos.
Model: LTX-2.3-22b-dev (Lightricks, 22B) · Output: ~5s 1080p 24fps · Infra: RunPod H100 (training) + A100 (inference) · Web app: Next.js on Vercel
- Architecture Overview
- Prerequisites
- One-Time Setup
- Adding a Collection
- Training a LoRA
- Running the Demo
- Script Reference
- Environment Variable Reference
- Collection YAML Reference
- Further Reading
Web App (Vercel)
└─ POST /api/inference X402 payment check → forward to inference server
└─ GET /api/status/:id proxy + generate signed GCS URL when complete
Inference Server (RunPod A100 80GB, on-demand during demo)
└─ FastAPI, model pre-loaded in GPU memory (~15 min pre-warm)
└─ Uploads output to GCS + Shelby on completion
Training Pipeline (RunPod H100 80GB, self-terminates)
└─ Downloads footage from HuggingFace
└─ Trains style LoRA via ltx-trainer
└─ Uploads LoRA weights to GCS + Shelby
For a detailed breakdown see docs/architecture.md.
Install these tools on your Mac before starting:
| Tool | Install | Required for |
|---|---|---|
gcloud CLI |
cloud.google.com/sdk | GCS operations |
gsutil |
Included with gcloud | GCS operations |
node ≥ 20 |
nodejs.org | Shelby CLI, web app |
vercel CLI |
npm i -g vercel |
Web app deployment |
python3 ≥ 3.12 |
python.org | Local script helpers |
Authenticate gcloud:
gcloud auth login
gcloud auth application-default loginYou will also need accounts on:
- RunPod — primary GPU provider for training and inference
- Lambda Labs — secondary provider (keep functional; use if RunPod has no availability)
These steps are done once per project, not per demo run.
Create the GCS bucket used for model weights, LoRAs, and video outputs:
gsutil mb -l us-central1 gs://kalpa-assetsVercel needs read access to GCS to generate signed URLs for video playback.
# Create the service account
gcloud iam service-accounts create kalpa-vercel \
--display-name="Kalpa Vercel SA"
# Grant read access to the bucket
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:kalpa-vercel@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"
# Download the key JSON
gcloud iam service-accounts keys create kalpa-vercel-key.json \
--iam-account=kalpa-vercel@YOUR_PROJECT_ID.iam.gserviceaccount.comThe contents of kalpa-vercel-key.json go into GCP_SA_KEY in Vercel's environment
settings. Keep this file out of the repo (it's in .gitignore).
Create an Aptos wallet for the pipeline. This wallet pays gas fees and ShelbyUSD for Shelby uploads, and receives X402 inference payments.
# Use the Aptos CLI or any Aptos wallet tool to create a wallet
# Note the private key and addressFund the wallet on testnet:
- APT (gas): aptos.dev/network/faucet
- ShelbyUSD (storage): follow Shelby Protocol funding docs
Before running a training job, verify that
shelby uploadworks:echo "test" > /tmp/test.txt shelby upload /tmp/test.txt kalpa-test -e "in 1 hour"A failed Shelby upload at the end of a 2-hour H100 run is expensive to re-run.
The Gemma text encoder is a gated model and requires explicit approval.
- Create an account at huggingface.co
- Accept the model terms at
huggingface.co/google/gemma-3-12b-it-qat-q4_0-unquantized - Generate a token at
huggingface.co/settings/tokens→ set asHF_TOKENin.env
cp .env.example .envEdit .env and fill in all required values. See Environment Variable Reference below.
Also set up the web app env:
cd web
cp .env.local.example .env.local
# Fill in web/.env.localOne-time download of ~47 GB from HuggingFace to your GCS bucket. Run from the repo root:
./scripts/setup-models.shRequired env vars: HF_TOKEN, GCS_BUCKET
Downloads:
ltx-2.3-22b-dev.safetensors(46.1 GB)ltx-2.3-spatial-upscaler-x2-1.1.safetensors(996 MB)google/gemma-3-12b-it-qat-q4_0-unquantized(~6 GB)
This takes 30–60 min. Models live at gs://kalpa-assets/models/ and are reused by
every training and inference pod. You never download them again.
cd web
npm install # or: pnpm install
vercel deploySet all variables from web/.env.local.example in Vercel project settings
(Settings → Environment Variables). The INFERENCE_SERVER_URL can be set to a
placeholder for now — the web app will show "Demo is offline" until the inference
server is running.
Each footage collection gets a YAML config. The Oregon coast collection is provided
as an example at collections/oregon-coast/collection.yaml.
-
Create
collections/<name>/collection.yaml— copy the Oregon coast file as a template and update:Field Description nameSlug — must match directory name descriptionHuman-readable hf_datasetHuggingFace dataset ID hf_splitDataset split (usually train)style_tokenUnique ALL_CAPS trigger word (e.g. MY_STYLE)training.steps1000–1500 for style LoRA default_prompts.videoPlaceholder prompt (include the style token) -
Train the LoRA — see next section.
For full field documentation see docs/collections.md.
Training runs on a RunPod H100 pod, self-terminates on completion, and takes ~1.5–2.5 hours.
# RunPod (primary)
./scripts/train-runpod.sh --collection oregon-coast
# Lambda Labs (alternative)
./scripts/train-lambda.sh --collection oregon-coastRequired env vars: GCS_BUCKET, HF_TOKEN, RUNPOD_API_KEY (or LAMBDA_API_KEY),
SHELBY_WALLET_PRIVKEY, SHELBY_WALLET_ADDRESS, SHELBY_NETWORK
What happens:
- Creates an H100 pod on RunPod/Lambda with the collection name as metadata
- Pod boots, runs
startup-train.sh:- Downloads model weights from GCS
- Downloads footage from HuggingFace
- Builds
dataset.jsonl(captions prepended with style token) - Preprocesses video latents
- Trains LoRA via
ltx-trainer - Uploads weights to GCS + Shelby
- Writes Shelby artifact IDs back to
collection.yamlin GCS - Self-terminates
train-runpod.shdetects termination, downloads updatedcollection.yaml
Monitor progress:
./scripts/logs.sh --collection oregon-coastFor the full step-by-step breakdown see docs/training.md.
Run this ~20 minutes before your demo:
# RunPod (primary)
./scripts/start-inference-runpod.sh --collection oregon-coast
# Lambda Labs (alternative)
./scripts/start-inference-lambda.sh --collection oregon-coastRequired env vars: GCS_BUCKET, RUNPOD_API_KEY (or LAMBDA_API_KEY),
INFERENCE_API_KEY, SHELBY_WALLET_PRIVKEY, SHELBY_WALLET_ADDRESS, SHELBY_NETWORK
What happens:
- Creates an A100 pod, retrieves its public IP
- Prints the inference server URL — update
INFERENCE_SERVER_URLin Vercel env vars - Pod boots, downloads model + LoRA from GCS, loads into GPU (~15–20 min)
- Script polls
/healthuntilstatus: "online", then exits - Web app detects the server and shows the prompt form
After starting the server, you must update
INFERENCE_SERVER_URLin your Vercel project settings to the new pod IP. The pod gets a new IP each time it starts.
Tail startup logs:
./scripts/watch-and-infer-runpod.sh --collection oregon-coastAfter your demo:
# RunPod
./scripts/stop-inference-runpod.sh --collection oregon-coast
# Lambda Labs
./scripts/stop-inference-lambda.sh --collection oregon-coastThe A100 costs ~$3–4/hr. Always stop it after a demo.
- Open the web app — the prompt form appears when
/healthis online - Enter a prompt including the style token (e.g.
KALPA_COAST dramatic cliffs...) - Click Generate — X402 payment is required in production;
X402_ENFORCE=falseskips it - Redirected to
/job/<id>— page polls every 10s - Video appears when complete (~8–12 min)
For troubleshooting and cost management see docs/operations.md.
| Script | Run on | Purpose | Duration |
|---|---|---|---|
scripts/setup-models.sh |
Mac | One-time: download LTX-2.3 weights to GCS | ~45 min |
scripts/train-runpod.sh |
Mac | Train a LoRA on RunPod H100 | ~2 hr |
scripts/train-lambda.sh |
Mac | Train a LoRA on Lambda Labs H100 | ~2 hr |
scripts/start-inference-runpod.sh |
Mac | Start inference server on RunPod A100 | ~20 min |
scripts/start-inference-lambda.sh |
Mac | Start inference server on Lambda Labs A100 | ~20 min |
scripts/stop-inference-runpod.sh |
Mac | Terminate RunPod inference instance | ~1 min |
scripts/stop-inference-lambda.sh |
Mac | Terminate Lambda Labs inference instance | ~1 min |
scripts/startup-train.sh |
H100 | Full training pipeline — boot script, not run manually | — |
scripts/startup-infer.sh |
A100 | Download model + LoRA, start FastAPI — boot script | — |
scripts/logs.sh |
Mac | Tail logs for a running instance | — |
scripts/status.sh |
Mac | Show running instances | — |
scripts/kill.sh |
Mac | Force-terminate a named instance | — |
scripts/check-gpus-runpod.sh |
Mac | Check H100/A100 availability on RunPod | — |
Boot scripts (startup-train.sh, startup-infer.sh) are uploaded to GCS and run
automatically on pods at boot. You never call them directly.
Copy .env.example to .env and fill in all required values.
| Variable | Required | Description |
|---|---|---|
GCS_BUCKET |
✅ | GCS bucket including gs:// prefix (e.g. gs://kalpa-assets) |
GCP_PROJECT |
✅ | GCP project ID (for service account and GCS access) |
GCP_SA_KEY_B64 |
✅ | Base64-encoded GCP service account JSON — used by training and inference pods to access GCS. Generate: base64 -i kalpa-vercel-key.json |
| Variable | Required | Description |
|---|---|---|
HF_TOKEN |
✅ | HuggingFace access token for the gated Gemma text encoder |
| Variable | Required | Description |
|---|---|---|
SHELBY_NETWORK |
✅ | Shelby/Aptos network — testnet or shelbynet |
SHELBY_WALLET_PRIVKEY |
✅ | Aptos wallet private key (0x...) |
SHELBY_WALLET_ADDRESS |
✅ | Aptos wallet address (0x...) |
| Variable | Required | Description |
|---|---|---|
RUNPOD_API_KEY |
✅ (RunPod) | RunPod API key |
LAMBDA_API_KEY |
✅ (Lambda) | Lambda Labs API key |
| Variable | Required | Description |
|---|---|---|
INFERENCE_API_KEY |
✅ | Shared secret between Vercel and the inference server. Generate: openssl rand -hex 32 |
INFERENCE_SERVER_URL |
✅ | Full URL of the running inference pod: http://{pod-ip}:8080. Updated each time a new pod is started. |
| Variable | Required | Default | Description |
|---|---|---|---|
INFERENCE_SERVER_URL |
✅ | — | Full URL of inference server. Update in Vercel each time a new pod starts. |
INFERENCE_API_KEY |
✅ | — | Same value as above |
GCP_PROJECT_ID |
✅ | — | GCP project ID |
GCP_SA_KEY |
✅ | — | Full JSON contents of the Vercel service account key, as a single-line string |
GCS_BUCKET |
✅ | — | Bucket name without gs:// prefix (e.g. kalpa-assets) |
INFERENCE_PRICE_APT |
❌ | 0.01 |
Price in APT per inference job |
X402_ENFORCE |
❌ | false |
Set to true to require real X402 payment |
X402_FACILITATOR_URL |
❌ | — | X402 facilitator endpoint |
X402_PAYTO_ADDRESS |
❌ | — | Aptos address receiving inference payments |
X402_NETWORK |
❌ | aptos:testnet |
X402 payment network |
Full reference with annotated fields: docs/collections.md
Quick summary of the most-edited fields:
name: oregon-coast # slug — matches directory name
style_token: KALPA_COAST # ALL_CAPS trigger word for all captions + prompts
training:
steps: 1500 # 1000–1500 for style LoRA
rank: 32 # 32 for style, 64 for subject/scene
learning_rate: 5.0e-5
artifacts: # filled automatically by training script
lora_gcs: null
shelby_lora: null
shelby_metadata: null| Document | Contents |
|---|---|
| PIPELINE_SPEC.md | High-level system overview |
| docs/architecture.md | Component details, data flows, security boundaries |
| docs/training.md | Training pipeline deep dive, step-by-step |
| docs/inference.md | Inference server API, job lifecycle, GPU memory notes |
| docs/web-app.md | Next.js app, API routes, X402 integration |
| docs/collections.md | Collection YAML schema, LoRA types, adding collections |
| docs/operations.md | Demo day checklist, troubleshooting, costs |