Headless Linux dev container: Godot + .NET + Xvfb for autonomous testing
Claude Code running inside the project's dev container can now build the
game, launch a real Godot instance under Xvfb, and drive the automation
harness end-to-end — no Windows dependency.
Dockerfile adds (as root, before USER node):
- X11 / Mesa software GL / audio runtime deps + python3
- .NET SDK 9.0 via upstream dot.net install script -> /usr/local/dotnet
- Godot 4.6.2-stable mono Linux x86_64 -> /opt/godot/godot
- /usr/local/bin/godot-xvfb wrapper: auto-wraps invocations in
xvfb-run -a --server-args="-screen 0 1280x720x24 ..."
harness.py picks GODOT_BIN from env, defaults to /opt/godot/godot on
Linux, and auto-wraps the subprocess in xvfb-run when DISPLAY is unset.
Windows code path unchanged.
init-firewall.sh adds api.nuget.org to the allowlist so dotnet restore
works post-boot. Godot + .NET SDK are fetched at image build time, before
the firewall exists.
New docs:
- autonomous_plan.md: design rationale, alternatives considered
- README.md: launch instructions for Windows terminal / Docker Desktop /
VS Code Dev Containers / WSL2 natif
- CLAUDE.md already documents the harness (done in previous commit)
Validation: docker build succeeds; inside the container, dotnet --version
=9.0.313, godot --version=4.6.2.stable.mono, dotnet test=102/102,
python3 tools/automation/smoke.py passes end-to-end with 14 non-black
1280x720 PNGs. Mission 1 screenshot is visually identical to the Windows
build, and Xvfb determinism is a bonus (det_a.png ≡ det_b.png bytewise).
2026-04-17 16:57:56 +02:00
# Chessistics
Jeu de logistique sur échiquier en Godot 4 / C#. Le joueur place des pièces
d'échecs sur un plateau ; elles se déplacent automatiquement et transportent
des ressources entre des productions et des demandes.
Voir [`CLAUDE.md` ](CLAUDE.md ) pour l'architecture (black-box simulation) et
les conventions internes.
## Arborescence
```
Chessistics/
├─ Scripts/ # Code Godot (présentation)
│ ├─ Automation/ # Harness autonome (CLI --automation=< dir > )
│ ├─ Board/ Input/ UI/ Pieces/ Presentation/
│ └─ Main.cs
├─ chessistics-engine/ # Moteur pur .NET, sans Godot
├─ chessistics-tests/ # Tests unitaires xUnit (sans Godot)
├─ Data/
│ ├─ campaigns/ # campaign_01.json (7 missions)
│ └─ levels/ # niveaux legacy
├─ tools/automation/ # Harness Python stdlib pour piloter Godot
├─ .devcontainer/ # Image Docker + firewall + Xvfb + Godot Linux
├─ Scenes/ icon.svg project.godot …
```
## Lancer le jeu (poste Windows direct)
Prérequis : Godot 4.6 mono + .NET 9 SDK installés localement.
```powershell
dotnet build Chessistics.csproj
"C:\Apps\godot\Godot_v4.6.2-stable_mono_win64.exe" --path .
```
Tests headless du moteur :
```powershell
dotnet test chessistics-tests/
```
Smoke test du harness d'automatisation :
```powershell
python tools/automation/smoke.py
```
## Dev container autonome (recommandé pour Claude Code)
Le dossier `.devcontainer/` contient une image Docker qui embarque :
- **.NET SDK 9.0** (build + tests)
- **Godot 4.6.2-stable mono Linux x86_64** sous `/opt/godot/godot`
- **Xvfb** + Mesa software GL pour un framebuffer virtuel 1280× 720
- **Python 3** pour le harness d'automatisation
- **Claude Code** installé automatiquement (`@anthropic-ai/claude-code` )
- Un firewall `iptables` qui restreint les sorties réseau à une allow-list
(GitHub, npm, Anthropic, NuGet, Sentry, Statsig)
Claude Code, lancé à l'intérieur, peut donc compiler le projet, exécuter
les tests, **démarrer une vraie instance de Godot en headless** et lire les
captures PNG produites — sans dépendance Windows.
### Option 1 — Docker Desktop + terminal Windows (le plus simple)
1. Installer [Docker Desktop pour Windows ](https://www.docker.com/products/docker-desktop/ ).
Docker Desktop utilise WSL2 en coulisses ; aucune configuration WSL
manuelle n'est nécessaire.
2. Installer la CLI devcontainers :
```powershell
npm install -g @devcontainers/cli
```
3. Depuis PowerShell ou Terminal Windows, à la racine du repo :
```powershell
cd C:\Projets\Chessistics
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . zsh
```
La première commande construit l'image (long le premier coup : Godot +
.NET à télécharger). La seconde ouvre un shell interactif dans le
container.
4. Dans le container :
```bash
dotnet build Chessistics.csproj
python3 tools/automation/smoke.py
claude # lance Claude Code inside the container
```
### Option 2 — VS Code + extension Dev Containers
1. Installer Docker Desktop + [VS Code ](https://code.visualstudio.com/ ) +
l'extension **Dev Containers** .
2. Ouvrir le dossier du repo dans VS Code.
3. Palette de commandes → `Dev Containers: Reopen in Container` .
4. Le terminal intégré est déjà dans le container. Lancer `claude` pour
démarrer Claude Code.
### Option 3 — WSL2 natif (plus performant si Docker Desktop rame)
Les bind-mounts Docker Desktop sur `C:\` sont plus lents qu'un fichier
stocké directement dans le système de fichiers WSL2. Pour un gros projet
c'est négligeable, mais si la lenteur devient visible :
1. Installer WSL2 + Ubuntu depuis le Microsoft Store.
2. Cloner le repo **à l'intérieur** de WSL2 (pas sur `/mnt/c/` ) :
```bash
cd ~ & & git clone < url > chessistics & & cd chessistics
```
3. Installer Docker dans WSL2 (via `docker.io` apt ou Docker Desktop avec
intégration WSL2 activée).
4. Installer la CLI devcontainers :
```bash
npm install -g @devcontainers/cli
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . zsh
```
Avantage : I/O disque natif Linux. Inconvénient : pas d'accès Explorer
direct aux fichiers (`\\wsl$\Ubuntu\home\…` ).
### Vérifier que tout fonctionne dans le container
```bash
dotnet --version # -> 9.0.x
godot --version # -> 4.6.2.stable.mono.official.*
dotnet test chessistics-tests/ # 102/102
python3 tools/automation/smoke.py # Godot boots, PNG screenshots written
ls .automation_runs/smoke/screens/ # 01_loaded.png, 02_placed.png, ...
```
Le harness Python détecte automatiquement Linux et enveloppe Godot dans
`xvfb-run` . Aucune variable d'environnement à positionner.
2026-04-17 20:50:38 +02:00
### Mode YOLO (`--dangerously-skip-permissions`)
Dans le container, tu peux lancer Claude Code sans prompt de confirmation à
chaque action :
```bash
claude --dangerously-skip-permissions
```
Avec ce flag Claude **n'affiche plus de "Allow this tool use? (y/n)"** avant
chaque appel d'outil (Bash, Edit, Write, etc.). Il agit en continu.
Pourquoi c'est raisonnable **dans ce container précis** :
| Frontière | Protection |
|-----------|-----------|
| Ton OS Windows, `C:\Users\…` , `~/.ssh` , autres projets | Inaccessibles — seul `/workspace` est bind-mounté |
| Réseau sortant | `iptables` en DROP par défaut ; allow-list : GitHub, npm, Anthropic, NuGet, Sentry, Statsig. Le reste est REJECTé |
| Privilèges | Claude tourne en user `node` (UID 1000), pas root. `sudo` whitelisté **uniquement** pour `init-firewall.sh` |
| Secrets | Aucun `~/.ssh` , `~/.aws` , cookies navigateur ou `.env` système montés |
Risques résiduels à garder en tête :
- **Perte de travail non committé dans `/workspace` .** Le mount est
read-write, donc un `rm -rf` ou un `git reset --hard` écrase tes fichiers
locaux. **Commit fréquemment** — c'est la seule garantie contre la perte.
- **Exfiltration via les domaines autorisés.** GitHub reste joignable : un
Claude compromis pourrait créer un gist public ou pousser sur un fork. Si
tu veux réduire ce vecteur, ne fais pas `gh auth login` dans le container,
ou utilise un PAT fine-grained limité à ce seul repo.
- **Capabilities `NET_ADMIN` /`NET_RAW` .** Actives pour le container (requis
par iptables). Exploitables uniquement via root, qui n'est pas accessible
à Claude en utilisation normale.
- **Pas de limites CPU/RAM.** Un process qui part en vrille peut saturer ta
machine jusqu'au prochain `docker stop` . Pas dramatique, juste gênant.
Ce que tu **ne risques pas** même en YOLO :
- Perte de données en dehors du projet
- Accès à tes autres dépôts, credentials personnelles, réseau domestique
- Modification de ton OS Windows
En pratique, le scénario à éviter : tu as des modifs locales importantes
non-pushées et Claude fait un `git reset --hard HEAD` . Donc : `git commit`
avant de lancer un long run autonome.
Headless Linux dev container: Godot + .NET + Xvfb for autonomous testing
Claude Code running inside the project's dev container can now build the
game, launch a real Godot instance under Xvfb, and drive the automation
harness end-to-end — no Windows dependency.
Dockerfile adds (as root, before USER node):
- X11 / Mesa software GL / audio runtime deps + python3
- .NET SDK 9.0 via upstream dot.net install script -> /usr/local/dotnet
- Godot 4.6.2-stable mono Linux x86_64 -> /opt/godot/godot
- /usr/local/bin/godot-xvfb wrapper: auto-wraps invocations in
xvfb-run -a --server-args="-screen 0 1280x720x24 ..."
harness.py picks GODOT_BIN from env, defaults to /opt/godot/godot on
Linux, and auto-wraps the subprocess in xvfb-run when DISPLAY is unset.
Windows code path unchanged.
init-firewall.sh adds api.nuget.org to the allowlist so dotnet restore
works post-boot. Godot + .NET SDK are fetched at image build time, before
the firewall exists.
New docs:
- autonomous_plan.md: design rationale, alternatives considered
- README.md: launch instructions for Windows terminal / Docker Desktop /
VS Code Dev Containers / WSL2 natif
- CLAUDE.md already documents the harness (done in previous commit)
Validation: docker build succeeds; inside the container, dotnet --version
=9.0.313, godot --version=4.6.2.stable.mono, dotnet test=102/102,
python3 tools/automation/smoke.py passes end-to-end with 14 non-black
1280x720 PNGs. Mission 1 screenshot is visually identical to the Windows
build, and Xvfb determinism is a bonus (det_a.png ≡ det_b.png bytewise).
2026-04-17 16:57:56 +02:00
### Personnaliser la version de Godot
L'image par défaut pose Godot 4.6.2-stable. Pour changer, modifier
l'argument de build :
```jsonc
// .devcontainer/devcontainer.json
"build": {
"args": {
"GODOT_VERSION": "4.7.0-stable"
}
}
```
Puis `devcontainer up --workspace-folder . --build-no-cache` .
## Dépannage
| Symptôme | Cause probable | Fix |
|----------|----------------|-----|
| `godot --version` donne *no such file* | PATH non mis à jour | `source /etc/profile` ou relancer le shell |
| Screenshot tout noir | Aucun DISPLAY + pas d'xvfb | Vérifier `which xvfb-run` ; utiliser `godot-xvfb` au lieu de `godot` directement |
| `dotnet restore` bloque | Firewall bloque `api.nuget.org` | Vérifier que `init-firewall.sh` s'est bien exécuté avec les changements récents |
| Build Docker échoue au download de Godot | Réseau restreint côté hôte | Retry, ou installer Godot manuellement et commenter les lignes correspondantes |
2026-04-17 20:50:38 +02:00
| Claude Code demande confirmation à chaque action | Comportement normal hors YOLO | Voir la section *Mode YOLO* ci-dessus |
Headless Linux dev container: Godot + .NET + Xvfb for autonomous testing
Claude Code running inside the project's dev container can now build the
game, launch a real Godot instance under Xvfb, and drive the automation
harness end-to-end — no Windows dependency.
Dockerfile adds (as root, before USER node):
- X11 / Mesa software GL / audio runtime deps + python3
- .NET SDK 9.0 via upstream dot.net install script -> /usr/local/dotnet
- Godot 4.6.2-stable mono Linux x86_64 -> /opt/godot/godot
- /usr/local/bin/godot-xvfb wrapper: auto-wraps invocations in
xvfb-run -a --server-args="-screen 0 1280x720x24 ..."
harness.py picks GODOT_BIN from env, defaults to /opt/godot/godot on
Linux, and auto-wraps the subprocess in xvfb-run when DISPLAY is unset.
Windows code path unchanged.
init-firewall.sh adds api.nuget.org to the allowlist so dotnet restore
works post-boot. Godot + .NET SDK are fetched at image build time, before
the firewall exists.
New docs:
- autonomous_plan.md: design rationale, alternatives considered
- README.md: launch instructions for Windows terminal / Docker Desktop /
VS Code Dev Containers / WSL2 natif
- CLAUDE.md already documents the harness (done in previous commit)
Validation: docker build succeeds; inside the container, dotnet --version
=9.0.313, godot --version=4.6.2.stable.mono, dotnet test=102/102,
python3 tools/automation/smoke.py passes end-to-end with 14 non-black
1280x720 PNGs. Mission 1 screenshot is visually identical to the Windows
build, and Xvfb determinism is a bonus (det_a.png ≡ det_b.png bytewise).
2026-04-17 16:57:56 +02:00
## Licence
Voir les fichiers du repo.