gda 0.1.24__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
gda-0.1.24/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aigengame
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
gda-0.1.24/PKG-INFO ADDED
@@ -0,0 +1,643 @@
1
+ Metadata-Version: 2.4
2
+ Name: gda
3
+ Version: 0.1.24
4
+ Summary: An agent-facing Godot CLI with structured output
5
+ Keywords: godot,cli,agent,mcp,game-development
6
+ Author: haihong.qin
7
+ Author-email: haihong.qin <haihongqin@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Games/Entertainment
16
+ Classifier: Topic :: Software Development :: Build Tools
17
+ Requires-Dist: pydantic>=2.13.4
18
+ Requires-Dist: typer>=0.26.7
19
+ Requires-Dist: mcp>=1.12,<2 ; extra == 'mcp'
20
+ Requires-Python: >=3.13
21
+ Project-URL: Homepage, https://github.com/aigengame/godot-agent
22
+ Project-URL: Repository, https://github.com/aigengame/godot-agent
23
+ Project-URL: Issues, https://github.com/aigengame/godot-agent/issues
24
+ Project-URL: Changelog, https://github.com/aigengame/godot-agent/blob/main/CHANGELOG.md
25
+ Provides-Extra: mcp
26
+ Description-Content-Type: text/markdown
27
+
28
+ # godot-agent (`gda`)
29
+
30
+ ![godot-agent title image](assets/godot-agent-title.png)
31
+
32
+ > An agent-first **CLI and MCP server** that lets AI agents drive the [Godot Engine](https://godotengine.org) to build games — with **structured output** built for programmatic consumption.
33
+
34
+ [![Status](https://img.shields.io/badge/status-Phase%201%20headless%20surface%20complete-brightgreen?cacheSeconds=3600)](#project-status)
35
+ [![CI](https://github.com/aigengame/godot-agent/actions/workflows/ci.yml/badge.svg?branch=main&event=push)](https://github.com/aigengame/godot-agent/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush)
36
+ [![Python](https://img.shields.io/badge/python-3.13%2B-blue)](https://www.python.org/)
37
+ [![Godot](https://img.shields.io/badge/godot-4.4%2B%20(tested%204.6)-478CBF)](https://godotengine.org)
38
+ [![Package manager](https://img.shields.io/badge/packaging-uv-DE5FE9)](https://github.com/astral-sh/uv)
39
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
40
+
41
+ `godot-agent` lets AI agents drive the Godot engine through **structured, machine-readable
42
+ operations** rather than raw logs: an agent issues an operation and gets back a single clean
43
+ result it can act on, not prose it has to scrape.
44
+
45
+ It is designed as three layers: **`gda`**, the agent-facing CLI that exposes Godot operations
46
+ with structured `--json` output and self-describing schemas; **`gda-mcp`**, a thin
47
+ [Model Context Protocol](https://modelcontextprotocol.io) server that turns those same
48
+ capabilities into MCP tools, derived mechanically from `gda`'s schemas; and **`gda-daemon`**, a
49
+ long-lived process holding a persistent connection to a running engine to serve *live operations*
50
+ that a one-shot headless process cannot. `gda` lands first as a standalone headless CLI (Phase 1);
51
+ live operations follow through `gda-daemon` (Phase 2). See [Architecture](#architecture-at-a-glance)
52
+ for the full picture.
53
+
54
+ ---
55
+
56
+ ## Why `gda`?
57
+
58
+ - **🤖 Agent-first, structured output.** Every command supports `--json` and emits exactly one
59
+ result object on stdout. Engine noise and diagnostics are routed to stderr, so an agent never
60
+ has to scrape prose. See the [structured-output contract](#the-structured-output-contract).
61
+ - **📐 Model-driven & self-describing.** Each command's input and output are defined as typed
62
+ models that back both `--json` and a machine-readable `--schema` (a JSON Schema contract). Carrying
63
+ a valid `--schema` is a hard, no-exception merge gate on every command — so an MCP adapter can
64
+ generate tool definitions mechanically instead of hand-maintaining them.
65
+ *(See [ADR-0004](docs/adr/0004-schema-flag-self-description.md).)*
66
+ - **🧩 Godot-native command surface.** Commands are grouped by Godot domain object
67
+ (`gda scene create`, `gda node add`, …) with a small, orthogonal verb vocabulary — zero learning
68
+ cost if you already know Godot. *(See [ADR-0005](docs/adr/0005-cli-command-taxonomy.md).)*
69
+ - **📦 Standalone, no service required.** The first delivery fulfils *headless operations* by
70
+ spawning one-shot `godot --headless` processes — nothing to install in the editor, no daemon to
71
+ run. Live, stateful operations arrive later behind the same CLI. *(See [ADR-0001](docs/adr/0001-godot-integration-mechanism.md).)*
72
+ - **🛡️ Fails loudly, not silently.** A missing or hung engine is bounded by a timeout and mapped
73
+ to a non-zero exit with a clear diagnostic — never an indefinite hang or a raw traceback.
74
+
75
+ ---
76
+
77
+ ## Project status
78
+
79
+ > **`gda`'s Phase-1 headless command surface is feature-complete.** The architecture and contracts
80
+ > are settled (see [`CONTEXT.md`](CONTEXT.md) and [`docs/adr/`](docs/adr/)), and every headless
81
+ > domain command group designed in
82
+ > [PRD #17](https://github.com/aigengame/godot-agent/issues/17) now ships end-to-end against a real
83
+ > engine. `gda` is still pre-1.0 and not yet published to a package index
84
+ > ([#207](https://github.com/aigengame/godot-agent/issues/207)); **`gda-mcp` now ships** alongside
85
+ > the CLI, and the next milestone is Phase 2 live operations.
86
+
87
+ **Working today — the full headless command surface**
88
+
89
+ - ✅ **Eight command groups, fulfilled headlessly:** `scene`, `node`, `script`, `project`,
90
+ `resource`, `export`, `shader`, and `theme`, plus the `info` meta command — and the `project`
91
+ static-analysis reads (`find-references`, `dependencies`, `find-unused-resources`, `statistics`).
92
+ See the [command reference](#command-reference) for every command
93
+ ([ADR-0005](docs/adr/0005-cli-command-taxonomy.md)).
94
+ - ✅ **The contract every command carries:** structured `--json` output, model-derived `--schema`
95
+ self-description as a hard merge gate
96
+ ([ADR-0004](docs/adr/0004-schema-flag-self-description.md)), and structured
97
+ `{"error": {category, code, …}}` failures with category-distinguishing
98
+ [exit codes](#exit-codes-the-cli-abi).
99
+ - ✅ **The engine plumbing underneath:** Godot binary resolution (flag / env var / default), the
100
+ bounded one-shot `godot --headless` runner with its sentinel output contract
101
+ ([ADR-0002](docs/adr/0002-headless-structured-output-contract.md)), command-agnostic failure
102
+ classification, and project-context / `res://` path resolution
103
+ ([ADR-0006](docs/adr/0006-project-context-and-path-resolution.md)).
104
+
105
+ **Also working today — the MCP adapter**
106
+
107
+ - ✅ `gda-mcp`, a thin [Model Context Protocol](https://modelcontextprotocol.io) stdio server that
108
+ exposes the whole `gda` surface as MCP tools, generated mechanically from `--schema`. Register it
109
+ with your agent using the [registration recipes](docs/gda-mcp-registration.md).
110
+
111
+ **On the roadmap** (designed, not yet implemented)
112
+
113
+ - 🔜 `gda-daemon` for *live operations* against a running engine (Phase 2): live scene tree,
114
+ runtime inspection, input simulation, `scene play`/`stop`, screenshots.
115
+
116
+ **Out of scope for now**
117
+
118
+ - **C# / .NET scripts.** The `script` group operates on GDScript (`.gd`) only; whether and how to
119
+ support the Godot .NET build and `.cs` scripts is deferred
120
+ ([#124](https://github.com/aigengame/godot-agent/issues/124)).
121
+ - **The deferred catalog groups** — animation, tilemap, physics, audio, particles, 3D scene,
122
+ navigation, Android deploy — each needs its own slice-level design before becoming a commitment.
123
+
124
+ The active backlog and per-command status live in the
125
+ [issue tracker](https://github.com/aigengame/godot-agent/issues) — the headless increment is
126
+ grouped under the [**Phase 1 — headless operations** milestone](https://github.com/aigengame/godot-agent/milestone/1).
127
+ The [command catalog](docs/command-catalog.md) maps the whole command surface (a non-binding
128
+ *feature map*, not a status tracker); this section deliberately duplicates neither. See also the
129
+ [roadmap](#roadmap).
130
+
131
+ ---
132
+
133
+ ## Architecture at a glance
134
+
135
+ `gda` is delivered bottom-up as three components and in two capability phases:
136
+
137
+ | Component | Role | Phase |
138
+ | ------------- | -------------------------------------------------------------------------------------- | ----- |
139
+ | **`gda`** | The agent-facing Godot CLI — the bottom layer that exposes Godot with structured output | 1 |
140
+ | **`gda-mcp`** | A thin MCP adapter that exposes `gda`'s capabilities as MCP tools, derived from `--schema` | 1+ |
141
+ | **`gda-daemon`** | A long-lived process holding a persistent connection to a running engine for *live operations* | 2 |
142
+
143
+ - **Headless operations** need no pre-existing engine state and are fulfilled by a one-shot
144
+ `godot --headless` process (e.g. report version, create a scene, export). This is the basis of
145
+ **Phase 1**.
146
+ - **Live operations** require an already-running engine (live scene tree, runtime inspection,
147
+ UndoRedo, input simulation) and are served by `gda-daemon` in **Phase 2**.
148
+
149
+ The vocabulary above is defined precisely in [`CONTEXT.md`](CONTEXT.md); the decisions behind it live
150
+ in [`docs/adr/`](docs/adr/).
151
+
152
+ ---
153
+
154
+ ## Requirements
155
+
156
+ - **[uv](https://github.com/astral-sh/uv)** — the Python toolchain/package manager used by this project.
157
+ - **Python 3.13+** (uv can provision this for you).
158
+ - **Godot 4.4+** — `gda` targets Godot 4.x with a minimum of 4.4; 4.6 is the tested baseline.
159
+ 3.x is not supported. *(See [ADR-0003](docs/adr/0003-target-godot-version.md).)*
160
+
161
+ ---
162
+
163
+ ## Installation
164
+
165
+ `gda` is not yet published to a package index; install it from source with `uv`.
166
+
167
+ ```bash
168
+ git clone https://github.com/aigengame/godot-agent.git
169
+ cd godot-agent
170
+ uv sync # create the environment and install dependencies
171
+ uv run gda --help
172
+ ```
173
+
174
+ To install `gda` as a standalone CLI on your `PATH`:
175
+
176
+ ```bash
177
+ uv tool install .
178
+ gda --help
179
+ ```
180
+
181
+ ### MCP server (`gda-mcp`)
182
+
183
+ `gda` ships a stdio [MCP](https://modelcontextprotocol.io) server behind an optional `[mcp]` extra,
184
+ so any MCP-speaking agent can drive Godot through it. Try it with no install:
185
+
186
+ ```bash
187
+ uvx --from "gda[mcp] @ git+https://github.com/aigengame/godot-agent" gda-mcp
188
+ ```
189
+
190
+ Register it by dropping the matching config in place. `gda-mcp` picks your Godot project from
191
+ `GDA_PROJECT` if set, otherwise the client's workspace `roots`, otherwise the working directory
192
+ (ADR-0014). An explicitly set `GDA_PROJECT` that is not a valid project is reported as an error, not
193
+ silently replaced.
194
+
195
+ **Claude Code** — project scope, `.mcp.json` at the repo root (auto-detects the project via `roots`):
196
+
197
+ ```json
198
+ {
199
+ "mcpServers": {
200
+ "gda-mcp": {
201
+ "command": "uvx",
202
+ "args": ["--from", "gda[mcp] @ git+https://github.com/aigengame/godot-agent", "gda-mcp"]
203
+ }
204
+ }
205
+ }
206
+ ```
207
+
208
+ User scope (every project) — the CLI, which writes `~/.claude.json`:
209
+
210
+ ```bash
211
+ claude mcp add --scope user gda-mcp -- \
212
+ uvx --from "gda[mcp] @ git+https://github.com/aigengame/godot-agent" gda-mcp
213
+ ```
214
+
215
+ **Codex** — project scope, `.codex/config.toml` at the repo root (the project must be trusted):
216
+
217
+ ```toml
218
+ [mcp_servers.gda-mcp]
219
+ command = "uvx"
220
+ args = ["--from", "gda[mcp] @ git+https://github.com/aigengame/godot-agent", "gda-mcp"]
221
+
222
+ [mcp_servers.gda-mcp.env]
223
+ GDA_PROJECT = "/absolute/path/to/your/godot/project"
224
+ ```
225
+
226
+ User scope (every project) — the same table in `~/.codex/config.toml`, or add it with the CLI
227
+ (Codex has no workspace variable, so `GDA_PROJECT` stays an absolute path):
228
+
229
+ ```bash
230
+ codex mcp add gda-mcp --env GDA_PROJECT=/absolute/path/to/your/godot/project -- \
231
+ uvx --from "gda[mcp] @ git+https://github.com/aigengame/godot-agent" gda-mcp
232
+ ```
233
+
234
+ **Cursor** — project scope, `.cursor/mcp.json` at the repo root (`${workspaceFolder}` tracks the open
235
+ project):
236
+
237
+ ```json
238
+ {
239
+ "mcpServers": {
240
+ "gda-mcp": {
241
+ "type": "stdio",
242
+ "command": "uvx",
243
+ "args": ["--from", "gda[mcp] @ git+https://github.com/aigengame/godot-agent", "gda-mcp"],
244
+ "env": {
245
+ "GDA_PROJECT": "${workspaceFolder}",
246
+ "PATH": "/opt/homebrew/bin:/usr/local/bin:${userHome}/.local/bin:${env:PATH}"
247
+ }
248
+ }
249
+ }
250
+ }
251
+ ```
252
+
253
+ User scope (every project) — the same config in `~/.cursor/mcp.json`, but set `GDA_PROJECT` to an
254
+ absolute path (`${workspaceFolder}` is only reliable in the project-level file). Cursor has no
255
+ `mcp add` shell command — register via the JSON above or the Settings → MCP UI.
256
+
257
+ > Cursor and Claude Desktop are GUI-launched with a minimal `PATH`, so a bare `uvx` may not resolve —
258
+ > the Cursor snippet above repairs it in `env`; if `uvx` is still not found (or for Claude Desktop),
259
+ > use an absolute path (`which uvx`) for `command`. Full recipes — user vs project scope, Claude
260
+ > Desktop, and per-agent project pinning — are in the
261
+ > [registration recipes](docs/gda-mcp-registration.md). Once `gda` is on PyPI
262
+ > ([#207](https://github.com/aigengame/godot-agent/issues/207)), the `@ git+…` part drops to just
263
+ > `"gda[mcp]"`.
264
+
265
+ ---
266
+
267
+ ## Quick start
268
+
269
+ Point `gda` at your Godot binary and ask for the engine version:
270
+
271
+ ```bash
272
+ # Use the GDA_GODOT environment variable (or the --godot flag, or the default path)
273
+ export GDA_GODOT="/path/to/Godot"
274
+
275
+ gda info --json
276
+ ```
277
+
278
+ ```json
279
+ {"major":4,"minor":6,"patch":3,"hex":263683,"status":"stable","build":"official","hash":"7d41c59c457bd5a245092b4e7eb2d833e3b3f8c3","string":"4.6.3-stable (official)","timestamp":0}
280
+ ```
281
+
282
+ Without `--json`, `gda info` prints the human-readable version string (`4.6.3-stable (official)`).
283
+ All engine and script diagnostics go to **stderr**, so stdout is always clean JSON you can pipe:
284
+
285
+ ```bash
286
+ gda info --json | jq .major # → 4
287
+ ```
288
+
289
+ Create a scene headlessly and read its structured tree back:
290
+
291
+ ```bash
292
+ gda scene create game/main.tscn --root-type Node2D --json
293
+ # {"path":"game/main.tscn","root_name":"main","root_type":"Node2D"}
294
+
295
+ gda scene get game/main.tscn --json
296
+ # {"path":"game/main.tscn","root":{"name":"main","type":"Node2D","children":[]}}
297
+ ```
298
+
299
+ Add a node into that scene and verify it landed — nodes are addressed by their path relative to
300
+ the scene root (`.` is the root itself):
301
+
302
+ ```bash
303
+ gda node add game/main.tscn --type Sprite2D --name Hero --json
304
+ # {"scene_path":"game/main.tscn","path":"Hero","name":"Hero","type":"Sprite2D","script_class":null}
305
+
306
+ gda node list game/main.tscn --json
307
+ # {"scene_path":"game/main.tscn","root":{"name":"main","type":"Node2D","path":".","children":[{"name":"Hero","type":"Sprite2D","path":"Hero","children":[]}]}}
308
+ ```
309
+
310
+ Read a node's properties as typed JSON, set one (the CLI value is coerced to the property's declared
311
+ Godot type), and verify the change round-trips via `get`:
312
+
313
+ ```bash
314
+ gda node set game/main.tscn --node Hero --property position --value 10,20 --json
315
+ # {"scene_path":"game/main.tscn","path":"Hero","property":"position","type":"Vector2","value":[10.0,20.0]}
316
+
317
+ gda node get game/main.tscn --node Hero --json
318
+ # {"scene_path":"game/main.tscn","path":"Hero","name":"Hero","type":"Sprite2D","properties":[…,{"name":"position","type":"Vector2","value":[10.0,20.0]},…]}
319
+ ```
320
+
321
+ Enumerate a project's scenes, then delete one — `scene list` walks the project's `res://` tree, so it
322
+ needs a project context (`--project`, `$GDA_PROJECT`, or a cwd that is a project):
323
+
324
+ ```bash
325
+ gda scene list --project game --json
326
+ # {"scenes":[{"path":"res://main.tscn","root_name":"main","root_type":"Node2D"}]}
327
+
328
+ gda scene delete res://main.tscn --project game --json
329
+ # {"path":"res://main.tscn","root_name":"main","root_type":"Node2D"}
330
+ ```
331
+
332
+ ---
333
+
334
+ ## Usage
335
+
336
+ ### Command surface
337
+
338
+ `gda` commands are **grouped by Godot domain object** and use a small, consistent verb vocabulary,
339
+ so the same verb means the same thing in every group:
340
+
341
+ ```
342
+ gda <group> <command> [options] # domain commands, e.g. gda scene create
343
+ gda <meta-command> [options] # meta commands about gda/the engine, e.g. gda info
344
+ ```
345
+
346
+ | Verb | Meaning |
347
+ | ------------------------ | ---------------------------------------------------------------- |
348
+ | `create` / `delete` | Make / remove a **standalone** entity (scene, script, resource) |
349
+ | `add` / `remove` | Add / remove a **sub-entity** within a container (node → scene) |
350
+ | `get` / `list` | Read one entity / enumerate many |
351
+ | `set` | Mutate a property |
352
+ | domain verbs | `play`, `run`, `export`, `import`, … kept with their natural meaning |
353
+
354
+ > The taxonomy and naming rules are specified in
355
+ > [ADR-0005](docs/adr/0005-cli-command-taxonomy.md). `gda --help` (and `gda <group> --help`) is the
356
+ > authoritative list of what is installed; the table below mirrors the shipped Phase-1 surface.
357
+
358
+ ### Command reference
359
+
360
+ Every command supports `--json` and `--schema`; commands that read or mutate a `res://` path resolve
361
+ a [project context](#project-context), and mutating commands run that project's code
362
+ ([project code execution](#project-code-execution)). Run `gda <group> <command> --help` for full
363
+ flags.
364
+
365
+ **Meta** — about `gda` / the engine itself
366
+
367
+ | Command | What it does |
368
+ | ------- | ------------ |
369
+ | `gda info` | Report the Godot engine version info. |
370
+
371
+ **`scene`** — scene files (`.tscn`)
372
+
373
+ | Command | What it does |
374
+ | ------- | ------------ |
375
+ | `scene create` | Create a new `.tscn` with the given root node type. |
376
+ | `scene get` | Read a scene and report its structured node tree. |
377
+ | `scene list` | Enumerate the `.tscn` scenes in the resolved project. |
378
+ | `scene get-exports` | List the `@export` properties a scene's nodes' scripts declare. |
379
+ | `scene delete` | Delete a scene file and report what was removed. |
380
+
381
+ **`node`** — nodes within a scene file
382
+
383
+ | Command | What it does |
384
+ | ------- | ------------ |
385
+ | `node add` | Add a node under a parent (built-in type or `class_name` script). |
386
+ | `node get` | Read a node's properties (by node path) as typed JSON. |
387
+ | `node list` | List a scene's node tree with each node's path relative to the root. |
388
+ | `node set` | Set a node property, coercing the value to its declared Godot type. |
389
+ | `node remove` | Remove a node (and its subtree) by node path. |
390
+ | `node duplicate` | Duplicate a node (and its subtree) under its parent. |
391
+ | `node move` | Reparent a node (and its subtree) under a new parent. |
392
+ | `node connect-signal` | Wire a source node's signal to a target node's method. |
393
+ | `node disconnect-signal` | Unwire an existing signal→method connection. |
394
+
395
+ **`script`** — GDScript files (`.gd`)
396
+
397
+ | Command | What it does |
398
+ | ------- | ------------ |
399
+ | `script create` | Create a new `.gd` script from a template or verbatim `--content`. |
400
+ | `script get` | Read a script's source plus its `class_name` / `extends` metadata. |
401
+ | `script list` | Enumerate the `.gd` scripts in the resolved project. |
402
+ | `script set` | Edit a script via search-replace, line-range, or full overwrite. |
403
+ | `script delete` | Delete a script file and report what was removed. |
404
+ | `script attach` | Attach a `.gd` script to a node (by node path) in a scene. |
405
+ | `script validate` | Syntax/compile-check a `.gd` script. |
406
+
407
+ **`project`** — the project as a whole (settings, autoloads, static analysis)
408
+
409
+ | Command | What it does |
410
+ | ------- | ------------ |
411
+ | `project info` | Report project metadata (name, main scene, viewport, engine version). |
412
+ | `project get` | Read a single project setting by section/key as typed JSON. |
413
+ | `project set` | Set a project setting, coercing the value to its declared type. |
414
+ | `project add-autoload` | Register an autoload singleton (name → script/scene). |
415
+ | `project remove-autoload` | Unregister an autoload singleton by name. |
416
+ | `project find-references` | Find every project file that references a given resource. |
417
+ | `project dependencies` | Map each scene/resource to the resources it depends on. |
418
+ | `project find-unused-resources` | Find resource files that nothing references. |
419
+ | `project statistics` | Report the project's file/line counts, autoloads, and more. |
420
+
421
+ **`resource`** — resource files (`.tres`)
422
+
423
+ | Command | What it does |
424
+ | ------- | ------------ |
425
+ | `resource create` | Create a new `.tres` resource of the given type. |
426
+ | `resource get` | Read a `.tres` resource's properties as typed JSON. |
427
+ | `resource set` | Set a `.tres` property, coercing the value to its declared type. |
428
+ | `resource delete` | Delete a `.tres` resource file and report what was removed. |
429
+ | `resource uid` | Resolve a resource UID ↔ its `res://` path in both directions. |
430
+
431
+ **`export`** — export presets and artifacts
432
+
433
+ | Command | What it does |
434
+ | ------- | ------------ |
435
+ | `export list` | Enumerate the project's export presets (name, platform, …). |
436
+ | `export get` | Report one preset's details plus export-template install status. |
437
+ | `export run` | Export a named preset (`release` / `debug` / `pack`) to a destination. |
438
+
439
+ **`shader`** — shader files (`.gdshader`)
440
+
441
+ | Command | What it does |
442
+ | ------- | ------------ |
443
+ | `shader create` | Create a new `.gdshader` from a template or verbatim `--content`. |
444
+ | `shader get` | Read a shader's source plus its `shader_type`. |
445
+ | `shader set` | Edit a `.gdshader` via search-replace, line-range, or full overwrite. |
446
+
447
+ **`theme`** — theme resources (`.tres`)
448
+
449
+ | Command | What it does |
450
+ | ------- | ------------ |
451
+ | `theme create` | Create a new, loadable `.tres` Theme resource (no-clobber). |
452
+
453
+ ### Global flags
454
+
455
+ | Flag | Description |
456
+ | ---------- | ------------------------------------------------------------------- |
457
+ | `--json` | Emit the result as a single JSON object on stdout. Without it, commands print a concise human-readable rendering. |
458
+ | `--schema` | Emit the command's input/output JSON Schema contract (no Godot spawned). |
459
+ | `--godot` | Path to the Godot binary (overrides `$GDA_GODOT` and the default). |
460
+ | `--project` | Godot project directory for `res://` resolution (overrides `$GDA_PROJECT`; defaults to the current directory if it is a project). Domain commands only. Resolving a project runs that project's code — see [Project code execution](#project-code-execution). |
461
+ | `--help` | Show usage for `gda` or any command. |
462
+
463
+ ---
464
+
465
+ ## Configuration
466
+
467
+ `gda` resolves the Godot binary in this order (highest precedence first):
468
+
469
+ 1. The **`--godot <path>`** flag.
470
+ 2. The **`GDA_GODOT`** environment variable.
471
+ 3. A **default development path** — `~/Applications/Godot.app/Contents/MacOS/Godot` (macOS).
472
+ On other platforms, set `GDA_GODOT` or pass `--godot`.
473
+
474
+ ```bash
475
+ gda info --godot "/Applications/Godot.app/Contents/MacOS/Godot" --json
476
+ ```
477
+
478
+ ### Project context
479
+
480
+ Domain commands resolve a **Godot project** so that `res://` paths and a scene's
481
+ inter-resource references resolve deterministically, in this order (highest precedence first):
482
+
483
+ 1. The **`--project <dir>`** flag.
484
+ 2. The **`GDA_PROJECT`** environment variable.
485
+ 3. The **current directory**, when it is a Godot project (contains `project.godot`).
486
+
487
+ A named directory must be a project, or `gda` reports it as an error. When none resolves, `gda`
488
+ runs **projectless** — only filesystem paths (absolute or cwd-relative) resolve, not `res://`.
489
+ Path normalization happens once at the CLI layer: `res://` / `user://` / `uid://` pass through to
490
+ the engine; filesystem paths get `~` expanded. See
491
+ [ADR-0006](docs/adr/0006-project-context-and-path-resolution.md).
492
+
493
+ ```bash
494
+ gda scene get res://main.tscn --project ~/game --json
495
+ ```
496
+
497
+ ### Project code execution
498
+
499
+ Resolving a project so `res://` paths work runs Godot against that project, and Godot runs
500
+ some of the project's own code as part of that. Concretely:
501
+
502
+ - **Autoloads run on every `--project` operation.** When a project is resolved, the engine
503
+ constructs the project's autoload singletons at startup — before the command's own work runs —
504
+ so their `_init` (and `_ready`) execute on **every** operation, including read-only ones like
505
+ `scene get` and `node list`. Without a resolved project, no autoloads are registered, so they do
506
+ not run.
507
+ - **Commands that instantiate a scene execute that scene's attached scripts' constructors.** A
508
+ command that needs a live node tree — every mutating command (`node add`, `node set`,
509
+ `node remove`, …), and `node get` (which reports runtime property defaults the stored data does
510
+ not carry) — loads and instantiates the scene, which constructs each node and runs the `_init` of
511
+ any script attached to a node in it. Commands that only read the stored scene data
512
+ (`scene get`, `scene list`, `node list`) walk it without instantiating, so they do not run those
513
+ scripts.
514
+
515
+ In short: pointing `gda` at a project executes that project's autoload code on every command, and
516
+ any command that instantiates a scene additionally executes that scene's attached scripts' `_init`.
517
+ The tracked decisions on this are [#61](https://github.com/aigengame/godot-agent/issues/61)
518
+ (autoloads) and [#62](https://github.com/aigengame/godot-agent/issues/62) (scene scripts on
519
+ instantiating operations); see also
520
+ [ADR-0009](docs/adr/0009-trust-boundary-trusted-project.md).
521
+
522
+ ---
523
+
524
+ ## The structured-output contract
525
+
526
+ Headless Godot interleaves its banner, warnings, and `print()` output into stdout. `gda` solves this
527
+ with a sentinel contract ([ADR-0002](docs/adr/0002-headless-structured-output-contract.md)):
528
+
529
+ - The GDScript payload emits **exactly one** result, wrapped in unique sentinels on stdout:
530
+
531
+ ```
532
+ <<<GDA:RESULT>>>{ ...json... }<<<GDA:END>>>
533
+ ```
534
+
535
+ - It routes **all** of its own diagnostics to stderr; stdout carries nothing but the contract.
536
+ - `gda` extracts and parses only the bytes between the sentinels, ignoring the surrounding engine
537
+ noise, and surfaces stderr for inspection.
538
+
539
+ This is what makes `gda`'s output safe to consume programmatically, and it generalizes to the
540
+ per-message protocol the daemon will use in Phase 2.
541
+
542
+ ### Exit codes (the CLI ABI)
543
+
544
+ A failed `gda` run exits with a small, stable code so a shell or agent can branch on the failure
545
+ **category without parsing the JSON error**:
546
+
547
+ | Exit code | Category | When |
548
+ | --------- | ------------- | --------------------------------------------------------------------- |
549
+ | `0` | — | Success. |
550
+ | `127` | `environment` | The Godot binary could not be launched (shell convention: not found). |
551
+ | `124` | `environment` | Godot launched but did not return before the runner timeout (shell convention: timed out). |
552
+ | `3` | `version` | The detected Godot version is below the supported minimum. |
553
+ | `4` | `operation` | The engine ran but the operation failed — a registered operation error, an engine crash, or an unstructured non-zero exit. |
554
+ | `5` | `parse` | The process claimed success but violated the structured-output contract. |
555
+
556
+ These values are the public ABI; their authoritative source is
557
+ [`src/gda/exit_codes.py`](src/gda/exit_codes.py) — that registry, not this table, defines them.
558
+ The `{"error": {category, code, …}}` envelope carries a **finer `code`** within each category
559
+ (e.g. `path_not_found`, `already_exists`, and `node_not_found` all sit under `operation` / exit `4`).
560
+ The full code → category → exit-code registry, kept in sync with the code by tests, lives in
561
+ [ADR-0002’s `GdaError.code` registry table](docs/adr/0002-headless-structured-output-contract.md#gdaerrorcode-registry).
562
+
563
+ ---
564
+
565
+ ## Development
566
+
567
+ ```bash
568
+ uv sync # set up the environment
569
+
570
+ uv run pytest # run the full suite (includes e2e tests against a real Godot)
571
+ uv run pytest -m "not e2e" # unit tests only (no Godot binary required)
572
+ uv run pytest -m e2e # only the end-to-end tests (needs Godot 4.4+ on this machine)
573
+ ```
574
+
575
+ The `e2e` tier runs by default with `uv run pytest`, and **fails loudly** — naming the
576
+ resolved path and how to fix it — if no Godot binary is found there, rather than skipping.
577
+ Deselect the whole tier with `-m "not e2e"` (CI's per-PR job uses exactly this) when you
578
+ have no engine; use `-m e2e` to run only the e2e tests.
579
+
580
+ ### Project layout
581
+
582
+ ```
583
+ src/gda/
584
+ cli.py # CLI entrypoint (Typer); command groups, --json/--schema, binary override
585
+ binary.py # Godot binary resolution (flag > $GDA_GODOT > default)
586
+ runner.py # GodotRunner seam (Protocol) + SubprocessGodotRunner (one-shot headless)
587
+ parser.py # sentinel-contract result parser (ADR-0002)
588
+ models.py # typed I/O models (Pydantic) backing --json and --schema (ADR-0004)
589
+ errors.py # failure classification: shared classify_run + per-command layers
590
+ error_codes.py # the registry of public GdaError.code values (ADR-0002 companion)
591
+ exit_codes.py # the single registry of process exit codes (the CLI ABI)
592
+ ops/operations.gd # GDScript payload, dispatched by operation name
593
+ tests/ # unit tests + e2e tests against a real engine (shared fixtures in conftest.py)
594
+ docs/adr/ # architecture decision records
595
+ CONTEXT.md # the project's shared domain language
596
+ ```
597
+
598
+ The only external boundary — spawning a Godot process — sits behind the `GodotRunner` Protocol
599
+ (`runner.py`). Fast unit and CLI tests inject a canned result through that boundary; the e2e suite
600
+ drives a real engine. Everything between the CLI and the runner runs as real code in both tiers.
601
+
602
+ ---
603
+
604
+ ## Roadmap
605
+
606
+ | Phase / component | Delivers | Status |
607
+ | ----------------- | ------------------------------------------------------------------------- | ------ |
608
+ | **Phase 1** | `gda` serving *headless operations* standalone: `info`, structured errors, `--schema`, and the domain command groups `scene`, `node`, `script`, `project` (incl. static-analysis), `resource`, `export`, `shader`, `theme`. | ✅ Surface complete |
609
+ | **`gda-mcp`** | A thin MCP adapter generated mechanically from `--schema` — first on top of Phase 1, following `gda` forward automatically. | ✅ Shipped |
610
+ | **Phase 2** | `gda` also serving *live operations* through `gda-daemon`'s persistent engine connection. | 🗓 Planned |
611
+
612
+ Track progress and proposals on the [issue tracker](https://github.com/aigengame/godot-agent/issues).
613
+
614
+ ---
615
+
616
+ ## Contributing
617
+
618
+ Contributions are welcome. Before starting:
619
+
620
+ - Read [`CONTEXT.md`](CONTEXT.md) to align with the project's shared language, and review the
621
+ relevant [ADRs](docs/adr/) for the area you're touching.
622
+ - Issues and PRDs live as GitHub issues in [`aigengame/godot-agent`](https://github.com/aigengame/godot-agent/issues).
623
+
624
+ Commits follow the [Conventional Commits](https://www.conventionalcommits.org/) specification.
625
+
626
+ > **Working with an AI coding agent?** This project is built to be agent-navigable.
627
+ > [`AGENTS.md`](AGENTS.md) is the entry point for coding agents — it wires in the project's
628
+ > rules, domain docs, and skills.
629
+
630
+ ---
631
+
632
+ ## Acknowledgements
633
+
634
+ `gda`'s design draws on two reference implementations from the Godot + agent ecosystem: the
635
+ one-shot-headless approach of `godot-mcp` and the persistent editor-plugin approach of
636
+ `godot-mcp-pro`. `gda` deliberately adopts a **hybrid, phased** strategy that combines their
637
+ strengths (see [ADR-0001](docs/adr/0001-godot-integration-mechanism.md)).
638
+
639
+ ---
640
+
641
+ ## License
642
+
643
+ Released under the [MIT License](LICENSE). Copyright (c) 2026 aigengame.