Install
Requirements
| What | Version |
|---|---|
| Godot | 4.7.0 or newer |
| Node, or Bun | Node 22 or newer for npx, or Bun 1.4 or newer for bunx |
One of the two runtimes, not both: npx ships with Node, bunx with Bun, and the server runs
under either.
setup finds Godot itself, in the usual install locations. Set GODOT_PATH to the binary if
yours is somewhere else, and it will write that path into the config it generates.
One command
npx -y gdharness@0.5.3 setupThat installs the addons, enables the editor plugins, registers the runtime autoload, rebuilds the class list, writes the gdharness skill, and registers the server with your harnesses.
Then reconnect the harness so it spawns the server, and check editor_status answers.
It asks
Run at a terminal with no harness named, it asks about each one it finds, and writes nothing you did not answer for:
Claude Code is set up here. Add gdharness to it? [Y/n]
Cursor is installed. Set it up for this project? [Y/n]
Codex CLI is on this machine and has no project-level config.
Write ~/.codex/config.toml? That affects every project. [y/N]Name harnesses by flag and it asks nothing, which is how a script or an agent runs it. With no terminal and no flags, it writes the harnesses this project already uses and names the rest, so it can never hang waiting for an answer nobody can give.
# exactly these two, no questions
npx -y gdharness@0.5.3 setup --cursor --vscode
# yes, write the machine-wide one
npx -y gdharness@0.5.3 setup --codex
# no questions, and nothing outside the project
npx -y gdharness@0.5.3 setup --yes
# the addons only, no configuration at all
npx -y gdharness@0.5.3 setup --no-connectWhat it writes, and where
Nothing outside the project directory without a flag or a typed yes. 11 of the 35 have no project-level config at all, and for those a yes writes the machine-wide file, because that is their limitation rather than a choice we can make better.
Claude Code, Copilot CLI, Qoder, Command Code: written /home/you/game/.mcp.json
skill: written /home/you/game/.agents/skills/gdharness
skill: written /home/you/game/.claude/skills/gdharness4 harnesses read the same .mcp.json, so it is written once and all of them are
named. The skill goes to .agents/skills/, which 32 of them read, and to its
own directory for each of the 3 that do not. --no-skill leaves it out.
How it works has every harness, its file, and what setup decides.
The entry is the same everywhere:
{
"mcpServers": {
"gdharness": {
"command": "npx",
"args": ["-y", "gdharness@0.5.3"],
"env": { "GODOT_PATH": "/path/to/godot" },
},
},
}The version is pinned rather than latest. The server and the addons it installed have to match,
and latest is how they drift apart: editor_status reports that as addonIsStale.
GODOT_PATH is the only environment variable read. Every tool call carries its own projectPath.
An existing config keeps everything already in it, including other servers. One that does not parse is refused rather than replaced.
Check it works
| Call | Expected |
|---|---|
editor_status, nothing open |
Reports no editor. Does not fail. |
editor_status, editor open |
connected true, addonVersion equal to serverVersion. |
project_info |
The project name and main scene. |
editor_run start, editor_output, stop |
The game starts, its console comes back, it stops. |
gdharness doctor exits 1 on any problem and names it.
Updating
The server asks the npm registry once every four hours, in the background, while it is being used,
and tells your agent when there is a newer release. One request to one host, carrying nothing about
you or the project. GDHARNESS_NO_UPDATE_CHECK=1 in the server's environment stops it.
npx -y gdharness@<new> upgradeupgrade asks nothing: it reinstalls the addons at the new version and re-pins every config that
already names gdharness, and touches no config that does not. Then two things it cannot do for you,
because the old version keeps answering until they are done:
- Reconnect the MCP server so the harness re-spawns it. In Claude Code,
/mcpand reconnect. Restarting the harness is not required. - Restart an open editor:
editor_launch restart, about seven seconds. A headless editor cannot be restarted and has to be started again by hand.
editor_status confirms: addonVersion equal to serverVersion, addonIsStale false.
The rest of the CLI
| Command | What it does |
|---|---|
setup |
Addons in, editor plugins on, class list rebuilt |
setup --no-connect |
The same, and no harness configuration written |
upgrade |
The same project, on this version |
uninstall |
All of it back out again |
doctor |
Says what holds and what does not; exits 1 on a problem |
classes |
Rebuilds the class cache from disk |
harnesses |
Every harness, its flag and the file it reads |
Each of these except harnesses takes the project directory as its argument and defaults to the
one you are in. It has to hold a project.godot either way, so the default cannot act on somewhere
that is not a Godot project. An unknown flag stops the command before it does anything.
setup copies each addon whole and writes the version beside it, so doctor can tell an old copy
from the shipped one. An editor that was already open keeps serving the addon it loaded at startup
until it is restarted.
Uninstalling
gdharness uninstallThe addons, the editor plugin entries, the runtime autoload, the skill, and gdharness's own entry
in every config it can parse. Other servers in those files keep their entries and the file stays; a
file that held nothing but gdharness goes with it, and so does the .agents/skills directory it
created. A harness's own directory is left alone, empty or not, because it is theirs.
A machine-wide config may be serving another project, so it is named rather than edited:
Codex CLI: left alone. Its config is machine-wide and may serve
another project; pass --codex to remove it.Writes to project.godot go through the engine, so the file keeps its comments and formatting.
The runtime autoload
setup registers it, because without it the runtime_* tools have nothing to talk to. Like
everything else setup installs it belongs to that project alone: its own copy of the addon, its
own entry in that project's project.godot. Twenty Godot projects means twenty independent
installs, each pinned to its own version and its own engine. --no-runtime leaves it out.
It is an autoload, so an export ships it unless it is removed. It refuses to serve outside a debug build, so it is not a server on a player's machine, but turn it off before you ship.
gdharness runtime on
gdharness runtime offInstalling from the signed archive
For a pinned or offline install, and for anything that verifies its own supply chain. The archive on the release is the same bytes npm serves, so either source verifies against the same attestation.
VERSION=0.5.3
gh release download "v${VERSION}" --repo Aureliolo/gdharness
sha256sum -c "gdharness-${VERSION}.tgz.sha256"
gh attestation verify "gdharness-${VERSION}.tgz" --repo Aureliolo/gdharness \
--bundle "gdharness-${VERSION}.intoto.jsonl" \
--signer-workflow Aureliolo/gdharness/.github/workflows/release-build.yml \
--source-ref "refs/tags/v${VERSION}" \
--deny-self-hosted-runnersWithout gh, with cosign instead:
IDENTITY="https://github.com/Aureliolo/gdharness"
IDENTITY="$IDENTITY/.github/workflows/release-build.yml@refs/tags/v${VERSION}"
cosign verify-blob-attestation "gdharness-${VERSION}.tgz" \
--bundle "gdharness-${VERSION}.intoto.jsonl" \
--new-bundle-format \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity "$IDENTITY"With neither, hash the file and look the digest up in a browser at github.com/Aureliolo/gdharness/attestations. That needs nothing installed, and it trusts GitHub over TLS rather than verifying a signature, which is weaker than either command above.
macOS: shasum -a 256 -c. PowerShell: Get-FileHash gdharness-$VERSION.tgz -Algorithm SHA256.
A failed check means stop. Then unpack and run it from where it landed:
mkdir -p .tools/gdharness
tar -xzf "gdharness-${VERSION}.tgz" -C .tools/gdharness --strip-components=1
node .tools/gdharness/build/cli.js setup /path/to/projectBefore the first change
Nothing. The skill the install writes is what your agent reads, and the rest is refusals: a tool that cannot answer says which state it is in and what changes it, rather than answering emptily.