Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
794712b
fix: Tier 1 friction fixes from cyberpunk HUD stress test
dsarno Apr 16, 2026
28dcd69
feat: Tier 2 friction fixes — scene instancing, animation delete, roo…
dsarno Apr 16, 2026
98ec743
feat: Tier 3 friction fixes — readiness race, autoload signals, anima…
dsarno Apr 16, 2026
9df9a92
fix: CI wait for editor readiness before running Godot tests
dsarno Apr 16, 2026
5ddf2d6
test: add integration tests for animation_delete and animation_validate
dsarno Apr 16, 2026
41c57a7
fix: CI open main scene when headless Godot starts with no_scene
dsarno Apr 16, 2026
862e7b5
fix: CI pass scene path to headless Godot and log scene_open result
dsarno Apr 16, 2026
5262195
fix: CI ensure editor_layout.cfg has main.tscn in open_scenes
dsarno Apr 16, 2026
8e3f454
fix: CI write clean editor_layout.cfg (overwrite not append)
dsarno Apr 16, 2026
a99ed26
fix: CI open scene immediately after session connects
dsarno Apr 16, 2026
99cce4c
Merge remote-tracking branch 'origin/main' into friction/tier1-fixes
dsarno Apr 16, 2026
be6a5a0
fix: remove test artifacts from main.tscn and project.godot
dsarno Apr 16, 2026
0330cd9
debug: add logging to diagnose 0 tests on CI
dsarno Apr 16, 2026
a077a84
debug: return discovery diagnostics in test_run error response
dsarno Apr 16, 2026
20b665e
debug: inline simpler diagnostic in run_tests response
dsarno Apr 16, 2026
0efc890
debug: test single script load and McpTestSuite check
dsarno Apr 16, 2026
0a3dbec
debug: instrument _discover_suites() loop with per-step logging
dsarno Apr 16, 2026
e1a09c8
fix: remove CACHE_MODE_IGNORE from test discovery and clean up debug
dsarno Apr 16, 2026
118c01d
fix: CI test discovery — remove scene_open and use untyped arrays
dsarno Apr 16, 2026
112ee8c
debug: add discovery diagnostics to test_run error response
dsarno Apr 16, 2026
e093a33
debug: inline discovery diagnostics (avoid separate function crash)
dsarno Apr 16, 2026
072420c
debug: print full content and raw response on test failure
dsarno Apr 16, 2026
c781685
debug: fix CI script syntax (broken break/else placement)
dsarno Apr 16, 2026
28e46f4
fix: CI test discovery — remove CACHE_MODE_IGNORE, clean up debug
dsarno Apr 16, 2026
9273289
chore: add CI regression-range helper script (#22)
dsarno Apr 16, 2026
5f244ea
debug: detect handler crashes in dispatcher (empty dict = crash)
dsarno Apr 16, 2026
98a2093
debug: dump raw MCP response before parsing
dsarno Apr 16, 2026
23214db
fix: revert all debug/CI changes — test with main's exact test infra
dsarno Apr 16, 2026
837b880
fix: remove accidentally committed .uid files and .claude/settings
dsarno Apr 16, 2026
0b9f80a
debug: verify test files visible in CI before test_run
dsarno Apr 16, 2026
c53c07e
fix: CI add sleep before test_run + step timeouts
dsarno Apr 16, 2026
80ec829
ci: retrigger after main cleanup (a738e7a)
dsarno Apr 16, 2026
289e897
fix: rename duplicate test function that broke all test discovery
dsarno Apr 16, 2026
88240c2
fix: resilient test discovery + GDScript validation CI step
dsarno Apr 16, 2026
4f5f998
fix: upgrade pip + add timeout in Linux Docker CI
dsarno Apr 16, 2026
41005ab
ci: retrigger with Linux pip fix
dsarno Apr 16, 2026
eb6cceb
fix: replace Docker image with chickensoft for Linux CI
dsarno Apr 16, 2026
a280460
Merge remote-tracking branch 'origin/main' into friction/tier1-fixes
dsarno Apr 16, 2026
1827279
refactor: simplify review — dedup, efficiency, TOCTOU fixes
dsarno Apr 16, 2026
b443312
docs: update project docs to reflect CI overhaul, new tools, and hard…
dsarno Apr 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,34 +109,45 @@ jobs:
godot-tests-linux:
name: Godot tests / Linux
runs-on: ubuntu-latest
container:
image: barichello/godot-ci:4.6.2

steps:
- uses: actions/checkout@v4

- uses: chickensoft-games/setup-godot@v2
with:
version: 4.6.2
use-dotnet: false

- name: Set up Python
timeout-minutes: 5
run: |
apt-get update -qq && apt-get install -y -qq python3 python3-pip python3-venv curl > /dev/null
python3 -m venv /tmp/venv
/tmp/venv/bin/pip install -e ".[dev]"
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install dependencies
run: pip install -e ".[dev]"

- name: Start MCP server
run: bash script/ci-start-server /tmp/venv/bin/python
run: bash script/ci-start-server

- name: Start Godot editor (headless)
- name: Import and validate GDScript
timeout-minutes: 3
run: |
timeout 30 godot --headless --path test_project --import || true
timeout 120 godot --headless --path test_project --editor &
godot --headless --path test_project --import > /tmp/godot-import.log 2>&1 || true
bash script/ci-check-gdscript /tmp/godot-import.log

- name: Start Godot editor (headless)
run: godot --headless --path test_project --editor &

- name: Run handler tests
timeout-minutes: 3
run: bash script/ci-godot-tests

- name: Reload smoke test
timeout-minutes: 2
run: bash script/ci-reload-test

- name: Quit smoke test
timeout-minutes: 2
run: bash script/ci-quit-test

godot-tests-macos:
Expand Down
7 changes: 6 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ The dock checks the GitHub releases API on startup. If a newer version exists, a

### Python tests
```bash
pytest -v # 375 unit + integration tests
pytest -v # 387 unit + integration tests
```

### Godot-side tests
Expand Down Expand Up @@ -198,6 +198,10 @@ New features don't ship without tests. Regressions are caught before they merge.
- **Re-entrant `_process()` during save**: `EditorInterface.save_scene()` internally renders a preview thumbnail, which triggers frame processing. If `Connection._process()` runs during this, WebSocket polling and command dispatch re-enter, crashing Godot (`SIGABRT` in `_save_scene_with_preview`). Fixed by setting `Connection.pause_processing = true` around save calls in `SceneHandler`. Any new handler that calls `save_scene()`, `save_scene_as()`, or `save_all_scenes()` must do the same.
- **GDScript tests must not call `EditorInterface.save_scene()` or `scene_create`/`scene_open`**: These trigger modal dialogs or scene switches that freeze or crash the test runner. Test only validation/error paths for these operations in GDScript; full behavior is covered by Python integration tests.
- **GDScript tests must not call `quit_editor` or `reload_plugin`**: These terminate or restart the plugin, killing the test runner. Tested via Python integration tests and CI smoke scripts (`script/ci-quit-test`, `script/ci-reload-test`). (Note: plugin command names stay `quit_editor` / `reload_plugin`; the MCP tool names are `editor_quit` / `editor_reload_plugin`.)
- **Resilient test discovery**: `_discover_suites()` in `test_handler.gd` catches per-file load errors and returns `{suites, errors}`. Individual broken test scripts do not prevent the rest from running. The `errors` list reports which scripts failed to load.
- **CI GDScript validation**: `script/ci-check-gdscript` runs before Godot tests in CI. It scans the `--import` log for `SCRIPT ERROR` / `Parse Error` lines and fails the build early if any GDScript has syntax errors, before the test runner even starts.
- **CI Linux runner**: Linux Godot CI uses `chickensoft-games/setup-godot@v2` on `ubuntu-latest` (not a Docker image). All three OS jobs (Linux, macOS, Windows) use the same chickensoft action for consistent Godot setup. Step timeouts are set on test and smoke steps to prevent CI hangs.
- **Sleep before test_run in CI**: `script/ci-godot-tests` includes a short sleep (8s) after Godot startup to let the editor filesystem scan settle before running tests. Without this, test discovery can miss files.

## What NOT to do

Expand All @@ -206,3 +210,4 @@ New features don't ship without tests. Regressions are caught before they merge.
- Don't use `pop_front()` on arrays in hot paths — use index + slice
- Don't add error handling in individual tools — `GodotClient.send()` raises on errors
- Don't use Python-style `"""docstrings"""` in GDScript — use `##` comments
- Don't forget the `overwrite` parameter on `animation_create` / `animation_create_simple` — without it, creating an animation with the same name errors instead of replacing
14 changes: 14 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ test_run suite=scene # run one suite
test_results_get # review last results
```

### CI regression range helper

When CI starts failing, identify the regression window (last green → first red):

```bash
script/ci-find-regression-range hi-godot/godot-ai ci.yml main
```

If your local clone has a valid `origin` GitHub remote, you can omit `owner/repo`:

```bash
script/ci-find-regression-range
```

## Dev Server with Auto-Reload

For Python-side changes without restarting Godot:
Expand Down
12 changes: 6 additions & 6 deletions docs/implementation-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Historical bootstrap material, architecture detail, packaging mechanics, go/no-g
- [x] Runtime feedback loop: `project.run`/`project.stop`, `editor.screenshot`, `performance.get_monitors`, `logs.clear`
- [ ] Runtime iteration loop is complete enough for AI-driven feel tuning
- [ ] Release/install path is complete enough for new users
- [~] Polished game-production extensions have started — `ui_*` (anchor presets, `ui_build_layout` composer), `theme_*` (color/constant/font-size/stylebox_flat/apply), and `animation_*` (AnimationPlayer + `animation_create_simple` composer) shipped; `camera_*`, `audio_*`, and animation preset helpers still pending
- [~] Polished game-production extensions have started — `ui_*` (anchor presets, `ui_build_layout` composer, `theme_override_*` pseudo-properties), `theme_*` (color/constant/font-size/stylebox_flat with per-side overrides/apply), and `animation_*` (AnimationPlayer + `animation_create_simple` composer + delete/validate + overwrite support) shipped; `camera_*`, `audio_*`, and animation preset helpers still pending

## What This Plan Optimizes For

Expand Down Expand Up @@ -57,7 +57,7 @@ Historical bootstrap material, architecture detail, packaging mechanics, go/no-g
### High-Leverage Authoring

- [x] `batch.execute` with stop-on-first-error semantics and optional grouped undo
- [x] `node.rename` with sibling-collision validation and char-safety checks (NodePath/script references in OTHER nodes are not auto-updated — documented in the tool)
- [x] `node.rename` with sibling-collision validation and char-safety checks (NodePath/script references in OTHER nodes are not auto-updated — documented in the tool). Now also allows renaming the scene root node.
- [x] complex `node.set_property` (`Resource` via res:// path, `NodePath`, `Array`, `Dictionary`, `StringName`)
- [x] `script.patch` shipped — anchor-based `old_text` → `new_text` replace with ambiguity detection and optional `replace_all`

Expand All @@ -80,7 +80,7 @@ Historical bootstrap material, architecture detail, packaging mechanics, go/no-g
- [x] batch execution is shipped with a clear contract
- [x] multi-instance routing works in practice
- [x] `script.patch` decision is made (shipped: anchor-based replace)
- [x] test coverage and smoke coverage increase where the new runtime loop needs it (375 Python + 312 GDScript = 687 total)
- [x] test coverage and smoke coverage increase where the new runtime loop needs it (387 Python + 333 GDScript = 720 total)

---

Expand All @@ -92,7 +92,7 @@ See [Packaging & Distribution](packaging-distribution.md) for full detail. The s
- [ ] PyPI / `uvx` path works reliably
- [ ] desktop binary path is real, not aspirational
- [~] plugin is downloadable from the Godot AssetLib — release ZIP workflow ships `godot-ai-plugin.zip` via GitHub Releases; AssetLib submission in progress; dock has self-update check
- [x] CI covers Python tests, Godot-side tests, and release-smoke install paths (3 OS × 2 Python + 3 OS Godot + release-smoke)
- [x] CI covers Python tests, Godot-side tests, and release-smoke install paths (3 OS × 2 Python + 3 OS Godot + release-smoke). Linux CI uses `chickensoft-games/setup-godot` on `ubuntu-latest`. GDScript parse validation (`ci-check-gdscript`) runs before tests. Step timeouts prevent hangs.
- [x] bump-and-release workflow — `gh workflow run bump-and-release.yml -f bump=patch/minor/major` bumps versions, commits, tags, and triggers release build
- [ ] compatibility guidance is published and maintained
- [ ] a new user can get from zero to working in under 10 minutes
Expand Down Expand Up @@ -132,9 +132,9 @@ These are not the next things to do blindly. They are the extensions that matter
- `camera.*` for follow, bounds, zoom, and screen shake
- `resource.create` / `resource.save` / `resource.instantiate`
- `scene.instantiate` and `scene.inherit`
- [ ] critical path for reusable `button.tscn` / `enemy.tscn` instanced into many parent scenes — the piece that turns the UI composer and node_create flows into "real Godot project structure" instead of one-shot scene builds
- [~] `node_create` now supports a `scene_path` parameter for instancing a `.tscn` as a child node. This covers the basic "instance a prefab" use case. Dedicated `scene.instantiate` (with transform overrides) and `scene.inherit` (inherited scenes) are still pending for full reusable-scene workflows.
- `animation_player.*` / `animation_tree.*`
- [~] AnimationPlayer scaffolding shipped (`animation_player_create`, `animation_create`, `animation_add_property_track`, `animation_add_method_track`, `animation_set_autoplay`, `animation_play`, `animation_stop`, `animation_list`, `animation_get`, `animation_create_simple` composer)
- [~] AnimationPlayer scaffolding shipped (`animation_player_create`, `animation_create`, `animation_add_property_track`, `animation_add_method_track`, `animation_set_autoplay`, `animation_play`, `animation_stop`, `animation_list`, `animation_get`, `animation_create_simple` composer, `animation_delete`, `animation_validate`). `animation_create` and `animation_create_simple` support `overwrite` parameter for re-creating animations in place.
- [ ] **Preset helpers** — `animation_preset_fade`, `animation_preset_slide_in`, `animation_preset_shake`, `animation_preset_pulse_loop`. Thin wrappers over `animation_create_simple` that bake in the right transition / loop_mode / two-keyframe shape for each effect. Cuts a "fade in this Panel" from a 6-line tween spec to one call.
- [ ] **Bezier and audio tracks** — `animation_add_bezier_track` (for hand-tuned curves where keyframe interpolation isn't enough) and `animation_add_audio_track` (timed AudioStreamPlayer cues; needs the audio resource handler first).
- [ ] **`animation_tree.*`** — state-machine and blend-tree authoring for character locomotion (idle ↔ walk ↔ run blends, attack one-shots). Larger surface; depends on the AnimationPlayer being solid first.
Expand Down
16 changes: 12 additions & 4 deletions docs/testing-strategy.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Godot AI — Testing Strategy

*Updated 2026-04-14*
*Updated 2026-04-16*

This document defines how Godot AI should prove that new capability is real, stable, and safe to extend.

Expand Down Expand Up @@ -99,9 +99,17 @@ If a tool has undo semantics, readiness constraints, or cross-session behavior,

The CI stack should exercise at least three tiers:

- Python unit and integration tests
- Godot-side editor test suites
- release-surface smoke, especially install and packaging paths once distribution work is active
- Python unit and integration tests (3 OS x 2 Python versions)
- Godot-side editor test suites (3 OS via `chickensoft-games/setup-godot@v2` on GitHub Actions runners)
- release-surface smoke, especially install and packaging paths once distribution work is active (3 OS)

### CI hardening measures

- **GDScript validation**: `script/ci-check-gdscript` runs after `--import` and before the editor launches. It scans the import log for `SCRIPT ERROR` / `Parse Error` lines and fails the build immediately if any GDScript file has syntax errors. This catches broken scripts before the test runner starts.
- **Step timeouts**: test and smoke steps have `timeout-minutes` set to prevent CI hangs from frozen Godot processes.
- **Filesystem scan settling**: `script/ci-godot-tests` includes a short sleep after editor startup so the filesystem scan completes and test discovery finds all suites.
- **Resilient test discovery**: `test_handler.gd` catches per-file load errors during `_discover_suites()`. A broken test file does not prevent the rest of the suite from running; errors are reported in the response alongside successful results.
- **Regression diagnostics**: `script/ci-find-regression-range` helps identify which commits introduced a CI regression by binary-searching recent history.

This should stay aligned with the release work in [packaging-distribution.md](packaging-distribution.md).

Expand Down
4 changes: 2 additions & 2 deletions docs/tool-taxonomy.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Godot AI — Tool Taxonomy

*Updated 2026-04-14*
*Updated 2026-04-16*

This document describes the intended Godot-native tool surface.

Expand Down Expand Up @@ -157,7 +157,7 @@ These are the next layers once the core runtime loop is dependable.

- `ui.*` for HUDs, menus, upgrade screens, theme/layout work
- `camera.*` for follow, bounds, zoom, shake, and capture helpers
- `animation_*` — AnimationPlayer authoring shipped (player + animation creation, property/method tracks, autoplay, dev-time play/stop, list/get, `animation_create_simple` composer). Auto-attaches a default `AnimationLibrary` on first write. Works for 2D, 3D, and UI; `animation_tree.*`, bezier/audio tracks, preset helpers, and 3D material-fade coercion are tracked as follow-ups in `implementation-plan.md`.
- `animation_*` — AnimationPlayer authoring shipped (player + animation creation, property/method tracks, autoplay, dev-time play/stop, list/get, `animation_create_simple` composer, `animation_delete`, `animation_validate`). `animation_create` and `animation_create_simple` support an `overwrite` parameter to replace existing animations in place. Auto-attaches a default `AnimationLibrary` on first write. Works for 2D, 3D, and UI; `animation_tree.*`, bezier/audio tracks, preset helpers, and 3D material-fade coercion are tracked as follow-ups in `implementation-plan.md`.
- `audio.*`

These are the tools that move the project from "functional prototype" toward "readable and polished prototype."
Expand Down
Loading
Loading