- Python 88.9%
- CSS 4.4%
- HCL 2.5%
- Shell 1.9%
- Dockerfile 1.7%
- Other 0.6%
|
Some checks failed
Build & push Docker image / build (push) Failing after 3m51s
Quand l'infra déploie chessia avec claude_credentials_link_to_host_user, data/claude/.credentials.json devient un symlink vers le fichier du compte chipster du host. Source de vérité = host claude CLI qui refresh les tokens en continu. L'entrypoint ne doit PAS le réécrire (risque d'écraser des refresh frais ou de write-faillir si le mount sous-jacent est RO). |
||
|---|---|---|
| .forgejo/workflows | ||
| chessia | ||
| docker | ||
| infra/module | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| Dockerfile | ||
| pyproject.toml | ||
| README.md | ||
ChessIA
Pipeline d'analyse pédagogique de parties d'échecs en français, cible FIDE 1600+.
Flux : PGN → Stockfish (multi-PV, seuils adaptatifs) → détection des coups critiques → Claude (routage Opus/Sonnet selon sévérité) → rapport HTML interactif avec graphique d'éval, mini-viewers et explications structurées.
Deux modes d'utilisation :
- CLI (
chessia partie.pgn -o rapport.html) - Web (
chessia-web) — formulaire d'upload + historique + suivi live + notifications push
Installation
python -m venv .venv && source .venv/bin/activate
pip install -e ".[web]" # extras [web] pour le serveur
cp .env.example .env # renseigner STOCKFISH_PATH
Prérequis
- Stockfish UCI avec NNUE (tablebases recommandées).
vendor/stockfish/stockfishpar défaut. - CLI
claude(Claude Code) authentifiée via l'abonnement Max — le pipeline passe parclaude -p(pas l'API Anthropic).
Variables d'environnement (.env)
| Variable | Défaut | Rôle |
|---|---|---|
STOCKFISH_PATH |
— | Chemin du binaire UCI (obligatoire) |
STOCKFISH_THREADS |
3 |
Threads Stockfish (Pi4 = 3, laisser 1 core pour l'OS) |
STOCKFISH_HASH_MB |
512 |
Hash table Stockfish en Mo |
CLAUDE_CONCURRENCY |
3 |
Appels Claude parallèles |
CLAUDE_MODEL_BLUNDER |
opus |
Modèle pour blunders / occasions manquées |
CLAUDE_MODEL_FORCE |
— | Override tous les modèles (debug) |
CHESSIA_REPORTS_DIR |
~/.chessia-reports |
Dossier des rapports |
CHESSIA_WEB_HOST / CHESSIA_WEB_PORT |
127.0.0.1:8000 |
Écoute du serveur web |
NTFY_SERVER / NTFY_TOPIC / NTFY_USER / NTFY_PASSWORD |
— | Notifs push début/fin de diag (voir ntfy.sh) |
Usage
CLI
chessia partie.pgn -o rapport.html # analyse les deux camps
chessia partie.pgn --side white -o rapport.html # limiter au côté Blancs
Serveur web
chessia-web # uvicorn sur 127.0.0.1:8000
/: formulaire d'upload (fichier PGN ou coller du texte, drag & drop)/history: tableau des diagnostics avec filtres et polling live/watch/<id>: suivi live d'un diag en cours (progress bar + timeline + logs colorés)/report/<id>: rapport final avec TOC sticky, coups critiques repliables, export PDF/example: redirige vers un rapport terminé aléatoire (démo sans uploader son PGN)
Régénérer des rapports existants
Quand l'UI évolue, régénérer les rapports terminés avec le nouveau template (le numéro de version d'origine est préservé dans le rapport) :
python -m chessia.regen # tous les jobs done
python -m chessia.regen --dry-run # aperçu
python -m chessia.regen --job <id> # un seul job
Le script crée un report.html.bak.<timestamp> avant chaque overwrite.
Pipeline
Phase 1 — Stockfish scan
Analyse chaque demi-coup avec multipv=2 (détecte les coups brillants : meilleur coup dans une position où les candidats sont proches).
Phase 2 — Re-analyse des coups critiques
Pour chaque coup flaggé blunder / mistake / inaccuracy / missed_win, ré-évalue avec multipv=3 pour fournir les 3 candidats à Claude.
Phase 3 — Explications Claude
Pour chaque coup critique, prompt structuré en 5 sections :
- Diagnostic — nom précis du motif tactique/positionnel
- Analyse comparative des 3 candidats Stockfish
- Ligne principale détaillée sur 6 à 10 demi-coups avec éval
[+0.53],[+M3] - Raison profonde (principe échiquéen violé)
- Exercice d'entraînement ciblé
Le prompt est enrichi par phase (ouverture / milieu / finale) et inclut :
- Code ECO + nom d'ouverture (détection offline via
chessia/data/eco.json) - Features positionnelles calculées (pions passés/doublés/isolés, paire de fous, contrôle centre)
- Top 5 moments de tension de la partie
- 15 derniers demi-coups d'historique
Catégories de coups
| Catégorie | Seuil | NAG |
|---|---|---|
blunder |
≥ 200 cp de perte | ?? ($4) |
mistake |
≥ 100 cp | ? ($2) |
inaccuracy |
≥ 50 cp | ?! ($6) |
missed_win |
gain décisif lâché (+300 → <150) | !? ($5) |
brilliant |
meilleur coup dans position contestée (gap top1-top2 ≤ 60 cp) | !! ($3) |
Les seuils sont adaptatifs : ils montent avec la décisivité de la position via une sigmoid win_prob(cp) — moins de faux positifs sur positions déjà gagnées/perdues.
Rapport HTML
- Autonome : styles inlinés, échiquier interactif via CDN
lichess-pgn-viewer - Graphique d'éval SVG de la partie avec marqueurs colorés sur les coups notables
- Coups critiques repliables (
<details>natifs), sommaire sticky à gauche - Navigation clavier
↑ ↓/j kpour sauter de coup en coup - Mini-viewer Lichess par bloc critique avec la variante Stockfish (PV 14 demi-coups)
- Cases mentionnées par Claude mises en surbrillance sur le diagramme
- Export PDF via
window.print()(mise en page impression optimisée) - Light mode (toggle ☾/☀ avec persistance localStorage)
Architecture
chessia/
├── __main__.py # CLI entrypoint
├── web.py # Serveur FastAPI (historique, watch, notifs, regen)
├── pipeline.py # Orchestration : engine + claude + rapport
├── engine.py # Wrapper Stockfish (python-chess UCI)
├── critical.py # Détection (blunder/mistake/inaccuracy/missed_win/brilliant)
├── explain.py # Appels Claude via subprocess claude -p
├── cache.py # Cache FS des explanations (sha256 fen|ply|model)
├── eco.py # Détection offline ECO + nom d'ouverture
├── position_features.py # Features positionnelles (pions, roi, centre, fous)
├── progress.py # ETA (EMA) + cancel/pause contextvars
├── report_html.py # Rendu rapport (graphique, TOC, mini-viewers, print CSS)
├── board_svg.py # Diagramme SVG avec highlighted squares
├── regen.py # Script CLI regen rapports (avec backup)
├── data/eco.json # Base ECO (3700 entrées, lichess-org/chess-openings, CC0)
└── static/ # Design system partagé (styles.css + theme.js)
Voir CLAUDE.md pour les conventions de développement et les règles non-évidentes depuis le code.
Déploiement Docker
Image multi-stage (build Stockfish from source + Python + Node.js pour Claude Code CLI).
Build local
docker build -t chessia:dev .
Run
docker run -d \
--name chessia \
-p 8000:8000 \
-v chessia-reports:/data/reports \
-v chessia-cache:/data/cache \
-v chessia-claude:/home/chessia/.claude \
-e CLAUDE_CREDENTIALS_JSON="$(cat ~/.claude/.credentials.json)" \
-e NTFY_SERVER=https://ntfy.exemple.com \
-e NTFY_TOPIC=chessia-diag \
-e NTFY_USER=chessia \
-e NTFY_PASSWORD=... \
git.greil.fr/chipster/chessia:latest
Volumes à persister
| Mount | Contenu |
|---|---|
/data/reports |
Rapports HTML + meta.json des diagnostics |
/data/cache |
Cache des explications Claude (évite les re-appels) |
/home/chessia/.claude |
OAuth refresh tokens Claude Code (mis à jour automatiquement par le CLI). Persister ce volume évite d'avoir à ré-injecter CLAUDE_CREDENTIALS_JSON à chaque redémarrage tant que le refresh token reste valide |
Secrets de run
CLAUDE_CREDENTIALS_JSON: contenu du fichier~/.claude/.credentials.jsonde l'utilisateur Claude Code Max. L'entrypoint l'écrit dans/home/chessia/.claude/.credentials.jsonau démarrage.NTFY_*: optionnel, pour les push mobiles (voir section Env ci-dessus).
Déploiement via tofu-maison
Le repo expose un module OpenTofu dans infra/module/ compatible avec le pattern du repo tofu-maison (provider kreuzwerker/docker en SSH vers le LXC cible).
Côté tofu-maison, dans docker/services.tf :
module "chessia" {
source = "git::ssh://git@git.greil.fr/chipster/chessia.git//infra/module?ref=main"
image = "git.greil.fr/chipster/chessia:latest"
external_port = 8000
claude_credentials_json = var.chessia_claude_credentials_json
ntfy_server = "https://ntfy.exemple.com"
ntfy_topic = "chessia-diag"
ntfy_user = "chessia"
ntfy_password = var.chessia_ntfy_password
}
Puis tofu -chdir=docker init && tofu -chdir=docker apply.
Un workflow .forgejo/workflows/deploy.yml dans ce repo trigger automatiquement un apply de tofu-maison quand :
- le module
infra/module/**change (push main) - le build Docker termine avec succès (nouveau tag à tirer)
- déclenché manuellement depuis l'UI Forgejo
Secret repo supplémentaire requis :
| Secret | Usage |
|---|---|
TOFU_MAISON_TOKEN |
Token Forgejo avec write:repository sur mat/tofu-maison (pour déclencher son workflow apply.yml) |
CI Forgejo Actions
Workflow dans .forgejo/workflows/docker-build.yml :
- Trigger : push sur
main, tagv*, ou déclenchement manuel - Build : image AMD64 (
linux/amd64) - Push :
git.greil.fr/chipster/chessiaavec tagssha-<short>,latest(main),<version>(tags semver) - Cache layers : stockées en registry (
:buildcache) - Runner : self-hosted
Secrets Forgejo à configurer dans les settings du repo :
| Secret | Usage |
|---|---|
REGISTRY_USERNAME |
User pour push vers le registry Forgejo |
REGISTRY_TOKEN |
Token d'accès avec scope write:package |
Licence
Code : usage personnel. data/eco.json dérivé de lichess-org/chess-openings sous CC0.