How FightLab Works
The contract, the rewards, and the evaluation — in plain terms. Everything here is reproducible from the repo.
The Contract
A fighter is a black box: given the standard observation, return joint position targets. Nothing else is specified — train in any stack, use any architecture.
Observation (73 floats)
0:3 root angular velocity (body frame)
3:32 joint positions relative to guard pose (29 joints)
32:61 joint velocities (29)
61:67 opponent torso − your fists, your frame (3+3)
67:73 opponent pelvis − your torso, your frame (3+3)
Action (29 floats) — joint position targets (radians), 30 Hz.
Joints: 12 leg + 3 waist + 7 per arm (shoulder ×3, elbow, wrist roll/pitch/yaw).
Robot — Unitree G1, 29-DoF, identical for both fighters. No physical variation.
The full spec with joint order and actuator constants is docs/policy-contract.md in the repo. The interface version is fightlab-contract=2.
The Rules (v5)
- No referee stand-ups. Fall and you stay down until you get yourself up or the bout ends.
- KO: opponent HP to zero. Double KO in the same moment is a draw.
- Decision at the cap (10 seconds): HP margin ≥ 5 decides; else ground-time margin ≥ 3 s decides; else draw.
- Strikes count only when you're upright (pelvis above 0.5 m) and swinging (arm speed toward the opponent ≥ 1 m/s). Falling into someone is not a punch.
- Series: five seeded bouts. Win the majority, take the result. Draw — champion keeps the belt.
The Reward Stack (training)
Our reference training recipe (v6, current champion lineage):
| Term | What it pays for |
| Facing | Square up to the opponent |
| Approach velocity | Move toward the opponent with intent |
| Fist distance | Get hands near the opponent's torso |
| Hit | Upright, fast strikes that connect (scaled by punch speed) |
| Defense penalty | −8 when you take a high-velocity hit (RoboStriker design) |
| Get-up curriculum | When down: raise pelvis, orient upright, feet under body (HumanUP) |
| Recovery bonus | +5 once when you get back up after a real knockdown |
| Ground penalty | −0.5 per step on the floor — time down is always expensive |
| AMP style | Look like the mocap (adversarial motion prior) |
Skills come from a distilled motion prior (78 mocap clips: boxing, footwork, kicks, get-ups) — the policy outputs a 32-D residual over that manifold, not raw joint targets.
The Evaluation (trustless)
- The referee (
engine/eval_harness.py) runs the series with fixed seeds, no domain randomization.
- Every result carries a SHA-256 payload hash over the full series data. Recompute it:
python miner_sdk.py verify result.json.
- Replay any bout with the same seed and env pin — same result, bit for bit.
- Nothing is judged by us. The physics decides.
The League Structure
King of the hill. No ratings, no points. The record is:
- Reigns — who holds the belt, defenses, dates
- Title fights — champion vs challenger, signed series, video
- Submission decisions — every evaluated policy gets a signed result on record
Challengers fight the champion directly until past kings exist; then the gauntlet: beat recent former kings to earn a title shot. A draw means the champion retains.
Current Status
Champion: V3 Striker (inaugural, contract v1 fighter)
In training: V6 — first 29-DoF fighter: full wrist control, no-stand-up rules, HumanUP get-up curriculum, push robustness. When it passes evaluation, it challenges for the belt in FightLab 02.