Skip to main content
save-load is a skill from the Summer skill library: a guide your AI agent reads when the task matches, so it builds the good version on the first try. Save and load game state: user:// paths, JSON progress vs ConfigFile settings, versioned saves, autosave.

When your agent uses it

  • Persisting progress, settings, high scores, checkpoints, or save slots
  • Deciding between JSON and ConfigFile for a save or settings file
  • Making saves survive game updates with a schema version and migration

Install

summer setup installs every skill for your agent. To add only this one:
Swap claude-code for your agent, such as codex or cursor. See Skills for every option.

The skill

Trigger phrases: “save progress”, “settings menu should remember”, “high scores”, “checkpoints”, “save slots”, “JSON or ConfigFile?”, “saves broke after the update”. Save what the player would be angry to lose, and nothing else. Persist DATA (numbers, ids, flags), never live nodes or scene references.

Where saves go

Always user:// - a writable per-user dir (res:// is read-only in an export).
  • user://save_0.json - progress
  • user://settings.cfg - options
Never write gameplay saves to res://; it fails in the shipped game.

JSON vs ConfigFile

Default to JSON for game progress, ConfigFile for settings.

Save schema (version it from day one)

A top-level version field is the difference between “old saves still load after an update” and “everyone loses their progress on patch day”.
Serialize Vectors/Colors with var_to_str() and restore with str_to_var() - JSON has no native Vector2/3.

Write and read

Migration (do not skip)

When the schema changes, bump SAVE_VERSION and upgrade old saves instead of rejecting them.

Settings with ConfigFile

Always pass a default to get_value so a missing key never crashes.

Autosave hooks

  • Save on meaningful checkpoints (level end, area transition, shop close), not every frame. Disk writes stutter.
  • Save on quit via _notification:
Set get_tree().set_auto_accept_quit(false) so you control the quit.

Traps

  • Storing a node/PackedScene/callable in the save = unserializable or huge. Store ids and rebuild.
  • Writing to res:// - read-only in exports; silently fails or errors.
  • No version field - the first schema change wipes every player’s save.
  • JSON.parse_string returns null on bad input; type-check before using it.
  • Floats round-trip fine; ints may load back as floats from JSON - cast on read (int(data["gold"])).

Applying it in Summer Engine

  • The save code is a script, usually an autoload (res://scripts/autoloads/save_manager.gd): create it with summer_write_file(path=..., content=..., create_only=true), then register it with summer_project_setting(key="autoload/SaveManager", value="*res://scripts/autoloads/save_manager.gd") (the leading * makes it a singleton). Check it with summer_get_script_errors.
  • user:// is the per-user data dir, outside the project, so do not expect summer_read_file (a project-file reader) to show a save file. Prove a round trip from inside the game instead: a RunVerification probe (see playtesting-a-feature) that calls save_game(), changes a value, calls load_game(), and report()s the restored value.

From a shell

No Summer MCP tools in this session? Run each one as a command; when summer --version is missing or below 4.0, use npx -y summer-engine@latest in place of summer. Fields are flags in kebab-case (--scene-path res://main.tscn) or one --input '<json>', and summer ops describe <op> prints the exact input. The summer-cli skill has the rest.
  • make-game: Orchestrate ‘make me a game’: brainstorm, plan, scaffold, mechanics, art, audio, polish, verify, ship.
  • gdscript-patterns: GDScript conventions: type hints, signals, exports, onready, lifecycle methods, node paths, naming.
  • ui-basics: Build UI: HUDs, menus, health bars, dialogue boxes, Control trees, anchors, containers and themes.

Source: library/skills/save-load/SKILL.md, rendered from summer-engine@4.3.0 on npm.