Skip to main content

AI Agent Arcade

Language models play chess against each other in a single terminal window. Each model receives the move history, FEN, and legal SAN moves, then picks one move without an engine. A replay-verifying referee applies the move and writes an inspectable archive.

AI Agent Arcade Textual app replaying a verified match: animated dot-field board, match panel, scrollable decisions, and series log

The recording above is the real Textual app replaying archived match-171 (MISTRAL-LARGE-4-NVFP4 0-1 MUSE-SPARK-BF16, 80 plies: Fried Liver \u2192 queen sac \u2192 pawn promotion \u2192 Qe5#), captured frame-by-frame through Textual's own App.export_screenshot(). Regenerate it with:

uv run --with pillow python cli/record_tui_gif.py games/chess/match-171 --theme ansi-dark --output docs/assets/arcade-tui-dark.gif --frames 80 --fps 10 --width 900
uv run --with pillow python cli/record_tui_gif.py games/chess/match-171 --theme ansi-light --output docs/assets/arcade-tui-light.gif --frames 80 --fps 10 --width 900

Install and run

Requirements: Python 3.11+, uv, and an ALCF account with inference access.

Available on TestPyPI:

uvx --index https://test.pypi.org/simple/ --index-strategy unsafe-best-match --with ai-agent-arcade ai-agent-arcade --games 20
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ ai-agent-arcade

Or directly from the repository:

uvx --from git+https://github.com/saforem2/ai-agent-arcade ai-agent-arcade --games 20

Or from a checkout:

git clone https://github.com/saforem2/ai-agent-arcade.git
cd ai-agent-arcade
uv run ai-agent-arcade --games 20

Both commands work without Herdr, tmux, or a local inference gateway. Pressing Ctrl-C stops the runner cleanly. Running the same command again detects and resumes an interrupted live game, including a valid staged move. To inspect an archive without launching a new series, pass --view --live-dir games/chess/match-049.

Reset a game

To throw away an interrupted game and start from the opening position:

uv run ai-agent-arcade --reset --games 20

Press R in the running app to do the same thing without restarting it.

Reset never deletes evidence. The partial transcript (moves, decisions, names, FEN, runner log) is copied to <live-dir>/abandoned/<timestamp>/ with a reason.txt first, and completed archives under games/ are untouched. The orphaned match record is flipped from live to abandoned so the next game is not blocked by match-NNN is still live. The headless runner takes the same flag:

uv run python -m arcade_cli.series --reset --games 20 --live-dir "$ARCADE_LIVE"

Configure another matchup

Pass a versioned TOML file to use any two OpenAI-compatible endpoints:

version = 1

[players.one]
name = "MODEL-A"
harness = "openai"
base_url = "http://localhost:8000/v1"
model = "model-a"
effort = "medium"               # optional
api_key_env = "MODEL_A_API_KEY" # optional

[players.two]
name = "MODEL-B"
harness = "openai"
base_url = "http://localhost:9000/v1"
model = "model-b"
# api_key = "..."               # optional; prefer api_key_env
uv run ai-agent-arcade --config matchup.toml --games 10

Override every player's reasoning effort for one run without editing the file (passed through as reasoning_effort):

uv run ai-agent-arcade --config matchup.toml --games 10 --effort medium

base_url may be an API root ending in /v1 or the complete /chat/completions URL. Use harness = "alcf" to obtain the cached ALCF inference token automatically. API keys are resolved only by the runner and are not included in match records or logs.

Two ALCF models on the same cluster (e.g. Minerva's inkling-bf16 vs muse-spark-bf16) is the same shape with harness = "alcf" on both seats:

version = 1

[players.one]
name = "INKLING-BF16"
harness = "alcf"
base_url = "https://inference-api.alcf.anl.gov/resource_server/minerva/api/v1"
model = "inkling-bf16"
effort = "low"

[players.two]
name = "MUSE-SPARK-BF16"
harness = "alcf"
base_url = "https://inference-api.alcf.anl.gov/resource_server/minerva/api/v1"
model = "muse-spark-bf16"
effort = "low"

The original board is rendered by the same dot-field engine used by the standalone terminal viewer: identical geometry, influence field, sprites, colors, and timing. Textual only hosts the returned frame.

ALCF authentication

AI Agent Arcade reads a cached Globus token through alcf-tokens, the shared ALCF client that also backs alcf-ai.

uvx alcf-tokens login
uvx alcf-tokens test-token inference

A healthy token prints {"ready": true, "error": null}. Access tokens last 48 hours and refresh automatically; re-run login when refresh expires.

Check which models are live before starting a long series:

uvx alcf-ai ls-endpoints
uvx alcf-ai ls-jobs metis
uvx alcf-ai ls-jobs minerva

Full access requirements and troubleshooting are in the ALCF Inference Endpoints guide. The token is never written to logs or match archives.

The TUI

The app is one Textual screen with four regions: the board, the match panel, the scrollable decision history, and the series log.

Key Action
b Switch board style
r Replay the current game with move animations
R Reset: abandon the live game and start a new one
j / k Scroll decisions down / up
g / G Jump to the newest / oldest decision
p / c Pause / continue the runner
q Quit, leaving a live match resumable

Board styles

--board-style original (default) is the animated dot field: squares are braille density and the field drifts between two frames.

--board-style compact is a dense glyph grid that fits a small terminal.

AI Agent Arcade compact board style

uv run ai-agent-arcade --games 20 --board-style compact

Decision history

Every move records the chosen SAN, up to three candidates, one sentence of self-reported rationale, an expected reply, and token counts. The panel keeps the whole game and scrolls with j, k, g, and G.

This is the model's own summary. It is not a provider's hidden chain-of-thought and does not claim to reproduce one.

Themes

The app ships the four Textual themes from pbs-tui: pbs-dark, pbs-light, ansi-dark, and ansi-light. The ansi-* pair uses muted terminal-blending tones, including a light dot-field board palette — the board paints its own background, so it follows the theme instead of staying black.

Startup defaults to the ansi-* pair and detects the terminal background automatically: COLORFGBG first, then a direct OSC 11 query to the terminal, then dark. Override once with --theme or persistently with ARCADE_THEME:

uv run ai-agent-arcade --games 20 --theme ansi-light
ARCADE_THEME=pbs-dark uv run ai-agent-arcade --games 20

Ctrl-P still switches themes at runtime, and the board repaints with it.

Series standings

When the series ends, the match panel grows a STANDINGS block:

STANDINGS
INKLING-BF16 won 6/10 games!!! (1 draw)

The same line is stored as standings in series-summary.json, appended as STANDINGS: … after SERIES COMPLETE: … in series-runner.log, and printed to stdout by the headless runner — so it shows in the TUI, the log tail, and the terminal alike. Ties and all-drawn series get their own phrasing (Dead even: …, All 10 games drawn — dead even).

Turn clock

While a model is thinking, the match panel shows a live clock:

status: running
thinking: MUSE-SPARK-BF16 42s

Every finished turn is also timed in series-runner.log (ply 68: MUSE-SPARK-BF16 Rd4+ (38s)) and each decision_log.jsonl row carries thinking_seconds. Display only — no time limits, no forfeits; a slow model just reads as a big number instead of a frozen screen.

Models

Seat ALCF cluster Model
GPT-OSS Metis gpt-oss-120b
Inkling Minerva inkling-bf16

Colors alternate every game across the series.

Run headless

export ARCADE_LIVE=/tmp/alcf-chess-20
uv run python -m arcade_cli.series --games 20 --live-dir "$ARCADE_LIVE"

Resume after a completed game:

uv run python -m arcade_cli.series \
  --games 20 \
  --start-index 12 \
  --live-dir "$ARCADE_LIVE"

The runner writes:

  • $ARCADE_LIVE/series-runner.log
  • $ARCADE_LIVE/series-summary.json
  • $ARCADE_LIVE/decision_log.jsonl
  • games/chess/match-NNN/ for every archived game

Verify an archive

Every move is replayed from the initial position and compared with the stored FEN.

ARCADE_LIVE=games/chess/match-009 \
  uv run --quiet --with chess python engine/ref.py verify
OK verified 11 plies | r1bqkb1r/pppppQp1/2n4p/6N1/8/8/PPPP1KPP/RNB2B1R b kq - 0 6

How it works

model A ─┐
         ├─> SAN move ─> pending.txt ─> referee ─> moves.txt + fen.txt
model B ─┘                                      │
                                                ├─> board
                                                ├─> match panel
                                                ├─> decision history
                                                └─> archived evidence

Models never edit game state. They return SAN chosen from the referee's legal move list. ref.py checks seat identity, reconstructs the position from ply one, validates the move, appends it, and records terminal results including claimable threefold and 50-move draws.

Replays and media

The GIF and stills are recomputed from an archived transcript, not screen- recorded.

Animated replay of MISTRAL-LARGE-4-NVFP4 vs MUSE-SPARK-BF16 (match-171, 80 plies: Fried Liver \u2192 Qe5#)

uv run --with pillow python cli/render_readme_media.py games/chess/match-171
uv run --with pillow python cli/render_readme_media.py games/chess/match-171 --palette light --suffix "-light"

Tests

uv run --with pytest --with pytest-asyncio python -m pytest cli/tests -q

The full engine suite:

uv run --with pytest --with chess --directory cli \
  python -m pytest ../engine/ tests/ -q

Acknowledgements

This project was inspired by Xule Lin's linxule/arcade, which introduced the file-bus arena, replay-verifying referees, dot-field terminal renderers, and agent-hosted match format used here. The original code is MIT licensed; its copyright and license notice remain in LICENSE.

ALCF model inference is provided through Argonne Leadership Computing Facility services. Herdr supplies the optional multi-pane terminal workspace.

License

MIT. See LICENSE.

Metadata

Release files for ai-agent-arcade 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ai-agent-arcade 0.1.3
File Size Uploaded Provenance Actions
ai_agent_arcade-0.1.3.tar.gz 477.5 kB With provenance Details for ai_agent_arcade-0.1.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ai-agent-arcade 0.1.3
File Interpreter ABI Platform Actions
ai_agent_arcade-0.1.3-py3-none-any.whl Python 3 none any Details for ai_agent_arcade-0.1.3-py3-none-any.whl

Total release size: 872.4 kB

Release files / ai_agent_arcade-0.1.3.tar.gz

Download URL ai_agent_arcade-0.1.3.tar.gz
Size 477.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e398167d7b891ae177523e47b605f5d233c4a5b6130a853e3d750a8d561c38f2
BLAKE2b-256 checksum
How to use checksums
a30a0536b8407c28997e536c927362f39d4b31e4b9ed839ddbfa2e38244a214e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Release files / ai_agent_arcade-0.1.3-py3-none-any.whl

Download URL ai_agent_arcade-0.1.3-py3-none-any.whl
Size 394.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a40b91892777384231d745fec8a1ebf29e9f988822cb5ec50ac9c7b1b62a9abd
BLAKE2b-256 checksum
How to use checksums
2635205ad33005efa199c7d009217c7da7a20350988d6774feb598ef6a0e0a06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Security for ai-agent-arcade 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ai_agent_arcade-0.1.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page