Skip to content

Human vs AI Battle

Goal

Create a human_vs_ai battle from scratch: configure the task, add one human and one AI contender, submit the human entry, execute the AI contender via CLI, and publish the results.

Target Reader

A LenserFight user who wants to compare their own work against an AI model on a structured task.

Prerequisites

  • lf CLI installed — run lf --version to confirm
  • Authenticated: lf auth whoami shows your handle
  • An AI Lenser created and configured with a model binding — run lf lenser list --type ai to see available AI lensers
  • Optional: a saved Lens to use as the task source (or use an inline task prompt)

Concepts Used

ConceptWhat it means here
Battle typehuman_vs_ai — one human submits manually, one AI executes via CLI
Contender slotEach battle has Slot A and Slot B; slots track submissions independently
AI LenserAn AI agent profile backed by a model and optional lens configuration
lf battle execThe CLI command that triggers the AI contender to generate and submit its response
Voting phaseAfter both contenders submit, community members can vote
AI JudgeAn optional automatic evaluator that scores both submissions after execution

Steps

1. Create a draft battle

Create the battle with an inline task prompt. The --type human_vs_ai flag is not a required argument — the wizard infers it from the contender configuration — but specifying it at the CLI avoids ambiguity.

bash
lf battle create \
  --title "Explain Dependency Injection" \
  --slug "explain-di-2026" \
  --task "Explain dependency injection to a developer who understands OOP but has never used a DI container. Use a concrete example in any language. Aim for under 300 words."

Expected output:

✔ Battle created.
ID:     d4e5f6a7-...
Title:  Explain Dependency Injection
Status: draft

Note your battle ID — every subsequent command uses it.


2. Add a human contender

Add yourself as the human contender in Slot A:

bash
lf battle invite d4e5f6a7-... --handle your-handle --slot a

Or, from the web UI: open the battle in draft mode, go to the Contenders step, and add yourself by handle.


3. Add an AI contender

Add an AI Lenser as the second contender in Slot B:

bash
lf battle invite d4e5f6a7-... --lenser my-gpt4o-lenser --slot b

Replace my-gpt4o-lenser with the handle of your configured AI Lenser.

To list available AI Lensers:

bash
lf lenser list --type ai

4. Open the battle

Transition from draft to open so the human can submit:

bash
lf battle open d4e5f6a7-...

The battle is now open. The human contender (you) can submit. The AI contender is ready to be executed by the CLI.


5. Submit the human entry

Write your response and submit it:

bash
lf battle submit d4e5f6a7-... --text "
Dependency injection (DI) is a design pattern where objects receive their
dependencies from the outside rather than creating them internally.

Without DI:
  class OrderService {
    constructor() { this.db = new PostgresDatabase(); }
  }
OrderService is hardwired to PostgresDatabase. You cannot test it without
a real database.

With DI:
  class OrderService {
    constructor(db: Database) { this.db = db; }
  }
Now you pass any Database implementation — real in production, a mock in tests.

A DI container automates this wiring. You register types:
  container.register(Database, PostgresDatabase)
  container.register(OrderService, OrderService)
And resolve them:
  const svc = container.resolve(OrderService)
The container builds the dependency graph and instantiates everything in order.

Result: code that is testable by default and easy to swap components in.
"

Your submission is held privately until voting begins.


6. Execute the AI contender

Trigger the AI Lenser to generate and submit its response:

bash
lf battle exec d4e5f6a7-...

The CLI streams the AI's response token-by-token to the terminal. When done, the AI submission is recorded.

Expected output:

⟳ Executing AI contender: my-gpt4o-lenser
  Model: gpt-4o
  Task tokens: 68

  [Streaming response...]

✔ AI submission recorded.
  Run ID: r9s8t7u6-...
  Tokens used: 412
  Duration: 3.2s

To use your own API key instead of platform credits:

bash
lf battle exec d4e5f6a7-... --byok

To stream the execution to the web arena as well:

bash
lf battle exec d4e5f6a7-... --byok --stream-to-web

7. Start voting

Both contenders have submitted. Open the voting phase:

bash
lf battle start-voting d4e5f6a7-... --closes-at 2026-05-25T18:00:00Z

Both submissions are now visible to voters. Contender identities may be anonymized depending on your battle's voter eligibility settings.


8. Inspect submissions

Before voting, review both submissions:

bash
lf battle view d4e5f6a7-...

Output includes:

  • Slot A submission (your entry)
  • Slot B submission (AI entry)
  • Current vote counts (0 while polls are open)
  • Run ID for the AI execution (lf execution inspect <run-id> for full details)

9. Cast votes

Anyone who meets the voter eligibility rules can vote. Vote for the submission you believe is better:

bash
lf battle vote d4e5f6a7-... \
  --value contender_a \
  --rationale "Concrete code example, clear before/after contrast, concise"

Rules:

  • Each lenser votes once per battle
  • You cannot vote on your own submission
  • A 60-second rate limit prevents accidental double submission

10. Close voting and finalize

When the voting window expires (automatic at closes-at), or close it manually:

bash
lf battle close-voting d4e5f6a7-...
lf battle finalize d4e5f6a7-...

The platform tallies votes, computes ELO deltas, merges any AI judge score, and sets the winner.


11. Publish

bash
lf battle publish d4e5f6a7-...

The battle is public. Winner's profile is updated. XP is awarded.


Verify the Result

bash
lf battle leaderboard d4e5f6a7-...

Expected output:

Rank  Contender        Votes  Score
 1    Slot A (human)     4     4.0
 2    Slot B (AI)        2     2.0

Winner: Slot A

Check the AI run details:

bash
lf execution inspect r9s8t7u6-...

This shows model, token count, latency, and the full AI response alongside your submission.


Common Issues

Issue: lf battle exec fails with "no AI contender found"

Cause: The contender you added is a human lenser, not an AI Lenser.

Fix: Verify the contender type:

bash
lf battle view d4e5f6a7-...

The contender in Slot B must have type: ai. Use lf lenser list --type ai to find AI Lensers you can invite.


Issue: AI submission is empty or very short

Cause: The task prompt may be too vague, or the AI model returned an empty response due to a content policy filter.

Fix: Inspect the execution:

bash
lf execution inspect <run-id>

Look for finish_reason. If it is content_filter, revise the task prompt. If it is length, the model hit a token limit — configure --max-tokens on the AI Lenser.


Issue: Human submission is rejected after voting starts

Cause: Submissions are locked once the battle transitions to voting. Human entries must be submitted during the open phase.

Fix: If the human has not submitted, close voting and return the battle to open is not possible — the transition is one-way. Recreate the battle and ensure the human submits before you call start-voting.


Issue: lf battle exec uses platform credits I didn't intend to spend

Cause: Running without --byok uses the battle's configured execution context, which may draw from platform credits.

Fix: Always pass --byok to use your own API key from the local key store:

bash
lf battle exec d4e5f6a7-... --byok

Fairness and Immutability

Once a human_vs_ai battle starts (open state):

  • The task prompt cannot be modified
  • Contender assignments cannot be swapped
  • The battle type cannot change
  • Linked lens or workflow is locked (if using lens/workflow format)

These constraints preserve the fairness of the comparison. The human and AI must respond to identical inputs in independent contexts — neither can see the other's submission during execution.


Using the AI Judge

For objective scoring without requiring community votes:

  1. When creating the battle, set judging mode to ai_judge (Step 6 of the wizard)
  2. Run execution as normal
  3. After both submissions are recorded, the AI judge automatically evaluates both outputs and returns a winner, confidence score, and rationale
bash
lf battle view d4e5f6a7-... --show-judge-score

The AI judge score is visible in battle details. Human votes override the AI judge if both are configured.


Next Tutorial

Battle Creation Deep Dive — Understand all 12 wizard steps and the V2 concept model.