This repository was archived by the owner on Oct 16, 2026. It is now read-only.
Repository navigation
Write a new scene file with no editor attached - #1469
Merged
Merged
Conversation
project_set_input_action answered 503 with no editor, so a new project's input map could not be set before anything opened it, though project_set_setting writes the same file offline. With no editor it now writes input/<action> straight into project.godot, refuses an action that is already there unless replace is set, as the live route does, and reads the file back. The event rules lived in the bridge alone. They are now one parser in offline/input_actions, which the bridge builds its InputEvent from and the offline route writes from, so the two cannot drift. Each event is written with its class, its device and the properties the call set; Godot fills the rest when it loads the file. Measured on 4.5.1, 4.6.2 and 4.7.2: once an engine loads and saves the project, the action's text is byte for byte what the live route saves for the same events. The setting writers keep refusing input/, so a generic write cannot skip the event checks; writeInputActionLiteral is the typed tool's own way in. A dry run reads the action from the file. Refs #1379
The refusal for an action that is already there carries retry_with in the call itself, which the refusal scanner reads. Refs #1379
signal_connect answered 503 with no editor, so a scene's signals could not be wired before anything opened it. With no editor it now takes scene_path and writes the [connection] line Godot itself writes into that scene, after the last connection and before any [editable] section, under the file's lock, and reads it back. With an editor attached scene_path is refused, because the live route connects in the edited scene. The engine says nothing about most bad connections: an emitter or target the scene lacks is dropped, and a method the target lacks is connected and fails only when the signal fires, measured on 4.5.1, 4.6.2 and 4.7.2. So the write judges what it can and refuses the rest. The emitter's signal and the target's method are found through each node's GDScript, each script it extends by path or class_name, and the engine class the chain ends on. A missing one is refused with the live route's code, a duplicate and an arity the method cannot take likewise, and a node inside an instanced scene, a built-in script or a step that does not resolve is connection_not_judged. An engine class's signals are known by name alone, so their arity is not checked and the answer says arity_checked: false. Connections written this way through didi.exe load and connect on all three lines with no ERROR line. The Phase 7 success contract now holds the offline shape beside the live one, and the request takes scene_path. Refs #1387
…offline # Conflicts: # CMakeLists.txt # src/mcp/tool_registry.cpp
scene_path and the new mode cost 152 bytes, which put both profiles over. The flags text gave its reasons twice. It is shorter now, and the prose for scene_path moves to the parameter table with the rest. Full is 210351 of 210400 and core is 96822 of 96900. The reference and the capability table now say what the file route checks. A Python test runs the server with no editor and checks its answer against the success contract. Three tests that used signal_connect as their example of a live tool now expect both modes.
scene_create answered 503 with no editor, so a project's scenes could not be laid out before anything opened it. Now it writes the .tscn itself: the gd_scene header with a fresh uid and one root node line. root_type is checked against the class reference the way the editor checks it against ClassDB. It must be a class, it must inherit Node, and it must not be abstract. root_name gets the rename Node.set_name makes, because a loaded file keeps whatever name it holds. An existing file needs overwrite, and a replaced scene keeps its uid. Measured on 4.5.1, 4.6.2 and 4.7.2 for every Node class the engine can build: this file loads to the same stored state as the scene the engine saves for that root. The node line matches the engine's byte for byte, except that \a and \v go in as they are, because the engine's parser reads its own escapes for them back as letters. Fixes #1380
The reference says what the file route writes and checks, and the capability table gives scene_create its own row. The Phase 2 intro said every Phase 2 tool is live only, and five now have a file route. The guide said project_set_setting is the only project writer with no session, which stopped being true when project_set_input_action got one. tools/list is 210397 of 210400 full and 96868 of 96900 core.
…fline # Conflicts: # CHANGELOG.md # CMakeLists.txt # README.md # docs/TEST_INVENTORY.md # src/mcp/refusal_remedies.cpp # src/mcp/tool_registry.cpp
saworbit
enabled auto-merge (squash)
October 15, 2026 22:43
This was referenced Oct 15, 2026
saworbit
added a commit
that referenced
this pull request
Oct 16, 2026
* Say which tools write files with no editor attached #1467, #1468 and #1469 gave project_set_input_action, signal_connect and scene_create a file route. The capability matrix still said Phase 2 tools never edit project.godot or a .tscn behind a disconnected editor, which stopped being true at #382. The README, the site cards and the roadmap named only the live route for the signal and wiring tools. The agent guide now says what scene_create and signal_connect do with no editor. * Record the change in the changelog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
scene_createanswered 503 with no editor attached, so an agent could not lay out a project's scenes before anything opened it. With no editor, the tool now writes the.tscnitself: thegd_sceneheader with a fresh uid, and one[node]line for the root. It reads the file back, and it opens nothing. With an editor attached nothing changes.What it checks first. The same things the editor's route checks, in the same words where it can.
root_typeis checked against the class reference the way the live route checks it against ClassDB. It must be a class, it must inherit Node, and it must not be abstract. A script'sclass_nameis refused on both routes, because neither ClassDB nor the reference has it. The answer'stype_checknames the reference and says whether it is the Godot line the project was last saved by.root_nameis refused for an empty name and for a path separator, as live. Then it gets the renameNode.set_namemakes,. : @ " %to_. A loaded file keeps whatever name it holds, so without this the offline file would hold a name the live route never writes.root_name_requestedis in the answer when the two differ.already_existsunlessoverwriteis set, as live. A replaced scene keeps its uid, as it does when the editor saves over it.What I measured. For every Node class the engine can build, on 4.5.1, 4.6.2 and 4.7.2, I saved a root-only scene with
ResourceSaverand compared it with this two-line file. Both load to the same stored state. The engine writes more on some lines:unique_idfrom 4.6,layout_modeandanchors_presetfor a Control root,formatfor a TileMap. None of it changes what loads, and the editor adds it when it next saves. Then I wrote 26 scenes through the server and checked them against the engine's own files. Every type loaded as itself and every name came back right. The editor's scan registered each uid and printed no ERROR or WARNING lines.The name line matches the engine's byte for byte, with one exception I chose. The engine writes
\aand\vin a name, and its own parser reads those back as the letters, so the engine's file loses the character. This writes them as they are, and they load back.Also corrected: the Phase 2 intro in the reference said every Phase 2 tool is live only, and the guide said
project_set_settingis the only project writer with no session. Both stopped being true before this, and five Phase 2 tools now have a file route.tools/listgrew by 46 bytes for the new mode and the tool description, which no longer says the tool always opens the scene. Full is 210,397 of 210,400 and core is 96,868 of 96,900. That leaves almost no room in full, so the next change that adds to it will need to shrink something. The contract snapshots move only for this tool.Tests:
NewScene.TextAndNames,WritesAScene,RefusesWhatTheEditorRefusesandToolOfflineRoute. Each fails with its part taken out: the Node check, the abstract check, the existing file check, the rename, the escapes and the routing. The full native suite, the Python suite, the docs validator and the test counts pass locally. The bridge did not change, and CI runs the live harness.Fixes #1380