@beremaran/godot-agent-loop 1.0.0 → 1.0.1
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.
- package/README.md +137 -652
- package/addons/godot_agent_loop/plugin.cfg +1 -1
- package/addons/godot_agent_loop/plugin.gd +1 -1
- package/agent-plugin/.claude-plugin/plugin.json +2 -2
- package/agent-plugin/.codex-plugin/plugin.json +3 -3
- package/agent-plugin/.mcp.json +1 -1
- package/agent-plugin/adapter-manifest.json +3 -3
- package/agent-plugin/pi/extension.ts +1 -1
- package/build/editor-plugin-installer.js +1 -1
- package/build/interaction-server-installer.js +1 -1
- package/build/scripts/mcp_editor_plugin.gd +1 -1
- package/build/tool-handlers/project-handler-services.js +5 -2
- package/build/tool-handlers/project-tool-handlers.js +6 -3
- package/build/utils.js +12 -1
- package/package.json +3 -4
- package/product.json +4 -4
package/README.md
CHANGED
|
@@ -1,57 +1,58 @@
|
|
|
1
|
-
|
|
2
1
|
# Godot Agent Loop
|
|
3
2
|
|
|
4
3
|
**Build it. Play it. Prove it.**
|
|
5
4
|
|
|
6
|
-
An
|
|
5
|
+
An MCP automation loop for Godot 4.
|
|
7
6
|
|
|
7
|
+
[](https://www.npmjs.com/package/@beremaran/godot-agent-loop)
|
|
8
|
+
[](https://github.com/beremaran/godot-agent-loop/actions/workflows/godot-integration.yml)
|
|
9
|
+
<!-- generated-coverage-badge:start -->
|
|
10
|
+
[](docs/coverage/coverage-report.md)
|
|
11
|
+
<!-- generated-coverage-badge:end -->
|
|
8
12
|
[](https://modelcontextprotocol.io/introduction)
|
|
9
13
|
[](https://godotengine.org)
|
|
10
|
-
[](https://opensource.org/licenses/MIT)
|
|
14
|
+
[](LICENSE)
|
|
12
15
|
|
|
13
16
|
Other integrations give agents tools. Godot Agent Loop gives them a tested
|
|
14
17
|
feedback loop to author, run, observe, playtest, and independently verify Godot
|
|
15
|
-
games
|
|
18
|
+
games:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
author → validate → run → observe → playtest → verify → refine
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
[](assets/demo/godot-agent-loop-launch.mp4)
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
<img src="assets/demo/launch-playing.png" alt="Agent-built game during play" width="32%"> <img src="assets/demo/launch-win.png" alt="Win screen" width="32%"> <img src="assets/demo/launch-lose.png" alt="Lose screen" width="32%">
|
|
18
27
|
|
|
19
|
-
[Watch the 65-second
|
|
28
|
+
[Watch the 65-second demo](assets/demo/godot-agent-loop-launch.mp4) ·
|
|
20
29
|
[Read the exact run evidence](docs/launch/launch-evidence.md) ·
|
|
21
30
|
[Inspect the resulting project](examples/launch-demo)
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
[](docs/coverage/coverage-report.md)
|
|
25
|
-
<!-- generated-coverage-badge:end -->
|
|
26
|
-
|
|
27
|
-
## Start the loop
|
|
32
|
+
## Quickstart
|
|
28
33
|
|
|
29
34
|
```bash
|
|
30
|
-
claude mcp add godot-agent-loop -- npx -y @beremaran/godot-agent-loop
|
|
35
|
+
claude mcp add godot-agent-loop -- npx -y @beremaran/godot-agent-loop
|
|
31
36
|
```
|
|
32
37
|
|
|
33
38
|
Then point the agent at a project directory—or an empty directory—and describe
|
|
34
|
-
the playable result. The
|
|
39
|
+
the playable result. The compact default surface exposes 39 tools for the loop
|
|
40
|
+
above; the `godot_tools` meta-tool searches, describes, and dispatches the full
|
|
41
|
+
167-tool catalog on demand. Runtime and editor bridges are installed
|
|
42
|
+
transiently and cleaned up automatically.
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
The compact default surface exposes 39 tools for that loop. `godot_tools`
|
|
41
|
-
searches, describes, and dispatches the specialized catalog only when needed.
|
|
42
|
-
Runtime and editor bridges are installed transiently and cleaned up
|
|
43
|
-
automatically.
|
|
44
|
+
Using Cline, Cursor, or another MCP client? See
|
|
45
|
+
[Configuration](#configuration).
|
|
44
46
|
|
|
45
47
|
## Proof before claims
|
|
46
48
|
|
|
47
|
-
- **167/167 tools** exercised through the complete MCP-to-Godot path
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- **
|
|
51
|
-
available through `godot_tools`.
|
|
49
|
+
- **167/167 tools** exercised through the complete MCP-to-Godot path, with
|
|
50
|
+
**358 public actions** traced to resolving tests; see the generated
|
|
51
|
+
[coverage report](docs/coverage/coverage-report.md).
|
|
52
|
+
- **201 full-path MCP E2E tests** run against real Godot builds in CI.
|
|
52
53
|
- A cold agent built and independently verified a playable win/lose game with
|
|
53
|
-
zero human corrections in
|
|
54
|
-
tools; see the [launch evidence](docs/launch/launch-evidence.md) and
|
|
54
|
+
zero human corrections, in under seven minutes, using 103 MCP calls and no
|
|
55
|
+
built-in tools; see the [launch evidence](docs/launch/launch-evidence.md) and
|
|
55
56
|
[deterministic acceptance record](docs/golden-agent-acceptance.md).
|
|
56
57
|
- Privileged reflection, code execution, and networking groups are denied by
|
|
57
58
|
default, and the editor provides a human **Pause Agent** control.
|
|
@@ -60,585 +61,52 @@ Support is deliberately bounded: Godot 4.4 is the compatibility floor and 4.7
|
|
|
60
61
|
the primary target; editor UI/rendering depth is verified on Linux, while
|
|
61
62
|
Windows and macOS receive the documented portable acceptance path. Full
|
|
62
63
|
debugger automation, native extension builds, and unbounded engine control are
|
|
63
|
-
not claimed.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
`
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
### Runtime Node Inspection & Manipulation
|
|
102
|
-
|
|
103
|
-
- **`game_get_property`** / **`game_set_property`** - Read/write any property on any node by path
|
|
104
|
-
- **`game_call_method`** - Call any method on any node with arguments
|
|
105
|
-
- **`game_get_node_info`** - Full node introspection: properties, signals, methods, children
|
|
106
|
-
- **`game_instantiate_scene`** - Dynamically add scenes to the running game
|
|
107
|
-
- **`game_remove_node`** - Remove nodes at runtime
|
|
108
|
-
- **`game_change_scene`** - Switch scenes at runtime
|
|
109
|
-
- **`game_reparent_node`** - Move nodes between parents
|
|
110
|
-
|
|
111
|
-
### Signal System
|
|
112
|
-
|
|
113
|
-
- **`game_connect_signal`** - Wire up signal connections at runtime
|
|
114
|
-
- **`game_disconnect_signal`** - Remove signal connections
|
|
115
|
-
- **`game_emit_signal`** - Emit signals with arguments
|
|
116
|
-
|
|
117
|
-
### Animation & Tweening
|
|
118
|
-
|
|
119
|
-
- **`game_play_animation`** - Control AnimationPlayer (play, stop, pause, list)
|
|
120
|
-
- **`game_tween_property`** - Smooth property animation with configurable easing
|
|
121
|
-
|
|
122
|
-
### Game Control & Debugging
|
|
123
|
-
|
|
124
|
-
- **`game_pause`** - Pause/unpause the game
|
|
125
|
-
- **`game_performance`** - FPS, frame time, memory, object counts, draw calls,
|
|
126
|
-
bounded profiler sessions, and live orphan-node diagnostics
|
|
127
|
-
- **`game_wait`** - Wait N frames (timing-sensitive operations)
|
|
128
|
-
- **`game_get_nodes_in_group`** - Query nodes by group
|
|
129
|
-
- **`game_find_nodes_by_class`** - Find all nodes of a specific class
|
|
130
|
-
|
|
131
|
-
### Scene Authoring Operations (No Running Game Needed)
|
|
132
|
-
|
|
133
|
-
- **`read_scene`** - Parse any .tscn file and get full node tree with properties as JSON
|
|
134
|
-
- **`modify_scene_node`** - Change node properties in scene files
|
|
135
|
-
- **`remove_scene_node`** - Remove nodes from scene files
|
|
136
|
-
- **`attach_script`** - Attach GDScript files to nodes in scenes
|
|
137
|
-
- **`create_resource`** - Create .tres resource files (materials, themes, etc.)
|
|
138
|
-
|
|
139
|
-
### Project Management
|
|
140
|
-
|
|
141
|
-
- **`read_project_settings`** - Parse project.godot as structured JSON
|
|
142
|
-
- **`modify_project_settings`** - Change project settings programmatically
|
|
143
|
-
- **`list_project_files`** - Paginate project files with extension/subdirectory filters
|
|
144
|
-
- **`run_project_tests`** - Discover or run native, GUT, and GdUnit4 tests with structured results
|
|
145
|
-
- **`manage_import_pipeline`** - Inspect/change import metadata, synchronously reimport, and trace imported files
|
|
146
|
-
- **`analyze_project_integrity`** - Find dependency/integrity defects and preview rename impact without mutation
|
|
147
|
-
- **`verify_export_readiness`** - Validate templates/presets, export, inspect artifacts, and smoke-run supported builds
|
|
148
|
-
- **`verify_dotnet_project`** - Detect managed prerequisites, restore/build, report diagnostics, and run C# projects
|
|
149
|
-
- **`manage_addon`** - Install and manage hash-pinned local EditorPlugins with rollback and reload validation
|
|
150
|
-
|
|
151
|
-
### File I/O
|
|
152
|
-
|
|
153
|
-
- **`read_file`** / **`write_file`** / **`delete_file`** - Full file system access within Godot projects
|
|
154
|
-
- **`create_directory`** - Create directory structures for scripts, scenes, assets
|
|
155
|
-
|
|
156
|
-
### Error & Log Capture
|
|
157
|
-
|
|
158
|
-
- **`game_get_errors`** - Get new push_error/push_warning messages since last call
|
|
159
|
-
- **`game_get_logs`** - Get new print output from the running game since last call
|
|
160
|
-
|
|
161
|
-
### Enhanced Input
|
|
162
|
-
|
|
163
|
-
- **`game_key_hold`** / **`game_key_release`** - Hold keys down for movement testing (WASD etc.)
|
|
164
|
-
- **`game_scroll`** - Mouse scroll wheel events
|
|
165
|
-
- **`game_mouse_drag`** - Drag between two points over multiple frames
|
|
166
|
-
- **`game_gamepad`** - Gamepad button and axis input events
|
|
167
|
-
|
|
168
|
-
### Project Creation & Configuration
|
|
169
|
-
|
|
170
|
-
- **`create_project`** - Create a new Godot project from scratch (pass `dotnet: true` to scaffold a .NET/C# project)
|
|
171
|
-
- **`create_csharp_script`** - Create a C# script in a Godot .NET project
|
|
172
|
-
- **`manage_autoloads`** - Add, remove, or list autoloads
|
|
173
|
-
- **`manage_input_map`** - Add, remove, or list input actions and key bindings
|
|
174
|
-
- **`manage_export_presets`** - Create or modify export preset configuration
|
|
175
|
-
|
|
176
|
-
### .NET / C# Support
|
|
177
|
-
|
|
178
|
-
- **`create_project`** with `dotnet: true` - Scaffold a Godot .NET project (`.csproj` with `Godot.NET.Sdk` matched to your Godot version, plus the `"C#"` feature flag)
|
|
179
|
-
- **`create_csharp_script`** - Generate an idiomatic C# script (partial class, correct `_Ready`/`_Process` override signatures); the class name is kept in sync with the file name so Godot can attach it
|
|
180
|
-
- **`get_project_info`** reports an `isDotnet` field
|
|
181
|
-
|
|
182
|
-
### GDScript Diagnostics
|
|
183
|
-
|
|
184
|
-
- **`validate_script`** - Check a single GDScript file for syntax and type errors headlessly, returning `{ valid, errors: [{ message, file, line }] }`
|
|
185
|
-
- **`validate_scripts`** - Batch-validate all git-changed `.gd` files (or the whole project), so an agent can verify its edits before running the game
|
|
186
|
-
|
|
187
|
-
### Camera, Physics & Audio
|
|
188
|
-
|
|
189
|
-
- **`game_get_camera`** / **`game_set_camera`** - Query and control 2D/3D cameras
|
|
190
|
-
- **`game_raycast`** - Cast physics rays (auto-detects 2D vs 3D)
|
|
191
|
-
- **`game_get_audio`** - Get audio bus layout and playing streams
|
|
192
|
-
- **`game_spawn_node`** - Create any node type at runtime with properties
|
|
193
|
-
- **`game_set_shader_param`** - Set shader parameters on materials
|
|
194
|
-
- **`game_audio_play`** / **`game_audio_bus`** - Full audio playback and bus control
|
|
195
|
-
- **`game_navigate_path`** - Query navigation paths (2D/3D)
|
|
196
|
-
- **`game_tilemap`** - Get/set TileMapLayer cells
|
|
197
|
-
- **`game_add_collision`** - Add collision shapes to physics bodies
|
|
198
|
-
- **`game_environment`** - Configure post-processing (fog, glow, SSAO, tonemap, etc.)
|
|
199
|
-
- **`game_manage_group`** - Add/remove nodes from groups
|
|
200
|
-
- **`game_create_timer`** - Create timer nodes programmatically
|
|
201
|
-
- **`game_set_particles`** - Configure GPUParticles2D/3D properties and process materials
|
|
202
|
-
- **`game_create_animation`** - Create animations with value/method/bezier/audio tracks and keyframes
|
|
203
|
-
- **`export_project`** - Trigger headless project export builds (CI/CD ready)
|
|
204
|
-
- **`game_serialize_state`** - Save/load entire node tree state as JSON
|
|
205
|
-
- **`game_physics_body`** - Configure mass, velocity, damping, friction, bounce
|
|
206
|
-
- **`game_create_joint`** - Create physics joints (pin, spring, hinge, cone, slider)
|
|
207
|
-
- **`game_bone_pose`** - Get/set skeleton bone poses for character animation
|
|
208
|
-
- **`game_ui_theme`** - Apply color, constant, and font size theme overrides
|
|
209
|
-
- **`game_viewport`** - Create/configure SubViewport nodes
|
|
210
|
-
- **`game_debug_draw`** - Draw debug geometry (lines, spheres, boxes)
|
|
211
|
-
|
|
212
|
-
### Networking
|
|
213
|
-
|
|
214
|
-
- **`game_http_request`** - HTTP GET/POST/PUT/DELETE with headers and body
|
|
215
|
-
- **`game_websocket`** - WebSocket client connect/disconnect/send messages
|
|
216
|
-
- **`game_multiplayer`** - ENet multiplayer create server/client/disconnect
|
|
217
|
-
- **`game_rpc`** - Call or configure RPC methods on nodes
|
|
218
|
-
|
|
219
|
-
### System & Window Control
|
|
220
|
-
|
|
221
|
-
- **`game_script`** - Attach, detach, or get source of node scripts at runtime
|
|
222
|
-
- **`game_window`** - Get/set window size, fullscreen, title, position
|
|
223
|
-
- **`game_os_info`** - Get platform, locale, screen, adapter, memory info
|
|
224
|
-
- **`game_time_scale`** - Get/set Engine.time_scale and timing info
|
|
225
|
-
- **`game_process_mode`** - Set node process mode (pausable/always/disabled)
|
|
226
|
-
- **`game_world_settings`** - Get/set gravity, physics FPS, and world settings
|
|
227
|
-
|
|
228
|
-
### Advanced Signals & Input
|
|
229
|
-
|
|
230
|
-
- **`game_list_signals`** - List all signals on a node with connections
|
|
231
|
-
- **`game_await_signal`** - Await a signal with timeout and return args
|
|
232
|
-
- **`game_touch`** - Simulate touch press/release/drag and gestures
|
|
233
|
-
- **`game_input_state`** - Query pressed keys, mouse position, connected pads
|
|
234
|
-
- **`game_input_action`** - Manage runtime InputMap actions and strength
|
|
235
|
-
|
|
236
|
-
### 3D Rendering & Geometry
|
|
237
|
-
|
|
238
|
-
- **`game_csg`** - Create/configure CSG nodes with boolean operations
|
|
239
|
-
- **`game_multimesh`** - Create/configure MultiMeshInstance3D for instancing
|
|
240
|
-
- **`game_procedural_mesh`** - Generate meshes via ArrayMesh from vertex data
|
|
241
|
-
- **`game_light_3d`** - Create/configure 3D lights (directional/omni/spot)
|
|
242
|
-
- **`game_mesh_instance`** - Create MeshInstance3D with primitive meshes
|
|
243
|
-
- **`game_gridmap`** - GridMap set/get/clear cells and query used cells
|
|
244
|
-
- **`game_3d_effects`** - Create ReflectionProbe, Decal, or FogVolume
|
|
245
|
-
- **`game_gi`** - Create/configure VoxelGI or LightmapGI
|
|
246
|
-
- **`game_path_3d`** - Create Path3D/Curve3D and manage curve points
|
|
247
|
-
- **`game_sky`** - Create/configure Sky with procedural/physical sky
|
|
248
|
-
- **`game_camera_attributes`** - Configure DOF, exposure, auto-exposure on camera
|
|
249
|
-
- **`game_navigation_3d`** - Create/configure NavigationRegion3D and bake
|
|
250
|
-
- **`game_physics_3d`** - Area3D queries and point/shape intersection tests
|
|
251
|
-
|
|
252
|
-
### 2D Systems
|
|
253
|
-
|
|
254
|
-
- **`game_canvas`** - Create/configure CanvasLayer and CanvasModulate
|
|
255
|
-
- **`game_canvas_draw`** - 2D drawing: line/rect/circle/polygon/text/clear
|
|
256
|
-
- **`game_light_2d`** - Create/configure 2D lights and light occluders
|
|
257
|
-
- **`game_parallax`** - Create/configure ParallaxBackground and layers
|
|
258
|
-
- **`game_shape_2d`** - Line2D/Polygon2D point manipulation
|
|
259
|
-
- **`game_path_2d`** - Path2D/Curve2D management and AnimatedSprite2D
|
|
260
|
-
- **`game_physics_2d`** - Area2D queries and 2D point/shape intersections
|
|
261
|
-
|
|
262
|
-
### Advanced Animation
|
|
263
|
-
|
|
264
|
-
- **`game_animation_tree`** - AnimationTree state machine travel and params
|
|
265
|
-
- **`game_animation_control`** - AnimationPlayer seek/queue/speed/info control
|
|
266
|
-
- **`game_skeleton_ik`** - SkeletonIK3D start/stop/set target position
|
|
267
|
-
|
|
268
|
-
### Advanced Audio
|
|
269
|
-
|
|
270
|
-
- **`game_audio_effect`** - Add/remove/configure audio bus effects
|
|
271
|
-
- **`game_audio_bus_layout`** - Create/remove/reorder audio buses and routing
|
|
272
|
-
- **`game_audio_spatial`** - Configure AudioStreamPlayer3D spatial properties
|
|
273
|
-
|
|
274
|
-
### Editor & Project Tools
|
|
275
|
-
|
|
276
|
-
- **`rename_file`** - Rename or move a file within the project
|
|
277
|
-
- **`manage_resource`** - Read or modify .tres/.res resource files
|
|
278
|
-
- **`create_script`** - Create a GDScript file from a template
|
|
279
|
-
- **`validate_script`** - Check a GDScript file for syntax/type errors headlessly (no run needed)
|
|
280
|
-
- **`validate_scripts`** - Batch-check GDScript files: git-changed ones by default, or all
|
|
281
|
-
- **`manage_scene_signals`** - List/add/remove signal connections in .tscn files
|
|
282
|
-
- **`manage_layers`** - List/set named layer definitions in project
|
|
283
|
-
- **`manage_plugins`** - List/enable/disable editor plugins
|
|
284
|
-
- **`manage_shader`** - Create or read .gdshader files
|
|
285
|
-
- **`manage_theme_resource`** - Create/read/modify Theme .tres resources
|
|
286
|
-
- **`set_main_scene`** - Set the main scene in project.godot
|
|
287
|
-
- **`manage_scene_structure`** - Rename/duplicate/move nodes within .tscn scenes
|
|
288
|
-
- **`manage_translations`** - List/add/remove translation files in project
|
|
289
|
-
- **`game_locale`** - Set/get locale and translate strings at runtime
|
|
290
|
-
|
|
291
|
-
### UI Controls
|
|
292
|
-
|
|
293
|
-
- **`game_ui_control`** - Set focus, anchors, tooltip, mouse filter on Control
|
|
294
|
-
- **`game_ui_text`** - LineEdit/TextEdit/RichTextLabel text operations
|
|
295
|
-
- **`game_ui_popup`** - Show/hide/popup for Popup/Dialog/Window nodes
|
|
296
|
-
- **`game_ui_tree`** - Tree control: get/select/collapse/add/remove items
|
|
297
|
-
- **`game_ui_item_list`** - ItemList/OptionButton: get/select/add/remove items
|
|
298
|
-
- **`game_ui_tabs`** - TabContainer/TabBar: get/set current tab
|
|
299
|
-
- **`game_ui_menu`** - PopupMenu/MenuBar: add/remove/get menu items
|
|
300
|
-
- **`game_ui_range`** - ProgressBar/Slider/SpinBox/ColorPicker get/set
|
|
301
|
-
|
|
302
|
-
### Rendering & Resources
|
|
303
|
-
|
|
304
|
-
- **`game_render_settings`** - Get/set MSAA, FXAA, TAA, scaling mode/scale
|
|
305
|
-
- **`game_resource`** - Runtime resource load, save, or preload
|
|
306
|
-
|
|
307
|
-
### Robustness Improvements
|
|
308
|
-
|
|
309
|
-
- **Reentrancy guard** - Prevents concurrent command processing during async operations
|
|
310
|
-
- **Full type conversion** - Supports Vector2/3, Color, Quaternion, Basis, Transform2D/3D, AABB, Rect2, and all packed array types
|
|
311
|
-
- **Smart property type detection** - Uses node's `get_property_list()` for automatic type conversion
|
|
312
|
-
- **PackedArray serialization** - Proper JSON arrays instead of string fallback
|
|
313
|
-
- **Graceful error handling** - Scene read fallback to raw .tscn text on missing dependencies
|
|
314
|
-
|
|
315
|
-
## Tool inventory
|
|
316
|
-
|
|
317
|
-
### Project Management (14 tools)
|
|
318
|
-
|
|
319
|
-
| Tool | Description |
|
|
320
|
-
| ------ | ------------- |
|
|
321
|
-
| `launch_editor` | Launch Godot editor for a project |
|
|
322
|
-
| `run_project` | Run a Godot project and capture output |
|
|
323
|
-
| `verify_project` | Run, assert bounded runtime evidence, optionally capture, and tear down |
|
|
324
|
-
| `run_project_tests` | Discover or run native, GUT, and GdUnit4 tests with structured cases and logs |
|
|
325
|
-
| `manage_import_pipeline` | Inspect/change importer settings, reimport, and query generated dependencies |
|
|
326
|
-
| `analyze_project_integrity` | Analyze resource graphs and preview non-mutating rename impact |
|
|
327
|
-
| `verify_export_readiness` | Validate export prerequisites and return artifact plus smoke-run evidence |
|
|
328
|
-
| `verify_dotnet_project` | Inspect, restore, build, and run against the matching Godot.NET.Sdk |
|
|
329
|
-
| `manage_addon` | Inspect/install/update/remove and toggle hash-pinned local EditorPlugins |
|
|
330
|
-
| `stop_project` | Stop the running project |
|
|
331
|
-
| `get_debug_output` | Get console output and errors |
|
|
332
|
-
| `get_godot_version` | Get installed Godot version |
|
|
333
|
-
| `list_projects` | Find Godot projects in a directory |
|
|
334
|
-
| `get_project_info` | Get project metadata |
|
|
335
|
-
|
|
336
|
-
Import changes require an editor-capable Godot binary. `reimport` runs Godot's
|
|
337
|
-
bounded `--import` workflow and returns diagnostics; it may rewrite `.import`
|
|
338
|
-
metadata and `.godot/imported` cache files. Integrity analysis is read-only,
|
|
339
|
-
skips generated/vendor directories, defaults to 10,000 resource files, and
|
|
340
|
-
labels unreferenced resources as candidates because dynamic loads cannot be
|
|
341
|
-
proven statically. Use `preview_rename` before moving a resource; it reports
|
|
342
|
-
direct textual dependents, destination conflicts, and UID sidecars but never
|
|
343
|
-
changes files.
|
|
344
|
-
|
|
345
|
-
Export readiness recognizes the bounded Linux, Windows, macOS, and Web template
|
|
346
|
-
filenames for the active Godot version. Local smoke execution is intentionally
|
|
347
|
-
limited to Linux exports on Linux; other targets are inspected but not claimed
|
|
348
|
-
as locally runnable. Export writes the requested artifact and companion files,
|
|
349
|
-
returns bounded process output and SHA-256 evidence, and classifies missing
|
|
350
|
-
templates, unsupported platforms, invalid output paths, timeouts, export errors,
|
|
351
|
-
missing artifacts, and smoke failures.
|
|
352
|
-
|
|
353
|
-
The managed workflow requires both a .NET-enabled Godot editor and a 64-bit
|
|
354
|
-
.NET SDK. It verifies that the versioned `Godot.NET.Sdk` in the unique or
|
|
355
|
-
selected `.csproj` matches the active engine, returns bounded structured MSBuild
|
|
356
|
-
diagnostics, and hashes the resulting assembly. Standard Godot builds return a
|
|
357
|
-
controlled `dotnet_editor_required` result and do not attempt restore or build.
|
|
358
|
-
|
|
359
|
-
Add-on installation is deliberately offline and provenance-first: `sourcePath`
|
|
360
|
-
must be an allowed local directory and `expectedSha256` must match its authored
|
|
361
|
-
tree before any write. Symlinks, oversized trees, malformed `plugin.cfg`,
|
|
362
|
-
non-`@tool` scripts, incompatible minimum Godot versions, and traversal are
|
|
363
|
-
rejected. Replacement is staged atomically, editor reload is mandatory, and a
|
|
364
|
-
parse/load failure restores the prior version and plugin configuration.
|
|
365
|
-
|
|
366
|
-
### Scene Management (7 tools)
|
|
367
|
-
|
|
368
|
-
| Tool | Description |
|
|
369
|
-
| ------ | ------------- |
|
|
370
|
-
| `create_scene` | Create a new scene with a root node type |
|
|
371
|
-
| `add_node` | Add a node to an existing scene |
|
|
372
|
-
| `load_sprite` | Load a texture into a Sprite2D node |
|
|
373
|
-
| `export_mesh_library` | Export a scene as MeshLibrary |
|
|
374
|
-
| `save_scene` | Save a scene (with optional variant path) |
|
|
375
|
-
| `get_uid` | Get UID for a file (Godot 4.4+) |
|
|
376
|
-
| `update_project_uids` | Resave resources to update UIDs |
|
|
377
|
-
|
|
378
|
-
### Scene Authoring Operations (5 tools)
|
|
379
|
-
|
|
380
|
-
| Tool | Description |
|
|
381
|
-
| ------ | ------------- |
|
|
382
|
-
| `read_scene` | Read full scene tree as JSON |
|
|
383
|
-
| `modify_scene_node` | Modify node properties in a scene file |
|
|
384
|
-
| `remove_scene_node` | Remove a node from a scene file |
|
|
385
|
-
| `attach_script` | Attach a GDScript to a scene node |
|
|
386
|
-
| `create_resource` | Create a .tres resource file |
|
|
387
|
-
|
|
388
|
-
### Project Settings (3 tools)
|
|
389
|
-
|
|
390
|
-
| Tool | Description |
|
|
391
|
-
| ------ | ------------- |
|
|
392
|
-
| `read_project_settings` | Parse project.godot as JSON |
|
|
393
|
-
| `modify_project_settings` | Change a project setting |
|
|
394
|
-
| `list_project_files` | Paginate/filter project files |
|
|
395
|
-
|
|
396
|
-
### Runtime Input (5 tools)
|
|
397
|
-
|
|
398
|
-
| Tool | Description |
|
|
399
|
-
| ------ | ------------- |
|
|
400
|
-
| `game_screenshot` | Capture a screenshot (base64 PNG) |
|
|
401
|
-
| `game_visual_regression` | Capture baselines or compare frames with masks, tolerances, and retained PNG diffs |
|
|
402
|
-
| `game_click` | Click at a position |
|
|
403
|
-
| `game_key_press` | Send key press or input action |
|
|
404
|
-
| `game_mouse_move` | Move the mouse |
|
|
405
|
-
|
|
406
|
-
### Runtime Inspection (3 tools)
|
|
407
|
-
|
|
408
|
-
| Tool | Description |
|
|
409
|
-
| ------ | ------------- |
|
|
410
|
-
| `game_get_ui` | Get all visible UI elements |
|
|
411
|
-
| `game_get_scene_tree` | Get full scene tree structure |
|
|
412
|
-
| `game_get_node_info` | Detailed node introspection |
|
|
413
|
-
|
|
414
|
-
### Runtime Code Execution (1 tool)
|
|
415
|
-
|
|
416
|
-
| Tool | Description |
|
|
417
|
-
| ------ | ------------- |
|
|
418
|
-
| `game_eval` | Execute arbitrary GDScript with return values |
|
|
419
|
-
|
|
420
|
-
### Runtime Node Manipulation (7 tools)
|
|
421
|
-
|
|
422
|
-
| Tool | Description |
|
|
423
|
-
| ------ | ------------- |
|
|
424
|
-
| `game_get_property` | Get any node property |
|
|
425
|
-
| `game_set_property` | Set any node property (auto type conversion) |
|
|
426
|
-
| `game_call_method` | Call any method on a node |
|
|
427
|
-
| `game_instantiate_scene` | Add a PackedScene to the running tree |
|
|
428
|
-
| `game_remove_node` | Remove a node from the tree |
|
|
429
|
-
| `game_change_scene` | Switch to a different scene |
|
|
430
|
-
| `game_reparent_node` | Move a node to a new parent |
|
|
431
|
-
|
|
432
|
-
### Runtime Signals (5 tools)
|
|
433
|
-
|
|
434
|
-
| Tool | Description |
|
|
435
|
-
| ------ | ------------- |
|
|
436
|
-
| `game_connect_signal` | Connect a signal to a method |
|
|
437
|
-
| `game_disconnect_signal` | Disconnect a signal |
|
|
438
|
-
| `game_emit_signal` | Emit a signal with arguments |
|
|
439
|
-
| `game_list_signals` | List all signals on a node with connections |
|
|
440
|
-
| `game_await_signal` | Await a signal with timeout and return args |
|
|
441
|
-
|
|
442
|
-
### Runtime Animation (2 tools)
|
|
443
|
-
|
|
444
|
-
| Tool | Description |
|
|
445
|
-
| ------ | ------------- |
|
|
446
|
-
| `game_play_animation` | Control AnimationPlayer |
|
|
447
|
-
| `game_tween_property` | Tween a property with easing |
|
|
448
|
-
|
|
449
|
-
### Runtime Utilities (5 tools)
|
|
450
|
-
|
|
451
|
-
| Tool | Description |
|
|
452
|
-
| ------ | ------------- |
|
|
453
|
-
| `game_pause` | Pause/unpause the game |
|
|
454
|
-
| `game_performance` | Get FPS, memory, draw calls |
|
|
455
|
-
| `game_wait` | Wait N frames |
|
|
456
|
-
| `game_get_nodes_in_group` | Query nodes by group |
|
|
457
|
-
| `game_find_nodes_by_class` | Find nodes by class type |
|
|
458
|
-
|
|
459
|
-
### File I/O (4 tools)
|
|
460
|
-
|
|
461
|
-
| Tool | Description |
|
|
462
|
-
| ------ | ------------- |
|
|
463
|
-
| `read_file` | Read a text file from a Godot project |
|
|
464
|
-
| `write_file` | Create or overwrite a text file |
|
|
465
|
-
| `delete_file` | Delete a file from a project |
|
|
466
|
-
| `create_directory` | Create a directory inside a project |
|
|
467
|
-
|
|
468
|
-
### Error & Log Capture (2 tools)
|
|
469
|
-
|
|
470
|
-
| Tool | Description |
|
|
471
|
-
| ------ | ------------- |
|
|
472
|
-
| `game_get_errors` | Get new errors/warnings since last call |
|
|
473
|
-
| `game_get_logs` | Get new print output since last call |
|
|
474
|
-
|
|
475
|
-
### Enhanced Input (8 tools)
|
|
476
|
-
|
|
477
|
-
| Tool | Description |
|
|
478
|
-
| ------ | ------------- |
|
|
479
|
-
| `game_key_hold` | Hold a key down (no auto-release) |
|
|
480
|
-
| `game_key_release` | Release a held key |
|
|
481
|
-
| `game_scroll` | Mouse scroll wheel event |
|
|
482
|
-
| `game_mouse_drag` | Drag between two points over N frames |
|
|
483
|
-
| `game_gamepad` | Gamepad button or axis input |
|
|
484
|
-
| `game_touch` | Simulate touch press/release/drag and gestures |
|
|
485
|
-
| `game_input_state` | Query pressed keys, mouse position, connected pads |
|
|
486
|
-
| `game_input_action` | Manage runtime InputMap actions and strength |
|
|
487
|
-
|
|
488
|
-
### Project Creation (5 tools)
|
|
489
|
-
|
|
490
|
-
| Tool | Description |
|
|
491
|
-
| ------ | ------------- |
|
|
492
|
-
| `create_project` | Create a new Godot project (supports `dotnet: true` for C#) |
|
|
493
|
-
| `create_csharp_script` | Create a C# script in a Godot .NET project |
|
|
494
|
-
| `manage_autoloads` | Add, remove, or list autoloads |
|
|
495
|
-
| `manage_input_map` | Add, remove, or list input actions |
|
|
496
|
-
| `manage_export_presets` | Create or modify export presets |
|
|
497
|
-
|
|
498
|
-
### Advanced Runtime (24 tools)
|
|
499
|
-
|
|
500
|
-
| Tool | Description |
|
|
501
|
-
| ------ | ------------- |
|
|
502
|
-
| `game_get_camera` | Get active camera position/rotation/zoom |
|
|
503
|
-
| `game_set_camera` | Move or rotate the active camera |
|
|
504
|
-
| `game_raycast` | Cast a ray and return collision results |
|
|
505
|
-
| `game_get_audio` | Get audio bus layout and playing streams |
|
|
506
|
-
| `game_spawn_node` | Create a new node of any type at runtime |
|
|
507
|
-
| `game_set_shader_param` | Set a shader parameter on a node's material |
|
|
508
|
-
| `game_audio_play` | Play, stop, or pause an AudioStreamPlayer node |
|
|
509
|
-
| `game_audio_bus` | Set volume, mute, or solo on an audio bus |
|
|
510
|
-
| `game_navigate_path` | Query a navigation path between two points |
|
|
511
|
-
| `game_tilemap` | Get or set cells in a TileMapLayer node |
|
|
512
|
-
| `game_add_collision` | Add a collision shape to a physics body node |
|
|
513
|
-
| `game_environment` | Get or set environment and post-processing settings |
|
|
514
|
-
| `game_manage_group` | Add or remove a node from a group, or list groups |
|
|
515
|
-
| `game_create_timer` | Create a Timer node with configuration |
|
|
516
|
-
| `game_set_particles` | Configure GPUParticles2D/3D node properties |
|
|
517
|
-
| `game_create_animation` | Create an animation with tracks and keyframes |
|
|
518
|
-
| `game_serialize_state` | Save or load node tree state as JSON |
|
|
519
|
-
| `game_physics_body` | Configure physics body properties (mass, velocity) |
|
|
520
|
-
| `game_create_joint` | Create a physics joint between two bodies |
|
|
521
|
-
| `game_bone_pose` | Get or set bone poses on a Skeleton3D node |
|
|
522
|
-
| `game_ui_theme` | Apply theme overrides to a Control node |
|
|
523
|
-
| `game_viewport` | Create or configure a SubViewport node |
|
|
524
|
-
| `game_debug_draw` | Draw debug lines, spheres, or boxes in 3D |
|
|
525
|
-
|
|
526
|
-
### Build & Export (1 tool)
|
|
527
|
-
|
|
528
|
-
| Tool | Description |
|
|
529
|
-
| ------ | ------------- |
|
|
530
|
-
| `export_project` | Export a Godot project using a preset |
|
|
531
|
-
|
|
532
|
-
### Networking (4 tools)
|
|
533
|
-
|
|
534
|
-
| Tool | Description |
|
|
535
|
-
| ------ | ------------- |
|
|
536
|
-
| `game_http_request` | HTTP GET/POST/PUT/DELETE with headers and body |
|
|
537
|
-
| `game_websocket` | WebSocket client connect/disconnect/send messages |
|
|
538
|
-
| `game_multiplayer` | ENet multiplayer create server/client/disconnect |
|
|
539
|
-
| `game_rpc` | Call or configure RPC methods on nodes |
|
|
540
|
-
|
|
541
|
-
### System & Window (6 tools)
|
|
542
|
-
|
|
543
|
-
| Tool | Description |
|
|
544
|
-
| ------ | ------------- |
|
|
545
|
-
| `game_script` | Attach, detach, or get source of node scripts |
|
|
546
|
-
| `game_window` | Get/set window size, fullscreen, title, position |
|
|
547
|
-
| `game_os_info` | Get platform, locale, screen, adapter, memory info |
|
|
548
|
-
| `game_time_scale` | Get/set Engine.time_scale and timing info |
|
|
549
|
-
| `game_process_mode` | Set node process mode (pausable/always/disabled) |
|
|
550
|
-
| `game_world_settings` | Get/set gravity, physics FPS, and world settings |
|
|
551
|
-
|
|
552
|
-
### 3D Rendering & Geometry (13 tools)
|
|
553
|
-
|
|
554
|
-
| Tool | Description |
|
|
555
|
-
| ------ | ------------- |
|
|
556
|
-
| `game_csg` | Create/configure CSG nodes with boolean operations |
|
|
557
|
-
| `game_multimesh` | Create/configure MultiMeshInstance3D for instancing |
|
|
558
|
-
| `game_procedural_mesh` | Generate meshes via ArrayMesh from vertex data |
|
|
559
|
-
| `game_light_3d` | Create/configure 3D lights (directional/omni/spot) |
|
|
560
|
-
| `game_mesh_instance` | Create MeshInstance3D with primitive meshes |
|
|
561
|
-
| `game_gridmap` | GridMap set/get/clear cells and query used cells |
|
|
562
|
-
| `game_3d_effects` | Create ReflectionProbe, Decal, or FogVolume |
|
|
563
|
-
| `game_gi` | Create/configure VoxelGI or LightmapGI |
|
|
564
|
-
| `game_path_3d` | Create Path3D/Curve3D and manage curve points |
|
|
565
|
-
| `game_sky` | Create/configure Sky with procedural/physical sky |
|
|
566
|
-
| `game_camera_attributes` | Configure DOF, exposure, auto-exposure on camera |
|
|
567
|
-
| `game_navigation_3d` | Create/configure NavigationRegion3D and bake |
|
|
568
|
-
| `game_physics_3d` | Area3D queries and point/shape intersection tests |
|
|
569
|
-
|
|
570
|
-
### 2D Systems (7 tools)
|
|
571
|
-
|
|
572
|
-
| Tool | Description |
|
|
573
|
-
| ------ | ------------- |
|
|
574
|
-
| `game_canvas` | Create/configure CanvasLayer and CanvasModulate |
|
|
575
|
-
| `game_canvas_draw` | 2D drawing: line/rect/circle/polygon/text/clear |
|
|
576
|
-
| `game_light_2d` | Create/configure 2D lights and light occluders |
|
|
577
|
-
| `game_parallax` | Create/configure ParallaxBackground and layers |
|
|
578
|
-
| `game_shape_2d` | Line2D/Polygon2D point manipulation |
|
|
579
|
-
| `game_path_2d` | Path2D/Curve2D management and AnimatedSprite2D |
|
|
580
|
-
| `game_physics_2d` | Area2D queries and 2D point/shape intersections |
|
|
581
|
-
|
|
582
|
-
### Advanced Animation (3 tools)
|
|
583
|
-
|
|
584
|
-
| Tool | Description |
|
|
585
|
-
| ------ | ------------- |
|
|
586
|
-
| `game_animation_tree` | AnimationTree state machine travel and params |
|
|
587
|
-
| `game_animation_control` | AnimationPlayer seek/queue/speed/info control |
|
|
588
|
-
| `game_skeleton_ik` | SkeletonIK3D start/stop/set target position |
|
|
589
|
-
|
|
590
|
-
### Advanced Audio (3 tools)
|
|
591
|
-
|
|
592
|
-
| Tool | Description |
|
|
593
|
-
| ------ | ------------- |
|
|
594
|
-
| `game_audio_effect` | Add/remove/configure audio bus effects |
|
|
595
|
-
| `game_audio_bus_layout` | Create/remove/reorder audio buses and routing |
|
|
596
|
-
| `game_audio_spatial` | Configure AudioStreamPlayer3D spatial properties |
|
|
597
|
-
|
|
598
|
-
### Editor & Project Tools (14 tools)
|
|
599
|
-
|
|
600
|
-
| Tool | Description |
|
|
601
|
-
| ------ | ------------- |
|
|
602
|
-
| `rename_file` | Rename or move a file within the project |
|
|
603
|
-
| `manage_resource` | Read or modify .tres/.res resource files |
|
|
604
|
-
| `create_script` | Create a GDScript file from a template |
|
|
605
|
-
| `validate_script` | Check a GDScript file for syntax/type errors (headless) |
|
|
606
|
-
| `validate_scripts` | Batch-check GDScript files (git-changed by default, or all) |
|
|
607
|
-
| `manage_scene_signals` | List/add/remove signal connections in .tscn files |
|
|
608
|
-
| `manage_layers` | List/set named layer definitions in project |
|
|
609
|
-
| `manage_plugins` | List/enable/disable editor plugins |
|
|
610
|
-
| `manage_shader` | Create or read .gdshader files |
|
|
611
|
-
| `manage_theme_resource` | Create/read/modify Theme .tres resources |
|
|
612
|
-
| `set_main_scene` | Set the main scene in project.godot |
|
|
613
|
-
| `manage_scene_structure` | Rename/duplicate/move nodes within .tscn scenes |
|
|
614
|
-
| `manage_translations` | List/add/remove translation files in project |
|
|
615
|
-
| `game_locale` | Set/get locale and translate strings at runtime |
|
|
616
|
-
|
|
617
|
-
### UI Controls (8 tools)
|
|
618
|
-
|
|
619
|
-
| Tool | Description |
|
|
620
|
-
| ------ | ------------- |
|
|
621
|
-
| `game_ui_control` | Set focus, anchors, tooltip, mouse filter on Control |
|
|
622
|
-
| `game_ui_text` | LineEdit/TextEdit/RichTextLabel text operations |
|
|
623
|
-
| `game_ui_popup` | Show/hide/popup for Popup/Dialog/Window nodes |
|
|
624
|
-
| `game_ui_tree` | Tree control: get/select/collapse/add/remove items |
|
|
625
|
-
| `game_ui_item_list` | ItemList/OptionButton: get/select/add/remove items |
|
|
626
|
-
| `game_ui_tabs` | TabContainer/TabBar: get/set current tab |
|
|
627
|
-
| `game_ui_menu` | PopupMenu/MenuBar: add/remove/get menu items |
|
|
628
|
-
| `game_ui_range` | ProgressBar/Slider/SpinBox/ColorPicker get/set |
|
|
629
|
-
|
|
630
|
-
### Rendering & Resources (2 tools)
|
|
631
|
-
|
|
632
|
-
| Tool | Description |
|
|
633
|
-
| ------ | ------------- |
|
|
634
|
-
| `game_render_settings` | Get/set MSAA, FXAA, TAA, scaling mode/scale |
|
|
635
|
-
| `game_resource` | Runtime resource load, save, or preload |
|
|
64
|
+
not claimed. Details in the
|
|
65
|
+
[verified support boundary](#verified-support-boundary).
|
|
66
|
+
|
|
67
|
+
## Highlights
|
|
68
|
+
|
|
69
|
+
- **Author without running** — create and edit scenes, nodes, scripts,
|
|
70
|
+
resources, shaders, and project settings directly in project files.
|
|
71
|
+
- **Run and observe** — launch the game, capture logs and errors
|
|
72
|
+
incrementally, take screenshots, and run visual-regression comparisons with
|
|
73
|
+
baselines, masks, and retained diffs.
|
|
74
|
+
- **Playtest like a player** — mouse, keyboard, key-hold, drag, scroll, touch,
|
|
75
|
+
and gamepad input against the running game.
|
|
76
|
+
- **Verify independently** — headless GDScript validation (`validate_script`,
|
|
77
|
+
`validate_scripts`), test runners for native/GUT/GdUnit4
|
|
78
|
+
(`run_project_tests`), bounded runtime evidence (`verify_project`), export
|
|
79
|
+
checks (`verify_export_readiness`), and static integrity analysis
|
|
80
|
+
(`analyze_project_integrity`).
|
|
81
|
+
- **Reach into the runtime** — inspect and manipulate any node, signal,
|
|
82
|
+
animation, physics body, or UI control through 100+ runtime tools;
|
|
83
|
+
`game_eval` executes GDScript with `await` support (privileged, opt-in).
|
|
84
|
+
- **Drive the editor** — `editor_control` applies reversible edits through
|
|
85
|
+
`EditorUndoRedoManager`, with a live Agent Activity dock and a human
|
|
86
|
+
**Pause Agent** lock.
|
|
87
|
+
- **.NET / C# support** — scaffold C# projects with a `Godot.NET.Sdk` matched
|
|
88
|
+
to your installed Godot, generate idiomatic scripts, and restore/build/run
|
|
89
|
+
via `verify_dotnet_project`.
|
|
90
|
+
- **Bounded by design** — deterministic pagination and size caps on large
|
|
91
|
+
responses, structured correlated diagnostics, and least-privilege security
|
|
92
|
+
defaults.
|
|
93
|
+
|
|
94
|
+
## Tool catalog
|
|
95
|
+
|
|
96
|
+
The full inventory of 167 tools — runtime interaction, scene authoring,
|
|
97
|
+
project management, verification, 2D/3D rendering, audio, UI, networking, and
|
|
98
|
+
more — lives in [docs/tools.md](docs/tools.md). Per-tool verification status
|
|
99
|
+
and test references are in the generated
|
|
100
|
+
[coverage report](docs/coverage/coverage-report.md).
|
|
636
101
|
|
|
637
102
|
## Requirements
|
|
638
103
|
|
|
639
|
-
- [Godot Engine](https://godotengine.org/download) 4.4 or later; the latest
|
|
640
|
-
|
|
641
|
-
- [
|
|
104
|
+
- [Godot Engine](https://godotengine.org/download) 4.4 or later; the latest
|
|
105
|
+
stable release, currently Godot **4.7**, is recommended
|
|
106
|
+
- (Optional) [.NET SDK](https://dotnet.microsoft.com/download) 8.0+ and the
|
|
107
|
+
Godot .NET (C#) build, only if you use `create_project`'s `dotnet: true`
|
|
108
|
+
flag or `create_csharp_script`
|
|
109
|
+
- [Node.js](https://nodejs.org/) >= 22.0.0 (active LTS)
|
|
642
110
|
- An AI assistant that supports MCP (Claude Code, Cline, Cursor, etc.)
|
|
643
111
|
|
|
644
112
|
### Godot compatibility policy
|
|
@@ -668,17 +136,11 @@ branch would receive critical fixes rather than new features.
|
|
|
668
136
|
| Profiler, leak, asset, localization, and accessibility audits | Verified in MCP E2E | `game_performance` and `analyze_project_integrity` return bounded live/static evidence; native extension builds remain unsupported |
|
|
669
137
|
| GDExtension builds | Not claimed | `analyze_project_integrity` inspects declarations and libraries without invoking arbitrary native toolchains |
|
|
670
138
|
|
|
671
|
-
## Installation
|
|
672
|
-
|
|
673
|
-
```bash
|
|
674
|
-
git clone https://github.com/beremaran/godot-agent-loop.git
|
|
675
|
-
cd godot-agent-loop
|
|
676
|
-
npm install
|
|
677
|
-
npm run build
|
|
678
|
-
```
|
|
679
|
-
|
|
680
139
|
## Configuration
|
|
681
140
|
|
|
141
|
+
The [quickstart](#quickstart) `npx` command is all most setups need. The
|
|
142
|
+
sections below cover other clients and a source checkout.
|
|
143
|
+
|
|
682
144
|
### Portable agent bundle
|
|
683
145
|
|
|
684
146
|
The repository ships one neutral bundle that starts the matching npm MCP server
|
|
@@ -694,7 +156,10 @@ For a local checkout, use `claude --plugin-dir ./agent-plugin`. See the
|
|
|
694
156
|
[portable agent bundle guide](docs/agent-plugin.md) for verified Claude Code,
|
|
695
157
|
Codex, OpenCode, and Pi install paths.
|
|
696
158
|
|
|
697
|
-
###
|
|
159
|
+
### MCP client configuration
|
|
160
|
+
|
|
161
|
+
<details>
|
|
162
|
+
<summary>Claude Code (manual settings)</summary>
|
|
698
163
|
|
|
699
164
|
Add to your Claude Code MCP settings:
|
|
700
165
|
|
|
@@ -702,8 +167,8 @@ Add to your Claude Code MCP settings:
|
|
|
702
167
|
{
|
|
703
168
|
"mcpServers": {
|
|
704
169
|
"godot": {
|
|
705
|
-
"command": "
|
|
706
|
-
"args": ["/
|
|
170
|
+
"command": "npx",
|
|
171
|
+
"args": ["-y", "@beremaran/godot-agent-loop"],
|
|
707
172
|
"env": {
|
|
708
173
|
"GODOT_PATH": "/path/to/godot",
|
|
709
174
|
"DEBUG": "true"
|
|
@@ -713,7 +178,10 @@ Add to your Claude Code MCP settings:
|
|
|
713
178
|
}
|
|
714
179
|
```
|
|
715
180
|
|
|
716
|
-
|
|
181
|
+
</details>
|
|
182
|
+
|
|
183
|
+
<details>
|
|
184
|
+
<summary>Cline (VS Code)</summary>
|
|
717
185
|
|
|
718
186
|
Add to your Cline MCP settings (`cline_mcp_settings.json`):
|
|
719
187
|
|
|
@@ -721,15 +189,18 @@ Add to your Cline MCP settings (`cline_mcp_settings.json`):
|
|
|
721
189
|
{
|
|
722
190
|
"mcpServers": {
|
|
723
191
|
"godot": {
|
|
724
|
-
"command": "
|
|
725
|
-
"args": ["/
|
|
192
|
+
"command": "npx",
|
|
193
|
+
"args": ["-y", "@beremaran/godot-agent-loop"],
|
|
726
194
|
"disabled": false
|
|
727
195
|
}
|
|
728
196
|
}
|
|
729
197
|
}
|
|
730
198
|
```
|
|
731
199
|
|
|
732
|
-
|
|
200
|
+
</details>
|
|
201
|
+
|
|
202
|
+
<details>
|
|
203
|
+
<summary>Cursor</summary>
|
|
733
204
|
|
|
734
205
|
Create `.cursor/mcp.json` in your project:
|
|
735
206
|
|
|
@@ -737,13 +208,34 @@ Create `.cursor/mcp.json` in your project:
|
|
|
737
208
|
{
|
|
738
209
|
"mcpServers": {
|
|
739
210
|
"godot": {
|
|
740
|
-
"command": "
|
|
741
|
-
"args": ["/
|
|
211
|
+
"command": "npx",
|
|
212
|
+
"args": ["-y", "@beremaran/godot-agent-loop"]
|
|
742
213
|
}
|
|
743
214
|
}
|
|
744
215
|
}
|
|
745
216
|
```
|
|
746
217
|
|
|
218
|
+
</details>
|
|
219
|
+
|
|
220
|
+
For a source checkout, use `node` as the executable and pass the built server
|
|
221
|
+
path as a separate argument:
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"command": "node",
|
|
226
|
+
"args": ["/absolute/path/to/godot-agent-loop/build/index.js"]
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Installation from source
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
git clone https://github.com/beremaran/godot-agent-loop.git
|
|
234
|
+
cd godot-agent-loop
|
|
235
|
+
npm install
|
|
236
|
+
npm run build
|
|
237
|
+
```
|
|
238
|
+
|
|
747
239
|
## Runtime Tools Setup
|
|
748
240
|
|
|
749
241
|
No setup is required when the game is started through `run_project`: the server
|
|
@@ -791,7 +283,7 @@ the event name, runtime component, numeric session ID, and timestamp.
|
|
|
791
283
|
| `GODOT_MCP_ALLOWED_DIRS` | Optional. Restrict `run_project` to projects under these roots (`;`, `,`, or `:` separated). When unset, any project path is allowed. |
|
|
792
284
|
| `GODOT_MCP_RUNTIME_SECRET` | Optional explicit shared runtime secret. The MCP server generates a fresh 256-bit value when omitted and passes it only to Godot processes it launches. Set the same value manually only when connecting to a separately launched runtime. |
|
|
793
285
|
| `GODOT_MCP_EDITOR_START_PAUSED` | Optional, default `false`. Start the editor addon's cooperative lock in human-editing mode so mutating MCP tools are refused until **Resume Agent** is pressed. |
|
|
794
|
-
| `GODOT_MCP_TOOL_SURFACE` | Optional, default `core`. Set to `full` to advertise the complete static tool catalog instead of the compact core
|
|
286
|
+
| `GODOT_MCP_TOOL_SURFACE` | Optional, default `core`. Set to `full` to advertise the complete static tool catalog instead of the compact 39-tool core, which includes `godot_tools` discovery/dispatch. |
|
|
795
287
|
| `GODOT_MCP_PRIVILEGED_GROUPS` | Optional comma-separated least-privilege grants: `reflection`, `code-execution`, and/or `network`. All are denied by default. |
|
|
796
288
|
| `GODOT_MCP_ALLOW_PRIVILEGED_COMMANDS` | Optional, default `false`. Explicitly enable runtime `eval`, arbitrary property/method access, script control, RPC, HTTP, and WebSocket commands for a trusted localhost developer workflow. |
|
|
797
289
|
|
|
@@ -841,11 +333,13 @@ The server uses three bounded execution paths:
|
|
|
841
333
|
|
|
842
334
|
| Path | Description |
|
|
843
335
|
| ------ | ------------- |
|
|
844
|
-
| `src/index.ts` | MCP server
|
|
845
|
-
| `src/
|
|
336
|
+
| `src/index.ts` | MCP server entry point |
|
|
337
|
+
| `src/tool-definitions.ts` | Tool names and JSON schemas |
|
|
338
|
+
| `src/tool-manifest.ts` | Per-tool domain, backend, and action declarations |
|
|
339
|
+
| `src/tool-handlers/` | Lifecycle, project, and game handler implementations |
|
|
846
340
|
| `src/scripts/godot_operations.gd` | Persistent and one-shot GDScript operations runner |
|
|
847
341
|
| `src/scripts/mcp_interaction_server.gd` | TCP interaction server autoload |
|
|
848
|
-
| `tests/` | Vitest
|
|
342
|
+
| `tests/` | Vitest unit, E2E, and Godot suites |
|
|
849
343
|
|
|
850
344
|
## Testing
|
|
851
345
|
|
|
@@ -866,44 +360,35 @@ npm run test:watch # watch mode
|
|
|
866
360
|
```text
|
|
867
361
|
"Run my Godot project and check for errors"
|
|
868
362
|
|
|
869
|
-
"
|
|
870
|
-
|
|
871
|
-
"Get the player's position in the running game"
|
|
872
|
-
|
|
873
|
-
"Set the player's health to 100"
|
|
363
|
+
"Create a new Godot project called 'MyGame' and write a player script"
|
|
874
364
|
|
|
875
365
|
"Read the test_level.tscn scene and show me the node tree"
|
|
876
366
|
|
|
877
|
-
"
|
|
878
|
-
|
|
879
|
-
"List all .gd files in my project"
|
|
367
|
+
"Check all my changed GDScript files for syntax errors before I run the game"
|
|
880
368
|
|
|
881
|
-
"
|
|
369
|
+
"Hold down the W key for 2 seconds to test walking"
|
|
882
370
|
|
|
883
|
-
"
|
|
371
|
+
"Pause the game and take a screenshot"
|
|
884
372
|
|
|
885
373
|
"Get performance metrics - what's my FPS and draw call count?"
|
|
886
374
|
|
|
887
|
-
"
|
|
888
|
-
|
|
889
|
-
"Find all CharacterBody3D nodes in the scene"
|
|
375
|
+
"Set the player's health to 100"
|
|
890
376
|
|
|
891
|
-
"
|
|
377
|
+
"Connect the enemy's 'died' signal to the game manager's 'on_enemy_died' method"
|
|
892
378
|
|
|
893
379
|
"Create a new C# (.NET) Godot project and add a CharacterBody2D script"
|
|
380
|
+
```
|
|
894
381
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
"Check all my changed GDScript files for syntax errors before I run the game"
|
|
898
|
-
|
|
899
|
-
"Hold down the W key for 2 seconds to test walking"
|
|
900
|
-
|
|
901
|
-
"Cast a ray from the player downward to check for ground"
|
|
902
|
-
|
|
903
|
-
"Get the camera position and move it to look at the player"
|
|
382
|
+
## Community
|
|
904
383
|
|
|
905
|
-
|
|
906
|
-
|
|
384
|
+
- [Contributing guide](CONTRIBUTING.md) — development workflow, checks, and
|
|
385
|
+
PR expectations
|
|
386
|
+
- [Security policy](SECURITY.md) — how to report vulnerabilities
|
|
387
|
+
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
388
|
+
- [Changelog](CHANGELOG.md) and
|
|
389
|
+
[release notes](docs/releases)
|
|
390
|
+
- [Issues](https://github.com/beremaran/godot-agent-loop/issues) — bug reports
|
|
391
|
+
and feature requests
|
|
907
392
|
|
|
908
393
|
## License
|
|
909
394
|
|
|
@@ -24,7 +24,7 @@ var _activity_entries: Array[Dictionary] = []
|
|
|
24
24
|
var _last_filesystem_sync: Dictionary = {}
|
|
25
25
|
const MAX_ACTIVITY_ENTRIES: int = 200
|
|
26
26
|
const PROTOCOL_VERSION: String = "1"
|
|
27
|
-
const ADDON_VERSION: String = "1.0.
|
|
27
|
+
const ADDON_VERSION: String = "1.0.1"
|
|
28
28
|
|
|
29
29
|
func _enter_tree() -> void:
|
|
30
30
|
set_process(true)
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "godot-agent-loop",
|
|
4
4
|
"displayName": "Godot Agent Loop",
|
|
5
|
-
"version": "1.0.
|
|
6
|
-
"description": "Build, playtest, and prove Godot games with an
|
|
5
|
+
"version": "1.0.1",
|
|
6
|
+
"description": "Build, playtest, and prove Godot games with an MCP automation loop.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Berke Arslan"
|
|
9
9
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "godot-agent-loop",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Build, playtest, and prove Godot games with an
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Build, playtest, and prove Godot games with an MCP automation loop.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Berke Arslan",
|
|
7
7
|
"url": "https://github.com/beremaran"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"interface": {
|
|
20
20
|
"displayName": "Godot Agent Loop",
|
|
21
21
|
"shortDescription": "Build, playtest, and prove Godot games",
|
|
22
|
-
"longDescription": "Build, playtest, and prove Godot games with an
|
|
22
|
+
"longDescription": "Build, playtest, and prove Godot games with an MCP automation loop.",
|
|
23
23
|
"developerName": "Berke Arslan",
|
|
24
24
|
"category": "Developer Tools",
|
|
25
25
|
"capabilities": [
|
package/agent-plugin/.mcp.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"$schema": "../docs/agent-adapter.schema.json",
|
|
3
3
|
"name": "godot-agent-loop",
|
|
4
4
|
"displayName": "Godot Agent Loop",
|
|
5
|
-
"version": "1.0.
|
|
6
|
-
"description": "Build, playtest, and prove Godot games with an
|
|
5
|
+
"version": "1.0.1",
|
|
6
|
+
"description": "Build, playtest, and prove Godot games with an MCP automation loop.",
|
|
7
7
|
"package": "@beremaran/godot-agent-loop",
|
|
8
8
|
"mcp": {
|
|
9
|
-
"command": ["npx", "-y", "@beremaran/godot-agent-loop@1.0.
|
|
9
|
+
"command": ["npx", "-y", "@beremaran/godot-agent-loop@1.0.1"],
|
|
10
10
|
"environment": {
|
|
11
11
|
"GODOT_MCP_TOOL_SURFACE": "compact"
|
|
12
12
|
},
|
|
@@ -98,7 +98,7 @@ export default function godotAgentLoopPi(pi: ExtensionAPI) {
|
|
|
98
98
|
try {
|
|
99
99
|
const launch = resolvePiServerLaunch();
|
|
100
100
|
const next = new Client(
|
|
101
|
-
{ name: 'godot-agent-loop-pi', version: '1.0.
|
|
101
|
+
{ name: 'godot-agent-loop-pi', version: '1.0.1' },
|
|
102
102
|
{
|
|
103
103
|
capabilities: {},
|
|
104
104
|
listChanged: {
|
|
@@ -154,7 +154,7 @@ export class EditorPluginInstaller {
|
|
|
154
154
|
'name="Godot Agent Loop Transient Bridge"',
|
|
155
155
|
'description="Session-owned authenticated editor bridge"',
|
|
156
156
|
'author="Godot Agent Loop"',
|
|
157
|
-
'version="1.0.
|
|
157
|
+
'version="1.0.1"',
|
|
158
158
|
'script="plugin.gd"',
|
|
159
159
|
`protocol_version="${EDITOR_BRIDGE_PROTOCOL_VERSION}"`,
|
|
160
160
|
'',
|
|
@@ -7,7 +7,7 @@ const RUNTIME_DIR_NAME = 'mcp_runtime';
|
|
|
7
7
|
/**
|
|
8
8
|
* The engine merges override.cfg over project.godot at startup, so the autoload
|
|
9
9
|
* is declared in a file MCP creates and deletes and never in a file the user
|
|
10
|
-
* tracks.
|
|
10
|
+
* tracks. Verified against Godot 4.7.
|
|
11
11
|
*/
|
|
12
12
|
const OVERRIDE_FILE_NAME = 'override.cfg';
|
|
13
13
|
const BLOCK_BEGIN = '; godot-agent-loop: begin interaction server (generated; removed automatically)';
|
|
@@ -24,7 +24,7 @@ var _activity_entries: Array[Dictionary] = []
|
|
|
24
24
|
var _last_filesystem_sync: Dictionary = {}
|
|
25
25
|
const MAX_ACTIVITY_ENTRIES: int = 200
|
|
26
26
|
const PROTOCOL_VERSION: String = "1"
|
|
27
|
-
const ADDON_VERSION: String = "1.0.
|
|
27
|
+
const ADDON_VERSION: String = "1.0.1"
|
|
28
28
|
|
|
29
29
|
func _enter_tree() -> void:
|
|
30
30
|
set_process(true)
|
|
@@ -187,14 +187,17 @@ export class ScriptValidationService {
|
|
|
187
187
|
return createErrorResponse('Invalid path.');
|
|
188
188
|
if (!/\.gd$/i.test(args.scriptPath))
|
|
189
189
|
return createErrorResponse('validate_script only checks GDScript (.gd) files.');
|
|
190
|
-
const
|
|
190
|
+
const projectPath = this.context.pathSecurity.canonicalProjectPath(args.projectPath);
|
|
191
|
+
if (!projectPath)
|
|
192
|
+
return createErrorResponse('Invalid path.');
|
|
193
|
+
const scriptPath = projectRelativePath(this.context, projectPath, args.scriptPath);
|
|
191
194
|
if (!existsSync(scriptPath))
|
|
192
195
|
return createErrorResponse(`Script does not exist: ${args.scriptPath}`);
|
|
193
196
|
if (!this.context.executable.path)
|
|
194
197
|
await this.context.executable.detect();
|
|
195
198
|
if (!this.context.executable.path)
|
|
196
199
|
return createErrorResponse('Could not find a valid Godot executable path');
|
|
197
|
-
const check = await this.context.projectSupport.runGdScriptCheck(
|
|
200
|
+
const check = await this.context.projectSupport.runGdScriptCheck(projectPath, scriptPath);
|
|
198
201
|
if (!check.completed)
|
|
199
202
|
return createErrorResponse(`validate_script could not check the script; ${check.error}`);
|
|
200
203
|
return { content: [{ type: 'text', text: JSON.stringify({ valid: check.errors.length === 0, scriptPath: args.scriptPath, errorCount: check.errors.length, errors: check.errors }, null, 2) }] };
|
|
@@ -631,9 +631,12 @@ export class ProjectToolHandlers {
|
|
|
631
631
|
return createErrorResponse(`Directory does not exist: ${args.projectPath}`);
|
|
632
632
|
}
|
|
633
633
|
try {
|
|
634
|
+
const projectRoot = this.context.pathSecurity.canonicalProjectPath(args.projectPath);
|
|
635
|
+
if (!projectRoot)
|
|
636
|
+
return createErrorResponse('Invalid path.');
|
|
634
637
|
const baseDir = args.subdirectory
|
|
635
|
-
? this.projectRelativePath(
|
|
636
|
-
:
|
|
638
|
+
? this.projectRelativePath(projectRoot, args.subdirectory)
|
|
639
|
+
: projectRoot;
|
|
637
640
|
if (!existsSync(baseDir)) {
|
|
638
641
|
return createErrorResponse(`Subdirectory does not exist: ${args.subdirectory}`);
|
|
639
642
|
}
|
|
@@ -662,7 +665,7 @@ export class ProjectToolHandlers {
|
|
|
662
665
|
}
|
|
663
666
|
}
|
|
664
667
|
};
|
|
665
|
-
scanDir(baseDir,
|
|
668
|
+
scanDir(baseDir, projectRoot);
|
|
666
669
|
files.sort((left, right) => left.localeCompare(right, 'en'));
|
|
667
670
|
const cursor = args.cursor ?? 0;
|
|
668
671
|
const limit = args.limit ?? 1000;
|
package/build/utils.js
CHANGED
|
@@ -68,9 +68,11 @@ export function validatePath(path) {
|
|
|
68
68
|
}
|
|
69
69
|
/** Centralized filesystem policy for project and project-relative paths. */
|
|
70
70
|
export class PathSecurity {
|
|
71
|
+
realpathResolver;
|
|
71
72
|
allowedRoots;
|
|
72
73
|
supportsRealpath = Object.keys(fs).includes('realpathSync');
|
|
73
|
-
constructor(allowedRoots) {
|
|
74
|
+
constructor(allowedRoots, realpathResolver) {
|
|
75
|
+
this.realpathResolver = realpathResolver;
|
|
74
76
|
const configured = allowedRoots ?? (process.env.GODOT_MCP_ALLOWED_DIRS || '')
|
|
75
77
|
.split(process.platform === 'win32' ? /[;,]/ : /[:,]/)
|
|
76
78
|
.map(value => value.trim())
|
|
@@ -104,6 +106,13 @@ export class PathSecurity {
|
|
|
104
106
|
? candidate
|
|
105
107
|
: null;
|
|
106
108
|
}
|
|
109
|
+
/** Return the allowed project's real path for relative-path calculations. */
|
|
110
|
+
canonicalProjectPath(projectPath) {
|
|
111
|
+
if (!validatePath(projectPath) || !fs.existsSync(projectPath))
|
|
112
|
+
return null;
|
|
113
|
+
const canonical = this.realpathWithFallback(projectPath);
|
|
114
|
+
return this.isWithinAllowedRoots(canonical) ? canonical : null;
|
|
115
|
+
}
|
|
107
116
|
isRelativePathAllowed(projectPath, relativePath) {
|
|
108
117
|
return this.resolveProjectPath(projectPath, relativePath) !== null;
|
|
109
118
|
}
|
|
@@ -117,6 +126,8 @@ export class PathSecurity {
|
|
|
117
126
|
realpathWithFallback(target) {
|
|
118
127
|
const absolute = resolve(target);
|
|
119
128
|
if (fs.existsSync(absolute)) {
|
|
129
|
+
if (this.realpathResolver)
|
|
130
|
+
return this.realpathResolver(absolute);
|
|
120
131
|
const mockedRealpath = (Object.keys(fs).includes('realpathSync'))
|
|
121
132
|
? fs.realpathSync
|
|
122
133
|
: undefined;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beremaran/godot-agent-loop",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "MCP automation loop with 167 tested tools for Godot 4",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"godot",
|
|
7
7
|
"mcp",
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"gdscript",
|
|
13
13
|
"runtime",
|
|
14
14
|
"agent-workflows",
|
|
15
|
-
"evidence-first",
|
|
16
15
|
"model-context-protocol",
|
|
17
16
|
"pi-package"
|
|
18
17
|
],
|
|
@@ -97,7 +96,7 @@
|
|
|
97
96
|
"yazl": "^3.3.1"
|
|
98
97
|
},
|
|
99
98
|
"engines": {
|
|
100
|
-
"node": ">=
|
|
99
|
+
"node": ">=22.0.0"
|
|
101
100
|
},
|
|
102
101
|
"pi": {
|
|
103
102
|
"extensions": [
|
package/product.json
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"schemaVersion": 1,
|
|
4
4
|
"name": "Godot Agent Loop",
|
|
5
5
|
"tagline": "Build it. Play it. Prove it.",
|
|
6
|
-
"category": "An
|
|
7
|
-
"description": "
|
|
8
|
-
"version": "1.0.
|
|
6
|
+
"category": "An MCP automation loop for Godot 4",
|
|
7
|
+
"description": "MCP automation loop with 167 tested tools for Godot 4",
|
|
8
|
+
"version": "1.0.1",
|
|
9
9
|
"repository": {
|
|
10
10
|
"owner": "beremaran",
|
|
11
11
|
"name": "godot-agent-loop",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"primaryGodotVersion": "4.7",
|
|
35
35
|
"protocolVersion": "1",
|
|
36
36
|
"license": "MIT",
|
|
37
|
-
"description": "
|
|
37
|
+
"description": "Godot Agent Loop Bridge is an authenticated editor companion that shows live agent activity and compatibility status, provides setup help, and gives you a human Pause/Resume control.",
|
|
38
38
|
"icon": "assets/previews/assetlib-icon.png",
|
|
39
39
|
"previews": [
|
|
40
40
|
"assets/previews/assetlib-editor-overview.png",
|