Create or extend data-driven config tables (WeaponData, EnemyData, LevelData, etc.) in a Godot 4 project so that designers can tweak numbers in .tres files via natural language. Use this skill whenever the user says something like "give weapons a config table", "extract hardcoded numbers into data", "add a new enemy type", "designer wants to tune damage/hp/speed", "add WeaponData/PlayerData/EnemyData", or asks to make Godot values editable without touching code.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add infometa/workbuddyskills --skill godot-data-driven-config --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Godot Data Driven Config?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/infometa-godot-data-driven-config)More formats (shields.io, HTML) on the badges page.
---
name: godot-data-driven-config
description: Create or extend data-driven config tables (WeaponData, EnemyData, LevelData, etc.) in a Godot 4 project so that designers can tweak numbers in .tres files via natural language. Use this skill whenever the user says something like "give weapons a config table", "extract hardcoded numbers into data", "add a new enemy type", "designer wants to tune damage/hp/speed", "add WeaponData/PlayerData/EnemyData", or asks to make Godot values editable without touching code.
---
# Godot Data-Driven Config Skill
## What this skill does
Turns hardcoded `const` / magic numbers inside `.gd` files into a clean **Resource-based config layer** that designers can edit via `.tres` or the Godot Inspector. Also generates a CLI validator (`bash tools/validate_data.sh`) so a human or CI can check "did I break the config table?" in one command.
## When to invoke
Trigger on intents like:
- "Create a WeaponData / EnemyData / LevelData / SkillData for this project"
- "Move these hardcoded numbers into a config table"
- "I want designers to tune damage/hp/speed without touching code"
- "Add a new weapon/enemy type through data"
- "Build an AI-native Godot config workflow"
## Canonical file layout (ALWAYS use this)
```
res://data/
├── specs/ # JSON specs, source of truth (git-tracked)
│ ├── weapon.spec.json
│ └── ...
├── resources/
│ ├── <name>_data.gd # class_name <Name>Data extends Resource
│ └── data_manager.gd # Autoload (AUTOGENERATED — do not hand-edit AUTOGEN regions)
├── <name>s/ # plural dir, one .tres per entry
│ └── default_<name>.tres
tools/
├── validate_data.gd # Godot-side CLI validator (autogen)
└── validate_data.sh # bash wrapper (exit code fix-up)
project.godot # [autoload] DataManager="*res://data/resources/data_manager.gd"
```
Rationale: plural-dir + `id` field makes `DirAccess` scanning trivial. Specs under `data/specs/*.spec.json` are the **source of truth**; regenerating `data_manager.gd` / `validate_data.gd` is always a pure function of that directory, so nothing can drift.
## Required workflow
### Step 1 — Discover & propose
1. Read target `.gd` files; collect hardcoded constants and literals.
2. Ask the user which category (weapon/player/enemy/level/skill/item/…). Each category becomes one `<Name>Data` class.
3. Produce a **field mapping table** (source constant → new field → range). Present it, wait for OK (max 1 round of confirmation).
### Step 2 — Write spec JSON under `data/specs/`
Every category is described by exactly one JSON file matching `schemas/field_spec.schema.json`. Commit these to git — they are the source of truth and diff well.
Minimal valid spec:
```json
{
"name": "weapon",
"default_id": "default_pistol",
"fields": [
{ "key": "id", "type": "StringName", "default": "&\"\"", "group": "Identity" },
{ "key": "damage", "type": "int", "default": 10, "range": [0, 9999, 1] }
],
"validators": ["damage >= 0"]
}
```
### Step 3 — Run `scaffold.py` once per new/updated category
```bash
python3 ~/.codebuddy/skills/godot-data-driven-config/scripts/scaffold.py \
--project-root <abs Godot project path> \
--spec <abs path to spec>.spec.json
```
The script:
- copies the spec into `res://data/specs/` (creates source-of-truth file)
- writes `res://data/resources/<name>_data.gd` (first time only; re-run with `--force-class` to overwrite)
- writes `res://data/<name>s/default_<name>.tres` (first time only; `--force-tres` to overwrite)
- **rebuilds** `res://data/resources/data_manager.gd` from **all** `data/specs/*.spec.json` — you never lose a previously-added category
- **rebuilds** `res://tools/validate_data.gd` (duck-typed against `Resource`, so cold-start without `.godot/` cache still works)
- writes `res://tools/validate_data.sh` wrapper
- patches `[autoload]` in `project.godot` idempotently
### Step 4 — Migrate consumer `.gd` files
For each file with hardcoded values:
1. Add at top of class:
```gdscript
@export var <name>_data: <Name>Data
```
2. In `_ready()`:
```gdscript
if <name>_data == null:
<name>_data = DataManager.get_<name>()
```
3. Replace literal(s): `JUMP_SPEED` → `<name>_data.jump_speed` etc.
4. **Keep purely-technical consts** unchanged (collision masks, shader paths, blend-tree parameter strings).
5. **DO NOT** edit `.tscn` unless necessary — the `DataManager` fallback covers unbound cases.
### Step 5 — Validate
```bash
bash tools/validate_data.sh
# exit 0 = OK
# exit 1 = validation failed (stdout/stderr has reasons)
# exit 2 = environment issue
```
On **cold clone** (no `.godot/` dir), the wrapper auto-refreshes the class cache once via `godot --headless --editor --quit` — designers/CI need no special knowledge.
### Step 6 — Document
Append to `PROJECT_OVERVIEW.md` or `README.md`:
- The mapping table from Step 1
- Designer workflow: "edit `.tres` → run `bash tools/validate_data.sh` → F5".
- Validator command.
## Hard rules
- **One Resource class per category**, never a god-class.
- Numeric fields MUST have `@export_range`.
- Every `<Name>Data` MUST have an `id: StringName` field; filename stem is used as fallback id.
- `DataManager` is ALWAYS an Autoload named `DataManager`.
- `data_manager.gd` returns `Resource` (not `<Name>Data`) from getters; callers cast with `as WeaponData` if they want static typing. This keeps cold-start safe.
- DO NOT mutate a Resource at runtime (shared reference). To modify: `var copy = data.duplicate(); copy.x = ...`.
- DO NOT try to `MultiplayerSynchronizer`-sync a Resource. Instead, guarantee the same `.tres` exists on all peers (git-managed).
- Validator never uses `exit_code` because Godot bug #88055 drops it under `--script`. Use the `VALIDATION_RESULT=OK|FAIL:n` stdout marker (the generated `validate_data.sh` does this).
- DO NOT hand-edit the `# region *_AUTOGEN` blocks; `scaffold.py` rewrites them on every run.
## Cold-start / CI notes
- Godot's `global_script_class_cache.cfg` is created by the editor. For headless/CI, the first run needs `godot --headless --editor --quit` to populate it (the generated wrapper does this automatically when `.godot/` is missing).
- Validator is intentionally written to NOT depend on `class_name` resolution (uses `Resource` base + `res.get("field")` duck-typing), so even if the cache is stale it still works.
## Anti-patterns to avoid
- ❌ Using CSV/JSON/YAML loaders at runtime — Godot's native `.tres` is already text, git-friendly, type-safe, and Inspector-editable.
- ❌ Putting everything in one god-resource — harder to diff, no grouping, single-file merge conflicts.
- ❌ Hardcoding defaults in the Resource script AND in the `.tres` at different values — keep `.tres` authoritative; script defaults only act as fallback when a consumer never binds a resource.
- ❌ Reading `.tres` with `FileAccess` / `JSON.parse` — always use `load()` / `preload()`.
## Smoke-test before declaring done
Run `scripts/selftest.sh` (in this skill) which:
1. Creates a fresh temp Godot project.
2. Runs `scaffold.py` with every example spec.
3. Refreshes class cache + runs the validator.
4. Injects a bad value and confirms the validator now exits 1.
5. Cleans up.
```bash
bash ~/.codebuddy/skills/godot-data-driven-config/scripts/selftest.sh
```
## Deliverables checklist
When you finish, confirm ALL of:
- [ ] `res://data/specs/<name>.spec.json` exists and is committed
- [ ] `res://data/resources/<name>_data.gd` with `class_name` + typed `@export` fields
- [ ] `res://data/<name>s/default_<name>.tres` with sensible defaults
- [ ] `res://data/resources/data_manager.gd` exists and references the new category
- [ ] `project.godot` has `DataManager` in `[autoload]`
- [ ] Consumer `.gd` reference `<name>_data.xxx` (no more magic numbers)
- [ ] `bash tools/validate_data.sh` → exit 0
- [ ] `PROJECT_OVERVIEW.md` / `README.md` updated
## Files in this skill
```
SKILL.md this file
QUICKREF.md one-page cheat sheet for the AI
schemas/field_spec.schema.json JSON schema for designer-facing spec
templates/
data_class.gd.tmpl Resource class template
data_resource.tres.tmpl .tres template
data_manager.gd.tmpl Autoload template (uses Resource base)
validate_data.gd.tmpl CLI validator template (duck-typed)
validate_data.sh.tmpl bash wrapper (exit-code fix-up)
scripts/
scaffold.py end-to-end generator
selftest.sh self-test / regression check
examples/
weapon_spec.json
enemy_spec.json
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!