skill · git:20261002.59c97fd · 2026-10-02 · sha256 3154d92f645f26b2
skill git:20261002.59c97fdA
Immutable. This exact content never changes and is served at /api/v1/blob/3154d92f645f26b2.
---
name: gda
description: Use the gda CLI to build, inspect, validate, and export Godot projects without opening the editor, or to inspect and control a running game through gda-daemon. Use when an agent builds or modifies a Godot game, or the user asks for gda or Godot automation.
---
# gda
`gda` is an agent-facing CLI for Godot. Use headless operations to create and
inspect scenes, nodes, scripts, resources, shaders, themes, and project settings;
validate or run scripts and scenes; and export artifacts. Use live operations to
inspect a running game, inject input, capture the viewport, and read diagnostics
or performance data. Headless operations support Godot 4.4+ on all platforms.
Live operations use `gda-daemon` with Godot 4.6+ on macOS or Linux.
## Configure and discover
- Set `GDA_GODOT` to the Godot executable, or pass `--godot PATH`.
- Pass `--project DIR`, set `GDA_PROJECT`, or run inside the project directory.
The project must contain `project.godot`. Use an explicit project when a
script or asset depends on `res://` or project autoloads.
- Keep the same engine and project for the related calls of one workflow.
- Use `gda --version --json` to identify the installed CLI and its source in a
long session. Use `gda info --json` to check the Godot engine.
- Use `gda --help` for command groups, `gda <group> --help` for a group's
commands, and `gda <group> <command> --help` for usage. Use
`gda <group> <command> --schema` for that command's arguments, JSON result,
and errors. `gda schema` describes the full installed surface. Consult
these sources for exact options and fields instead of assuming this skill is a
command catalog.
Pass `--json` on operations, for example
`gda scene validate res://main.tscn --project game --json`. Read the one JSON
object on stdout; engine output goes to stderr. On failure, branch on the
structured `error.code` and inspect any `evidence`; do not parse
`error.message`. An exit code of zero does not always mean the requested check
passed:
| Operation | Check in the successful result |
| --- | --- |
| `scene validate`, `script validate` | `valid`; `false` is not a pass. |
| `scene preflight` | `status` and `started`; static validation does not boot the target scene. |
| `script run`, `export smoke` | Child `exit_status` and diagnostics; use `--strict` when non-zero status or a recognized shutdown leak must fail the command. |
| `game set` | `verified`; `false` means the observed read-back differs. Follow up with `game get` or a domain-specific observation when the side effect matters. |
For precision-sensitive values, inspect the result or read-back. Godot can
change a decimal value while parsing it; `gda` refuses values that the parser
would destroy. Consult the relevant command schema for accepted value forms
and limits.
## Headless workflow
With no project yet, run `gda project create DIR --name NAME --json` first.
DIR must be a new directory in an existing parent, or an empty directory;
dot-prefixed entries such as `.git` do not count. The new `project.godot` sets
only the name, so set the main scene and other settings with `project set`.
Then use DIR as the project.
Run `gda project scan --json` on a fresh checkout or a project the editor
never opened, and after you add, rename or delete a `class_name` script: the
engine finds a project `class_name` only through the index a scan writes, and
gda does not check whether that index is current.
1. Create or edit a scene with `scene`, `node`, `script`, and `resource`
commands. Use `script attach` to bind a script to a node; generic
`node set --property script` is refused. Create assets used by
`preload("res://...")` before you attach the script. Supply a `res://`
Resource path when assigning a Resource-typed property.
2. Run `scene validate` and `script validate` for the changed files. Check
their `valid` verdicts. `scene validate` checks dependencies and scripts,
but does not prove that the target scene starts.
3. Run `scene preflight` to boot the target scene for a bounded interval.
Check its startup verdict and diagnostics. Use `script run` for a
project test script; inspect the child status even when `gda` succeeds.
4. Use `export list` to select a preset. Optionally inspect it with
`export get`, then run `export run`. If needed, use `export smoke` on the
built artifact. A smoke run proves only what that bounded process
observed; it does not prove that the game completed its intended task.
When `scene create` uses a `Control-derived` root from `--root-type`, it writes
zero anchors and zero offsets. A root with no intrinsic minimum size renders as
a zero-size rect; a root with an intrinsic minimum size renders at that minimum
instead, not at viewport size. Set `anchor_right` and `anchor_bottom` to `1`
with `node set`, then confirm the layout with `game rect` in an Engine session.
For a `Control` inside a `Container`, change minimum size, size flags, or
the container layout instead of offsets. A root from `--inherits` keeps the
base's anchors and offsets.
For a variant of a base scene, use `scene create PATH --inherits BASE`, not
`node add --instance`: the new scene's root is the base's root. In the variant,
override inherited nodes with `node set` and add its own nodes; edit or remove
inherited nodes in the base. `scene get` and `node list` show the variant's
composed tree and mark inherited nodes with `inherited_from`; an inherited
instance whose scene is missing carries no mark.
`export run` checks the export templates itself before it exports, and
refuses with `export_templates_missing` when they are not available.
`--mode pack` needs no templates. `export get` is optional inspection. Give
it the same engine, project, preset, and data root (`--user-data-root`) as
`export run`:
- `templates_installed: false` means that the `templates_version` directory
is missing under `templates_root`. Then a non-null `templates_root_host`
means that the host has these templates but the data root hides them; a
null value means that they are not installed.
- `templates_installed: true` means only that the version directory exists.
It does not prove that the preset's platform can export.
To recover, put matching templates, including the files for the preset's
platform, under `templates_root`. With a data root, you can instead select
another data root, or run without one where the environment permits.
Template readiness does not prove that an export succeeds or that the
Export artifact runs.
### Data root in restricted environments
A headless run sends the engine log to a private temporary file. Godot can
still write to its data directory during engine initialization, including
for a validation. If that directory is not writable, select a writable data
root. The global option comes before the command group:
```bash
gda --user-data-root /writable/gda-data scene validate res://main.tscn --project game --json
```
The data root moves the engine data directory (`user://` and the export
templates) and the engine log. The editor configuration and cache locations
depend on the platform and can stay in place; on Linux they do not move.
Judge the impact from the operation verdict and the engine diagnostics. A
directory warning does not by itself make a successful operation invalid.
`script run` reports `engine_data_path` and `log_file`; inspect them before
you treat a failed `user://` save as a game defect.
- Use one data root for the engine-launching headless operations of one
restricted workflow.
- Use a separate data root for each invocation that runs at the same time.
Each launch truncates the one engine log under a data root.
- Do not set the data root (`GDA_USER_DATA_ROOT`) for unrelated commands.
- Do not give `export smoke` a data root unless it refuses with
`user_data_unwritable`. Without one, each smoke run creates a private data
root, so no `user://` state carries from one smoke run to the next.
- `--user-data-root` does not reconfigure an Engine session that the daemon
manages.
- A successful validation under a data root does not prove that the export
templates are available there.
## Live workflow
A live run needs a main scene. Set `application/run/main_scene` or pass a
valid `--scene res://...` to `daemon start`. An explicit `res://` scene
also bypasses an unresolved `uid://` main scene.
1. Start the daemon with `gda daemon start --project game --json`. This can
install the gda harness and update `project.godot`; inspect the change.
The Engine session starts when a live operation needs it.
2. Run `gda daemon wait-ready --project game --json` before read-only
diagnostics. Inspect `clean_start` and `startup_diagnostics`. A serving
session can still have a scene script that failed to compile. A null
`clean_start` means the startup log was unavailable, not that it was clean.
3. Discover runtime node paths with a bounded `game tree --max-depth N` or
`game find` query. Narrow with `--root`; a truncated result or a bounded
empty search does not prove absence. Then use `game get`, `game rect`,
or other live commands on the exact path.
4. Use `input` for interaction, `diag errors` and `logger tail` for
diagnostics, and `perf` for measurements. Start the daemon with
`--windowed` if you need `screen capture`; a rendered capture requires
an available desktop session.
5. Stop with `gda daemon stop`. This stops the daemon and its Engine
session, but the gda harness stays installed. To remove the gda harness
installation, run `gda daemon uninstall` after `daemon stop`. A
disposable project copy is an optional way to keep the harness out of
the source project. You do not need to uninstall before `gda export run`:
it removes the harness for the export and restores the project's prior
harness state. Other export routes do not remove it.
For a windowed launch, `live_windowed_unavailable` means skip rendered
checks in this environment. `live_windowed_permission_denied` means retry
outside the restriction before deciding whether the host can render.
After updating gda, stop and start the daemon before using live commands.
Repeating `daemon start` updates the installed harness but does not reload
the code in the running game.
A `live_timeout` discards the Engine session. The next live operation starts
a new game, so do not assume that earlier runtime changes still exist.
Input has two injection routes, reported as `injection_route`. The default
`input action` uses `action_state` to change the polled action state; it
does not send an event to `_input`, `_unhandled_input`, or `_gui_input`.
A key or mouse command uses `viewport_event` to send an event through the
viewport. Use `input action --as-event` only when an event handler must
receive that action rather than the mapped key:
| Injection | `Input.is_action_pressed` | `_input` / `_unhandled_input` | `_gui_input` |
| --- | --- | --- | --- |
| `input action` | yes | no | no |
| `input action --as-event` | no | yes | yes (focused Control) |
| `input key` of the mapped key | no | yes | yes (focused Control) |
The table describes eligible delivery under normal propagation and
consumption rules, not proof that a handler ran. For UI activation, use
`input mouse-click` or `input tap` to send a complete press/release
gesture. A default `BaseButton` activates on the release; `action_mode` or
subclasses such as `MenuButton`/`OptionButton` can activate on press.
To verify an interaction:
1. Find out whether the game polls input state or handles input events.
Select the route from the table.
2. Find the runtime target with a bounded `game tree` or `game find` query.
3. Inject the matching input.
4. Read the expected game state, for example with `game get`. This read is
the proof. An injected gesture alone does not prove that the intended
handler or gameplay action ran.
`game rect` reports coordinates relative to the Control's canvas. A
transformed `CanvasLayer` or an active `Camera2D` can make them differ from
click coordinates. Do not take click coordinates from the pixels of a
viewport capture.
`script run` runs your script as written. It does not add coordinate
conversion, gesture completion, or event timing to the script's own
`push_input()` calls. Your tests must establish those details and the
actual UI layout. Input that a script sends is separate from input that
gda injects with `input` commands into an Engine session. See Godot's
[InputEvent guide](https://docs.godotengine.org/en/4.6/tutorials/inputs/inputevent.html).
A `screen capture` is evidence only when it shows the intended state:
- Use the `--await-*` predicate to capture when the relevant state holds.
The predicate must represent the visible state. Text kept on a hidden
`Label` is not sufficient.
- Use `--await-events` to trigger a short-lived state and capture it in one
operation.
- Use `--settle-frames` when the game draws the state later. A settle moves
the capture later than the predicate's first match. The earlier state can
be gone by then.
- Inspect the image. When timing matters, also inspect the returned frame
counters and predicate evidence.
- Do not assume that one settle count works for every state. Process
frames are not a fixed wall-clock duration.
If the game needs structured records in `logger tail`, resolve the harness
by node path and check that the daemon launched the session. Do not refer to
the `GdaHarness` global in game code: a project or export without the harness
cannot parse that name.
```gdscript
var harness := get_node_or_null("/root/GdaHarness")
if harness != null and harness.is_daemon_launched():
harness.gda_log("info", "player spawned", {"hp": 100})
else:
print("player spawned")
```