Train lightweight chess personas from PGN files.
Project description
persona-chess
persona-chess is a Python library for training lightweight chess personas from PGN
files. The goal is not to find the strongest move. The goal is to predict how a
specific player is likely to move.
The current foundation includes PGN ingestion, player filtering, neural persona training, legal move masking, checkpoint inference, baseline comparison models, profile reports, JSON artifacts, and a CLI.
Install
pip install persona-chess
pip install "persona-chess[ml]"
pip install "persona-chess[evaluation]"
pip install "persona-chess[formats]"
CUDA is handled through PyTorch. persona-chess uses CUDA automatically when the
installed PyTorch build can see a compatible GPU; otherwise it safely trains on
CPU. If CUDA is requested but unavailable, install the PyTorch wheel that matches
your NVIDIA driver/CUDA runtime.
For local development:
pip install -e ".[dev]"
Python API
The normal workflow is train once, then load the checkpoint as a bot.
from persona_chess import PersonaChess
result = PersonaChess().train(
"games.pgn",
player="Target Player",
epochs=3, # optional
batch_size=32, # optional
device="cuda", # optional; auto uses CUDA when PyTorch can see it
)
print(result.checkpoint_dir)
print(result.model_state_path) # .../model.pt
bot = PersonaChess.load_neural(result.checkpoint_dir)
move = bot.move("startpos")
print(move.move_uci, move.san)
By default, persona checkpoints are tagged against malcouffe/chessgpt, a
432M-parameter UCI-move ChessGPT model trained on Lichess move sequences under
Apache-2.0. This is the selected upstream base model direction for
persona-chess because it treats chess as move language instead of engine
evaluation. The native checkpoint trainer remains compatible with local
init_checkpoint files while the Hugging Face base adapter path is hardened.
For large PGNs, keep the same API and switch on streaming. This writes training records under the checkpoint folder and trains batch by batch instead of keeping the whole dataset in memory:
persona = PersonaChess()
result = persona.train(
"large-games.pgn.zst",
player="Target Player",
streaming=True,
validation_ratio=0.1,
)
Baseline personas are still available for quick comparison:
from persona_chess import PersonaChess
persona = PersonaChess().fit_pgn("games.pgn", player="Target Player", model_type="blend")
persona.save("target-player.persona.json")
CLI
persona-chess profile games.pgn "Target Player"
persona-chess model-card games.pgn "Target Player" --out target-player.model-card.json
persona-chess train games.pgn "Target Player" --model-type blend --out target-player.persona.json
persona-chess move target-player.persona.json --fen "startpos"
persona-chess export-training games.pgn "Target Player" --out target-player.train.jsonl
persona-chess export-training-stream games.pgn "Target Player" --out target-player.train.jsonl
persona-chess export-base-training-stream public-games.pgn --out base.train.jsonl
persona-chess split-training-stream target-player.train.jsonl --train-out target-player.fit.jsonl --validation-out target-player.valid.jsonl
persona-chess split games.pgn "Target Player" --train-out train.jsonl --test-out test.jsonl
persona-chess benchmark games.pgn "Target Player" --model-type blend --out benchmark.json
persona-chess prepare-neural games.pgn "Target Player" --manifest-out adapter.manifest.json --move-vocab-out moves.vocab.json --position-vocab-out positions.vocab.json
persona-chess prepare-neural-stream target-player.train.jsonl "Target Player" --manifest-out adapter.manifest.json --move-vocab-out moves.vocab.json --position-vocab-out positions.vocab.json
persona-chess recommend-neural-config --training-examples 100000 --device cuda
persona-chess validate-neural adapter.manifest.json moves.vocab.json positions.vocab.json
persona-chess train-neural games.pgn "Target Player" --checkpoint-dir checkpoints/player --use-lora
persona-chess train-neural-stream target-player.train.jsonl --manifest adapter.manifest.json --move-vocab moves.vocab.json --position-vocab positions.vocab.json --checkpoint-dir checkpoints/player --init-checkpoint checkpoints/base
persona-chess neural-move checkpoints/player --fen "startpos"
persona-chess engine-move target-player.persona.json --engine-path /path/to/stockfish --fen "startpos"
persona-chess persona-report target-player.persona.json games.pgn "Target Player" --baseline-model baseline.persona.json --out persona-report.json
persona-chess download-model persona-chess/base-small --registry models.json
Built-in model backends:
blend: weighted baseline combining exact position memory, opening book, and phase priors.frequency: exact position memory with global legal fallback.opening_book: early-game repertoire memory.phase: game-phase move prior for opening, middlegame, and endgame positions.
Persona Model Cards
Model cards turn a PGN collection into a portable style and data-quality report. They include style tags, move and phase breakdowns, data warnings, and a recommended inference path.
persona-chess model-card games.pgn "Target Player" --out target-player.model-card.json
persona-chess model-card games.pgn "Target Player" --format markdown --out target-player.model-card.md
Persona Evaluation
persona-report is the main product-level evaluation command. It keeps the
project-specific persona metrics in persona-chess, while optionally using common
scientific Python tooling through persona-chess[evaluation] when available.
The report includes move-match top-1/top-k, MRR, baseline deltas, phase metrics, piece metrics, style similarity, opening similarity, score confidence, optional SciPy distribution distances, and optional UCI-engine centipawn/blunder metrics.
persona-chess train games.pgn "Target Player" --model-type blend --out target.persona.json
persona-chess train games.pgn "Target Player" --model-type frequency --out baseline.persona.json
persona-chess persona-report target.persona.json games.pgn "Target Player" --baseline-model baseline.persona.json --out persona-report.json
persona-chess persona-report target.persona.json games.pgn "Target Player" --engine-path /path/to/stockfish --out engine-report.json
Engine-Guided Persona Moves
persona-chess can rerank persona candidates with an external UCI engine such as
Stockfish or Lc0. The engine is not bundled and the persona model still supplies
the candidate style; the UCI engine only acts as a quality signal.
persona-chess engine-move target-player.persona.json --engine-path /path/to/stockfish --fen "startpos" --engine-weight 0.35
Large PGN Training
For large PGN collections, use the streaming commands. They keep the training
records on disk and only materialize the active batch during neural training.
Input can be plain .pgn or compressed .pgn.gz, .pgn.bz2, .pgn.xz, and
.pgn.zst files. Zstandard support is optional:
pip install "persona-chess[formats]"
persona-chess export-training-stream games.pgn "Target Player" --out target-player.train.jsonl
persona-chess split-training-stream target-player.train.jsonl --train-out target-player.fit.jsonl --validation-out target-player.valid.jsonl
persona-chess prepare-neural-stream target-player.train.jsonl "Target Player" --manifest-out adapter.manifest.json --move-vocab-out moves.vocab.json --position-vocab-out positions.vocab.json
persona-chess train-neural-stream target-player.fit.jsonl --manifest adapter.manifest.json --move-vocab moves.vocab.json --position-vocab positions.vocab.json --checkpoint-dir checkpoints/player --validation-records target-player.valid.jsonl --use-lora
To build a general chess policy foundation before persona adaptation, export every move from a large public PGN instead of filtering by one player:
persona-chess export-base-training-stream public-games.pgn --out base.train.jsonl
persona-chess split-training-stream base.train.jsonl --train-out base.fit.jsonl --validation-out base.valid.jsonl
persona-chess prepare-neural-stream base.fit.jsonl "persona-chess-base" --manifest-out base.manifest.json --move-vocab-out base.moves.json --position-vocab-out base.positions.json --config-profile large
persona-chess train-neural-stream base.fit.jsonl --manifest base.manifest.json --move-vocab base.moves.json --position-vocab base.positions.json --checkpoint-dir checkpoints/base --validation-records base.valid.jsonl --full-finetune
persona-chess train-neural-stream target-player.fit.jsonl --manifest adapter.manifest.json --move-vocab base.moves.json --position-vocab base.positions.json --checkpoint-dir checkpoints/player --validation-records target-player.valid.jsonl --init-checkpoint checkpoints/base --use-lora
Neural preparation uses a stable chess-wide position vocabulary by default so base
checkpoints and persona adapters can share the same embedding shapes. Use
--data-position-vocab only for isolated experiments that will not initialize from
another checkpoint.
There are two training modes:
PersonaChess().fit_pgn(...)andpersona-chess train ...fit a fast baseline persona artifact. This is the quickest way to create a playable opponent.export-training-streamplusprepare-neural-streamplustrain-neural-streamruns the neural Transformer/LoRA path. Use this for a base model and stronger per-player adaptation.
Neural Auto Configuration
Neural commands use hardware-aware defaults when training settings are omitted.
persona-chess inspects CPU memory and optional CUDA memory, then chooses a
small, balanced, or large Transformer + LoRA profile. Users can still override
training knobs directly:
persona-chess recommend-neural-config --training-examples 500000 --device cuda
persona-chess prepare-neural-stream target-player.train.jsonl "Target Player" --manifest-out adapter.manifest.json --move-vocab-out moves.vocab.json --position-vocab-out positions.vocab.json --config-profile balanced --epochs 3 --batch-size 32 --gradient-accumulation-steps 4
persona-chess train-neural-stream target-player.train.jsonl --manifest adapter.manifest.json --move-vocab moves.vocab.json --position-vocab positions.vocab.json --checkpoint-dir checkpoints/player --validation-records target-player.valid.jsonl --epochs 2 --batch-size 16
For very large datasets, keep the streaming path: export once, prepare the neural artifacts from JSONL, then train from the manifest. This avoids loading the full PGN or training set into memory at once.
The neural trainer reports train loss, optional validation loss, legal top-1 accuracy, legal top-3 accuracy, optimizer steps, active mixed precision mode, and trainable parameter counts. Training uses AdamW, learning-rate warmup plus cosine decay, gradient accumulation, gradient clipping, and CUDA mixed precision when available.
Long neural runs can save resumable checkpoints:
persona-chess train-neural-stream target-player.fit.jsonl --manifest adapter.manifest.json --move-vocab moves.vocab.json --position-vocab positions.vocab.json --checkpoint-dir checkpoints/player --validation-records target-player.valid.jsonl --save-best --checkpoint-every-epoch
persona-chess train-neural-stream target-player.fit.jsonl --manifest adapter.manifest.json --move-vocab moves.vocab.json --position-vocab positions.vocab.json --checkpoint-dir checkpoints/player-resumed --resume-checkpoint checkpoints/player/best
Remote base checkpoints can be distributed as zip archives through a registry JSON.
Each archive must contain a checkpoint.json at or below its root.
{
"schema_version": "persona-chess/model-registry/v1",
"models": [
{
"name": "persona-chess/base-small",
"version": "0.1.0",
"url": "https://example.com/persona-chess-base-small.zip",
"sha256": "..."
}
]
}
Project Direction
The planned model path is:
- A clean PGN-to-position dataset pipeline.
- Deterministic train/test splitting at game level.
- Strong baseline models for honest comparison.
- A chess-native base Transformer trained on large public PGN data.
- A training JSONL schema with legal move masks and target move indexes.
- Per-player LoRA adapters trained from personal PGNs.
- Legal move masking through
python-chess. - Evaluation by move-match accuracy and style similarity metrics.
The neural command currently prepares versioned adapter manifests, move
vocabularies, and position vocabularies. The package also includes an optional
PyTorch Transformer policy skeleton behind the ml extra, with PEFT-powered LoRA,
legal-masked policy batches, checkpoint helpers, and checkpoint inference. It is not
enabled for standard installs.
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file persona_chess-0.2.0.tar.gz.
File metadata
- Download URL: persona_chess-0.2.0.tar.gz
- Upload date:
- Size: 74.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee9c8d526f41f57c0a81b685be9e786fcdf27c59c1b6652e2297947bd08568be
|
|
| MD5 |
5dd559d2873a7de28f237eb7f987efc0
|
|
| BLAKE2b-256 |
88f83115be23e3af958eb2b658e2969a7ab5ace125f8d50a7bdc70f5bdc03f44
|
Provenance
The following attestation bundles were made for persona_chess-0.2.0.tar.gz:
Publisher:
publish.yml on brutalstein/persona-chess
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
persona_chess-0.2.0.tar.gz -
Subject digest:
ee9c8d526f41f57c0a81b685be9e786fcdf27c59c1b6652e2297947bd08568be - Sigstore transparency entry: 1686561210
- Sigstore integration time:
-
Permalink:
brutalstein/persona-chess@f04e2e3f1e9639e28412995bdb57d57052c8b996 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/brutalstein
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f04e2e3f1e9639e28412995bdb57d57052c8b996 -
Trigger Event:
release
-
Statement type:
File details
Details for the file persona_chess-0.2.0-py3-none-any.whl.
File metadata
- Download URL: persona_chess-0.2.0-py3-none-any.whl
- Upload date:
- Size: 88.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1d68a01aef99d16bdcd37d151bbe77bb77095deea7193da200768784a299ff9
|
|
| MD5 |
c2952e45df7bd74e9a9581411cd12368
|
|
| BLAKE2b-256 |
8cfb4f8a6e4e721789a2ca7cda3845d18c12b9a7f41d121431a3c780993a4779
|
Provenance
The following attestation bundles were made for persona_chess-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on brutalstein/persona-chess
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
persona_chess-0.2.0-py3-none-any.whl -
Subject digest:
f1d68a01aef99d16bdcd37d151bbe77bb77095deea7193da200768784a299ff9 - Sigstore transparency entry: 1686561342
- Sigstore integration time:
-
Permalink:
brutalstein/persona-chess@f04e2e3f1e9639e28412995bdb57d57052c8b996 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/brutalstein
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f04e2e3f1e9639e28412995bdb57d57052c8b996 -
Trigger Event:
release
-
Statement type: