Configure engine and version. Pins it in CLAUDE.md; WebSearch fills reference docs when the version is beyond LLM training data.
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-setup-engine-658feea6f951 ,按照其中的说明把「setup-engine」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
When this skill is invoked:
!bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys workflow
Tier awareness. The workflow tier resolved above governs which design
artifact this skill expects and the finish path it recommends in §12:
minimal — the design artifact is the one-page design/game-brief.md
(no GDDs, systems decomposition, or per-system design at this tier).
/setup-engine runs first in the minimal path, so a missing brief here is
normal, not a gap. The finish path is the 4-step floor.standard / full — the design artifact is design/gdd/game-concept.md
and the finish path is the full pipeline.If the block did not render (shell preprocessing disabled), assume standard.
Four modes:
/setup-engine godot 4.6 — engine and version provided/setup-engine unity — engine provided, version will be looked up/setup-engine — fully guided mode (engine recommendation + version)/setup-engine refresh — update reference docs (see Section 10)/setup-engine upgrade [old-version] [new-version] — migrate to a new engine version (see Section 11)If no engine is specified, run an interactive engine selection process:
Read the design artifact for the resolved tier (see Tier awareness above):
standard / full: read design/gdd/game-concept.md if it exists —
extract genre, scope, platform targets, art style, team size, and any engine
recommendation from /brainstorm.
minimal: read design/game-brief.md if it exists — extract genre,
scope, platform, and art direction from its fields. Its absence is expected
at minimal (the brief is authored after engine setup in the minimal path), so
do not treat a missing brief as a gap — proceed straight to guided selection.
If no concept or brief exists, inform the user:
"No game concept found. Consider running
/brainstormfirst to discover what you want to build — it will also recommend an engine. Or tell me about your game and I can help you pick."
(At minimal this is optional, not a prerequisite — you can pick an engine now
and write the brief next.)
Question 1 — Prior experience (ask this first, always, via AskUserQuestion):
Godot / Unity / Unreal Engine 5 / Multiple — I'll explain / None of themQuestions 2-6 — Decision matrix inputs (only if no prior engine experience):
Question 2 — Target platform (ask this second, always, via AskUserQuestion — platform eliminates or heavily weights engines before any other factor):
PC (Steam / Epic) / Mobile (iOS / Android) / Console / Web / Browser / Multiple platformsDo NOT use a simple scoring matrix that eliminates engines. Instead, reason through the user's profile against the honest tradeoffs below, then present 1-2 recommendations with full context. Always end with the user choosing — never force a verdict.
Engine honest tradeoffs:
Godot 4
Unity
Unreal Engine 5
Genre-specific guidance (factor this into the recommendation):
Recommendation format:
AskUserQuestion to confirm: "Does this recommendation feel right, or would you like to explore a different engine?"
[Primary engine] (Recommended) / [Alternative engine] / [Third engine] / Explore further / Type somethingIf the user picks "Explore further":
Use AskUserQuestion with concept-specific deep-dive topics. Always generate these options from the user's actual concept — do not use generic options. Always include at minimum:
The user can select multiple topics. Answer each selected topic in depth before returning to the engine confirmation question.
Once the engine is chosen:
"[engine] latest stable version [current year]"A version found by web search is what exists, not what the developer has. Pinning one they cannot run means every later instruction — build, test, smoke, the engine reference docs — targets an engine that is not on the machine.
Probe for the binary (Bash), and treat failure as unknown, never as absent:
| Engine | Probe |
|---|---|
| Godot | godot --version, else look for godot/Godot_v* on PATH or in the platform's usual install location |
| Unity | Unity -version, else the Hub's editor directory |
| Unreal | UnrealEditor-Cmd -version, else the launcher's install directory |
Then:
installed version NOT DETERMINED and
continue with the chosen version. Do not report this as "no engine
installed": a probe that could not run has not established absence.Whatever the outcome, write it into Section 7's VERSION.md as an
Installed at pin time row, so a later reader can tell a deliberate
version-ahead pin from an accident.
If Godot was chosen, ask the user which language to use before showing the proposed Technology Stack:
"Godot supports two primary languages:
A) GDScript — Python-like, Godot-native, fastest iteration. Best for beginners, solo devs, and teams coming from Python or Lua. B) C# — .NET 8+, familiar to Unity developers, stronger IDE tooling (Rider / Visual Studio), slight performance advantage on heavy logic. C) Both — GDScript for gameplay/UI scripting, C# for performance-critical systems. Advanced setup — requires .NET SDK alongside Godot.
Which will this project primarily use?"
Record the choice. It determines the CLAUDE.md template, naming conventions, specialist routing, and which agent is spawned for code files throughout the project.
Read CLAUDE.md and show the user the proposed Technology Stack changes.
Ask: "May I write these engine settings to CLAUDE.md?"
Wait for confirmation before making any edits.
Update the Technology Stack section, replacing the [CHOOSE] placeholders with the actual values:
For Godot — use the template matching the language chosen above. See .claude/skills/setup-engine/references/godot-language-config.md (A1) for all three variants (GDScript, C#, Both).
For Unity:
- **Engine**: Unity [version]
- **Language**: C#
- **Build System**: Unity Build Pipeline
- **Asset Pipeline**: Unity Asset Import Pipeline + Addressables
For Unreal:
- **Engine**: Unreal Engine [version]
- **Language**: C++ (primary), Blueprint (gameplay prototyping)
- **Build System**: Unreal Build Tool (UBT)
- **Asset Pipeline**: Unreal Content Pipeline
In the same CLAUDE.md write, set the Engine Version Reference import to the
chosen engine. Find the line marked ENGINE-REFERENCE-IMPORT (an
@docs/engine-reference/<engine>/VERSION.md line under its comment) and Edit it
to point at the configured engine:
@docs/engine-reference/godot/VERSION.md@docs/engine-reference/unity/VERSION.md@docs/engine-reference/unreal/VERSION.mdThis is why a fresh Unity or Unreal project no longer loads the Godot reference in
every session. It is idempotent — re-running /setup-engine for a different
engine rewrites the same line. (The target docs/engine-reference/<engine>/
directory is created in Section 8 below if it does not yet exist.)
After updating CLAUDE.md, create or update .claude/docs/technical-preferences.md with
engine-appropriate defaults. Read the existing template first, then fill in:
For Godot — see .claude/skills/setup-engine/references/godot-language-config.md (A2) for GDScript, C#, and Both variants.
For Unity (C#):
PlayerController)MoveSpeed)_moveSpeed)TakeDamage())PlayerController.cs)For Unreal (C++):
A for Actor, U for UObject, F for struct)MoveSpeed)TakeDamage())b prefix (e.g., bIsAlive)PlayerController.h)Populate ## Input & Platform using the answers gathered in Section 2 (or extracted
from the game concept). Derive the values using this mapping:
| Platform target | Gamepad Support | Touch Support |
|---|---|---|
| PC only | Partial (recommended) | None |
| Console | Full | None |
| Mobile | None | Full |
| PC + Console | Full | None |
| PC + Mobile | Partial | Full |
| Web | Partial | Partial |
For Primary Input, use the dominant input for the game genre:
Genre may not exist yet — check before deriving from it. At
minimalthe design artifact isdesign/game-brief.md, and it is authored after this skill runs (Section 2 says so explicitly). There is no genre to map. The same is true at any tier when/setup-engineis run before the concept exists.When genre is unavailable, ask — do not infer one from the platform, and do not leave the field silently blank:
- Prompt: "Primary input for a [2D/3D] [platform] game? Genre isn't established yet — the brief comes next — so this can't be derived."
- Options: the plausible inputs for that platform, plus
Leave as [TO BE CONFIGURED]— a legitimate answer here, revisited via/settingsonce the brief exists.Gamepad Support and Touch Support still come from the platform table above; only Primary Input depends on genre.
Present the derived values and ask the user to confirm or adjust before writing.
Example filled section:
## Input & Platform
- **Target Platforms**: PC, Console
- **Input Methods**: Keyboard/Mouse, Gamepad
- **Primary Input**: Gamepad
- **Gamepad Support**: Full
- **Touch Support**: None
- **Platform Notes**: All UI must support d-pad navigation. No hover-only interactions.
AskUserQuestion:
[A] Set defaults now (60fps, 16.6ms frame budget, engine-appropriate draw call limit) / [B] Leave as [TO BE CONFIGURED] — I'll set these when I know my target hardwareMust match
commands.testin Section 5.5.1, which writesgodot --headless --script tests/gdunit4_runner.gd, and.claude/docs/coding-standards.md, which names the same runner. Naming GUT here would have the skill recommend one framework and configure another in the same run.
Guardrail: Never add speculative dependencies to Allowed Libraries. For example, do NOT add GodotSteam unless Steam integration is actively beginning in this session. Post-launch integrations should be added to Allowed Libraries when that work begins, not during engine setup.
Also populate the ## Engine Specialists section in technical-preferences.md with the correct routing for the chosen engine:
For Godot — see .claude/skills/setup-engine/references/godot-language-config.md (A3) for the routing table matching the language chosen.
For Unity:
## Engine Specialists
- **Primary**: unity-specialist
- **Language/Code Specialist**: unity-specialist (C# review — primary covers it)
- **Shader Specialist**: unity-shader-specialist (Shader Graph, HLSL, URP/HDRP materials)
- **UI Specialist**: unity-ui-specialist (UI Toolkit UXML/USS, UGUI Canvas, runtime UI)
- **Additional Specialists**: unity-dots-specialist (ECS, Jobs system, Burst compiler), unity-addressables-specialist (asset loading, memory management, content catalogs)
- **Routing Notes**: Invoke primary for architecture and general C# code review. Invoke DOTS specialist for any ECS/Jobs/Burst code. Invoke shader specialist for rendering and visual effects. Invoke UI specialist for all interface implementation. Invoke Addressables specialist for asset management systems.
### File Extension Routing
| File Extension / Type | Specialist to Spawn |
|-----------------------|---------------------|
| Game code (.cs files) | unity-specialist |
| Shader / material files (.shader, .shadergraph, .mat) | unity-shader-specialist |
| UI / screen files (.uxml, .uss, Canvas prefabs) | unity-ui-specialist |
| Scene / prefab / level files (.unity, .prefab) | unity-specialist |
| Native extension / plugin files (.dll, native plugins) | unity-specialist |
| General architecture review | unity-specialist |
For Unreal:
## Engine Specialists
- **Primary**: unreal-specialist
- **Language/Code Specialist**: ue-blueprint-specialist (Blueprint graphs) or unreal-specialist (C++)
- **Shader Specialist**: unreal-specialist (no dedicated shader specialist — primary covers materials)
- **UI Specialist**: ue-umg-specialist (UMG widgets, CommonUI, input routing, widget styling)
- **Additional Specialists**: ue-gas-specialist (Gameplay Ability System, attributes, gameplay effects), ue-replication-specialist (property replication, RPCs, client prediction, netcode)
- **Routing Notes**: Invoke primary for C++ architecture and broad engine decisions. Invoke Blueprint specialist for Blueprint graph architecture and BP/C++ boundary design. Invoke GAS specialist for all ability and attribute code. Invoke replication specialist for any multiplayer or networked systems. Invoke UMG specialist for all UI implementation.
### File Extension Routing
| File Extension / Type | Specialist to Spawn |
|-----------------------|---------------------|
| Game code (.cpp, .h files) | unreal-specialist |
| Shader / material files (.usf, .ush, Material assets) | unreal-specialist |
| UI / screen files (.umg, UMG Widget Blueprints) | ue-umg-specialist |
| Scene / prefab / level files (.umap, .uasset) | unreal-specialist |
| Native extension / plugin files (Plugin .uplugin, modules) | unreal-specialist |
| Blueprint graphs (.uasset BP classes) | ue-blueprint-specialist |
| General architecture review | unreal-specialist |
Present the filled-in preferences to the user. For Godot, include the chosen language and note where the full naming conventions and routing tables live:
"Here are the default technical preferences for [engine] ([language if Godot]). The naming conventions and specialist routing are in this skill's references directory — I'll apply the [GDScript/C#/Both] variant. Want to customize any of these, or shall I save the defaults?"
For all other engines, present the defaults directly without referencing the appendix.
Wait for approval before writing the file.
project.yaml (Primary Config Store)v1.1:
project.yamlat the repo root is the primary store for project configuration. The.claude/docs/technical-preferences.mdfile written in Section 5 is kept as a legacy mirror for backward compatibility. This step is a dual-write — the same engine facts go into both files, andproject.yamlwins when a skill reads a key present in both.
After technical-preferences.md is written and approved, dual-write the
structured config into project.yaml. Four blocks are written: engine,
specialists, naming, and commands.
Derive every value from the engine and language already chosen in Sections 3–4. Do NOT re-ask for the engine, version or language — reuse those decisions.
That is not a blanket "never ask".
renderingandphysicsbelow depend on two further inputs — target platform and 2D-vs-3D — which Section 2 collects on only one of the four entry paths. When they were never collected, ask; the unavailable-branch under the project-shape table says how.
engine block:
engine:
name: "<Godot|Unity|Unreal>"
version: "<version from Section 3>"
language: "<GDScript|C#|C++|Blueprint>"
rendering: "<engine default — see table>"
physics: "<engine default — see table>"
On Godot these two values depend on the answers Section 2 already collected —
the target platform and 2D-vs-3D — so do not pick them from the engine name
alone. On Unity and Unreal the table has a single any row and the engine name
is sufficient; take those rows directly.
| Engine | Project shape | rendering default | physics default |
|---|---|---|---|
| Godot 4.x | 2D · web target | Compatibility | Godot Physics 2D |
| Godot 4.x | 2D · non-web | Forward+ | Godot Physics 2D |
| Godot 4.x | 3D · web target | Compatibility | Jolt |
| Godot 4.x | 3D · non-web | Forward+ | Jolt |
| Unity | any | URP | PhysX |
| Unreal | any | Lumen + Nanite (deferred) | Chaos |
Why this table has a shape column and the others do not. Both Godot defaults were wrong for a 2D browser game, and both were wrong from data this skill had already collected and then discarded.
- Jolt is Godot's default 3D engine.
docs/engine-reference/godot/modules/physics.md: "Jolt Physics is the DEFAULT 3D engine" and "2D physics UNCHANGED (still Godot Physics 2D)". WritingJolton a 2D project sends the implementer to tune a backend their game does not use.- Forward+ is desktop-focused.
docs/engine-reference/godot/modules/rendering.md: Forward+ is "Full featured, desktop-focused"; Compatibility is "OpenGL 3.3 / WebGL 2, broadest hardware support" — the browser path.If Section 2's platform answer was
Multiple platformsincluding web, use the web row: the renderer must work everywhere the game ships.
Godot only — Unity and Unreal have one row each, keyed
any. Shape cannot changerenderingorphysicsfor those two, so do not run the resolution below for them: asking an operator a question whose answer you will discard is exactly what §5.5.1 opens by forbidding. On Unity writeURP/PhysXand on Unreal writeLumen + Nanite (deferred)/Chaosstraight from the table.Section 2 did not necessarily run — check before reading its answers. Target platform and 2D-vs-3D are collected under Questions 2–6, only if no prior engine experience. Three of the four entry paths never reach them:
/setup-engine <engine> <version>and/setup-engine <engine>skip Section 2 outright, and guided mode skips the matrix as soon as the user names an engine they have worked in before. Only guided mode answeredNoneorMultiplecollects both.Resolve each input in this order and stop at the first that answers:
- Section 2's answers, if that path ran.
- The design artifact —
design/gdd/game-concept.mdatstandard/full,design/game-brief.mdatminimal. Section 2 already extracts platform targets from these; extract 2D-vs-3D the same way when it is stated.- Ask. Do not infer the shape from the engine name, and do not write a row you could not justify:
- Prompt: "
renderingandphysicsdepend on the project's shape, which hasn't been established yet. Is this 2D or 3D, and does it ship to web?"- Options:
2D · non-web/2D · web/3D · non-web/3D · web, plusLeave as [TO BE CONFIGURED]— a legitimate answer here, revisited via/settingsonce the concept exists.
[TO BE CONFIGURED]is a valid value for both keys. A wrongJolton a 2D project is worse than an unset one, because nothing downstream questions it.
rendering and physics are engine-typical defaults — tell the user they can
be changed later via /settings if the project uses a different setup.language: "GDScript" (the primary gameplay
language); the C# usage is recorded in technical-preferences.md.language: "C++" — or "Blueprint" only if the project is
Blueprint-primary. Blueprint as a secondary tool does not change this value.specialists block — copy directly from the routing table chosen in
Section 5 (A3 in .claude/skills/setup-engine/references/godot-language-config.md for Godot):
| Engine / language | code | shader | ui | additional |
|---|---|---|---|---|
| Godot — GDScript | godot-gdscript-specialist | godot-shader-specialist | godot-specialist | [godot-gdextension-specialist] |
| Godot — C# | godot-csharp-specialist | godot-shader-specialist | godot-specialist | [godot-gdextension-specialist] |
| Godot — Both | godot-gdscript-specialist | godot-shader-specialist | godot-specialist | [godot-csharp-specialist, godot-gdextension-specialist] |
| Unity | unity-specialist | unity-shader-specialist | unity-ui-specialist | [unity-dots-specialist, unity-addressables-specialist] |
| Unreal | unreal-specialist | unreal-specialist | ue-umg-specialist | [ue-gas-specialist, ue-blueprint-specialist, ue-replication-specialist] |
specialists:
code: "<code specialist>"
shader: "<shader specialist>"
ui: "<ui specialist>"
additional: ["<...>"]
naming block — enum values (NOT the prose form used in
technical-preferences.md). Use the column matching the engine and, for Godot,
the language:
| Field | Godot GDScript | Godot C# | Unity | Unreal |
|---|---|---|---|---|
classes | PascalCase | PascalCase | PascalCase | PascalCase |
variables | snake_case | camelCase | camelCase | PascalCase |
constants | SCREAMING_SNAKE | PascalCase | SCREAMING_SNAKE | SCREAMING_SNAKE |
signals | past_tense | on_event_name | PascalCase On<Event> | PascalCase On<Event> |
files | snake_case | PascalCase | PascalCase | PascalCase |
scenes | snake_case | PascalCase | PascalCase | PascalCase |
The Unreal column is sourced, not inherited from the table's generic shape.
variables: camelCaseandsignals: on_event_nameare the two rows that shape would produce, and both are wrong for Unreal. Checked against this repo's pinned reference:docs/engine-reference/unreal/contains zero camelCase variable declarations and uses PascalCase throughout (int32 Health;,FVector ServerPosition;), and the word "signal" never appears in it at all — it is Godot vocabulary. Unreal has delegates and events, and the reference's handlers are PascalCaseOn<Event>.Two caveats kept rather than smoothed over. (1)
classes: PascalCaseis incomplete for Unreal, not wrong: UE requires a mandatory type prefix (U/A/F/E/I/T) that this enum cannot express, so an Unreal project's coding standards must state it separately. (2)scenesis a category mismatch — Unreal has Levels and Maps under World Partition, not scenes — left in place because the key is shared across engines and renaming it is a schema change, not a value fix.The blast radius is limited:
naming.*is currently a documented-but-unread setting, so wrong values misinform a human readingproject.yamlrather than driving any automated check — today. That is a reason to get them right now, while it is cheap.
Three further rules for this table.
The Unity
buildrow must not hardcode-buildTarget StandaloneLinux64. A hardcoded target gives every Unity project a Linux build command, whatever platform it actually ships on. The row reads<TARGET>: ask the operator for the build target and write the value they give. The correct-buildTargetidentifiers are not sourceable fromdocs/engine-reference/unity/, so this skill must not emit one from recall — the same call made for/security-audit's save patterns and for Unity's release dates. A wrong-but-plausible default is worse than an explicit question: it produces acommands.buildthat runs, succeeds, and builds the wrong artifact.The Godot
buildrow must not hardcode'Linux/X11'either — same defect, same remedy. A Godot export preset name is project-defined: it is whatever string the operator typed intoexport_presets.cfg, and the shipped defaults are per-platform (Windows Desktop,macOS,Web,Linux/X11). Writing'Linux/X11'gives a Windows-targeting project a build command that fails withUnknown export preset, and gives a project that does have a Linux preset a command that silently builds the wrong platform. The row reads<PRESET>: ask the operator which export preset to build and write the value they give, exactly as the Unity row does. If no presets exist yet — common, since/setup-engineusually runs before the Godot project has any — write[TO BE CONFIGURED]and say so, rather than guessing a name that does not exist.The
constantsrow must not contradict this skill's own prose. The table saysSCREAMING_SNAKEfor Unity; the Unity section of this same file says "Constants: PascalCase or UPPER_SNAKE_CASE". Both cannot be authoritative, and an agent following one produces config the other rejects. The row is left unchanged pending sourcing rather than picked by preference — neitherdocs/engine-reference/unity/norunreal/contains a SCREAMING_SNAKE constant to confirm or refute it, and the Unreal run flagged the same row as wrong for Unreal on the same grounds. Resolve by adding a naming section to the engine references, then correct table and prose together. Until then, treatnaming.constantsas unverified for Unity and Unreal.On Unity and Unreal, emit the line with a trailing comment:
For Godot Both, use the GDScript column — .gd files dominate gameplay
scripting; .cs files follow C# conventions per-file (see A2 in .claude/skills/setup-engine/references/godot-language-config.md).
naming:
classes: <value>
variables: <value>
constants: <value>
signals: <value>
files: <value>
scenes: <value>
commands block — engine-default shell commands, simple-string form:
| Engine | build | test | run | smoke |
|---|---|---|---|---|
| Godot | godot --headless --export-debug '<PRESET>' (ASK — do not default) | godot --headless --script tests/gdunit4_runner.gd | godot --path . --windowed --resolution 1280x720 | godot --headless --quit-after 5 |
| Unity | Unity -batchmode -quit -projectPath . -buildTarget <TARGET> (ASK — do not default) | Unity -runTests -projectPath . -testPlatform PlayMode | Builds/<Target>/<Game>.exe -screen-width 1280 -screen-height 720 -screen-fullscreen 0 | Unity -batchmode -quit -projectPath . -executeMethod SmokeCheck.Run |
commands.runis the one the run-and-observe step depends on. It must launch the game, windowed, at a fixed resolution — never the editor, and never with a headless / batch / null-RHI flag, which exist to skip rendering./dev-storyPhase 6 step 4 appends the per-engine capture flags to it (.claude/docs/run-and-observe.md).testandsmokefeed the parse check and/smoke-check;buildis the one row you must ask for.
YAML quoting rule — applies to EVERY command value.
yaml-helper.sh— the parser every config read in this framework goes through — decodes no escape sequences: neither\"inside a double-quoted scalar nor''inside a single-quoted scalar. It takes the first matching quote character as the end of the value and discards the rest, so"he said \"hi\" now"parses ashe said \. Verified against the parser, not inferred. The rule is preventative here — it applies the moment anything does readcommands.*, and to every other quoted value inproject.yamltoday. Pick the quote style that needs no escaping:
- value contains a single quote
'(e.g. the Godotbuildabove) → wrap it in a double-quoted YAML scalar:"... 'Linux/X11' ..."- value contains a double quote
"(e.g. the Unrealtest/smokebelow) → wrap it in a single-quoted YAML scalar:'... "Quit" ...'- value contains neither → use a double-quoted scalar for consistency. Never use a quote style that forces an escape (
\"or'') — the parser truncates the value at the escape. A value containing BOTH quote types cannot be represented for this parser; rewrite the command to drop one.
Godot / Unity — write the table values directly, substituting the operator's
answer for <PRESET> / <TARGET>. Godot's build contains a single quote, so it
takes a double-quoted scalar (Windows Desktop below is the example answer, not
a default — write what the operator said):
commands:
build: "godot --headless --export-debug 'Windows Desktop'"
test: "godot --headless --script tests/gdunit4_runner.gd"
run: "godot --path . --windowed --resolution 1280x720"
smoke: "godot --headless --quit-after 5"
Also write
engine.pathif the editor is not onPATH. These commands name the executable bare, which assumes it resolves — and on Windows none of the three engines installs ontoPATHby default. Ask for or probe the install location and record it:engine: path: "C:/Program Files/Epic Games/UE_5.7" # omit if the editor is on PATHThis is not cosmetic. Without it, an agent reports "no editor on this machine" and ships C++ it never compiled — on a machine where that engine WAS installed. Nothing in the project told it where to look, so absence of a path read as absence of an engine.
For Unreal, UE build/test commands vary by version and project setup. Write
best-effort values and add a # TODO comment so the user knows to confirm them.
The test/smoke commands embed double quotes, so they take single-quoted
scalars:
commands:
# TODO: confirm these for your UE version and project — adjust via /settings
build: 'RunUAT.bat BuildCookRun -project=<project>.uproject -platform=Win64 -build -cook'
test: 'UnrealEditor-Cmd.exe <project>.uproject -ExecCmds="Automation RunTests <project>; Quit" -unattended -nullrhi'
run: 'UnrealEditor.exe <project>.uproject -game -windowed -ResX=1280 -ResY=720'
smoke: 'UnrealEditor-Cmd.exe <project>.uproject -game -nullrhi -unattended -ExecCmds="Quit"'
Two details are load-bearing. smoke needs -game: without it
UnrealEditor-Cmd boots the editor, where a bare Quit console command only
ends a play-in-editor session — the process stays resident and the command
never returns; with -game the same line boots headless and exits in seconds.
test needs the ; Quit inside the Automation string: the automation
runner handles that trailing Quit itself and exits the editor once the tests
finish, and without it the run also never returns.
project.yamlShow the user the full set of four blocks and ask:
"May I write the
engine,specialists,naming, andcommandsblocks toproject.yaml?"
Wait for confirmation, then apply based on the file's current state:
project.yaml does not exist — create it with the Write tool using this
v1.1 template (the four blocks appended after framework; replace <...> and
the date):
# CCGS project configuration — single source of truth for project settings.
# Schema: grep the `## <key>` section of .claude/docs/effects-map.md —
# it is ~31k tokens whole, ~900 per section. Do not open it entire.
schema_version: 1
framework:
version: 1.1.1
last_upgraded: <today's date>
engine:
name: "<...>"
version: "<...>"
language: "<...>"
rendering: "<...>"
physics: "<...>"
specialists:
code: "<...>"
shader: "<...>"
ui: "<...>"
additional: ["<...>"]
naming:
classes: <...>
variables: <...>
constants: <...>
signals: <...>
files: <...>
scenes: <...>
commands:
build: "<...>"
test: "<...>"
run: "<...>"
smoke: "<...>"
Do not seed modes.review_mode here. It is a rigor-fronted knob — modes.rigor
supplies its value, so an explicit value would shadow the rigor expansion and pin
the review mode regardless of the project's rigor. Test Y.6 locks this in.
project.yaml exists — Read it first (the Edit tool requires the file to
have been read this session), then, processing the blocks in the order
engine → specialists → naming → commands, for each block:
/setup-engine) — Edit the existing
keys in place, and add any keys the block is missing (a partial block must
end up with its full key set). Do NOT add a second copy of the block.Preserve all other content in project.yaml (schema_version, framework,
modes, project, etc.) — only the four blocks are touched.
Read project.yaml back and confirm the four blocks are present and that
engine.name, engine.language, and the naming values match what was written
to technical-preferences.md. If they diverge, report the discrepancy to the
user and stop — a split config corrupts skill and hook reads.
Check whether the engine version is likely beyond the LLM's training data.
Known approximate coverage — last re-checked 2026-08-28:
This table goes stale silently, and a stale table fails in the dangerous direction only if it is too new. A cutoff left unchanged for a year after it stopped being true over-classifies risk — safe, but every project then pays for full reference docs it may not have needed. The opposite error is the harmful one: a cutoff claimed later than the model's actual one marks post-cutoff versions LOW RISK and suppresses the reference docs that exist to stop invented APIs.
If the date above is more than six months old, do not trust it. Say so, and treat the engine version as
HIGH RISKregardless of the comparison — an unverifiable cutoff is not a cutoff that was met.
Compare the user's chosen version against these baselines:
LOW RISK — reference docs optional but recommendedMEDIUM RISK — reference docs recommendedHIGH RISK — reference docs requiredInform the user which category they're in and why.
Check before doing anything else. The template ships
docs/engine-reference/godot/, unity/ and unreal/ already populated, so
"the directory exists and pins a version" is the state of every fresh project,
not an edge case. Both branches below say "create", and following either one
literally on a pre-populated directory either overwrites curated content or
leaves project.yaml and the CLAUDE.md-imported reference disagreeing.
Read docs/engine-reference/<engine>/VERSION.md and compare its
Engine Version to the version chosen in Section 3:
VERSION.md → create, using the risk branch below.Last Docs Verified only if you
actually re-verified against the docs this run. Do not restamp a date you did
not check.VERSION.md in place: new Engine Version, new Project Pinned
and Last Docs Verified, the Installed at pin time row from Section 3,
and a new row in the post-cutoff timeline for each version added.breaking-changes.md, deprecated-apis.md and
current-best-practices.md under a heading naming the version span
(## 4.6 → 4.7). Never truncate the older spans — a project migrating
across two versions still needs the earlier one.Never fill a gap from training data. Write the gap down instead.
The whole purpose of these files is to be the thing agents consult instead of their training data. A confidently wrong entry here is worse than no entry: it produces work that looks verified and is not.
NOT SOURCEABLE — <what>, not stated at <url> and move on.NOT SOURCEABLE line is a successful outcome, not a failure to finish.Create a minimal docs/engine-reference/<engine>/VERSION.md:
# [Engine] — Version Reference
| Field | Value |
|-------|-------|
| **Engine Version** | [version] |
| **Project Pinned** | [today's date] |
| **LLM Knowledge Cutoff** | May 2025 |
| **Risk Level** | LOW — version is within LLM training data |
## Note
This engine version is within the LLM's training data. Engine reference
docs are optional but can be added later if agents suggest incorrect APIs.
Run `/setup-engine refresh` to populate full reference docs at any time.
Do NOT create breaking-changes.md, deprecated-apis.md, etc. — they would add context cost with minimal value.
Create the full reference doc set by searching the web:
Search for the official migration/upgrade guide:
"[engine] [old version] to [new version] migration guide""[engine] [version] breaking changes""[engine] [version] changelog""[engine] [version] deprecated API"Fetch and extract from official documentation:
Ask: "May I create the engine reference docs under docs/engine-reference/<engine>/?"
Wait for confirmation before writing any files.
Create the full reference directory:
docs/engine-reference/<engine>/
├── VERSION.md # Version pin + knowledge gap analysis
├── breaking-changes.md # Version-by-version breaking changes
├── deprecated-apis.md # "Don't use X → Use Y" tables
├── current-best-practices.md # New practices since training cutoff
└── modules/ # Per-subsystem references (create as needed)
Populate each file using real data from the web searches, following the format established in existing reference docs. Every file must have a "Last verified: [date]" header.
For module files: Only create modules for subsystems where significant changes occurred. Don't create empty or minimal module files.
Without this step the framework produces source files no engine can open.
/dev-story writes .gd/.cs/.cpp under the resolved code root, and the minimal path
advertises "four steps to running code" — but nothing anywhere created a project
for the engine to load. Verified by grep across every skill: no project.godot,
no Unity project, no .uproject was ever written. The files were real and
orphaned.
project.godot if one is absentNever overwrite an existing project.godot. If the file is already there,
say so and skip to Section 8 — the developer has a project and its settings are
theirs.
Show the proposed file, then ask: "May I create project.godot at the repo
root?" On approval, write:
config_version=5
[application]
config/name="<project name>"
config/features=PackedStringArray("<major.minor>", "<renderer feature>")
[rendering]
renderer/rendering_method="<rendering method>"
Fill it from decisions already made — do not ask again:
| Field | Source |
|---|---|
config/name | the brief's working title, else the repo directory name |
<major.minor> | engine.version from Section 3, major and minor only (4.7.2 → 4.7) |
<renderer feature> / <rendering method> | the rendering value chosen in Section 5.5.1 — Compatibility → "GL Compatibility" / gl_compatibility; Forward+ → "Forward Plus" / forward_plus; Mobile → "Mobile" / mobile |
Leave run/main_scene unset. There is no scene yet at engine-setup time.
Add a comment saying /dev-story or the developer sets it once a scene exists;
an empty project with no main scene opens fine in the editor.
Then verify, and report what the verification actually was. If the engine
binary was found in Section 3, run its headless import
(godot --headless --path . --import) and report the result. If the binary was
not found, or its version differs from the pinned one, write
project.godot NOT VERIFIED — <reason>. The config_version and feature
strings are stable across Godot 4.x, but "stable in the versions I know" is not
the same as "checked against the version you pinned", and only the run
establishes the latter.
A Unity project and an .uproject are editor-generated and span many files,
several of them binary or machine-specific. This repo cannot source their
correct contents, and a hand-written scaffold would be the exact failure
Section 7's sourcing rule forbids — something that looks finished and is quietly
wrong.
Tell the user, in one short block, that CCGS does not create the project for these engines and they should create it first:
/setup-engine.UnrealEditor,
then re-run.Report the outcome in the Section 12 summary either way — created, already present, or "not created, engine requires the editor" — so the user leaves this skill knowing whether a runnable project exists.
Deliberately not a
project.yamlkey. Anengine.project_scaffoldedflag would be written here and read by nothing, which is a dead setting — the same writer-without-reader defect the config gates exist to catch. The filesystem is the source of truth: any skill that needs to know globs forproject.godot,*.uproject, orProjectSettings/ProjectVersion.txt.
This import was already written in Section 4 — do not edit it again and do not
ask again. Section 4 sets it as part of the same CLAUDE.md write, anchored to
the ENGINE-REFERENCE-IMPORT marker. This step only confirms the result.
Read CLAUDE.md and confirm the line under the marker reads:
@docs/engine-reference/<engine>/VERSION.md
with <engine> the engine just configured. If it still points at a different
engine, Section 4 did not complete — go back and finish it rather than patching
the line here.
Why this is a check and not a second write. Repeating the edit here with its own approval prompt would ask the user twice for one change, and the second ask would be for work already done. Locate the line by its marker, never by the
## Engine Version Referenceheading — the marker exists precisely so the line can still be found when the heading moves or is reworded.
This section exists because prose did not hold. Section 5.5.1's rendering/physics
table already carries an emphatic, source-cited warning naming the two mistakes
most often made here -- and it is still entirely possible to make both of
them anyway, writing Forward+ and Jolt for a 2D browser game. Section 3's
Installed at pin time row is just as easy to drop silently, because a missing
row leaves no trace.
Neither is fixed by adding more instructions. They are fixed by verifying the files after writing them:
bash .claude/scripts/project-coherence.sh
It compares project.yaml against docs/engine-reference/<engine>/VERSION.md,
against project.godot, and against the engine binary actually on PATH, and it
checks that the files commands.build and commands.test name exist.
Report every [DIFFERS] line to the user and resolve it before finishing.
Each one means two files this skill just wrote disagree, or describe something
that is not there.
[NOT CHECKED] is not a pass. Each such line names why a comparison could
not be made -- an absent binary, a missing project.godot. Say which ones
applied. A comparison that could not run has not established agreement.
The script emits observations and never a verdict, per the convention in CLAUDE.md. The judgement is yours and the user's.
Ask: "May I add a Version Awareness section to the engine specialist agent files?" before making any edits.
For the chosen engine's specialist agents, verify they have a "Version Awareness" section. If not, add one following the pattern in the existing Godot specialist agents.
The section should instruct the agent to:
docs/engine-reference/<engine>/VERSION.mdIf invoked as /setup-engine refresh:
docs/engine-reference/<engine>/VERSION.md to get
the current engine and versionIf invoked as /setup-engine upgrade [old-version] [new-version]:
Read docs/engine-reference/<engine>/VERSION.md to confirm the current pinned
version, risk level, and any migration note URLs already recorded. If
old-version was not provided as an argument, use the pinned version from this
file.
Use WebSearch and WebFetch to locate the official migration guide between
old-version and new-version:
"[engine] [old-version] to [new-version] migration guide""[engine] [new-version] breaking changes changelog"Extract: renamed APIs, removed APIs, changed defaults, behavior changes, and any "must migrate" items.
Scan the code root (resolve per .claude/docs/code-root-resolution.md) for code that uses APIs known to be deprecated or changed in the
target version:
Present the audit results as a table:
Pre-Upgrade Audit: [engine] [old-version] → [new-version]
==========================================================
Files requiring changes:
File | Deprecated API Found | Effort
--------------------------------- | -------------------------- | ------
src/gameplay/player_movement.gd | old_api_name | Low
src/ui/hud.gd | removed_node_type | Medium
Breaking changes to watch for:
- [change description from migration guide]
- [change description from migration guide]
Recommended migration order (dependency-sorted):
1. [system/layer with fewest dependencies first]
2. [next system]
...
If no deprecated APIs are found in the code root, report: "No deprecated API usage found in the code root — upgrade may be low-risk."
Ask the user before making any changes:
"Pre-upgrade audit complete. Found [N] files using deprecated APIs. Proceed with upgrading VERSION.md to [new-version]? (This will update the pinned version and add migration notes — it does NOT change any source files. Source migration is done manually or via stories.)"
Wait for explicit confirmation before continuing.
After confirmation:
Update docs/engine-reference/<engine>/VERSION.md:
Engine Version → [new-version]Project Pinned → today's dateLast Docs Verified → today's dateRisk Level and Post-Cutoff Version Timeline
table if the new version falls beyond the LLM knowledge cutoff## Migration Notes — [old-version] → [new-version] section
containing: migration guide URL, key breaking changes, deprecated APIs
found in this project, and recommended migration order from the auditIf breaking-changes.md or deprecated-apis.md exist in the engine
reference directory, append the new version's changes to those files.
If project.yaml exists at the repo root and has an engine block, Read it
first, then update engine.version to [new-version] so the primary config
store stays in sync with VERSION.md.
After updating VERSION.md, output:
VERSION.md updated: [engine] [old-version] → [new-version]
Next steps:
1. Migrate deprecated API usages in the [N] files listed above
2. Run /setup-engine refresh after upgrading the actual engine binary to
verify no new deprecations were missed
3. Run /architecture-review — the engine upgrade may invalidate ADRs that
reference specific APIs or engine capabilities
4. If any ADRs are invalidated, run /propagate-design-change to update
downstream stories
After setup is complete, output:
Engine Setup Complete
=====================
Engine: [name] [version]
Language: [GDScript | C# | GDScript + C# | C# | C++ + Blueprint]
Knowledge Risk: [LOW/MEDIUM/HIGH]
Reference Docs: [created/skipped]
CLAUDE.md: [updated]
Tech Prefs: [created/updated]
project.yaml: [created/updated]
Agent Config: [verified]
Next Steps:
1. Review docs/engine-reference/<engine>/VERSION.md
Then print one Next-Steps list, matching the resolved workflow tier:
minimal — the lean 4-step floor (you are on step 1):
2. Run /brainstorm to produce your one-page design/game-brief.md (the lean-tier design artifact)
3. Run /create-stories to turn the brief's MVP list into stories
4. Run /dev-story — first line of game code
(No /map-systems, /design-system, /prototype, or /sprint-plan at
minimal — the brief replaces the GDDs and its build order is the plan.)
standard / full — the full pipeline:
2. [If from /brainstorm] Run /map-systems to decompose your concept into individual systems
3. [If from /brainstorm] Run /design-system to author per-system GDDs (guided, section-by-section)
4. [If from /brainstorm] Run /prototype [core-mechanic] to validate the core idea before writing GDDs
5. [If fresh start] Run /brainstorm to discover your game concept
6. Create your first milestone: /sprint-plan new
Verdict: COMPLETE — engine configured and reference docs populated.
project.yaml is the primary config store (v1.1). Always dual-write engine
config to BOTH project.yaml (primary) and technical-preferences.md (legacy
mirror). If the two ever diverge, project.yaml is authoritative..claude/skills/setup-engine/references/godot-language-config.md exactly. NEVER add "C++ via GDExtension" to the Language field. GDScript projects may use GDExtension, but it is not a primary project language. The godot-gdextension-specialist in the routing table is available for when native extensions are needed — it does not make C++ a project language.Moved out of this file so it costs nothing on non-Godot runs.
When the chosen engine is Godot, read
.claude/skills/setup-engine/references/godot-language-config.md
and use the subsection for the chosen language:
Load discipline. On any engine other than Godot, never load it — nothing in Sections 4, 5 or 5.5 needs it, and reading it anyway spends the tokens the split exists to save. On Godot, read it once when you first reach Section 4 and keep using it for Sections 5 and 5.5; do not re-read it at each reference.
project.yaml, do not leave it here.constantsnaming:
constants: SCREAMING_SNAKE # UNVERIFIED — not sourceable from
# docs/engine-reference/<engine>/; confirm before relying on it
Without it, a value the skill knows is unsourced is recorded as flatly as
classes: PascalCase, which is sourced, and the reader of the primary config
store cannot tell them apart. The commands block nine lines below already does
exactly this with its # TODO: confirm these line — this is the same pattern,
applied to the value that needs it just as much.