Codebase Guide¶
This page gives a folder-by-folder tour of the GodotMaker repository, with enough depth to orient you before you start editing. For a shorter overview, see Development setup. For how all the pieces wire together at runtime, keep reading.
Repository layout¶
GodotMaker/
├── hooks/ 8 hook scripts + hooks/metrics/ subsystem
├── agents/ 5 sub-agent definitions (worker, verifier, reviewer, analyst, gdd-auditor)
├── skills/
│ ├── core/ Role skills + supporting skills + _shared/
│ └── reviewer/ 8 reviewer skills (gotchas.md + checklist.md each)
├── tools/ publish.py, check_env.py, check_project.py, asset_gen.py, migrate.py
├── config/ config.yaml.default, stage_schemas.json, addon_versions.json
├── agent-runtimes/ Runner-specific references, templates, and hook config
├── templates/ Document templates (GDD, PLAN, STRUCTURE, SCENES, ASSETS, GAP, MEMORY, TOC)
├── tests/ ~320 unit tests for hooks and tools
├── docs/ versioning.md, hooks.md, wiki/, update/, contributing/, reference/
├── shell/ publish.sh / publish.ps1, report.sh / report.bat
├── migrations/ Per-version-jump migration scripts
├── VERSION Semantic version source of truth
└── CHANGELOG.md Per-release notes
hooks/¶
Eight Python scripts enforcing pipeline rules. Each script reads a JSON payload from sys.stdin, decides whether to allow or block the action, and writes a JSON response to stdout (or exits 0 silently for a quiet allow).
Scripts and the events they handle:
| Script | Event | Blocks? |
|---|---|---|
session_start.py |
SessionStart | No |
check_file_permissions.py |
PreToolUse (Write|Edit) | Yes |
stage_reminder.py |
PreToolUse (Write|Edit) | Yes |
check_stage_prerequisites.py |
PreToolUse (Agent) | Yes |
check_asset_access.py |
PreToolUse (Read) | Yes |
log_subagent.py |
SubagentStart | No |
on_subagent_stop.py |
SubagentStop | Delegates |
check_worker_report.py |
Called by on_subagent_stop.py | Yes |
check_completion.py |
Stop | Yes |
Hook registration (which script fires on which event) lives under
agent-runtimes/<agent>/config/ and is deployed into the selected runner's
project-local hook config (.claude/settings.json or .codex/hooks.json).
hooks/metrics/¶
A small subsystem for recording what happened during a session. Hooks call record_event() to append a JSON line to .godotmaker/metrics_current.jsonl (current session) and .godotmaker/metrics_total.jsonl (lifetime). The state.py module manages mutable per-session counters (block counts, etc.) in .godotmaker/state.json. session_start.py resets both on every new session.
For details on writing hooks and using the metrics API, see Writing a hook.
Permission contract layers¶
Role permissions are expressed in three places. They overlap on purpose, but each layer has a distinct job — when you change one, check whether the others need to follow:
| Layer | What it controls | Source of truth |
|---|---|---|
config/stage_schemas.json |
Did the role finish? Which output files must exist before the next role can start. | Read by stage_reminder.py (validate completion) and check_stage_prerequisites.py (gate worker dispatch). |
hooks/check_file_permissions.py |
What can the role write right now? Per-role write-scope whitelist enforced on every Write/Edit tool call. | Authoritative for runtime permissions. Schemas do not define write scope. |
skills/core/gm-*/SKILL.md "Permission" section |
Human-readable mirror of the hook rule for the role's owner. | Should match the hook; if they drift, the hook wins at runtime — but a contributor reading the skill will be misled. |
A common mistake is reading stage_schemas.json as if it were the full write contract. It is not — it only lists output files for the completion gate. Adding a file to a role's schema does not grant write permission; you also have to extend the hook's allow-list.
agents/¶
Sub-agent definitions, one Markdown file per agent. Each file has YAML front-matter (name, description, model) and a system-prompt body. publish.py deploys them to <target>/.claude/agents/, where Claude Code picks them up by subagent_type.
| Agent | Role | Dispatched by |
|---|---|---|
worker.md |
Implements one task end-to-end (code + unit tests) | /gm-build, /gm-fixgap |
verifier.md |
Mechanically checks a worker's output (build, tests, file presence) | /gm-build, /gm-fixgap |
reviewer.md |
Reads code against skills/reviewer/<domain> checklists and reports issues |
/gm-build, /gm-fixgap |
analyst.md |
Analyses user-provided assets and produces a manifest | /gm-asset |
gdd-auditor.md |
Independently audits a draft GDD against a 9-category checklist and returns 5–8 follow-up questions per pass | game-planner (Rounds 6 + 7) |
The dispatch protocols (call format and brief templates) live in skills/core/_shared/{worker,verifier,reviewer,analyst}-dispatch.md. gdd-auditor is invoked inline from skills/core/game-planner/SKILL.md.
The two-pass GDD audit¶
gdd-auditor is the only sub-agent whose dispatch protocol does not live in _shared/. It is invoked from one place (game-planner Rounds 6 + 7) and the dispatch only makes sense as part of that interview script. Promoting it to _shared/ would add indirection without buying reuse.
Two passes, both fresh-context, both invoked with the same subagent_type:
| Pass | Round | Input | Output | Why this pass exists |
|---|---|---|---|---|
| 1 | Round 6 | GDD v1 + empty Previously Asked |
5–8 follow-up questions | Catches gaps the planner missed during the interview |
| 2 | Round 7 | GDD v2 + the exact Round-6 questions in Previously Asked |
5–8 new questions | Forces the auditor to look at second-tier gaps instead of repeating itself |
The Previously Asked field in the Round 7 brief is mandatory, not advisory. Without it the auditor has no memory of pass 1 (fresh context) and re-asks the same questions, wasting a round. game-planner SKILL.md marks the field with **You MUST populate** and gdd-auditor.md lists "repeating questions in Previously Asked" as a hard prohibition — both layers enforce the same contract.
auditor_model defaults to sonnet (in config/config.yaml.default); the audit task is checklist-driven and does not need opus-tier reasoning.
skills/core/¶
Role skills and supporting skills, one directory per skill. Each directory contains at minimum a SKILL.md with YAML front-matter and the prompt body.
Role skills (9): gm-scaffold, gm-gdd, gm-asset, gm-build, gm-verify, gm-evaluate, gm-fixgap, gm-accept, gm-finalize. These map 1:1 to the /gm-* slash commands. Each role skill writes its role name to .godotmaker/current_role as its first action, which is what check_file_permissions.py reads to enforce write rules.
Supporting skills (11): game-planner, project-scaffold, godot-api, gecs, input-mapper, headless-build, gdunit-driver, godot-e2e, visual-qa, screenshot, mcp-driver. These are reference documents loaded by role skills — users do not invoke them directly.
skills/core/_shared/¶
Any reference document consumed by more than one skill lives here as the single source of truth. Examples: worker-dispatch.md, verifier-dispatch.md, reviewer-dispatch.md, analyst-dispatch.md.
At publish time, publish_shared_refs() reads _shared/manifest.json and writes each source file into every listed consumer skill's references/ folder. Deployed copies carry an <!-- AUTO-GENERATED --> header and are overwritten on every publish.
Edit rules:
- Edit only the source under _shared/<file>.md. Never edit the deployed copies.
- Inside a consumer SKILL.md, reference the doc as references/<file>.md (the deployed path). Do not write _shared/<file> — that path does not exist in a published project.
- After adding or changing a shared doc, run python -m pytest tests/tools/test_publish_shared.py -q to confirm the manifest and all consumer references are consistent.
The manifest schema, add/remove flows, and debugging tips are in docs/contributing/shared-refs.md.
skills/reviewer/¶
Eight reviewer skills, one per domain: physics, animation, ui, tilemap, navigation, shader, audio, particles.
Each reviewer skill directory contains exactly three files:
- SKILL.md — the reviewer prompt
- gotchas.md — a catalogue of domain-specific pitfalls that LLMs reliably get wrong
- checklist.md — systematic checks that map back to gotcha IDs
The reviewer sub-agent (dispatched by gm-build and gm-fixgap) reads these dynamically based on which Godot classes and APIs appear in the worker's output. For details on the reviewer structure, see Writing a skill.
tools/¶
Python CLI scripts that contributors and users run directly.
| Tool | Purpose |
|---|---|
publish.py |
Deploy GodotMaker into a target Godot project |
check_env.py |
Verify Godot, Python, API keys are set up correctly |
check_project.py |
Validate a generated project for missing files and broken paths |
asset_gen.py |
Generate API-backed art via Gemini / OpenAI / xAI (called by /gm-asset, can run standalone) |
migrate.py |
Apply pending migrations to a target on any non-MAJOR upgrade; also scaffolds new ones via --new <slug> |
How publish.py wires everything together¶
When you run python tools/publish.py <target>:
- Read
VERSIONfrom the repo root and compare against<target>/.godotmaker/version. Prompt or block on MINOR / MAJOR upgrades. - Copy skills (flat): all directories under
skills/core/andskills/reviewer/to the selected agent skill directory (<target>/.claude/skills/for Claude Code or<target>/.agents/skills/for Codex). Directories whose name starts with_(i.e.,_shared/) are skipped bypublish_skills(); shared docs are deployed into consumerreferences/folders instead bypublish_shared_refs(). - Copy hooks to
<target>/.godotmaker/hooks/. - Copy tools to
<target>/tools/. - Copy templates to the selected agent template directory.
- Copy
config/stage_schemas.jsonto<target>/.godotmaker/stage_schemas.json. - On fresh install (or
--force): write agent-specific instructions (CLAUDE.mdorAGENTS.md), prompt forgodotmaker.yaml, and write the selected runner's hook config. - Stamp
<target>/.godotmaker/versionwith the current version.
config/¶
| File | What it controls |
|---|---|
stage_schemas.json |
Per-role required outputs and programmatic checks (keys are role names) |
addon_versions.json |
Pinned Godot addon versions per engine version |
stage_schemas.json is the schema that stage_reminder.py and check_stage_prerequisites.py both read. Its keys are role names (scaffold, gdd, build, etc.); each value has an optional files array (paths that must exist) and an optional checks array (programmatic validator names). See Writing a skill for the full schema description.
templates/¶
Markdown document templates that publish.py deploys into new game projects under the selected agent template directory. The role skills fill these in during their work. Templates include: GDD.md, PLAN.md, STRUCTURE.md, SCENES.md, ASSETS.md, GAP.md, MEMORY.md, TOC.md, game-claude.md.
tests/¶
The test suite, organized by what it covers.
tests/
├── hooks/
│ ├── helpers.py Shared utilities: run_hook, is_blocked, write_completed_roles, ...
│ ├── test_check_completion.py
│ ├── test_check_file_permissions.py
│ ├── test_check_stage_prerequisites.py
│ ├── test_check_worker_report.py
│ ├── test_metrics.py
│ ├── test_session_start.py
│ └── test_stage_reminder.py
├── tools/
│ ├── conftest.py
│ ├── test_addon_versions.py
│ ├── test_check_classname.py
│ ├── test_check_env.py
│ ├── test_check_project.py
│ ├── test_migrate.py
│ ├── test_publish.py
│ └── test_publish_shared.py
└── test_pipeline_e2e.py End-to-end pipeline smoke test
pyproject.toml adds hooks/ to pythonpath so that from metrics import ... resolves in hook tests without installing anything. For writing new tests, see Testing.
docs/¶
Human-readable documentation that lives in the repo alongside the code.
| Path | What it contains |
|---|---|
docs/hooks.md |
Accurate per-hook reference (post-rewrite) |
docs/versioning.md |
Version scheme and upgrade behaviour |
docs/wiki/ |
The user-facing and contributor wiki |
docs/contributing/ |
Shared-refs schema, release checklist |
docs/update/ |
next.md (pending changes) and archived vX.Y.Z.md files |
docs/reference/ |
API and config reference stubs |
shell/¶
Thin wrappers for the two operations that contributors run from a terminal:
publish.sh/publish.ps1— delegates topython tools/publish.pyreport.sh/report.bat— runspython -m hooks.metrics.reporterto generate an HTML report from a JSONL metrics file
migrations/¶
Migration scripts run by tools/migrate.py on any non-MAJOR upgrade. Scripts are stored directly under migrations/, named by UTC timestamp (<YYYYMMDDhhmmss>_<slug>.py), and applied in chronological order. Each target tracks which IDs it has applied in .godotmaker/applied_migrations.json; the system is decoupled from the product's MAJOR.MINOR.PATCH version. MAJOR upgrades skip migrations entirely and use --force clean re-init, after which baseline_applied() re-marks every current migration as applied. See Release process for the full upgrade flow.