Skip to content

How to Run a Local Battle

Local battles execute entirely on your machine. No cloud account, no auth, no credits required. New state is persisted in user runtime storage outside the project. Legacy .lenserfight/local-battles/<id>.json files are still read for compatibility.


Overview

lf battle local <subcommand> [options]
SubcommandDescription
initCreate a new local battle
add-contenderAdd or replace a contender slot (A or B)
runExecute both contenders with BYOK keys
voteRecord a vote on an executed battle
statusShow state, contenders, and vote tally
listList all local battles
pushPublish a local battle to LenserFight Cloud

State files live in the CLI user runtime directory under local-battles/<uuid>.json. Do not commit legacy project-root local battle JSON files.


lf battle local init

Create a new local battle in draft state.

lf battle local init --name <name> --task <prompt> [--json]
FlagRequiredDescription
--nameyesHuman-readable battle name
--taskyesTask prompt both contenders will answer
--jsonnoOutput full state as JSON

Example:

bash
lf battle local init \
  --name "CSV Parser Duel" \
  --task "Write a Python function parse_csv(path) -> list[dict]"

lf battle local add-contender

Add or replace contender slot A or B. The battle transitions to ready once both slots are filled.

lf battle local add-contender <A|B> --provider <p> --model <m> [options]
Arg / FlagRequiredDefaultDescription
<A|B>yesSlot to assign
--provideryesanthropic | openai | google | mistral | ollama
--modelyesModel key, e.g. claude-sonnet-4-6
--labelnomodel nameDisplay label shown in output
--key-varnoCustom env var name for API key (overrides default)
--idnomost recentBattle UUID or prefix
--jsonnofalseOutput updated state as JSON

Examples:

bash
# Anthropic (reads ANTHROPIC_API_KEY automatically)
lf battle local add-contender A --provider anthropic --model claude-sonnet-4-6

# OpenAI with explicit env var name
lf battle local add-contender B --provider openai --model gpt-4o --key-var MY_OPENAI_KEY

# Ollama — no key needed
lf battle local add-contender B --provider ollama --model llama3

lf battle local run

Execute both contenders simultaneously. Streams tokens to the terminal color-coded by slot.

lf battle local run [<id>] [--json]
Arg / FlagRequiredDefaultDescription
<id>nomost recentBattle UUID or prefix
--jsonnofalseOutput execution result as JSON

Terminal output uses ANSI color codes:

  • [A] prefix in blue
  • [B] prefix in green

Both contenders run in parallel via Promise.all(). Results are saved to the state file on completion.


lf battle local vote

Record a vote on an executed battle. Multiple votes are allowed (each is appended).

lf battle local vote --slot <A|B|draw> [options]
FlagRequiredDefaultDescription
--slotyesA | B | draw
--idnomost recentBattle UUID or prefix
--rationalenoOptional explanation for your vote
--jsonnofalseOutput updated state as JSON

Example:

bash
lf battle local vote --slot A --rationale "More concise and idiomatic"

lf battle local status

Show the current state, contenders, and vote tally.

lf battle local status [<id>] [--json]
Arg / FlagRequiredDefaultDescription
<id>nomost recentBattle UUID or prefix
--jsonnofalseOutput raw state as JSON

The winner is computed as the slot with the highest vote count. Ties are shown as "Tied".


lf battle local list

List all local battles, sorted by creation date (newest first).

lf battle local list [--json]

lf battle local push

Create a draft cloud battle from a local battle's name and task. Requires lf auth login.

lf battle local push [<id>] --slug <slug> [--json]
Arg / FlagRequiredDefaultDescription
<id>nomost recentBattle UUID or prefix
--slugyesURL-safe cloud slug (must be unique on LenserFight)
--jsonnofalseOutput cloud battle record as JSON

What is pushed: battle title and task prompt.
What stays local: contender configs, outputs, and votes.

After pushing, continue with lf battle open <cloud-id> to accept entries.


Key resolution order

When a contender runs, keys are resolved in this priority order:

  1. --key-var — env var name set on the contender (e.g. MY_ANTHROPIC_KEY)
  2. Default provider env var — standard name per provider (see table below)
  3. Error — if no key found and provider is not Ollama

Supported providers

ProviderDefault env varNotes
anthropicANTHROPIC_API_KEY
openaiOPENAI_API_KEY
googleGOOGLE_AI_API_KEY
mistralMISTRAL_API_KEY
ollamanoneRuns locally, no key needed

Resuming after power-off

State files persist across restarts. Find your battle IDs with:

bash
lf battle local list

Then continue from any step:

bash
lf battle local run <id>       # re-run (overwrites outputs)
lf battle local vote --id <id> --slot A
lf battle local status <id>

See also