mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios.git
synced 2026-10-16 10:17:06 +00:00
Release 1.1.3 — long skills keep their later steps
Fix release for 1.1.2: the 14 longest skills keep their later phases after a compaction, a question nobody answered is never taken as an answer, settings read the same from a subfolder, the commit check works for a project in a subfolder of a larger repository, every skill opens with a title, and the shipped allow rules no longer approve deleting a branch or writing files without asking. Details in CHANGELOG.md; upgrade steps in UPGRADING.md (v1.1.2 → v1.1.3). Refs #83 Refs #133 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0185en4t76fPn7315q4c3nko
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b21fa0f7f2
commit
be8993bbc5
@@ -0,0 +1,520 @@
|
||||
# /setup-engine — Section 5.5: Populate project.yaml
|
||||
|
||||
> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it
|
||||
> resolved and the rules under its later headings still apply here.
|
||||
|
||||
## 5.5 Populate `project.yaml` (Primary Config Store)
|
||||
|
||||
**In this file:**
|
||||
|
||||
- 5.5.1 Build the four blocks
|
||||
- 5.5.2 Write the blocks to `project.yaml`
|
||||
- 5.5.3 Verify the dual-write
|
||||
|
||||
> **v1.1:** `project.yaml` at the repo root is the **primary** store for project
|
||||
> configuration. The `.claude/docs/technical-preferences.md` file 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, and
|
||||
> `project.yaml` wins 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`.
|
||||
|
||||
### 5.5.1 Build the four blocks
|
||||
|
||||
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".** `rendering` and `physics` below 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:**
|
||||
|
||||
```yaml
|
||||
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)". Writing `Jolt` on 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 platforms` **including** 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
|
||||
> change `rendering` or `physics` for 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 write `URP`/`PhysX` and on
|
||||
> Unreal write `Lumen + Nanite (deferred)`/`Chaos` straight 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 answered `None` or `Multiple`
|
||||
> collects both.
|
||||
>
|
||||
> Resolve each input in this order and stop at the first that answers:
|
||||
> 1. **Section 2's answers**, if that path ran.
|
||||
> 2. **The design artifact** — `design/gdd/game-concept.md` at `standard`/`full`,
|
||||
> `design/game-brief.md` at `minimal`. Section 2 already extracts platform
|
||||
> targets from these; extract 2D-vs-3D the same way when it is stated.
|
||||
> 3. **Ask.** Do not infer the shape from the engine name, and do not write a row
|
||||
> you could not justify:
|
||||
> - Prompt: "`rendering` and `physics` depend 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`, plus
|
||||
> `Leave as [TO BE CONFIGURED]` — a legitimate answer here, revisited via
|
||||
> `/settings` once the concept exists.
|
||||
>
|
||||
> `[TO BE CONFIGURED]` is a valid value for both keys. A wrong `Jolt` on 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.
|
||||
- For Godot **Both**, write `language: "GDScript"` (the primary gameplay
|
||||
language); the C# usage is recorded in `technical-preferences.md`.
|
||||
- For Unreal, write `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 `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] |
|
||||
|
||||
```yaml
|
||||
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: camelCase` and `signals: on_event_name` are 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 PascalCase `On<Event>`.
|
||||
>
|
||||
> Two caveats kept rather than smoothed over. (1) `classes: PascalCase` is
|
||||
> **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) `scenes` is 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 reading
|
||||
> `project.yaml` rather 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 `build` row 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 `-buildTarget` identifiers
|
||||
> are not sourceable from `docs/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 a `commands.build` that runs, succeeds,
|
||||
> and builds the wrong artifact.
|
||||
>
|
||||
> **`-buildTarget` alone builds nothing.** It switches the active platform and
|
||||
> exits 0 (verified on 6000.3.23f1). The row also needs a player-build flag,
|
||||
> `-build<PLATFORM>Player <output path>` — for Windows 64-bit,
|
||||
> `-buildWindows64Player Builds/Win64/<Game>.exe` (verified: exit 0 and an
|
||||
> `.exe`; exit 1 on a compile error or when no scene is in the build settings).
|
||||
> Ask which platform, and confirm any other platform's flag against Unity's
|
||||
> command-line documentation rather than recalling one.
|
||||
>
|
||||
> **The Godot `build` row 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 into `export_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 with
|
||||
> `Unknown 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-engine` usually runs before the Godot project has any — write
|
||||
> `[TO BE CONFIGURED]` and say so, rather than guessing a name that does not exist.
|
||||
>
|
||||
> **The `constants` row must not contradict this skill's own prose.** The table says
|
||||
> `SCREAMING_SNAKE` for 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 — neither
|
||||
> `docs/engine-reference/unity/` nor `unreal/` 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, treat
|
||||
> `naming.constants` as unverified for Unity and Unreal.
|
||||
>
|
||||
> **Write that caveat into `project.yaml`, do not leave it here.** On Unity and
|
||||
> Unreal, emit the `constants` line with a trailing comment:
|
||||
> ```yaml
|
||||
> naming:
|
||||
> 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.
|
||||
|
||||
For Godot **Both**, use the GDScript column — `.gd` files dominate gameplay
|
||||
scripting; `.cs` files follow C# conventions per-file (see **A2** in `references/godot-language-config.md`).
|
||||
|
||||
```yaml
|
||||
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 -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode` | `godot --path . --windowed --resolution 1280x720` | `godot --headless --quit-after 5` |
|
||||
| Unity | `"<Unity editor>" -batchmode -quit -projectPath . -buildTarget <TARGET> -build<PLATFORM>Player Builds/<Target>/<Game>.exe` **(ASK — do not default)** | `"<Unity editor>" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml` | `Builds/<Target>/<Game>.exe -screen-width 1280 -screen-height 720 -screen-fullscreen 0` | `"<Unity editor>" -batchmode -quit -projectPath . -logFile -` |
|
||||
|
||||
> **What each exit code proves — every row verified on the pinned engines.**
|
||||
> Godot `test` exits 0 when all pass, 100 on a failure, 101 when all pass but
|
||||
> nodes leaked (a warning, not a failure), 105 when a test script does not
|
||||
> parse, and 103 / 104 when gdUnit4 cannot run at all (headless refused, Godot
|
||||
> older than 4.3). Keep `--remote-debug tcp://127.0.0.1:0`: without it a script
|
||||
> error opens Godot's interactive debugger and the run waits at a `debug>`
|
||||
> prompt forever instead of exiting. Run `godot --headless --path . --import`
|
||||
> before it on a fresh clone: with no `.godot/` class cache,
|
||||
> `GdUnitCmdTool.gd` did not load and the run exits 1 having run nothing. Unity `test`
|
||||
> exits 0 / 2, and a results file with `testcasecount="0"` means no test was
|
||||
> compiled — not a pass. It runs Edit Mode only: Play Mode tests under
|
||||
> `Assets/Tests/PlayMode/` need a second run into their own results file
|
||||
> (`-testPlatform PlayMode -testResults test-results/playmode.xml`), which
|
||||
> `/smoke-check` makes whenever that folder holds tests and CI runs as its own
|
||||
> step. Unity `smoke` exits 1 on a compile error, 0 when clean.
|
||||
> **Godot `smoke` exits 0 even on a parse error** — it is a boot check: read its
|
||||
> output for `SCRIPT ERROR`. It also needs `run/main_scene` set: without one it
|
||||
> prints `Can't run project: no main scene defined` and never exits, so run it
|
||||
> under a timeout. Unity `smoke` compiles only the editor-side assemblies; an
|
||||
> error that exists only in a player build (an `Editor/` script without its own
|
||||
> assembly) shows up in `build`, not here. The real Godot parse check is
|
||||
> `godot --headless --path . --import`, then
|
||||
> `godot --headless --path . -s res://.claude/scripts/godot-parse-check.gd -- res://<file>.gd …`
|
||||
> (exit 1 when a script does not load). `--check-only` is not one: it fails
|
||||
> valid code that names an autoload. `<Unity editor>` is the **editor**
|
||||
> executable's full path, quoted. Never write bare `Unity`: on `PATH` that name
|
||||
> may be Unity's separate CLI, which rejects `-batchmode` with exit 2 — the same
|
||||
> code as a failed test.
|
||||
|
||||
> **`commands.run` is 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-story` Phase 6 step 4 appends the per-engine capture flags to it
|
||||
> (`.claude/docs/run-and-observe.md`). `smoke` is Unity's parse check, `test`
|
||||
> feeds `/smoke-check`; `build` is 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 as
|
||||
> `he said \`. Verified against the parser, not inferred. The rule is
|
||||
> load-bearing: `/smoke-check` and `/dev-story` run these values, `/settings`
|
||||
> reads and writes them through this parser, and the same holds for every other
|
||||
> quoted value in `project.yaml`.
|
||||
> Pick the quote style that needs **no escaping**:
|
||||
> - value contains a single quote `'` (e.g. the Godot `build` above) → wrap it in
|
||||
> a **double-quoted** YAML scalar: `"... 'Linux/X11' ..."`
|
||||
> - value contains a double quote `"` (e.g. the Unreal `test`/`smoke` below) →
|
||||
> 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>` / `<PLATFORM>`, and the editor's full path for
|
||||
`<Unity editor>`. 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):
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
build: "godot --headless --export-debug 'Windows Desktop'"
|
||||
test: "godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode"
|
||||
run: "godot --path . --windowed --resolution 1280x720"
|
||||
smoke: "godot --headless --quit-after 5"
|
||||
```
|
||||
|
||||
**Write bare `godot` only when Section 3's `godot --version` ran** — that is,
|
||||
`godot` is on `PATH`. Otherwise (the usual case on Windows and macOS)
|
||||
substitute the executable the probe found or the user gave — a Windows
|
||||
`Godot_v<version>-stable_win64.exe`, macOS `/Applications/Godot.app/Contents/MacOS/Godot`
|
||||
— as its full path, in double quotes, for the leading `godot` in all four
|
||||
values, exactly as `<Unity editor>` is. The value then holds double quotes, so it
|
||||
takes a single-quoted scalar, and `build` quotes its preset with double quotes
|
||||
too, so no value holds both quote types. Godot not on PATH, installed under
|
||||
`C:/Program Files/Godot/`:
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
build: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless --export-debug "Windows Desktop"'
|
||||
test: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode'
|
||||
run: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --path . --windowed --resolution 1280x720'
|
||||
smoke: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless --quit-after 5'
|
||||
```
|
||||
|
||||
If the probe found no executable and the user does not know where it is, keep
|
||||
bare `godot`, put `# TODO: godot is not on PATH here — set the editor's full
|
||||
path via /settings` above the block, and say so: those commands will not run
|
||||
until one of the two is fixed.
|
||||
|
||||
For Unity, probe the Hub install (`C:/Program Files/Unity/Hub/Editor/<version>/Editor/Unity.exe`
|
||||
on Windows, `/Applications/Unity/Hub/Editor/<version>/Unity.app/Contents/MacOS/Unity`
|
||||
on macOS, `/home/<user>/Unity/Hub/Editor/<version>/Editor/Unity` on Linux) or ask.
|
||||
Write the expanded absolute path — a `~` inside quotes is not expanded, and the
|
||||
command then exits 127. The
|
||||
quoted path puts double quotes in the command, so the value takes a
|
||||
single-quoted scalar:
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
test: '"C:/Program Files/Unity/Hub/Editor/6000.3.23f1/Editor/Unity.exe" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml'
|
||||
smoke: '"C:/Program Files/Unity/Hub/Editor/6000.3.23f1/Editor/Unity.exe" -batchmode -quit -projectPath . -logFile -'
|
||||
```
|
||||
|
||||
> **Also write `engine.path` if the editor is not on `PATH`.** Agents and
|
||||
> `/smoke-check` read it to find the editor, but a command is run as written —
|
||||
> `engine.path` is never spliced into `commands.*` at run time, which is why the
|
||||
> full path goes into the commands above — and on Windows and macOS none of
|
||||
> the three engines installs onto `PATH` by default (on macOS the editor is inside an app
|
||||
> bundle, e.g. `/Applications/Godot.app/Contents/MacOS/Godot`). Ask for or probe the
|
||||
> install location and record it — the editor executable for Godot and Unity,
|
||||
> the engine folder (`<UE root>`) for Unreal:
|
||||
>
|
||||
> ```yaml
|
||||
> engine:
|
||||
> path: "C:/Program Files/Epic Games/UE_5.7" # omit if the editor is on PATH
|
||||
> ```
|
||||
>
|
||||
> **This 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.
|
||||
Substitute the engine's install folder for `<UE root>` (the value you record as
|
||||
`engine.path`) — none of the editor binaries is on `PATH`. The commands embed
|
||||
double quotes, so they take single-quoted scalars. Write the block for the
|
||||
machine the project is developed on (`uname -s`: `Linux`, `Darwin` = macOS,
|
||||
anything else = Windows). The Windows block was run on UE 5.7; the Linux and
|
||||
macOS lines come from Epic's documentation, recorded with their sources in
|
||||
`docs/engine-reference/unreal/current-best-practices.md` ("Command Line").
|
||||
|
||||
Windows:
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
# TODO: confirm these for your UE version and project — adjust via /settings
|
||||
build: '"<UE root>/Engine/Binaries/DotNET/AutomationTool/AutomationTool.exe" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -platform=Win64 -build -cook'
|
||||
test: '"<UE root>/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -ExecCmds="Automation RunTests <project>.; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput'
|
||||
run: '"<UE root>/Engine/Binaries/Win64/UnrealEditor.exe" "$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -game -windowed -ResX=1280 -ResY=720'
|
||||
smoke: '"<UE root>/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -game -nullrhi -unattended -stdout -ExecCmds="Quit"'
|
||||
```
|
||||
|
||||
Linux — the editor binary is `Engine/Binaries/Linux/UnrealEditor`, the build
|
||||
scripts are shell scripts:
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
# TODO: confirm these for your UE version and project — adjust via /settings
|
||||
build: '"<UE root>/Engine/Build/BatchFiles/RunUAT.sh" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -platform=Linux -build -cook'
|
||||
test: '"<UE root>/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -ExecCmds="Automation RunTests <project>.; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput'
|
||||
run: '"<UE root>/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -game -windowed -ResX=1280 -ResY=720'
|
||||
smoke: '"<UE root>/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -game -nullrhi -unattended -stdout -ExecCmds="Quit"'
|
||||
```
|
||||
|
||||
macOS — only the build is sourced. Epic documents the `UnrealEditor.app`
|
||||
bundle but no command-line editor inside it, so write `build` and leave the
|
||||
other three as TODO lines rather than a guessed path; `/smoke-check` reports
|
||||
NOT ASSESSED for tests until the user sets `commands.test`:
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
# TODO: confirm this for your UE version and project — adjust via /settings
|
||||
build: '"<UE root>/Engine/Build/BatchFiles/RunUAT.sh" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/<project>.uproject" -platform=Mac -build -cook'
|
||||
# TODO: test, run and smoke — no documented command-line editor on macOS.
|
||||
# Set them via /settings to the editor command you run for this project.
|
||||
```
|
||||
|
||||
On Windows, `build` calls AutomationTool directly: from Git Bash, `RunUAT.bat` fails
|
||||
(`'C:\Program' is not recognized`) whenever the project path has a space.
|
||||
AutomationTool.exe runs on the machine's .NET 8 runtime; `RunUAT.bat` brings
|
||||
its own SDK, so with no space in the path and no .NET 8 installed, use it.
|
||||
`-build` builds the editor target too (verified on 5.7).
|
||||
|
||||
**Three details are load-bearing.** The project path is absolute: UE 5.7
|
||||
does not find a relative `<project>.uproject` and exits 1 (`Project file not
|
||||
found`) before anything runs. `$(pwd -W 2>/dev/null || pwd)` gives the `C:/…`
|
||||
form in Git Bash and the plain path elsewhere, run from the project root;
|
||||
`$PWD` alone fails when `MSYS_NO_PATHCONV` is set. `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. Its filter runs every test
|
||||
whose full name *contains* `<project>.` — a substring match, not a prefix — so
|
||||
name tests `<project>.[System].[Scenario]` as `qa-tester` does. If the
|
||||
project's name is also an engine area — `Audio`, `Core`, `Input`, `Test`,
|
||||
`System`, `Engine`, `Editor`, `AI`, `Math` — `<project>.` also runs hundreds
|
||||
to thousands of the engine's own tests; give the tests a distinct root (say
|
||||
`<project>Game.`) and put the same root in the filter. This form exits 255 on
|
||||
a failing test AND on a filter that matches nothing (`No automation tests
|
||||
matched`, verified on 5.7), so `/smoke-check` reads the output, not the exit
|
||||
code. `smoke` carries `-stdout` for the same reason: without it a failed boot
|
||||
prints nothing. Do not swap in
|
||||
`-TestExit="Automation Test Queue Empty"`: that form exits **0** on a failing
|
||||
test unless its report JSON is parsed.
|
||||
|
||||
### 5.5.2 Write the blocks to `project.yaml`
|
||||
|
||||
Show the user the full set of four blocks and ask:
|
||||
|
||||
> "May I write the `engine`, `specialists`, `naming`, and `commands` blocks to `project.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):
|
||||
|
||||
```yaml
|
||||
# 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.3
|
||||
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.
|
||||
|
||||
- **`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:
|
||||
- **Block absent** — insert the whole block, appended after the last existing
|
||||
top-level block.
|
||||
- **Block already present** (a re-run of `/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.
|
||||
|
||||
**Unreal on macOS is the exception in both cases:** `commands.test`, `run` and
|
||||
`smoke` are written as the TODO comment lines from the macOS block — never as
|
||||
`<...>` placeholders or a guessed path — and a re-run leaves them unset until the
|
||||
user sets them.
|
||||
|
||||
Preserve all other content in `project.yaml` (`schema_version`, `framework`,
|
||||
`modes`, `project`, etc.) — only the four blocks are touched.
|
||||
|
||||
### 5.5.3 Verify the dual-write
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user