Synthèse automatique
Guide la procédure d'ajout d'un nouveau moteur de jeu (backend) ou d'un adaptateur Gymnasium au projet fmri-gym, du code d'adaptation jusqu'aux tests et à la configuration.
Points forts
- Checklist ordonnée et numérotée couvrant adaptateur, config, extras pyproject, tests et workflows CI
- Distinction claire entre logique du jeu (env Gym) et adaptateur, avec des modèles de fichiers existants à imiter
- Met l'accent sur la reproduction (replay) comme critère d'acceptation réel, pas seulement la jouabilité
- Signale des pièges concrets comme les noms de touches pygame ou l'absence de valeurs par défaut dans les phases de jeu
Limites
- Très spécifique au dépôt fmri-gym et à ses conventions internes, peu réutilisable ailleurs
- Le texte fourni s'interrompt en pleine phrase sur la gestion des espaces d'action
- Suppose une familiarité avec Gymnasium, uv, pytest et les workflows GitHub Actions
À utiliser lorsqu'on doit ajouter, porter ou connecter un jeu à fmri-gym et qu'on veut suivre toutes les étapes sans en oublier.
Inutile pour un projet qui n'utilise pas fmri-gym ou qui ne cherche pas à intégrer un environnement de jeu.
Analyse de sécurité
SûrThe skill is pure developer documentation for adding a game-engine backend: it describes file layout, hooks, config conventions and reproducibility pitfalls, and its only commands are local test/lint/play invocations (`pytest`, `uv run`, `ruff`). There is no destructive command, no obfuscated payload, no credential or token handling, and no instruction to disable safety checks. The single supply-chain surface is the pinned git dependency on a maintainer fork, which is disclosed in-line and used for a stated determinism reason rather than concealment.
- •Step 4 introduces a pinned third-party dependency installed directly from a GitHub fork (`crafter @ git+https://github.com/chengfanbrain/crafter.git@deterministic`); this is a legitimate determinism fix but pulls code from a non-upstream personal repository, so provenance should be confirmed before wide use.
Exemples
Add a new backend for the game NetHack to fmri-gym: create the adapter, the curriculum config, the pyproject extra and the tests row, then run the backend test suite.Does an existing fmri-gym backend like ale or gym already play this ROM out of the box, or do I need to write a new adapter?My new backend passes playable and recorded checks but fails the replays test — what should I look at in the curriculum keys map?name: add-backend description: Add a new game engine (backend) to fmri-gym, or wrap a game that has no Gymnasium env: the adapter, the gym/ package, the config, the pyproject extra, the tests row, and the traps that make a backend look fine and replay wrong. Use when asked to add, port or wire up a game.
Adding a backend
Read AGENTS.md first: rule 1 (the game logic lives in the gym env, not the adapter) decides where every line below goes.
The checklist
- Check that no existing backend already plays the game, possibly out of the box:
aletakes any Atari ROM,retroany libretro core,gymany registered Gymnasium env,vizdoomany Doom scenario. If one does, all you need is a config. fmri_gym/adapters/<BACKEND>.py: module docstring (what the engine is, why it was chosen, what its observation/action spaces look like, what is not supported), then a subclass ofEnvAdapteroverriding only the hooks you actually need. Everything else is inherited; do not re-state the defaults.adapters/vizdoom.py,baba.pyandminihack.pyare the models; stay under about 150 lines, one file.fmri_gym/adapters/__init__.py: oneif backend == ...:branch with a lazy import.configs/curricula/<BACKEND>/<GAME>.json: a runnable curriculum, andconfigs/curricula/<BACKEND>/common/README.mdwith any install step that is not a plainpip installand what the action indices in itskeysmean. Comments in the JSON ("## ..."keys) are for what is particular to one file, and few. Lay it out like the others: one##comment per line, the message'stextone screen line per line, fixations as one-liners, and the game block on a few lines withkeys(andmenu) inline, not one key per line. A game with several levels gets one curriculum per level, whose game phases__includea sharedconfigs/curricula/<BACKEND>/common/<GAME>.json(the keys, the instructions, the settings) and state only the level and its title (README, "Shared phases").pyproject.toml: one extra under[project.optional-dependencies](and a mention indbp/allif it belongs there), thenuv lock. A game without a Gymnasium env gets one first, as its own small package undergym/<GAME>/(pyproject.toml,README.md,<game>_gym/{__init__,env}.py, agym.registerid), listed in[tool.uv.sources]; the extra installs that package. It wraps the game, it does not contain it.tests/backends.py: aBackendrow (the extra, the module that proves it is installed, one or two short smoke configs, thegym/dirs it runs on, itsexternal/checkout, acireason if a hosted Linux runner cannot play it), and a line in.github/workflows/tests.yml's matrix unless it has one.test_configsfails until the row exists.README.md: only if the backend needs setup beyondpip install(a repo checkout, a binary, an env var).
Then play it, through the suite and by hand:
uv run pytest --backend <BACKEND>
uv run fmri-play --subject sub-test --dummy-trigger --ses 1 --run 1 --rig configs/rigs/example/laptop.json \
--curriculum configs/curricula/<BACKEND>/<GAME>.json
uv run ruff check fmri_gym fmri_play.py agents tests
The suite's four checks (playable, recorded, replays, runs) are the acceptance test; the testing skill says how to read a failure. A backend that passes everything but replays is not done: reproducibility is the product.
Things that are easy to get wrong
- Key names are pygame names, upper-cased, without
K_("LEFT","SPACE","Z"). Add unlisted keys to_PYGAME_KEY_NAMESinkeys.pyrather than mapping keycodes yourself;validate_curriculumrefuses a config that names a key outside that table. - Every game phase writes its whole
keysmap; there is no default. AMultiBinaryenv takes button indices (held keys combine), anything else takes the action itself and a real-time phase also needs the""entry, the action for no key held. One class per action space inadapters/keymap.py. Don't add a per-backend default or a merge step: the map depends on the site's input device, not on the engine. - Copy observations you keep. Several envs reuse their observation buffers, so
capturemust.copy()anything it stores (seeminihack.py). The replay check is what found nethack logging each frame's variables one frame late: a view of a reused buffer, pickled after the loop had moved on. render()is not always free of side effects. An engine that draws from the same RNG its dynamics use spends a draw on every render, so one extra call shifts everything after it and the run silently stops matching its own log. Return the framestepalready produced rather than rendering again; crafter's night noise is the live example, and it is whygym/craftercaches the observation and hands that back.- Reproducibility is the product. A block must be replayable from
episode_seeds+actions. If the env has no savestate of its own, wrap it inreplay_state_gym.ReplayState(gym/replay_state/: the seed and the actions since, restored by replay) and make surereset(seed=...)really determines the episode. Test it rather than assume it:uv run python -m tests.verify_replay --curriculum <config>records a block with the random policy, replays it in a second process under anotherPYTHONHASHSEEDand compares every frame, every sound chunk and every savestate anchor bit for bit. A second process because the usual culprit is hash order, which is fixed for the life of one interpreter and would let a replay inside the recording process pass. Crafter passes every surface check (a seed argument, a seededRandomState, deterministic worldgen) and still diverges, because one creature list is built from a Pythonsetand the despawn pick therefore follows objectid(), which moves withPYTHONHASHSEED. Sorting that list is the whole fix, and it lives in a fork the env package pins (gym/crafter/pyproject.toml:crafter @ git+https://github.com/chengfanbrain/crafter.git@deterministic), not in the adapter: when the bug is in the engine, fix the engine and pin the build, or the rig starts owning game behaviour. - Sound is part of the record. An engine that makes sound returns this step's PCM from
sound()(the contract is inEnvAdapter.sound;retro.pyis a two-line example); the loop plays it and logs it, and the replay check compares it chunk for chunk. ViZDoom's first episode afterinit()sounded different from one afternew_episode(), which is whyvizdoom_gymbegins every episode the same way. - Turn-based games (grid worlds, puzzles) need
"is_turn_based": truein the config. - Slow real-time games (a grid world that must keep ticking, so
is_turn_basedis out) need"has_latched_keys": true: the default real-time path polls held keys, and at a few frames per second a tap that begins and ends between two frames is never seen.
Du fichier au premier essai
Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.
Consulter la source et ses fichiers annexesCe téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.
1. Télécharger le fichier
Télécharger SKILL.mdDepuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/add-a-game-backend-to-fmri-gym-mvg6txds/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.
Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.
mkdir -p '.skill-downloads/add-a-game-backend-to-fmri-gym-mvg6txds' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/add-a-game-backend-to-fmri-gym-mvg6txds/download' --output '.skill-downloads/add-a-game-backend-to-fmri-gym-mvg6txds/SKILL.md.part' && mv '.skill-downloads/add-a-game-backend-to-fmri-gym-mvg6txds/SKILL.md.part' '.skill-downloads/add-a-game-backend-to-fmri-gym-mvg6txds/SKILL.md'2. Vérifier les prérequis
Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.
Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.
Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.
3. Charger la skill
Le fichier ne fournit pas un en-tête name/description exploitable pour cette procédure native. Le téléchargement reste disponible pour lecture ; utilisez le mode manuel ci-dessous.
Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.
4. Faire un premier essai
Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :
Lis .skill-downloads/add-a-game-backend-to-fmri-gym-mvg6txds/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.
Bonnes pratiques React Hook Form
Developpement
Maîtrisez React Hook Form : évitez les anti-patterns, gérez les abonnements, et traitez correctement reset, dirty state et entrées contrôlées.
Migration Emotion vers Mantine
Developpement
Migrer les styled-components Emotion vers des composants Mantine avec style props et modules CSS. Pour convertir .styled.tsx ou supprimer les imports @emotion.
Détecteur de dérive de périmètre
Developpement
Analyse les diffs git par rapport à une intention pour détecter la dérive de périmètre, fichiers non liés et PR trop larges, puis suggère de garder, diviser ou justifier.