Engineering tools
Small, game-agnostic tools for an agent working on a live Studio place. Python needs only the standard library (plus zstandard for some .rbxm files). Luau tests need the luau CLI.
2 min read
Small, game-agnostic tools for an agent working on a live Studio place. Python needs only the standard
library (plus zstandard for some .rbxm files). Luau tests need the luau CLI.
| File | Kind | What it does |
|---|---|---|
| stage.py | Python | Wraps edited sources (plus their base copies) into one .rbxmx with a unique folder name |
| stage_apply.luau | Luau (execute_luau) | All-or-nothing base-compare apply of a staged folder |
| rbxm_extract.py | Python | Snapshot exporter: every script in a binary .rbxm to .luau files, byte-exact |
| fingerprint.luau | Luau (execute_luau) | Path, size and hash of every script in Studio, no source text |
| snapshot_diff.py | Python | Diff two trees, or a Studio fingerprint against a local tree |
| game_check.py | Python | Syntax-check every .luau before staging; optional lints |
| SessionStore.luau | Luau module | Saves with session lock, retry/backoff, kick on failed load, idempotent receipts, BindToClose wait |
| mock_datastore.luau | Luau | Mock DataStore + fake clock + fake players for plain-luau tests |
| test_sessionstore.luau | Luau test | 20 checks of SessionStore against the mock (luau test_sessionstore.luau) |
| Scheduler.luau | Luau module | Time-budgeted coroutine jobs |
| devproducts.py | Python | List/create developer products via Open Cloud; key from a chmod-600 file, never printed |
The push loop
# 1. pull (Studio is the source of truth)
# MCP: export_rbxm ServerScriptService.Game -> /tmp/sss.rbxm
python3 rbxm_extract.py /tmp/sss.rbxm snapshot/ServerScriptService
cp snapshot/ServerScriptService/Game/Services/Data.luau base/Data.luau # your base copy
cp snapshot/ServerScriptService/Game/Services/Data.luau src/server/Services/Data.luau
# 2. edit src/..., then check
python3 game_check.py src --lint
# 3. stage with a unique name
python3 stage.py --name Stage_FixA_1 "ServerScriptService/Game/Services/Data=src/server/Services/Data.luau@base/Data.luau"
# 4. MCP: import_rbxm build/Stage_FixA_1.rbxmx into ServerStorage
# 5. MCP: execute_luau with stage_apply.luau (STAGE_NAME = "Stage_FixA_1")
# -> "ok ServerScriptService/Game/Services/Data" or "CONFLICT (nothing applied): ..."
Snapshots and drift
- Extract each exported folder into
snapshot/<date>/<Service>/(e.g. an export ofServerScriptService.Gamegoes intosnapshot/<date>/ServerScriptService). Then paths matchfingerprint.luau, which writes them relative to the service's parent. python3 snapshot_diff.py snapshot/<date> srcshows which disk files are stale.- Before editing, run
fingerprint.luau, save its output, andpython3 snapshot_diff.py --fingerprint fp.txt snapshot/<date>to see what a collaborator changed since the snapshot, with no source download.
The mock-DataStore pattern
For any save module, inject the Roblox bits (store, clock, time, wait, spawn, warn) instead of
reading globals, so plain luau can run it. The mock store deep-copies in and out, can be told to throw a
queue of errors, and the fake wait advances time instantly and calls an onWait hook (that is how the
test makes "another server" release its lock after three waits). See
../data-and-saves.md.
For modules you cannot change to take injected dependencies, generate shimmed copies: prepend a header
that defines game, script and a require that resolves instance paths to files, and keep line numbers
shifted by a known amount.