Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add Simone-Tarantino/godot-superpowers --skill setup-save-systemgit clone --depth 1 https://github.com/Simone-Tarantino/godot-superpowersWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/simone-tarantino/godot-superpowers/setup-save-system)<a href="https://agentmods.dev/skills/simone-tarantino/godot-superpowers/setup-save-system"><img src="https://agentmods.dev/badge/skills/simone-tarantino/godot-superpowers/setup-save-system.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00051 | $0.01897 |
| Opus 5 | $0.00026 | $0.00949 |
| Sonnet 5 | $0.00010 | $0.00379 |
| Haiku 4.5 | $0.00005 | $0.00190 |
Grade A, and why
setup-save-system scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 8d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 207 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Setup Save System
Resource-backed save system. Survives reboots, handles typed data (Vector2, Color, Resources, custom classes), and uses a group + method convention so each persistable node owns its own serialization.
Why Resource over JSON
| Format | Vector2 / Color | Resource refs | Custom classes | Human-readable |
|---|---|---|---|---|
JSON |
❌ string | ❌ | ❌ | ✅ |
ConfigFile |
✅ | ❌ (path only) | ❌ | ✅ |
Resource (.tres) |
✅ | ✅ | ✅ | ✅ (text) |
Resource (.res) |
✅ | ✅ | ✅ | ❌ (binary, faster) |
FileAccess.store_var |
✅ | ❌ (path only) | ❌ | ❌ |
Use Resource for save data. JSON / ConfigFile are fine for settings (which are simple key-value).
Files to create
resources/save_data.gd
class_name SaveData
extends Resource
## Top-level save container. One file per slot.
@export var version: int = 1
@export var timestamp: int = 0
@export var play_time_seconds: float = 0.0
@export var current_scene: String = ""
@export var entries: Dictionary[NodePath, Variant] = {}
Bumping version lets you migrate old saves in SaveManager.load_game.
autoload/save_manager.gd
extends Node
## Resource-based save/load. Walks the "persist" group and calls
## save_data() / load_data() on each node. Per-node payloads are stored
## by NodePath in the SaveData.entries dictionary.
const SAVE_DIR := "user://saves/"
const VERSION := 1
signal save_started(slot: int)
signal save_finished(slot: int, ok: bool)
signal load_started(slot: int)
signal load_finished(slot: int, ok: bool)
# Cumulative play time across sessions. Previous form `Time.get_ticks_msec() / 1000.0`
# resets to engine-boot every save, throwing away prior sessions.
var _play_time_accum: float = 0.0
var _session_start_msec: int = 0
func _ready() -> void:
_session_start_msec = Time.get_ticks_msec()
func save_game(slot: int) -> bool:
save_started.emit(slot)
DirAccess.make_dir_recursive_absolute(SAVE_DIR)
var data := SaveData.new()
data.version = VERSION
data.timestamp = Time.get_unix_time_from_system()
var now_msec: int = Time.get_ticks_msec()
_play_time_accum += float(now_msec - _session_start_msec) / 1000.0
_session_start_msec = now_msec
data.play_time_seconds = _play_time_accum
data.current_scene = get_tree().current_scene.scene_file_path if get_tree().current_scene else ""
for node in get_tree().get_nodes_in_group("persist"):
if node.has_method("save_data"):
data.entries[node.get_path()] = node.save_data()
var err := ResourceSaver.save(data, _path_for(slot))
var ok := err == OK
save_finished.emit(slot, ok)
return ok
func load_game(slot: int) -> bool:
load_started.emit(slot)
var path := _path_for(slot)
if not FileAccess.file_exists(path):
load_finished.emit(slot, false)
return false
var data := load(path) as SaveData
if data == null:
load_finished.emit(slot, false)
return false
if data.version != VERSION:
data = _migrate(data)
_play_time_accum = data.play_time_seconds
_session_start_msec = Time.get_ticks_msec()
if data.current_scene != "" and data.current_scene != get_tree().current_scene.scene_file_path:
await get_tree().create_timer(0.0).timeout # let frame settle
# Dynamic path from save → load() + change_scene_to_packed(); use preload() for static paths.
var packed: PackedScene = load(data.current_scene) as PackedScene
get_tree().change_scene_to_packed(packed)
await get_tree().process_frame
for node in get_tree().get_nodes_in_group("persist"):
var entry: Variant = data.entries.get(node.get_path())
if entry != null and node.has_method("load_data"):
node.load_data(entry)
load_finished.emit(slot, true)
return true
func has_save(slot: int) -> bool:
return FileAccess.file_exists(_path_for(slot))
func delete_save(slot: int) -> bool:
var path := _path_for(slot)
if not FileAccess.file_exists(path):
return false
return DirAccess.remove_absolute(path) == OK
func get_save_info(slot: int) -> SaveData:
var path := _path_for(slot)
if not FileAccess.file_exists(path):
return null
return load(path) as SaveData
func _path_for(slot: int) -> String:
return "%sslot_%d.tres" % [SAVE_DIR, slot]
func _migrate(data: SaveData) -> SaveData:
# add migrations here as VERSION bumps
data.version = VERSION
return data
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 8d ago First seen · 207 lines · 51 tokens per session scan A ee155b5affad
setup-save-system is a skill published in the GitHub repository Simone-Tarantino/godot-superpowers (2 stars, last pushed 4mo ago), licensed MIT. It adds 51 tokens to every session and 1,897 once invoked, about $0.0003 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other skills, from other repositories
game-build-team
Build a Godot 4 / GDScript game feature with a coordinated agent team — a Manager (you), a Creative Director, a Logic Developer, an Animation Developer, and a Tester — that iteratively and autonomously design, build, juice, and verify the feature against the project's design contract to a strict, un-skippable quality…
avatar-contribution-pr
Turn an avatar GitHub issue (from the in-app avatar-editor easter egg) into a merged sprite — validate the art, then either add a new module or replace an existing one, and open a PR that closes the issue. Handles both "Avatar contribution: " (a brand-new sprite) and "Avatar edit: " (a hand-redraw of an existing…
wavedash
Use when building, integrating, testing, uploading, publishing, or preparing a browser game for Wavedash, including CLI setup, Wavedash SDK features, multiplayer, achievements, leaderboards, cloud saves, player identity, user-generated content, store metadata, monetization, and content guidelines.
godot-engineer
!cat skills/shared/protocols/3d-spatial-foundations.md 2>/dev/null || true !cat skills/shared/game-visual-foundations.md 2>/dev/null || echo "=== Visual Foundations not loaded ===" !cat skills/shared/protocols/ux-protocol.md 2>/dev/null || true !cat skills/shared/protocols/game-test-protocol.md 2>/dev/null || true…
bootstrap-game-qa-system
Use ONCE per browser-game project to set up the game-qa infrastructure. Copies the shipped runner template, the adapter skeleton, and the journey schema; gap-fills the project's existing debug system if one is present. Skip for non-game projects.
requesting-game-qa
Use ONLY for QA on browser-game feature work. Triggers when the engineer signals readiness for QA: "request QA on X", "verify X", "QA this", "ready for QA on X", "this should be ready, can we make sure it works?" Compiles a brief, drives test-plan sign-off, then hands off to game-qa. Skip for tooling, build scripts…