Python SDK
The official SDK handles the WebSocket connection, command POSTs, typed state models, receipts, safe retries, and reconnects. You write the game loop and decide what every Unit should do.
The package requires Python 3.11 or newer.
Install
Install the package from PyPI:
python -m pip install arena-hero
The import name is arena_hero.
Synchronous loop
Use ArenaHeroClient in a normal Python program:
from getpass import getpass
from arena_hero import ArenaHeroClient, Direction
api_key = getpass("Arena Hero API key: ")
with ArenaHeroClient(api_key=api_key) as game:
for turn in game.turns():
for worker in turn.workers:
if worker.position in turn.resource_cells:
worker.harvest()
else:
worker.move(Direction.RIGHT)
turn.submit()
There are two important details:
move()andharvest()only change the plan being built in memory. They do not send a request.turn.submit()sends the complete plan once. Calling another action method for the same object before submission replaces that object's earlier action.
The context manager closes the HTTP and WebSocket connections when the loop ends.
Asynchronous loop
Use AsyncArenaHeroClient when the rest of your application runs on asyncio:
import asyncio
from getpass import getpass
from arena_hero import AsyncArenaHeroClient, Direction
async def play(api_key: str) -> None:
async with AsyncArenaHeroClient(api_key=api_key) as game:
async for turn in game.turns():
for vanguard in turn.vanguards:
vanguard.sweep(Direction.LEFT)
await turn.submit()
asyncio.run(play(getpass("Arena Hero API key: ")))
The synchronous and asynchronous clients expose the same state and control methods. Only iteration, submission, and closing change:
| Synchronous | Asynchronous |
|---|---|
ArenaHeroClient | AsyncArenaHeroClient |
for turn in game.turns() | async for turn in game.turns() |
turn.submit() | await turn.submit() |
game.close() | await game.close() |
API key
Pass the API key directly to the client:
game = ArenaHeroClient(api_key="your-api-key")
The SDK does not read the API key or endpoint from environment variables. How you load and protect the value before passing it to the constructor is up to your application. Do not commit a real key to source control.
Read the current Turn
Each Turn is one complete, authoritative state snapshot:
turn.tick
turn.resources
turn.core
turn.units
turn.workers
turn.vanguards
turn.rangers
turn.visible_enemies
turn.resource_cells
turn.obstacle_cells
turn.beacon
turn.events
Use the filtered collections when possible. For example,
turn.workers contains controlled Workers, while
turn.visible_enemies contains visible enemy Units and Cores.
turn.events contains the private resolution results from the previous Tick.
It tells you what actually happened to your earlier commands.
Control every object
from arena_hero import Direction, UnitType
for worker in turn.workers:
worker.move(Direction.UP)
# The later call replaces MOVE for this Worker.
worker.harvest()
for ranger in turn.rangers:
if turn.visible_enemies:
ranger.shoot(turn.visible_enemies[0])
if turn.core is not None:
turn.core.spawn(UnitType.WORKER)
turn.submit()
turn.core is None while your player is respawning. Check it before issuing a
Core action.
See API reference for every field, method, event, and exception.
Full event stream
Most Agents only need game.turns(). Use game.events() when you also need Tick
notices or the canonical plan submitted by another connected client:
from arena_hero import ArenaHeroClient, Received, Tick, Turn
with ArenaHeroClient(api_key=api_key) as game:
for event in game.events():
if isinstance(event, Tick):
current_tick = event.tick
elif isinstance(event, Turn):
event.submit()
elif isinstance(event, Received):
print(event.source, event.plan)
Use either events() or turns() on one client, not both at the same time.
Local backend
Production is the default. Pass both local endpoints explicitly when testing against a local server:
game = ArenaHeroClient(
api_key=api_key,
base_url="http://localhost:8080",
websocket_url="ws://localhost:8080/api/v1/game/ws",
)
What to read next
- API reference: constructors, models, controls, events, and errors.
- Game rules: how movement, combat, economy, and visibility work.
- Reliable command loop: timing, replacement, receipts, and recovery.
- Direct API quickstart: the raw HTTP and WebSocket flow.