# AGENTS.md This repository is managed with `uv`. Use `uv run ...` for commands so the project environment and Cython extensions are built/loaded consistently. ## Project Layout - `src/coolrl_lost_cities/games/classic/game.pyx`: Cython Lost Cities engine. - `src/coolrl_lost_cities/games/classic/deep_cfr/`: Deep CFR training, traversal, evaluation, analysis, and CLI code. - `configs/deep_cfr/`: Deep CFR YAML configs. - `runs/`: generated training runs. This path is gitignored and may be a symlink to larger storage. - `docs/`: profiling notes, migration notes, and experiment documentation. ## Core Commands Run lint: ```bash uv run ruff check . ``` Run all tests: ```bash uv run pytest -q ``` Run focused Deep CFR tests: ```bash uv run pytest -q tests/games/classic/test_deep_cfr_trainer.py ``` Run the CLI through the console script: ```bash uv run lost-cities-deep-cfr --help ``` Equivalent module form: ```bash uv run python -m coolrl_lost_cities.games.classic.deep_cfr.cli --help ``` ## Deep CFR Training Main full config: ```bash uv run lost-cities-deep-cfr train \ --config configs/deep_cfr/deep_cfr_selfplay_full_depth_slot_playability.yaml ``` Unbounded config: ```bash uv run lost-cities-deep-cfr train \ --config configs/deep_cfr/deep_cfr_selfplay_full_depth_slot_playability_unbounded.yaml ``` Short capped run: ```bash uv run lost-cities-deep-cfr train \ --config configs/deep_cfr/deep_cfr_selfplay_full_depth_slot_playability.yaml \ --max-iterations 100 \ --save-latest-only ``` Use explicit run directories for experiments. Put Deep CFR runs under `runs/deep_cfr/` and prefix generated run names with the date: ```bash RUN_DIR="runs/deep_cfr/$(date +%Y-%m-%d_%H%M%S)_deep_cfr_experiment_name" uv run lost-cities-deep-cfr train \ --config configs/deep_cfr/deep_cfr_selfplay_full_depth_slot_playability.yaml \ --checkpoint-dir "$RUN_DIR" \ --max-iterations 100 ``` Date-prefixed examples: - `runs/deep_cfr/2026-05-08_010000_deep_cfr_100iter` - `runs/deep_cfr/2026-05-08_020000_deep_cfr_unbounded` ## Long Runs Run long jobs in a real `tmux` session so the user can attach and stop them. Do not rely on Codex command sessions for long user-observable training runs. Start a long unbounded run: ```bash tmux new-session -s coolrl-deepcfr-unbounded -c /home/coolguy/dev/coolrl-lost-cities uv run lost-cities-deep-cfr train \ --config configs/deep_cfr/deep_cfr_selfplay_full_depth_slot_playability_unbounded.yaml ``` Attach later: ```bash tmux attach -t coolrl-deepcfr-unbounded ``` Detach without stopping: ```text Ctrl+B, D ``` Stop training: ```text Ctrl+C ``` Follow logs from another terminal: ```bash tail -f runs/deep_cfr/deep_cfr_selfplay_full_depth_slot_playability_unbounded/train.log ``` The unbounded config intentionally has: ```yaml run: iterations: null max_iterations: null max_hours: null checkpoint: save_iteration_interval: 100 ``` `latest.pt` is updated continuously; archive checkpoints are written every 100 iterations. If disk is tight, prefer `--save-latest-only` or increase `save_iteration_interval`. ## Evaluation And Analysis Evaluate a checkpoint: ```bash uv run lost-cities-deep-cfr eval \ --checkpoint runs/deep_cfr//latest.pt \ --opponent random \ --games 100 \ --device cpu ``` Generate analysis plots from `metrics.jsonl`: ```bash uv run lost-cities-deep-cfr analyze \ --run runs/deep_cfr/ ``` Write plots to a separate directory: ```bash uv run lost-cities-deep-cfr analyze \ --run runs/deep_cfr/ \ --output-dir runs/deep_cfr//analysis ``` The analyzer reads `metrics.jsonl` and writes PNG files grouped by diagnostic section. Opponents are compared within each plot using fixed colors. Smoothing uses a 5-iteration moving average by default; pass `--no-smoothing` to disable it or `--smoothing-window N` to choose a different window. Current output files: - `analysis_01_loss.png` - `analysis_02_match.png` - `analysis_03_action.png` - `analysis_04_gameflow.png` - `analysis_05_open_quality.png` - `analysis_06_expedition_outcomes.png` - `analysis_07_calibration.png` - `analysis_08_traversal.png` - `analysis_final_eval_summary.png` ## Runtime Artifacts Each training run writes: - `metrics.jsonl`: structured metrics, one completed iteration per line. - `train.log`: human-readable timestamped logs. - `runtime_progress.json`: latest progress snapshot. - `latest.pt`: latest checkpoint. - `iteration_*.pt`: archive checkpoints when enabled. - `config.json`: resolved config for the run. If a run is stopped mid-iteration, the in-progress iteration may not appear in `metrics.jsonl`. Analyze the latest completed metric row. ## Notes For Future Agents - Prefer `rg`/`rg --files` for search. - Use `apply_patch` for manual edits. - Do not commit generated run artifacts from `runs/`. - Cython-generated `.c` files are gitignored; edit `.pyx`/`.pxd` sources. - Before committing, run `uv run ruff check .` and at least the relevant pytest subset. For Deep CFR changes, run `uv run pytest -q tests/games/classic/test_deep_cfr_trainer.py`.