godot-mcp is now Swallowtail. Same toolkit, new name. Why, and how to migrate

esc
↑↓ navigate↵ openSearch documentation
llm.txt

Playtest sessions

Record a play-through in the running game, then read the report and compare runs.

A playtest session records each frame's time, the engine counters, and every input, checkpoint, game event, and runtime error, each with a timestamp. Recording runs inside the game. Reading a session is local: playtest report and playtest compare read the saved file and need no editor.

Record a session

Terminal window
swallowtail scene play
swallowtail playtest start --name reach-lighthouse
swallowtail playtest mark --label approach
swallowtail input tap --keycode KEY_W
swallowtail playtest event --name boss_seen --data '{"hp": 400}'
swallowtail playtest status
swallowtail playtest stop
swallowtail scene stop

playtest start measures every frame's time and samples the engine counters every 30 frames and on each spike frame. Change the interval with --sample-every N, from 1 to 3600. playtest status reads the live counters while the session runs.

Each playtest mark starts a report section. Mark the same label again on a retry, and the report shows the second visit as its own section.

playtest stop writes one JSON file under the game's user://swallowtail-playtests/ and returns its absolute path. Run it before scene stop: stopping the game from the editor ends its process, and the session goes with it. A game that quits on its own still writes its session. One session records at a time, so a second playtest start returns -32009.

Report game events

The engine has no idea what a death or a pickup is, so difficulty numbers come from your game. Add one line where your game decides the fact:

MCPGameInspector.playtest_event("death", {"wave": wave})
MCPGameInspector.playtest_mark("boss")

Both calls return false and do nothing when no session is recording, so the lines can stay in place between sessions. playtest event posts the same fact from the terminal. Event data is a JSON object of up to 4 KiB.

Read the report

Terminal window
swallowtail playtest report --latest
swallowtail playtest report session.json --format json --out report.json

--latest reads the newest session in the game's user-data directory. Run it inside the project, or pass --project DIR. The report is Markdown unless you ask for --format json, and --out FILE writes it to a file.

The report opens with findings. Each one names a number and a place to look:

  • spikes that keep following the same input or event
  • a texture or memory jump on a spike frame
  • static memory, orphan nodes, or the node count climbing across a minute or more
  • a section whose p95 frame time stands above the rest
  • events bunched into one section, and sections entered more than once
  • runtime errors raised while recording

The tables follow: frame-time percentiles (p50, p95, p99), the worst frame, the 1% and 0.1% lows, each spike with the input or event in the second before it, every counter at start, end, and peak with a slope per minute, per-section numbers, event counts, and input rate.

Frame time is the wall-clock time between frames, so vsync and frame pacing count. A spike is a frame at least twice the median and 8 ms over it. --target-fps sets the frame budget the findings measure against, 60 by default.

Compare two runs

Change one thing, record the same route again, then compare:

Terminal window
swallowtail playtest compare --latest
swallowtail playtest compare before.json after.json --format json

compare --latest diffs the two newest sessions. Each metric gets a verdict: improved, regressed, unchanged, or changed for a metric with no better direction, such as input rate. A metric changes only past 5% of its old value and its own floor.

Short runs leave some metrics ungraded. p95 frame time needs 200 frames in each session; p99, the worst frame, and the 1% low need 1,000; the memory slope needs a minute. A frame-time change of 50% or more is graded on any run, since jitter never moves a tail that far. Record a minute or more before you trust a smaller change.

Differences in how the two sessions ran (headless, window size, vsync, GPU, engine version) are listed above the table, since each one moves frame times.

Record without the editor

With the direct-to-player channel enabled, a debug build records the same way:

Terminal window
swallowtail --game playtest start --name ci-route
swallowtail --game playtest stop

Over MCP, the playtest_* tools take the same game flag as the runtime_* and input_* tools.

Limits

  • Difficulty numbers exist only where your game reports events. Findings are recommendations. The report never edits your game.
  • A headless run's frame times are not what a player sees. The session records headless, and the report flags it.
  • A session keeps up to 216,000 frame times (an hour at 60 fps), 20,000 counter samples, 10,000 events, 20,000 inputs, 1,000 checkpoints, and 1,000 errors. Past a limit it keeps recording, sets truncated, and counts what it dropped.
Built with the help of swallowtail. MIT licensed.