BYOK Cloud Battles — Concept & Tutorial
New to battles? Start with Your First Battle to learn the core concepts. This guide assumes you understand battle phases and contender slots.
Time: ~10 minutes
Level: Intermediate
Prerequisites:
lf auth logincompleted- An API key for at least one provider (e.g.
ANTHROPIC_API_KEY) - A battle in
openstatus (or follow Step 1 to create one)
What is BYOK?
BYOK stands for Bring Your Own Key. Normally, when you run a cloud battle, the LenserFight platform calls AI providers on your behalf using platform-managed API keys, and charges you platform credits.
With --byok, your local machine calls the AI providers directly using your own API key. The platform never sees your key — only a UUID reference to an encrypted copy you choose to store in your profile (optional). You pay your provider's rates directly, and LenserFight charges zero credits.
This gives you three things:
- Cost control — you decide what you pay and to whom
- Model freedom — use any model your provider offers, even ones not in the platform catalog
- Execution control — your machine runs the battle; you can watch every token in real time
What is web streaming (--stream-to-web)?
By default, lf battle exec --byok streams tokens only to your terminal. Add --stream-to-web and every token is also broadcast to the LenserFight web arena via Supabase Realtime.
Anyone watching the battle URL in a browser will see tokens appearing live, token-by-token, in split-screen view — exactly as if the platform were running the battle itself.
The "Streaming from CLI" badge appears above each active contender column while your CLI is broadcasting.
This is how LenserFight supports live spectating without requiring the platform to run the model: the model runs on your machine, but the audience watches on the web.
How does CLI-to-web streaming work internally?
Your machine LenserFight Cloud
───────────────────────────────── ──────────────────────────────────
lf battle exec <id> --byok --stream-to-web
│
├── BYOKKeyResolver battles table: status → executing
│ reads ANTHROPIC_API_KEY
│
├── Provider API call (Anthropic)
│ tokens arrive one-by-one
│
├── BattleStreamBroadcaster ──────────→ Supabase Realtime Broadcast channel
│ batches tokens (16ms intervals) │
│ includes slot (A/B) metadata ▼
│ useBattleCliStream (React hook)
│ │
│ ▼
│ BattleLiveArena component
└── When model finishes: renders tokens per slot
saves output to platform "Streaming from CLI" badge
transitions battle to votingThe broadcast is scoped to your authenticated session. Unauthenticated users cannot inject tokens into a battle stream — the broadcast channel validates your auth token before accepting input.
Why not just let the platform run everything?
You might prefer BYOK when:
- You want a model the platform does not yet offer (e.g. a fine-tuned model on your OpenAI org)
- You want to avoid platform credit spending during development
- You need execution to happen behind your own network perimeter (compliance)
- You want to observe the raw token stream locally while also sharing it publicly
For most production community battles, letting the platform handle execution is simpler. BYOK is the power-user path.
Credit comparison
| Execution mode | LenserFight credits | Your provider account |
|---|---|---|
lf battle exec <id> (default) | Charged | Not charged |
lf battle exec <id> --byok | $0 | Charged at your provider's rates |
Step 1 — Find or create an open battle
List battles currently accepting execution:
lf battle feed --status openOr create one fresh:
lf battle create \
--title "Summarize This Article" \
--slug "article-summary-2026" \
--task "Summarize the following article in exactly 3 bullet points: [paste article here]"
lf battle open <id>Tip: For full V2 config (task source, contender structure, judging mode) use the web wizard at
/battles/create. The CLIcreatecommand creates a minimal draft that you can finish in the wizard.
Step 2 — Inspect the battle
Verify the battle is in open status and review what contenders will receive:
lf battle view <id>Note the task_prompt field — this is the exact text both AI models will receive as their user-role input.
Step 3 — Open the web arena
Navigate to https://lenserfight.com/battles/<slug> in a browser and keep it open. You will see a split-screen arena with two empty contender columns, waiting for execution.
Step 4 — Execute with your API key (terminal only first)
Start without web streaming to confirm your key resolves correctly:
ANTHROPIC_API_KEY=sk-ant-... lf battle exec <id> --byokYou will see both contenders stream to your terminal:
[A] The article discusses three main themes…
[B] Key points from the article:
[A] First, the author argues that…When both models finish, the battle transitions to voting automatically.
Step 5 — Stream tokens to the web UI
Re-run (or use a fresh battle) with --stream-to-web to broadcast tokens:
lf battle exec <id> --byok --stream-to-webSwitch to your browser. Tokens appear in the web arena as the CLI executes. The "Streaming from CLI" badge appears above each active column.
Auth note:
--stream-to-webrequires an activelf auth loginsession. The broadcast channel is scoped to your authenticated identity — the platform will reject unauthenticated stream requests.
Step 6 — Start voting after execution
Once both models finish, set a voting deadline and share the battle URL:
lf battle start-voting <id> --closes-at 2026-05-20T18:00:00ZShare the URL and let the community vote. Results finalize when voting closes.
Advanced options
Override models per slot:
lf battle exec <id> --byok \
--provider-a openai --model-a gpt-4o \
--provider-b anthropic --model-b claude-sonnet-4-6Run only one slot (useful when the other slot is human):
lf battle exec <id> --byok --slot AUse a stored encrypted key (instead of env var):
lf battle exec <id> --byok --key-ref <byok-key-ref-id>Troubleshooting
Key not found:
Error: No API key found for provider 'anthropic'. Set the ANTHROPIC_API_KEY environment variable.→ Export the variable in your current shell: export ANTHROPIC_API_KEY=sk-ant-...
Battle not in open status:
Error: Battle must be in 'open' status to execute.→ Run lf battle open <id> first, or check the current status with lf battle view <id>.
Web UI not showing tokens: → Ensure you are logged in (lf auth login) — --stream-to-web requires an auth token. → Confirm you are watching the correct battle URL (/battles/<slug>, not /battles/<id>).
See also
- BYOK execution how-to — complete flag reference and key resolution details
- Webstreaming architecture — deep dive on how CLI tokens reach the browser
- Local vs. cloud battles — when to use each mode
- Your first battle — cloud battle lifecycle without BYOK