 Command

Sam Foreman's personal site. Vim-style keybinds for navigation; theme + font pickers below.

Theme
 Font Body Code
Reader
Keybinds
Navigation
j / ↓ Next item k / ↑ Previous item g First item in region G Last item in region zz Center focused item h / l Sidebar / main content ] / [ Next/previous heading } / { Next/previous block d / u Half-page down/up
Layout
<zh> Toggle sidebar <zr> Toggle reader view <zj> / <zk> Focus main / actions ⇧C / ⇧E  ·  <zM> / <zR> Collapse / expand all sections
Dialogs
⌃P / : Command palette ⌃X Theme picker / Search ? Show keybinds ⌃N / ⌃P Next/prev search result Esc Close dialog / exit reader
History
n Next document b Previous document ⌃O History back ⌃I History forward
Sections
a about p posts t talks m more s style
 Search
about: Sam Foreman about/more: 🪪 More ideas: 💡 Ideas more: ➕ More now: Now posts: 📬 Posts posts/2023/12/05: 🔳 l2hmc-qcd Example: 4D SU(3) posts/2025: 📆 2025 posts/2025/04/28: 🔥 Building PyTorch 2.6 from Source on Aurora posts/2025/05/03: 🚧 Frameworks Issue with numpy \› 2 posts/2025/06: 06 posts/2025/06/01: 📰 Nice Headings posts/2025/06/02: 🧜‍♀️ Mermaid posts/2025/06/14: 🏗️ Building PyTorch 2.8 from Source on Aurora posts/2025/09/12: 🍹 BlendCorpus + TorchTitan @ ALCF posts/2025/09/17: 📊 pbs-tui: TUI for PBS Job Scheduler Monitoring posts/2025/10/06: 🎨 Mixing Between Distributions While Training posts/2025/11/12: 🧊 Cooling Down Checkpoints: Best Practices for Model Evaluation posts/2026/01/07: 🎉 Happy New Year! posts/2026/01/10: 🍋 ezpz: distributed PyTorch across any hardware posts/2026/02/28: ⏱️ Comparing Launchers on Aurora posts/2026/02/28: ## torchrun posts/2026/02/28: ## ezpz posts/2026/04/27: Pre-Training AuroraGPT with TorchTitan posts/2026/04/27: ## Two-Week Summary (Apr 12–27, 2026) posts/2026/04/27: ## Detailed Breakdown posts/2026/04/27: ### Week 1: Apr 12–18 — Benchmarking, LR Finder, XPU Fixes posts/2026/04/27: #### Benchmarking (Apr 12–15) posts/2026/04/27: #### LR Finder (Apr 12–14) posts/2026/04/27: #### Scaling Study (Apr 12) posts/2026/04/27: #### Upstream Syncs (Apr 12–18, syncs 6–14) posts/2026/04/27: #### XPU Bug Fixes (Apr 18) posts/2026/04/27: #### RL Experiment (Apr 18) posts/2026/04/27: ### Week 1.5: Apr 18–25 — Production Readiness posts/2026/04/27: #### Torch 2.12 Benchmarks (Apr 18) posts/2026/04/27: #### LR Finder Extensions (Apr 20–21) posts/2026/04/27: #### XPU Fixes (Apr 23) posts/2026/04/27: #### Torch 2.13 Environment (Apr 25) posts/2026/04/27: #### 2B Scaling Study on Torch 2.13 (Apr 25) posts/2026/04/27: #### Production Training (Apr 25) posts/2026/04/27: ### Week 2: Apr 26–27 — Optimizer Competition posts/2026/04/27: #### RL Multi-Task Refactor (Apr 26) posts/2026/04/27: #### Docs Reorganization (Apr 26) posts/2026/04/27: #### Generic HF Dataset Streaming (Apr 26) posts/2026/04/27: #### New Optimizers (Apr 26) posts/2026/04/27: #### Architecture Tweaks (Apr 26–27) posts/2026/04/27: ## Competition Results posts/2026/04/27: ### Round 1–3: Speedrun — 2N, GBS=48, 1000 steps posts/2026/04/27: ### 10B Full Training — 8N, GBS=384, ~3,178 steps posts/2026/04/27: ### Round 4: Reproducible Speedrun — 2N, GAS=8, GBS=384, 1000 steps posts/2026/04/27: ## Key Discoveries posts/2026/04/27: ## Infrastructure Built posts/2026/04/27: ## High-Level posts/2026/04/27: ## Detailed Breakdown posts/2026/04/27: ### Week 1: Apr 12–18 — Benchmarking, LR Finder, XPU Fixes posts/2026/04/27: #### Benchmarking (Apr 12–15) posts/2026/04/27: #### LR Finder (Apr 12–14) posts/2026/04/27: #### Scaling Study (Apr 12) posts/2026/04/27: #### Upstream Syncs (Apr 12–18, syncs 6–14) posts/2026/04/27: #### XPU Bug Fixes (Apr 18) posts/2026/04/27: #### RL Experiment (Apr 18) posts/2026/04/27: ### Week 1.5: Apr 18–25 — Production Readiness posts/2026/04/27: #### Torch 2.12 Benchmarks (Apr 18) posts/2026/04/27: #### LR Finder Extensions (Apr 20–21) posts/2026/04/27: #### XPU Fixes (Apr 23) posts/2026/04/27: #### Torch 2.13 Environment (Apr 25) posts/2026/04/27: #### 2B Scaling Study on Torch 2.13 (Apr 25) posts/2026/04/27: #### Production Training (Apr 25) posts/2026/04/27: ### Week 2: Apr 26–27 — Optimizer Competition posts/2026/04/27: #### RL Multi-Task Refactor (Apr 26) posts/2026/04/27: #### Docs Reorganization (Apr 26) posts/2026/04/27: #### Generic HF Dataset Streaming (Apr 26) posts/2026/04/27: #### New Optimizers (Apr 26) posts/2026/04/27: #### Architecture Tweaks (Apr 26–27) posts/2026/04/27: ## Competition Results posts/2026/04/27: ### Round 1–3: 1000-step speedruns, 2 nodes, GBS=48 (17 configs) posts/2026/04/27: ### Round 4 (10B full training, 8 nodes, GBS=384, 5 configs) posts/2026/04/27: ### Round 5 (2 nodes, GAS=8, GBS=384, local dataset, 8 configs — in progress) posts/2026/04/27: ## Key Discoveries posts/2026/04/27: ## Infrastructure Built posts/2026/05/01: Running 50k Python Processes on Aurora with ezpz yeet posts/2026/06/27: Local AI Apps on ALCF: Argo, Inference Endpoints, and One Gateway posts/2026/06/28: Migrating from Quarto to Astro: samforeman.me → samf.sh posts/2026/08/08: Pre-Training LLMs on a Supercomputer posts/2026/09/22: Working From Anywhere: Persistent Access to Compute and Context posts/2026/09/25: A Small Service Mesh for My Macs and Supercomputers posts/2026/10/16: ezpz from anywhere: remote submission via the ALCF IRI API posts/2026/11/11: Benchmarking ALCF systems with torch-hammer posts/2026/11/14: ♟️ AI Agent Arcade — LLMs play chess, a referee keeps score posts/ai-for-physics: ⚛️ AI for Physics posts/ai-for-physics/diffusion: 🎲 MCMC + Diffusion Sampling posts/ai-for-physics/l2hmc-qcd: 🎢 L2HMC for LQCD posts/ai-for-physics/l2hmc-qcd/2du1: 🎢 l2hmc-qcd Example: 2D U(1) posts/auroragpt: 🤖 AuroraGPT posts/auroragpt/aurora-gpt: 🏎️ Megatron-DeepSpeed on Intel XPU posts/auroragpt/checkpoints: 💾 Converting Checkpoints posts/auroragpt/determinstic-flash-attn/deterministic-flash-attn: 🎰 Deterministic flash-attn posts/auroragpt/flash-attn-sunspot: 📸 flash-attn on Sunspot posts/auroragpt/long-sequences: 🚂 Loooooooong Sequence Lengths posts/auroragpt/mpi4py-reproducer: 🐛 mpi4py bug on Sunspot posts/auroragpt/spike-skipper: 🏔️ Spike Skipper posts/auroragpt/startup-times: 🐢 Starting Up Distributed Training on Aurora posts/auroragpt/startup-times: ## Response posts/auroragpt/startup-times: ### Measuring / Calculating Startup Time posts/auroragpt/startup-times: ## Minimal Working Example posts/croon: croon: Synced Lyrics in the Terminal, for Whatever Is Playing posts/dope-slides: 💅 How to Make Dope Slides posts/drafts/2025/09/22: 📝 2025 Annual Report posts/ezpz-at-alcf: 🍋 ezpz @ ALCF posts/ezpz-v1: 📝 ezpz-v1 posts/globusfs: globusfs: an fsspec Filesystem for Globus Collections posts/jupyter: 📗 Jupyter posts/jupyter/test: 🏁 l2hmc Example: 2D $U(1)$ posts/resume: 🧑🏻‍💻 Sam Foreman’s Résumé posts/svgbob: 🫥 svgbob posts/torchtune-aurora: 🪛 Torchtune on Aurora posts/torchtune-patch-aurora: 🚑 Torchtune Patch on Aurora posts/wandb-tui: wandb-tui: Comparing W&B Runs Without Leaving the Terminal projects: 📚 Projects talks: 🎙️ Talks talks/2025/09/24: Training Foundation Models on Supercomputers talks/2025/10/08: AERIS: Argonne's Earth Systems Model talks/2025/10/15: Training Foundation Models on Supercomputers talks/2025/10/24: Training Foundation Models on Supercomputers talks/2025/12/16: AuroraGPT: Training Foundation Models on Supercomputers talks/2026/06/03: Production Pre-Training at Scale: The Good, the Bad, and the Restarts talks/2026/07/14: Pre-Training AuroraGPT at Scale on Aurora talks/2026/08/03: Pre-Training LLMs on a Supercomputer talks/2026/10/15: Profiling and Optimization of AI Training Workloads talks/2026/10/21: Scaling PyTorch on Intel XPU: Field Notes from AI for Science on Aurora talks/2026/10/30: Towards Resilient Training and Fault-Tolerant Software at ALCF talks/ai-for-science-2024: Parallel Training Methods talks/alcf-hpc-workshop-2024/alcf-hpc-workshop-2024: Deep Learning and Foundation Models at Scale talks/aurora-gpt-fm-for-electric-grid/auroragpt-fm-for-electric-grid: AuroraGPT: Foundation Models for Science talks/auroragpt-siam25: AuroraGPT talks/auroragpt/alcf-hpc-workshop-2024/auroragpt-alcf-hands-on-hpc-workshop-2024: AuroraGPT: ANL's General Purpose Scientific LLM talks/demo-slides: AuroraGPT: Training Foundation Models on Supercomputers talks/hpc-user-forum/auroragpt: AuroraGPT talks/incite-hackathon-2025: ALCF Incite Hackathon 2025 talks/incite-hackathon-2025/auroragpt: LLMs on Aurora: Overview talks/incite-hackathon-2025/ezpz: LLMs on Aurora: Hands-On talks/llms-at-scale: Training LLMs at Scale talks/llms-on-polaris: Training LLMs on Polaris talks/openskai25: Open SkAI2025 talks/openskai25/ai4science: Scientific AI at Scale: AuroraGPT talks/openskai25/training: Scientific AI at Scale: Distributed Training webtui: Style webtui/components/accordion: Accordion webtui/components/badge: Badge webtui/components/button: Button webtui/components/checkbox: Checkbox webtui/components/dialog: Dialog webtui/components/input: Input webtui/components/popover: Popover webtui/components/pre: Pre webtui/components/progress: Progress webtui/components/radio: Radio webtui/components/range: Range webtui/components/separator: Separator webtui/components/spinner: Spinner webtui/components/switch: Switch webtui/components/table: Table webtui/components/textarea: Textarea webtui/components/tooltip: Popover webtui/components/typography: Typography webtui/components/view: View webtui/contributing/contributing: Contributing webtui/contributing/contributing: ## Local Development webtui/contributing/contributing: ## Issues webtui/contributing/contributing: ## Pull Requests webtui/contributing/style-guide: Style Guide webtui/contributing/style-guide: ## CSS Units webtui/contributing/style-guide: ## Selectors webtui/contributing/style-guide: ## Documentation webtui/installation/astro: Astro webtui/installation/astro: ## Scoping webtui/installation/astro: ### Frontmatter Imports webtui/installation/astro: ### ‹style› tag webtui/installation/astro: ### Full Library Import webtui/installation/nextjs: Next.js webtui/installation/vite: Vite webtui/plugins/plugin-dev: Developing Plugins webtui/plugins/plugin-dev: ### Style Layers webtui/plugins/plugin-nf: Nerd Font Plugin webtui/plugins/theme-catppuccin: Catppuccin Theme webtui/plugins/theme-custom: Custom Theme webtui/plugins/theme-everforest: Everforest Theme webtui/plugins/theme-gruvbox: Gruvbox Theme webtui/plugins/theme-nord: Nord Theme webtui/plugins/theme-vitesse: Vitesse Theme webtui/start/ascii-boxes: ASCII Boxes webtui/start/changelog: Changelog webtui/start/installation: Installation webtui/start/installation: ## Installation webtui/start/installation: ## Using CSS webtui/start/installation: ## Using ESM webtui/start/installation: ## Using a CDN webtui/start/installation: ## Full Library Import webtui/start/installation: ### CSS webtui/start/installation: ### ESM webtui/start/installation: ### CDN webtui/start/intro: Introduction webtui/start/intro: ## Features webtui/start/plugins: Plugins webtui/start/plugins: ## Official Plugins webtui/start/plugins: ### Themes webtui/start/plugins: ## Community Plugins webtui/start/theming: Theming webtui/start/theming: ## CSS Variables webtui/start/theming: ### Font Styles webtui/start/theming: ### Colors webtui/start/theming: ### Light & Dark webtui/start/theming: ## Theme Plugins webtui/start/theming: ### Using Multiple Theme Accents webtui/start/tuis-vs-guis: TUIs vs GUIs webtui/start/tuis-vs-guis: ## Monospace Fonts webtui/start/tuis-vs-guis: ## Character Cells
 Theme Current: Light j/k or ↑/↓ + Enter

♟️ AI Agent Arcade — LLMs play chess, a referee keeps score

Language models play chess against each other in one terminal window. No engine, no hints — just SAN, FEN, and a replay-verifying referee. Here is how it works and what 250+ games look like.

Language models play chess against each other in one terminal window.

No engine. No hints. Each model receives the move history, the current FEN, and the legal SAN moves, picks one, and a referee applies it. The result is an inspectable archive per game.

ai-agent-arcade is on PyPI (pip install ai-agent-arcade), runs from a checkout with uv, and authenticates to ALCF inference through alcf-tokens — the same cached Globus token that backs alcf-ai. No Herdr, no tmux, no local gateway.

The TUI

One Textual screen, four regions: the board, the match panel, the scrollable decision history, and the series log.

KeyAction
bSwitch board style
rReplay the current game with move animations
RReset — abandon the live game and start a new one
yRetry the last abandoned game in the series
j / kScroll decisions down / up
g / GJump to newest / oldest decision
p / cPause / continue the runner
qQuit, leaving a live match resumable

uvx ai-agent-arcade --games 20 starts a 20-game series with alternating colors. Ctrl-C stops cleanly, running it again resumes the interrupted game.

pip install ai-agent-arcade
uvx ai-agent-arcade --games 20

# any two OpenAI-compatible endpoints
uvx ai-agent-arcade --config matchup.toml --games 10

# override reasoning effort for one run
uvx ai-agent-arcade --config matchup.toml --games 10 --effort medium

Headless, same thing:

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

How a move works

model A ─┐
         ├─> SAN move ─> pending.txt ─> referee ─> moves.txt + fen.txt
model B ─┘                                         └─> archived evidence

The referee is engine/ref.py. moves.txt is the single append-only source of truth. Every move replays the full log from the start and checks it against fen.txt — tampering with fen.txt does not change the game, it halts the game. Moves staged through game.sh are signed (<name>\t<san> in pending.txt) and the referee refuses a move from the wrong seat. resign, offer-draw, and accept-draw are the three non-SAN tokens, same staging path.

Verification is one command against any archive:

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

Each move also records a decision row in decision_log.jsonl: chosen SAN, up to three candidates, one sentence of self-reported rationale, expected reply, and token counts. This is the model’s own summary, not a provider’s hidden chain-of-thought.

What the series runner does

cli/src/arcade_cli/series.py loops game_index from start_index to games. Colors alternate every game. Each play_one call:

  1. start_match — allocates match-NNN, deploys the engine runtime into live_dir, writes names.txt / series.txt.
  2. Up to 300 plies — ask the player on move, apply_move through the referee, time the turn.
  3. verify — replay from the start, compare FEN.
  4. archive_match — copy the transcript into games/chess/match-NNN/.

A live game is resumable. --resume-live re-attaches series.txt → match-NNN and replays moves.txt to recover ply and board. --start-index picks up mid-series by replaying existing_series_rows for standings.

Transient 502s and OSErrors retry with backoff inside ask. When retries are exhausted, GameFailed fires: the series flips that match.json to abandoned, copies the partial transcript to abandoned/<timestamp>/, and continues to the next game. That is PR #1 — one bad ply fails one game, not the whole series.

--reset and R do the same abandon-and-clear for a live game the user wants to throw away. The new y (PR #2) goes the other way: it scans series-runner.log for the most recent GAME N/M match-NNN ABANDONED line and re-runs that index from the opening with the same seat order, then continues N+1…M.

Themes and board styles

Four Textual themes ship with the app (pbs-dark, pbs-light, ansi-dark, ansi-light), auto-detected from COLORFGBG and OSC 11. Ctrl-P switches at runtime. The board repaints with the theme — ansi-light gets its own light dot-field palette instead of staying black.

Two board styles: original is the animated dot field (braille density + drift between two frames, same engine as engine/tui_dots.py), compact is a dense glyph grid for small terminals. b toggles, --board-style sets the default.

The showcase GIF on the repo README is the real app replaying match-171 (MISTRAL-LARGE-4-NVFP4 0-1 MUSE-SPARK-BF16, 80 plies: Fried Liver → queen sac → promotion → Qe5#), captured frame-by-frame through App.export_screenshot() → rsvg-convert → GIF.

Results so far

250+ archived games under games/chess/match-NNN/, each with match.json, moves.txt, decision_log.jsonl, fen.txt, and result.txt. Early series pitted GPT-OSS-120B (Metis) against INKLING-BF16 (Minerva); recent ones use MISTRAL-LARGE-4-NVFP4 vs MUSE-SPARK-BF16. A representative game:

match-009: GPT-OSS-120B 1-0 INKLING-BF16, 11 plies. match-171: MISTRAL-LARGE-4-NVFP4 0-1 MUSE-SPARK-BF16, 80 plies.

series-summary.json and series-runner.log track standings across games:

STANDINGS
INKLING-BF16 won 6/10 games!!! (1 draw)
Dead even: GPT-OSS-120B 3 — 3 INKLING-BF16 across 6 games (+2 draws)
All 10 games drawn — dead even

Same line goes to standings in series-summary.json, STANDINGS: … in the log, and stdout from the headless runner. The TUI grows a STANDINGS block when the series ends.

Configure another matchup

Any two OpenAI-compatible endpoints via a versioned TOML:

version = 1

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

[players.two]
name = "MODEL-B"
harness = "openai"
base_url = "http://localhost:9000/v1"
model = "model-b"

harness = "alcf" resolves the cached inference token automatically. base_url can be the API root (…/v1) or the full /chat/completions URL.

Artifacts

  • Code: saforem2/ai-agent-arcade · PyPI ai-agent-arcade
  • Engine: engine/ref.py (referee), engine/game.sh + game_cli.py (staging), engine/tui_dots.py (dot field)
  • Runner: cli/src/arcade_cli/series.py + arcade_app.py (TUI)
  • Archives: games/chess/match-NNN/ — 250+ games, each verifiable with ref.py verify

Two models, one board, one log file. Everything else is just making that reproducible.

 samf.sh / posts / 2026 / 11 / 14 · Top 1:1