# AGENTS.md Guide for coding agents working on this repository. ## What this is Godotwright is a coding toolkit for Godot 4.7.x: a CLI and (later) an MCP server that make any coding agent better at Godot. See `ROADMAP.md` for the plan and the "done" check of each step. ## Commands ```sh npm ci # install exact dependencies npm run typecheck # tsc, no output files npm test # vitest npm run build # compile src/ to dist/ npm run check # all of the above, run this before every commit node dist/cli.js --help ``` ## Layout - `src/cli.ts`: executable entry point (`godotwright` bin). Keep it tiny. - `src/program.ts`: builds the commander program. Commands are added here. - `src/commands/`: one file per CLI command. - `src/godot/`: readers for Godot file formats (Variant text, project.godot, .tscn/.tres, GDScript outline). No I/O in here. - `src/project/`: finding the project root and listing its files. - `src/scan/`: builds the project map and formats it (brief, full, JSON). - `src/check/`: runs Godot headless (import, checker script, optional run) and turns its output into diagnostics. - `src/lsp/`: Godot's own GDScript language server (`godot_code`). `jsonrpc.ts` is the JSON-RPC client with LSP framing, `server.ts` starts `godot --editor --headless --lsp-port` and keeps one warm server per project (idle stop, killed on exit, restarted when a class_name, project.godot or a file that needs an import changes; a restart waits for the calls queued on the old server), `code.ts` holds the ops and output. - `src/shaders/`: the GPU pass over shaders: draws every shader in Godot (Compatibility renderer, xvfb-run on Linux without a display), for what only the GPU driver rejects (a uniform block that is too big, a sampler array indexed by a variable). Language errors are found headless, without it: `src/check/shader-compile.ts` (`Shader.get_rid()` runs Godot's full shader compiler on the dummy renderer) for `godot_shader`, and the checker of `godot_check`. `runner.ts` is the GDScript it runs, `log.ts` reads Godot's shader errors, `hints.ts` names the Godot 4 form of Godot 3 shader code, and `shaders.ts` maps each error to the line in the .gdshader, .gdshaderinc or .tres/.tscn. `godotwright shaders`, `check --shaders` and `shader --gpu` use it; `src/shader/shader.ts` (`godot_shader`) puts the static review, the headless compile and this pass together. - `src/screenshot/`: `screenshot.ts` renders a scene or model with Godot; `png.ts` is the one PNG reader and writer, `diff.ts` the pixel compare (areas of change, moves, blank pictures; diffs in red), and `baseline.ts` the one baseline implementation ("auto", a .png path, or a name with its settings in JSON) that screenshots, scenario screenshot steps and `godotwright ci` share. Option names released in 0.5.0 (`baseline`, `threshold`, `tolerance`, `update_baseline`) keep their meaning. - `src/api/`: lookup and search over the bundled Godot 4.7 class reference. - `src/review/`: the AAA review. `src/review/model.ts` resolves classes, types, members and scene nodes; `checks/` holds one file per category (`pitfalls.ts` and `runtime.ts` hold the rules that came from lessons); `rules.ts` lists every rule. New rules need a test in `test/review.test.ts` (shader rules in `test/review-shader.test.ts`), and must stay quiet on the official demo projects (`test/integration/review-demos.test.ts`). - `src/model/`: checks `.glb` and `.gltf` files without Godot. `inspect.ts` reads what is in a model, `lint.ts` and `rules.ts` hold the AAA model review, `contract.ts` reads and checks `model.contract.json`, and `gltf.ts` is the glTF reader. - `src/build/`: makes models from code. `mesh.ts` and `shapes.ts` are the mesh kit, `glb.ts` writes the GLB, `generators/` holds the ready-made kinds (`house`, `terrain`, `sea`), `spec.ts` builds a JSON model spec, `recipes.ts` loads `data/recipes/`, and `run.ts` builds a model and lints it. - `src/library/`: the asset library (`model library`, `godot_model_library`). `kit.ts` is the authoring kit (node and parameter builders, `combos`, `rng`), `palette.ts` the named materials, `families//` one file per family (each a `Family` that makes its variants as specs), `library.ts` loads and searches them (English and Dutch words), and `format.ts` prints them and makes `LIBRARY.md` (`npm run build:library`; a test keeps it in sync). Every asset must build clean against its archetype at its defaults and parameter extremes (`test/library/`; run one family with `LIBRARY_FAMILY=`, every extreme with `LIBRARY_EXTREMES=all`, and keep the .glbs with `LIBRARY_DUMP=`). `test/integration/library-godot.test.ts` imports and loads them in Godot (`LIBRARY_GODOT=all` for every asset), and `scripts/render-library.mjs` renders contact sheets in Godot (`--out [category] [family]`), or the README gallery `docs/library.png` (`npm run render:library`): look at them, a clean lint does not mean a model looks good. - `src/archetype/`: what a thing is, from `data/archetypes/` (`library.ts` loads it). `identify.ts` matches a name in English or Dutch, `check.ts` checks a model against its archetype, and `format.ts` prints the results. - `src/project/git.ts`: the little of git the tools need (which project files changed against a commit, a file as it was there). Read-only; commit names are checked before they reach git. - `src/diff/`: `godot_diff`, the diff by meaning: scenes and resources (`diffResourceText`), scripts (`diffScriptText`), settings, shaders and import files, and what each removal breaks elsewhere in the project. - `src/impact/`: `godot_impact`: the file graph of `src/deps/` walked backwards from the changed files to scenes, tests and saved scenarios, and the checks to run. - `src/collisions/`: `godot_collisions`: physics layers and masks read from the scenes, who detects whom, and what can never work. A new problem rule must stay quiet where code makes shapes or sets layers. - `data/godot-api.json.gz`: generated by `scripts/build-api.ts`; never edit by hand. - `src/collector/`: the reference collector for shared reports and the aggregation into `data/learned.json` (k-anonymity: at least 3 installs). `src/learn/bundled.ts` loads that file at runtime. - `src/lessons/`: lessons from real projects. `data/lessons.json` holds the bundled ones (`library.ts` loads it), `search.ts` finds them by words, Godot message, rule and archetype and ranks them by feedback, `local.ts` keeps the lessons learned on this machine, `anonymize.ts` scrubs names, paths, codes and source code from them (bundled lessons must pass it unchanged; `test/lessons.test.ts` checks this), `hints.ts` adds lessons to check and review output, and `format.ts` prints lessons and gaps. A new rule that comes from a lesson names it in the lesson's `rules`. - `src/mcp/server.ts`: the MCP tools and the cheap/premium profiles. Register tools with `tool(...)`, never `server.registerTool`: every tool must be in one set in `src/mcp/toolsets.ts` (`--tools`, `--read-only` and the read-only refusals), `src/mcp/instructions.ts` holds the server instructions (filtered by the enabled tools), and `src/mcp/structured.ts` the `outputSchema`s and `structuredContent` of review, check, doctor and test. - `src/mcp/lean.ts`: lean mode (`--lean`): the tools are kept out of the tool list and run through `godot`, with `godot_help` for their parameters. A tool needs nothing extra for it; keep its `title` short, it is the tool's line in the catalogue. - `src/check/progress.ts`: the run context of a tool call: progress messages from Godot's output and cancellation; `runGodot` uses it, so code that starts Godot needs nothing extra. - `src/project/protect.ts`: protected paths (godotwright.json `"protect"`, `$GODOTWRIGHT_PROTECT`). Every write Godotwright makes to a project goes through `JournalWriter` or calls `assertWritable` itself. - `src/hooks/agent-hooks.ts`: hooks for coding agents (`godotwright hook `, Claude Code hook JSON on stdin): review after an edit, lessons under Godot errors in command output, open errors before the agent stops, a project brief at the start. A hook must never fail the agent: on any problem it prints nothing. The plugin calls it through `plugins/godotwright/hooks/run.mjs`, which starts the same godotwright version as the plugin's MCP server. - `src/learn/`: local learning. `store.ts` reads and writes the learning file, `learn.ts` turns reviews, checks, lookups and feedback into counters and applies them, `hooks.ts` is what the CLI and MCP server call, `share.ts` builds and sends the opt-in anonymous report (see `PRIVACY.md`; keep it in sync). Learning must never break a tool, and must never store code, names or paths. Local lessons are free text: they are scrubbed when kept and are never part of a report (only counts per bundled lesson id are). - `src/dream/`: dreaming (`godotwright dream`, `godot_dream`). `dream.ts` turns the learning file, the journal's log of undone writes and (only when asked) session transcripts into numbered proposals with evidence, applies them through the journal (lessons through `src/lessons/local.ts`, so they are scrubbed), keeps the "Godotwright lessons for agents" note in the private dream folder (`src/project/local-dir.ts`: the project's untracked `.godot/godotwright/`, else Godotwright's state folder), and holds the due logic the session-start hook uses. `transcripts.ts` reads Claude Code and Codex transcripts into anonymous facts only (tool names, message templates, Godot API names): never let their text reach an output, a lesson or a report. Deterministic: no model calls, no network. - `src/version.ts`: package version and the Godot target version. - `server.json`: the MCP Registry entry. Its name and versions must match `package.json` (`mcpName`, `version`); a test checks this. - Install packages, kept in step with `package.json` by `scripts/sync-version.mjs` (which `npm version` runs) and checked by `test/install.test.ts`: - `.claude-plugin/marketplace.json` and `plugins/godotwright/`: the Claude Code marketplace and plugin (MCP server in `.mcp.json`, skills in `skills/`, subagents in `agents/`, hooks in `hooks/`). Skills and agents may only name MCP tools the server has; `test/install.test.ts` checks it. - `gemini-extension.json`: the Gemini CLI extension. - `mcpb/`: the Claude Desktop bundle manifest and icon; `npm run build:mcpb` builds `build/godotwright.mcpb`, and the Release workflow attaches it to every release. - `docs/install.html`: every client, with the Cursor and VS Code one-click links. - `Dockerfile`: builds the MCP server from this repository, for directories such as Glama that build and test servers in a container. - `llms-install.md`: install steps written for agents such as Cline. - `src/index.ts`: public library exports. - `bench/`: the benchmark (tasks with Godot behavior tests, runner, grader). See `bench/README.md`. Task tests run in CI by the Bench workflow. - `docs/`: the GitHub Pages site (`index.html`, `demo.svg`, `og.png`), deployed by the Pages workflow. Keep its claims in sync with the README. - `test/`: vitest tests, one file per area. `test/setup.ts` points `GODOTWRIGHT_HOME` at a temp dir, so tests never touch the real learning file. `test/fixtures/demo` is a small, valid Godot 4.7 project; keep it error-free. `test/fixtures/broken` has known errors. `test/fixtures/messy` has one example of most review findings. - `test/integration/`: tests that need a real Godot binary in `$GODOT` (and `$GODOT_DEMOS` for the official demo projects), or the Claude Code and Codex CLIs (`AGENT_CLIS=1`). CI runs them. - Never write to stdout in code the MCP server runs: stdout is the protocol channel. ## Conventions - Node.js >= 22.12, TypeScript in strict mode, ES modules only. - Relative imports use the `.js` extension (`./program.js`), as NodeNext requires. - Prefer Node built-ins over new dependencies. Add a dependency only when it clearly pays for itself. - Every new feature comes with tests. Tests must not need a Godot install unless they are marked as integration tests. - Output meant for agents is compact and stable, so it is cheap to read and easy to parse. ## Privacy - Never game code: no code, file contents, paths, or project, file or node names in lessons, hints, reports, learned data or anything sent. Scrub free text (`src/lessons/anonymize.ts`) and drop what still looks like code or a name. - Private data only on the user's machine, and only with their permission: reading session transcripts and applying dreams are opt-in per run; automatic applies need the user's one-time consent on that machine. - Never into the repository and never online: learned data goes to untracked folders (`.godot/` when git ignores it) or Godotwright's state folder, never into AGENTS.md, CLAUDE.md or any tracked file. - Learning across machines only anonymously, through the existing opt-in sharing (`src/learn/share.ts`, `PRIVACY.md`). ## Commits and content - Small commits with a short imperative subject (`Add project scan`). - No trailers, chat or session links, or personal information in commits or files. - Update the status list in `ROADMAP.md` when a step is done. - Releases: add the version's section to `CHANGELOG.md`, run `npm version X.Y.Z` (it also writes the version into `server.json`, the Claude Code plugin and the Gemini CLI extension), then push the commit and the tag `vX.Y.Z`. The Publish workflow publishes to npm and the MCP Registry; the Release workflow writes the notes and attaches the Claude Desktop bundle. Bump the version only in the release commit: the plugin and the extension start that exact npm version.