agentsclimarketplace

Builder

Skill qmertesdorf/GameForge/.claude/skills/builder

Use when generating a runnable Godot 4.x project from a manifest's concept block. Produces games/<id>/, writes manifest.build, and sets status to "generated".From its SKILL.md

Install
npx -y skills add qmertesdorf/GameForge --skill builder

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

28.7 KB, ~6.9k tokens by cl100k_base, as published. Nobody here has run it

builder

Generate a Godot 4.x project that opens and runs without manual code fixes, with a functional core loop, deliberate primitive visuals, and enough game feel that it reads as an intentional toy rather than a tech demo. "Runs without errors" is the floor, not the goal — a playtester should feel feedback on every action.

Inputs

  • manifests/<id>.json with a populated concept block (status = "concept").
  • The pinned Godot version from README.md (the source of truth for engine_version).

Outputs

  • A project under games/<id>/.
  • A populated manifest.build block and assets[] entries.
  • status = "generated".

Hard requirements

  • The project MUST import and run headless with no script errors (the validator enforces this).
  • Wire touch/tap input for Android (InputEventScreenTouch and/or _input), not just keyboard.
  • Implement every mechanic listed in concept.mechanics, plus game over + restart so the loop is replayable.
  • Keep one main scene runnable on launch (run/main_scene set in project.godot).
  • Ship the Game feel & juice and Tuning & fairness requirements below — they are not optional polish, they are what separates "playable" from "terrible but playable".

Staged build for systems-heavy genres (REQUIRED when the loop is too large to one-shot)

A turn-based deckbuilder, a tactics game, or any title with a rules engine + content DB + meta layer is too large to scaffold correctly in one pass — a one-shot produces a tangled Main.gd where rules and rendering are fused and nothing is testable. Decompose along the rules/rendering seam and build in dependency order, each stage gated by an assertion in selftest.gd before the next:

  1. Rules engine first, headless, pure. A RefCounted (e.g. CombatState.gd) holding all state and rules — no nodes, no rendering, a seedable RandomNumberGenerator so runs are deterministic. Every rule (play_card, end_turn, enemy_act, win/lose) is a method that mutates state and returns a list of events (plain dictionaries) describing what happened. This is what selftest.gd drives.
  2. Content as data classes. Card/enemy/item definitions live in data files (e.g. data/CardDB.gd, data/EnemyDB.gd returning typed Dictionaries) so the pool extends without touching the engine. Never inline content into the rules. Reach them via preload(...) + static func, NOT autoload globals — a headless --script self-test does not instantiate autoloads (see the turn-based self-test rules below), so autoload-based data is invisible to the test.
  3. Orchestration (run/map/progression, e.g. RunController.gd) on top of the engine.
  4. Persistence (user://save.json via a MetaSave.gd) — read at boot, write at the meta milestone.
  5. Rendering + juice LAST (CombatView.gd): reads engine state, replays the engine's returned events as animations (tweens, pop-ups, shake, particles), and never owns a rule. If the view computes damage, the seam is broken — move it into the engine. Event-contract completeness: every engine method that mutates the phase/screen state MUST emit the transition event (e.g. phase_changed) — the view rebuilds only on events. A method that flips phase silently (shopkeep-0001: start_day() reached via Next Day / retry) leaves a dead stale screen, and it passes the state-level self-test AND per-screen pixel audits; only a real click-through catches it. Don't let an explicit _rebuild_ui() on the boot path mask a missing event on the loop path.

Build and self-test each stage before starting the next; commit per stage. The decomposition is the deliverable as much as the game — a fused build that "works" is a skill failure even if it runs.

Deliberate primitives (no external art — that is M1)

Derive a coherent palette and shape language from concept.art_direction. Use in-engine drawing only: ColorRect, Polygon2D, _draw(), Line2D, simple GPUParticles2D/CPUParticles2D. Aim for intentional — clean shapes and a 3–5 color palette. Record each visual as an asset entry:

{ "type": "sprite", "name": "player", "source": "placeholder", "origin": "primitive" }

Compose a layered scene, not a flat field of rects (flat is the #1 cause of "looks terrible"):

  • Background layer: never leave dead space. Add cheap depth — a subtle gradient, parallax lines/dots/stars that scroll slower than the play layer, or a faint grid.
  • Play layer: the actors (player, obstacles, pickups).
  • HUD layer: a large, high-contrast score read-out (top-center is safe), drawn last so it's always readable.
  • Glow recipe for "neon"/primitive shapes: draw an oversized, low-alpha halo behind each shape (e.g. a rect/circle ~1.5–2× the size at ~15–25% alpha), then the crisp shape on top. Thick additive Line2D reads as a glowing edge. Asserting a neon palette is not enough — you must execute the glow.

Game feel & juice (REQUIRED — wire at least these)

Every action needs feedback. Cheap, headless-safe techniques:

  • Impact on death: a brief screen shake (offset the camera/draw origin by a decaying random vector for ~0.2s) and/or a full-screen flash.
  • Reward on score/milestone: a quick scale-pop or color pulse on the score, or a particle burst at the actor.
  • Squash/stretch: scale the player non-uniformly on jump take-off and landing (even ±15% for a few frames reads as life).
  • Responsive controls: act on input immediately; for a jump, allow a short coyote-time window (~0.1s after leaving the ground) and/or input buffering so taps feel honored, not dropped. Keep effects timer/tween-driven and reset cleanly on restart.

Tuning & fairness (REQUIRED)

A loop that is unfair or arbitrarily paced reads as broken even when it "works":

  • Make every challenge clearable. Derive limits from the player's own capabilities — e.g. compute jump airtime/horizontal reach and set the minimum obstacle spacing so a perfectly-timed input always succeeds. Never spawn an unavoidable obstacle.
  • Start gentle, ramp gradually. Define an explicit starting difficulty (speed/spawn rate) and a slow ramp with a hard cap (MAX_* constants), so the first ~10s is forgiving and tension builds.
  • Pull the intended curve from concept.core_loop if it specifies one; otherwise choose sane defaults and note them in a comment.

Hybrid / dual-loop concepts (REQUIRED when concept.genre blends two genres)

A blended concept (e.g. "match-3 + survival") is still just another concept the steps below consume — but the scaffold and rules above assume a single actor/threat loop. When the concept fuses two subsystems, the dominant failure mode is two systems that merely coexist on screen instead of fusing into one loop — a playtester reads it as "genre A, with something random happening at the same time" (POC run-004). Wire the fusion deliberately:

  • Name and honor the shared-resource tension. Identify the single resource both subsystems compete for (run-004: the player's matches — each swap could serve offense or defense). That contention is the game; make spending the resource on one subsystem visibly cost the other, so the player must choose.
  • State the concurrency contract explicitly (in a comment): does the real-time subsystem keep advancing during the other subsystem's discrete actions (swaps / resolves / animations)? "It keeps advancing" is usually what creates pressure — but make it a deliberate, tuned choice, not an accident.
  • Prefer shared-space fusion over a periodic interrupt. If the concept puts the threat on genre A's board (enemies corrupt gems, the advancing line eats grid rows), wire it so a single player action resolves in both subsystems at once — that's what makes seconds feel blended rather than alternating (POC run-005). A discrete, telegraphed event (a heavy strike every ~6s you must respond to) and a continuously-advancing threat (a line creeping forward every frame) are two distinct patterns: the telegraphed event creates a "drop everything and defend" spike but reads as an interrupt if it's the only coupling; the continuous threat creates steady background pressure. Reach for each deliberately, and lead with the continuous/shared-space coupling so the telegraph is a spike on top of fusion, not the sole link.
  • Make the cross-subsystem causal link SALIENT. The player must see and feel that action A drove effect B — a bright tracer from the match to the threat, a wall pulse on repair, a number that visibly jumps. A correct-but-invisible link is exactly what reads as "random stuff happening at once."
  • Tune fairness across BOTH axes. The dominant strategy must neither trivially win nor be unwinnable: a steady stream of the offense action should be able to out-pace the capped threat, while ignoring the defense action should reliably lose. Watch the threat/HP values over your 3000-frame headless run to confirm — and if the genre is logic-heavy, assert it in selftest.gd (below).

Godot 4.6 GDScript typing (REQUIRED — this prevents build-error loops)

Godot 4.6 enforces strict typing and treats an inferred Variant as an error. Three consecutive POC runs lost (or would have lost) build iterations to exactly this, so follow it from the first draft — doing so took the two most logic-dense builds to zero build iterations:

  • Never :=-infer off a Variant-returning expression. Indexing an untyped Array/Dictionary returns Variant; so do clamp, lerp, min, max, abs (even with float args). Annotate the receiving variable explicitly: var x: float = clamp(v, 0.0, 1.0), var c: Color = lerp(a, b, t), var cell: int = grid[i].
  • Array.filter() / Array.map() return an untyped Array — assigning to a typed Array[T] needs an explicit annotation or a rebuilt typed array.
  • Prefer typed containers where natural (e.g. var board: Array = []), but always annotate the read site rather than relying on inference.

Reference scaffold (adapt to the genre)

Orientation (read from the manifest — do NOT hard-code). Read build.orientation from manifests/<id>.json. Absent or "portrait"viewport_width=720, viewport_height=1280, window/handheld/orientation="portrait" (the values shown below). "landscape"viewport_width=1280, viewport_height=720, window/handheld/orientation="landscape". Lay out the scene for the chosen frame: a landscape game uses the width (e.g. a fanned card hand along the bottom, actors staged left↔right); a portrait game uses height. The concept/manifest is the source of truth — never assume portrait. Write the build block including the orientation you used so the validator/packager pick the matching splash/screenshot dims (splashSize(orientation)).

games/<id>/project.godot:

config_version=5

[application]
config/name="<Title Name>"
run/main_scene="res://Main.tscn"

[display]
window/size/viewport_width=720
window/size/viewport_height=1280
window/handheld/orientation="portrait"
window/stretch/mode="canvas_items"
window/stretch/aspect="keep"

[input]
tap={
"deadzone": 0.5,
"events": []
}

[rendering]
renderer/rendering_method="mobile"
textures/vram_compression/import_etc2_astc=true

Android export requirement (proven on a real Android export): the [rendering] block above is mandatory for an Android build. import_etc2_astc=true is required — without it godot --export-debug "Android" fails the export validation with an empty/opaque "configuration errors:" message (the headless CLI does not name the cause; the editor's Export dialog does). rendering_method="mobile" (Vulkan) is the authored default and runs on real devices; note that the GL-compatibility renderer needs GLES 3 and that Android emulators often cannot drive either renderer (Vulkan → black, GLES3 → EGL crash), so emulators are an unreliable visual test for Godot — confirm visuals on desktop or a real device, not an AVD. (See packager/README "Android export" for the build seam.)

games/<id>/Main.gd (skeleton — fill the genre-specific loop):

extends Node2D

var score: int = 0
var alive: bool = true

func _ready() -> void:
	_start_game()

func _start_game() -> void:
	score = 0
	alive = true
	# spawn player + initial world here

func _input(event: InputEvent) -> void:
	# Android tap + desktop click both arrive here.
	if event is InputEventScreenTouch and event.pressed:
		_on_tap()
	elif event is InputEventMouseButton and event.pressed:
		_on_tap()

func _on_tap() -> void:
	if not alive:
		_start_game()
		return
	# core action (jump / shoot / swap ...) goes here

func _process(delta: float) -> void:
	if not alive:
		return
	# advance the world; on the loss condition call _game_over()

func _game_over() -> void:
	alive = false
	# show "tap to restart"

Create Main.tscn as a text scene referencing Main.gd on the root node, plus the primitive nodes the genre needs.

Steps

  1. Read manifests/<id>.json; confirm concept is populated.
  2. Scaffold games/<id>/ with project.godot, Main.tscn, Main.gd, and any extra scenes/scripts the mechanics need. Use the pinned engine_version from README.md.
  3. Implement the core loop from concept.core_loop + concept.mechanics, including game-over + restart and touch input.
  4. Apply the primitive visual style from concept.art_direction as a layered scene (background + play + HUD) with the glow recipe.
  5. Wire the Game feel & juice feedback and apply Tuning & fairness (clearable spacing, gentle start + capped ramp).
  6. Write the build block:
    node tools/manifest.mjs merge <id> "{\"build\": {\"engine\": \"godot\", \"engine_version\": \"<pinned>\", \"language\": \"gdscript\", \"project_path\": \"games/<id>/\", \"addons\": [], \"export_presets\": [\"android\"]}}"
    
  7. Record primitive assets:
    node tools/manifest.mjs merge <id> "{\"assets\": [ ...primitive entries... ]}"
    
  8. Advance status:
    node tools/manifest.mjs set-status <id> generated
    node tools/manifest.mjs validate <id>
    
    Expected: <id> OK. Hand off to validator.

Notes

  • Importing a .gd script generates a sibling <name>.gd.uid file. This is expected Godot 4.x output, not stray junk — commit it alongside the script.
  • MOUSE_FILTER_PASS does NOT pass input to siblings underneath. The viewport hit-test stops at the topmost non-IGNORE Control under the point; PASS only bubbles the event to ancestors. A full-screen container Control with PASS layered over clickable siblings silently swallows every tap on them (shopkeep-0001: a 720×1280 patron-queue box over the shelf tiles killed all shelf taps). Pure container/overlay Controls must be MOUSE_FILTER_IGNORE — IGNORE skips only the box itself; its own children stay clickable.

Self-test for logic-heavy genres (REQUIRED when the loop has non-trivial state logic)

"Runs headless without errors" does NOT prove the loop is correct — a match-3 with broken match-detection, or a hybrid whose offense match never actually damages the threat, will pass the programmatic gate and only fail a human (POC runs 002–004). For logic-heavy genres (puzzle/grid, state machines, multi-subsystem hybrids), emit games/<id>/selftest.gd: a headless SceneTree script that loads the game, drives the core action over N frames (drive state directly or synthesize InputEvents — never wait on real input), ASSERTS observable state changes, then prints exactly SELFTEST OK and exits 0, or SELFTEST FAIL: <reason> and exits non-zero.

Lifecycle gotcha (POC run-005): in a SceneTree/headless self-test, when you add_child the game node its _ready() is deferred — it has not run yet on the line after add_child, so the board/world is still empty if you assert immediately. Drive setup explicitly (call the game's _start_game()/setup method yourself, or await a frame) before the first assertion. Fix the harness, not the game, when this bites.

Turn-based / scripted-turn genres (deckbuilder, tactics, roguelike): a real-time _process loop does not exercise a turn-based engine — drive scripted turns through the rules engine directly with a fixed RNG seed, and assert the full turn cycle. Think in turn-cycle primitives, not one genre's nouns; instantiate each primitive in your genre's terms:

  • Setup → opening state populated. Seed the engine and start the encounter → assert the starting state exists (deckbuilder: opening hand drawn to its size; tactics: units placed on the board; roguelike: starting room/stats initialized).
  • Spend a resource for a primary effect → assert both. Take the core offensive action → assert the resource was deducted and its effect landed (deckbuilder: a card costs mana and drops enemy HP by its value; tactics: a unit spends action points and its attack lands; RPG: an ability spends MP and hits).
  • Establish a state for later → assert it appears. Take a setup action → assert the state it creates is present (deckbuilder: a damage-over-time or stacking status on the enemy; tactics: a buff/zone/marked target).
  • Exploit that state for a conditional payoff → assert the bonus branch. Take the payoff action against that state → assert the bonus branch fired, not the base one (effect > base) (deckbuilder: a payoff card vs an afflicted target; tactics: bonus damage vs a marked/flanked unit).
  • End turn / opponent phase → assert the opponent acted AND time-based state advanced. Resolve the turn → assert the opponent took its action (player state changed or was absorbed) and durational state ticked — applied and decremented (deckbuilder: a DoT dealt damage + decremented, a consumable status consumed; tactics: cooldowns/buff durations advanced; roguelike: a temporary effect expired).
  • Force the win condition → assert win + progression. Drive the encounter to a win → assert the win-state (e.g. is_won()), then assert the post-encounter progression resolved (a reward choice advances the run, the next mission unlocks).
  • Force the loss condition → assert loss. Drive the player to defeat → assert the lose-state (e.g. is_lost()).
  • Persistence milestone → assert the save wrote. Drive the save trigger → assert the persistent file (user://save.json) was written with the expected keys. Seeded RNG makes every assertion deterministic; the validator's Method 1.6 runs this and fails the build on SELFTEST FAIL.

Three hard rules for turn-based self-tests:

  • Headless --script runs don't instantiate autoloads. godot --script starts a minimal SceneTree that skips the [autoload] section — Engine.has_singleton("CardDB") returns false, /root/CardDB is absent. Reach data layers (CardDB, EnemyDB, etc.) via const X := preload("res://data/X.gd") + static func only. Drop the [autoload] block from project.godot for any data file the self-test must reach, or make those files static-accessible so the self-test can preload them directly. (This silently breaks any turn-based build that expects autoload globals in its self-test.)
  • Seed every RNG path via a RandomNumberGenerator and shuffle with an explicit Fisher–Yates loop. Array.shuffle() uses the global RNG and ignores any custom seed — deterministic assertions break silently. Use rng.randi_range() inside a manual Fisher–Yates on every shuffle that the self-test depends on.
  • Reset persistent side-effects before asserting on them. If the self-test writes user://save.json (or any other file) and then asserts its contents, delete the file immediately before the write — a stale file from a prior run will false-positive the assertion without the write actually having occurred.

Assert what a human would check, e.g.:

  • a known swap that should clear cells actually reduces the gem count / fires the match path,
  • after a forced resolve the board has no floating gaps,
  • an offense match lowers the threat's HP and a defense match raises wall HP (the hybrid's whole point),
  • _game_over() fires when the loss condition is forced. Keep it deterministic and headless-safe. The validator runs it automatically and will fail the build on SELFTEST FAIL. For a trivially simple arcade loop where a state assertion adds nothing, you may skip it — but say so explicitly in the build notes so the omission is a deliberate, legible choice, not a gap.

Interaction self-test for tap/click-driven games (REQUIRED — emit games/<id>/uitest.gd)

A state-level self-test (drives the engine directly) and a pixel audit (judges renders) both miss a whole bug class: the screen looks right and the rules are right, but taps never reach handlers (mouse-filter shadowing, missing rebuild events — both shipped in shopkeep-0001 and survived every gate including the human playtest). For any game whose core loop is driven by tapping/clicking controls, emit games/<id>/uitest.gd alongside selftest.gd — its view↔input twin (selftest.gd proves the rules; uitest.gd proves a tap reaches them). The validator runs it (Method 1.7) and fails the build on UITEST FAIL; view-mutating passes (asset / deepen / visual-audit fixes) re-run it before handoff. Reference implementation: games/shopkeep-0001/uitest.gd.

Contract and technique:

  • A headless SceneTree script that boots Main.tscn, then walks the full core loop with real clicks: build InputEventMouseButton down+up pairs at each control's get_global_rect().get_center() and push via root.push_input(ev, true) (in_local_coords=true — the headless window ignores project size, so window-coord pushes get mis-stretched).
  • After every click, assert engine state changed (resource collected, phase advanced, sale counted) — never assert only view internals; the point is proving input reaches the rules.
  • Print one UITEST PASS:/UITEST FAIL: line per check, then exactly UITEST OK + exit 0, or UITEST FAIL: <n> checks failed + exit 1. (Track failures — a script that always exits 0 cannot gate anything.)
  • Make outcome checks deterministic: fixed seed, and force the relevant state before an outcome-dependent click (e.g. set the patron's want to the shelf item you'll tap) — post-action UI resets make "did the tap land" ambiguous otherwise.
  • If the test triggers a persistence write, clear the real user:// save at start AND end so test state never leaks into the next boot.
  • Cover at minimum: one tap per distinct control type, every phase/screen transition button, and the loop seam back to the start (e.g. next-day → first screen rebuilt).

Run your own self-test before handing off:

& "<godot exe>" --headless --path games/<id>/ --script res://selftest.gd

Expect exit 0 and SELFTEST OK. Fix the loop logic (not the assertion) until it passes.

Balance / playability self-test (REQUIRED for any game with a win/economy/progression loop — emit games/<id>/playtest.gd)

selftest drives the engine directly, so it proves the rules in the abstract and is blind to whether the assembled loop is winnable — a game can pass every logic/UI gate and be physically unplayable (diver-0001 shipped 100% unwinnable: its resource gate sat past the nearest reward, so a player could never make progress, with every other gate green). For any game with a win condition, an economy, or progression, emit games/<id>/playtest.gd per the playtest-audit skill: a headless competent-player bot that drives the real loop (real spawns/collision/resource math, stepping _process at a fixed dt) and asserts the game is winnable, fair, and progressable, printing PLAYTEST OK/PLAYTEST FAIL. The validator runs it (Method 1.8). A trivially-endless arcade toy with no economy may skip it — say so in the build notes. A PLAYTEST FAIL is a tuning bug (spawn geometry, gate depths, costs, the ramp) — fix the tuning, never weaken selftest to match.

Winnable-by-construction: generate-and-verify for discrete generated content (REQUIRED when applicable)

playtest.gd discovers unwinnability after the fact, by sampling whatever instances the run's RNG happened to produce. That is the right gate for the assembled loop — but if your game generates discrete content instances (a puzzle board, a procedural map/layout, a wave composition, a shop's offered economy), you can do better than sampling: make each instance verifiably solvable at the moment it is created, so an unsolvable one can never reach the player. This pushes winnability upstream of playtest.gd, which then becomes confirmation (the per-instance guarantee survived assembly) rather than the first and only place it's checked.

Applicability decision test — do this FIRST; the gate is not universal. Apply generate-and-verify only when solvability is a combinatorial / emergent property of a discrete generated instance that you cannot prove with a closed-form formula:

  • Applies: puzzle boards (nonogram / sort / block / path), generated maps or room layouts, enemy-wave compositions, a generated shop/economy the player must be able to afford a path through, any "deal the player a situation" step.
  • Does NOT apply: continuous action games whose winnability is a spacing/timing property already provable by closed form (a runner's obstacle gaps — keep using the existing "derive limits from the player's own capabilities" math under Tuning & fairness). Don't bolt a solver onto a game that doesn't deal discrete instances.

If it applies, the running game itself carries a generator and a fast in-game solver/feasibility checker, and every instance is produced through a verified path:

# On the seedable RefCounted rules engine — the same substrate selftest/playtest drive.
const MAX_TRIES := 40

func make_verified(seed: int) -> Instance:
    var rng := RandomNumberGenerator.new()
    rng.seed = seed
    for attempt in MAX_TRIES:
        var inst := _generate(rng)              # propose a candidate
        if Solver.is_solvable(inst):            # VERIFY before it can ship
            return inst                         # guaranteed winnable
    return _fallback_template()                 # known-good; loop always terminates winnable

The solver has two tiers — match it to the genre (this is the "solver / simulator" gate):

  • Exact solver — combinatorial puzzles. Actually solve it (or prove a solution exists): a constraint pass for a nonogram, a BFS/DFS reachability for a path/maze, a deal-out check that a sort/stack is unscramblable. GameForge boards are small, so exact is cheap. Returns a real yes/no.
  • Simulation feasibility checker — systemic games (survivors / economy / roguelike) where exact solving is intractable. Run a bounded competent-policy forward-simulation of the instance and assert a reachable good outcome exists (the wave can be survived; the shop offers an affordable path to the next tier). Reuse the playtest.gd competent-bot policy as a library here — same harness, called as a generation-time feasibility oracle — don't fork a second copy.

selftest.gd gains generate-and-verify regression assertions (RED→GREEN like any other system). Over K seeds (e.g. K=200):

  1. Every make_verified(seed) output passes Solver.is_solvable — the core guarantee.
  2. The retry budget is rarely exhausted. Count fallbacks; assert they're the exception (e.g. < 5%). A high fallback rate means the generator is mistuned (it mostly proposes garbage and leans on the template) — a real defect, not something to paper over by raising MAX_TRIES.
  3. The fallback template is itself solvable — assert Solver.is_solvable(_fallback_template()). The safety net must be safe.

Guard culture (mirrors playtest's): a failing solver gate is a generator/tuning bug — fix the generator or the instance space so it proposes solvable instances. Never weaken Solver.is_solvable to make the assertion pass — a solver that rubber-stamps everything guarantees nothing, exactly as a weakened selftest proves nothing. This needs no manifest change (the guarantee is enforced by selftest, which the validator already runs).

Reference implementation: games/deckbuilder-0001/MapGen.gd — a Slay-the-Spire-style run map. is_solvable() is an exact structural solver (single terminal boss + every node still reaches the boss, so no choice traps the player); make_verified(rng) rejection-samples and falls back to _fallback_map(); RunController.start_run ships only verified maps. selftest.gd Stage 7b is the regression spine: over 200 seeds every make_verified output is solvable, the raw generator's first-try solvable rate stays ≥ 95% (else the generator is mistuned), the fallback is itself solvable, and the solver is fed a path-broken map to prove it returns false (not a rubber stamp).

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,835. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.