Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
SPAWN_API_URLNoDev override only; must be https (or localhost)
SPAWN_PLAY_HEADEDNoSet to 0 to force headless play sessions1
SPAWN_PROJECT_DIRNoGame project holding game.json / .envprocess cwd
SPAWN_HTTP_TIMEOUT_MSNoAbort API calls that hang60000
PLAYWRIGHT_BROWSERS_PATHNoOverride where Chromium is installed

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
prompts
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
spawn_getting_startedA

START HERE before any other spawn tool. The whole workflow in one call: setup order, the art/UI skills to load BEFORE building anything visual, the push → screenshot → fix loop, and the multi-agent rules. Also reports what this project already has (token, variant, game.json, docs) so you know which step you're on. Needs no credentials.

spawn_bootstrapA

Trade a one-time setup bootstrap key (sbk_…) for a durable agent token. Writes SPAWN_AGENT_KEY to the project .env. The full token is NEVER returned — only a masked prefix. Bootstrap keys expire in ~5 minutes and work once.

spawn_meA

Whoami — returns { userId, username } for the connected Spawn agent token.

spawn_list_gamesA

List games this token can push to: { games: [{ appId, variantId, name, playUrl }] }. Ask the creator which one by name.

spawn_create_gameB

Create a new game in the creator's account. Optionally writes SPAWN_VARIANT_ID to .env. Creator should open the play URL and keep it open. The engine a new world is pinned to is the platform's choice, not an argument here — the result reports which lane it landed on, and spawn_init then provisions for that lane (a clone on 6.0+, a scaffold on pre-6.0).

spawn_set_variantA

Set SPAWN_VARIANT_ID in the project .env (join an existing game from spawn_list_games).

spawn_initA

Provision the project directory for this world — what that means depends on the engine, and this detects it. On engine 6.0+ (the git lane) the world's code IS a git repository: this CLONES it into projectDir (the agent token is the git password, supplied per-command and never written to .git/config), fetches the spawn notes ref, keeps .env and .spawn/ out of the tree via .git/info/exclude, and saves the docs. A non-empty directory that is not already this world's clone is refused rather than cloned over. On a pre-6.0 world (the document lane) it scaffolds as before: gitignore secrets, world/ + scripts/, pull current spec → game.json, materialize scripts. Either way the docs land in .spawn/ (guide.md, tome-api.md, skills.json).

spawn_docsA

Fetch this world's guide, the Tome API reference, and the skills index — all matched to the engine version the world is pinned to, and this is also the cheapest authoritative answer to WHICH engine that is (era + semver come back in the result). On engine 6.0+ the guide IS the world's AGENTS.md: the tree grammar, the API in one screen, the git loop. On a pre-6.0 world it is the document lane's one paragraph. Optionally save under .spawn/. For just the skill menu with descriptions, spawn_skills is cheaper.

spawn_skillsA

The menu of skill ids to pass to spawn_skill, each with what it covers. Browse it when planning a build so the spawn_skill call can carry every domain the work touches — mechanic and look together. Reads .spawn/skills.json when present (no network, no credentials) and falls back to the API. If you already know roughly what you need, skip this and pass ids straight to spawn_skill; a wrong id answers with this list anyway.

spawn_skillA

Load the craft for what you are about to build — pass EVERY skill the work touches, not one. This is where the engine's real technique lives (how a HUD is actually built, how a material is written, how terrain is sculpted); the API reference only lists fields, so code written without the skills works but looks and behaves like a default. Anything visual should carry the look skills alongside the mechanic: a HUD is game-ui + drawn-art, a glowing surface is custom-materials + looks, a scene is world-composition + looks. Guessing an id is fine and cheap — a miss answers with the real menu.

spawn_latestA

Take upstream's work into your project. ON ENGINE 6.0+ (git lane) this is git pull --rebase: Savi, exec, and other clones commit to the same repo, so pull before you build and again after a refused push. A dirty tree is refused rather than stashed, and a rebase that collides is aborted with your commits intact and the colliding paths named. mode / version / updateSlug / applyLocal are document-lane concepts and are refused there. ON A PRE-6.0 WORLD (document lane) it is unchanged: pull a saved spec — head (mode=dev, default), published live (mode=live), an exact version, or a published updateSlug. Head pulls sync scripts (untouched fast-forward; both-changed → .theirs) and update the base-version rail — use after version_conflict. Non-head pulls are read-only unless applyLocal:true. version and updateSlug are mutually exclusive.

spawn_validateA

Check the project before pushing. ON ENGINE 6.0+ (git lane) there is no server-side validator — the push itself is the authority and refuses typed, naming the row, the line and the field — so this runs a LOCAL pre-flight over the tree instead: every script and template is ESM-parsed, .scene files are checked against the # spawn-scene v2 yaml <cellKey> header and their filename's cell key, image bytes are checked against their extension, and binaries under assets/ are caught (law.git.asset-kind refuses them). Clean here does NOT mean the push will land. ON A PRE-6.0 WORLD it is unchanged: compile the project and run authoritative server-side schema validation. Either way, valid is not the same as good — it says nothing about how the result looks or feels, which comes from the skills you loaded (spawn_skill) before writing the code.

spawn_pushA

Push your work live (~1s in every open room). The lane is detected from the world's engine. ON ENGINE 6.0+ (git lane) this stages, commits and git-pushes the clone: message is REQUIRED and is not a log line — its first line lands in the creator's chat and their changes list under your name, so write one plain sentence about what changed for the PLAYER ("the getaway car keeps its grip on wet streets"), never how you did it, never a file or a function; put the how in body, which is also where you leave Savi what she needs. The result carries the remote: verdict lines — rooms, players, and each room's reading of your change. A push refused as non-fast-forward means origin moved: spawn_latest, then push again. ON A PRE-6.0 WORLD (document lane) it is unchanged: compile the project and PUT the spec; on 409 version_conflict call spawn_latest, merge .theirs receipts and push again. In team mode document-lane pushes are serialised and rebased onto head first. Either way a successful push proves it parsed, nothing more — look at spawn_play_screenshot before calling the work done, and if what you pushed is visual and untextured or plainly styled, the missing piece is a skill you did not load (spawn_skill ids: drawn-art, custom-materials, looks, game-ui); spawn_audit_ui answers the other question, what UI you never built at all.

spawn_execA

Run a read-only JavaScript snippet against the live room (e.g. query objects, read an object's state). Pushing is the only write path. Needs a LIVE ROOM, and a room boots for a PLAYER, never for a door: the cheapest way to get one is spawn_client_join, which stands your own body in the world with no browser and no GPU (spawn_play_open boots one too, and is the right call when you need to SEE rather than query). Without either you get 409 no_live_room or a 5xx. api.sql is NOT available here at all (the endpoint is read-only server-side and refuses SQL outright, even SELECT) — there is no way to read the game database through this server.

spawn_logsA

Variant logs + live room script logs. Use when behavior doesn't match what you pushed — script syntax and runtime errors surface here, not in a push receipt. Needs a live room: spawn_client_join stands your own body and boots one without a browser.

spawn_roomsA

Active rooms + player counts for the current variant, and the room exec/logs will target. An empty list is a room you can boot yourself: spawn_client_join puts your body in the world and it appears here while the body stands.

spawn_saviA

Write into the creator's studio chat, where Savi (their in-game AI companion) reads it. Two uses, and the second is the valuable one. (1) Context after a meaningful push, so you don't fight over the world. (2) HAND OFF WORK: pass task and Savi can take it on, fanning it out across its own sub-agents — up to 8 in the studio, needing no bootstrap key, worktree, or browser of its own. Check spawn_savi_status first: it counts the lanes already burning, and every idle one is a sub-agent that would be finishing work while you build. The strongest targets are the ones where your own lane is weakest: you make art by naming a cdn/ path, and that path is spent on first fetch and cannot be re-rolled, so art that needs iterating — or that the creator wants to steer — is better handed to Savi, who can try it again with them in the loop. Delegate BROAD and GENERAL ("build out the northern district"), never as a step list — the splitting is what the fan-out is good at, and a narrow task wastes it. NOTHING COMES BACK: no reply, no acknowledgement, no completion event, and no endpoint on this API reports who pushed. So declare your boundary with keepOff rather than asking for one, and never put a delegated task on your own critical path. Uptake is visible even though acknowledgement is not: spawn_savi_status shows a new wisp lighting up and what Savi has it doing, which tells you the fan-out started — not that it started on YOUR task, since nothing here reports an author. Detect the finished work by inference rather than by reading a field — head moving past your own last push (spawn_status remote.headVersion) is Savi or the creator, and in team mode spawn_team_status recentPushes is what rules out a teammate. Then spawn_latest to take it and LOOK at it: work arriving on your rail is unverified until you screenshot it, exactly like your own.

spawn_revokeA

Revoke the durable agent token (disconnect). Removes SPAWN_AGENT_KEY from project .env after success.

spawn_statusB

Where this project stands. Always reports env (masked), credential source, docs present, and — once credentials allow — the world's ENGINE (era + semver), which decides everything else. On engine 6.0+ the remote block is git: branch, HEAD, how many commits ahead of and behind origin, and the uncommitted files. On a pre-6.0 world it is the version rail: base version, conflict receipts, headVersion vs publishedVersion.

spawn_play_openA

Open the live Spawn play URL in a local Chromium (Playwright). Headed by default so you can watch. Use this as the agent's eyes/hands on the game — Spawn is WebGPU/canvas, so screenshot + input beat accessibility trees. Resolves play URL from the variant if omitted. Keep it HEADED: headless Chromium has no WebGPU adapter, so Spawn refuses to start and every screenshot shows its 'One graphics fix away' gate instead of the game. The result reports webgpu:'ok'|'unavailable'.

spawn_play_screenshotA

Screenshot the open play session. Primary visual check after spawn_push — look at the image before calling the change done. Judge it as a player would: if it reads as grey boxes, flat untextured shapes, or default browser UI, that is a missing skill rather than a missing feature — load the relevant craft (spawn_skill ids: drawn-art, custom-materials, looks, game-ui, world-composition) and rewrite that code, since none of it is discoverable from the API reference. Optionally save under the project.

spawn_play_inputA

Send keyboard/mouse actions to the play session (WASD, jump, click UI, etc.). Clicks the canvas center ONCE per session to give it keyboard focus — later batches send only the actions you list, so no stray clicks fire your weapon or dismiss UI. This is also the ONLY way to click your game's UI (ui.js renders into a cross-origin iframe that spawn_play_eval cannot reach): screenshot first, read the button's position off the image, then click those coordinates. After acting, call spawn_play_screenshot to see the result.

spawn_play_reloadA

Reload the play tab (e.g. if a push didn't hot-apply to this client). Prefer waiting ~1s after spawn_push first — rooms usually reshape in place.

spawn_play_consoleA

Return recent browser console / pageerror messages from the play session. Pair with spawn_logs for server-side script errors.

spawn_play_evalA

Evaluate JavaScript in the play page's TOP frame (browser context — not the Spawn room api). Use it for page-level diagnostics: WebGPU support, network state, document title. It CANNOT see or click the game's UI: Spawn renders the UI in a cross-origin sandboxed iframe, so document.querySelector finds none of your ui.js buttons and reaching into the frame throws. Click game UI with spawn_play_input coordinates instead, and read live world state with spawn_exec.

spawn_savi_statusA

How many sub-agents Savi is running right now, and what they are doing. Savi's fan-out is EIGHT lanes wide, and this is the only way to see how much of it is spoken for — no API endpoint reports it. Call it BEFORE spawn_savi to size a handoff, and after one to see whether it was picked up. Idle lanes are the finding worth acting on: they are parallelism that costs you nothing and finishes work while you build, so free lanes mean you should be delegating a broader slice, not building it yourself. Reads the open play session (spawn_play_open) — the wisps are the flames along the top of the play page, one per sub-agent, and the studio broadcasts what each is working on to that same page. Attribution still does not exist: this shows that Savi is busy and on what, never that the work is yours.

spawn_play_closeA

Close the Playwright Chromium session.

spawn_play_statusA

Whether a play browser session is open, its URL, headed mode, recent error count, and a one-line read of Savi's fleet (spawn_savi_status has the detail).

spawn_client_joinA

Put YOUR OWN BODY in the world as a real player — no browser, no GPU. This is the cheap way to get a LIVE ROOM, and a live room is what spawn_exec and spawn_logs need: a room boots for a player and never for a door, so until a body stands they answer 409 no_live_room / 5xx. Before this, the only way to boot one was spawn_play_open (headed Chromium with a working WebGPU adapter); this needs neither, so it works on a machine with no GPU and costs a fraction of the time. It is also how you PLAY the game you are building: the body is a real player wearing your name, it appears in the room's census beside the creator and Savi, and the world's own player hooks fire for it like anyone's.

The session is a detached background process that outlives this call, so join once and then use spawn_exec / spawn_logs / spawn_client freely. It SELF-EXPIRES at ttl (default 600s) — that is the safety net that stops a forgotten body standing in someone's world forever — so raise ttl for a long session and call spawn_client_leave when you are done. Needs Bun (the client's session shell is spawned as bun); the error says so if it is missing.

Joining is the same on every engine — it is the play door, not the write path — so this takes no engineVersion.

spawn_client_leaveA

End the session and despawn the body — the graceful departure (the despawn is journaled before the socket closes). The room folds when the last body leaves, so spawn_exec and spawn_logs stop working after this until something else is standing. Call it when you are done; a session left alone self-expires at its ttl anyway.

spawn_client_statusA

Is a body standing, and for how much longer? Reports each session's pid, world, connection phase, entity id and REMAINING TTL. Check it before spawn_exec / spawn_logs when they answer no_live_room: an expired session is the usual reason, and the fix is to join again rather than to debug the endpoint.

spawn_clientA

Run any other verb of the packaged client against your standing body — spawn client <verb> …. Join first (spawn_client_join); these all act through that session.

The verbs the current client serves: where (your pose, world, place and the nearest objects — a sim read, no pixels), players (every body in the room and where it is), inputs (the world's declared actions — what a key actually does HERE, read it before sending any), move <x> <y> <z> or move --to <objectId> with --speed walk|run|teleport, look --at <objectId|x,y,z>, witness (the room as a picture), crossing (portals and slot census), screenshot, run <file> or run -e "<source>" (a play script: play.key / press / hold / release / walk / face / moveTo / where / players / entities / state / until).

The verb list belongs to the client the STACK serves, not to this server, so it can gain verbs without this tool changing — if one is not recognised, spawn_client verb:"--help" is not it; the client's own error names what it takes. --origin is refused: it would send your token to another stack.

spawn_asset_syncA

Sync the asset bank with your Spawn ACCOUNT: list every game you own, fetch each one's current server-side spec, and harvest the cdn/ assets it actually uses. This is the authoritative fill — it covers games you have no local checkout of, and assets a teammate or Savi added that never landed on your disk, neither of which a local spawn_asset_scan can see. SLOW BY DESIGN: one spec fetch per game, each carrying every script source, so expect seconds to low minutes on a large account. Run it once to populate an empty bank, and again when the other asset tools say the bank is stale. There is no asset API on Spawn — the specs are the only account-wide record of which assets exist.

spawn_asset_scanA

Harvest every cdn/ asset path used in a project (or any directory) into the local cross-project asset bank, recording which files and which game use it. Spawn generates an asset on first fetch of its path and keeps it there forever, so the same path in another game is the same asset — but there is no catalog API, and this bank is the only record of which names you have already used and how they turned out. Run it on each of your game projects once, then use spawn_asset_search before inventing a new asset name.

spawn_asset_searchA

Search the local asset bank for assets you (or your other projects) have already used. Call this BEFORE inventing a new cdn/ asset name: a path that already produced good art is reusable across games verbatim, and a path marked bad tells you what not to spell. Every result reports how many distinct GAMES use it — the strongest signal that an asset actually worked. Pass facets:true with no query to see what categories, kinds and style families the bank holds.

spawn_asset_noteA

Name, categorize, describe or judge an asset in the bank — including a path that has not been scanned or even used yet. A name is a short handle you can use in place of the path in every other asset tool. This is the memory the platform does not keep: a Spawn asset is generated once from its path and cached there forever, so you cannot re-roll a name, and 'this name produced the wrong thing, use that one instead' is information nothing else records. Write the description while you can still see the asset.

spawn_asset_previewA

Check whether an asset actually exists on Spawn's CDN, and LOOK AT IT if it is an image (returned inline, so you can judge it rather than guess from the filename). Use it on an unfamiliar path before building around it, and after generating a new one to see what the name produced. Safe to call: it queries the storage host directly, which never triggers generation — a 404 means the asset has not been created yet, not that you are forbidden to ask.

spawn_audit_scanA

List a game's exported functions and say which can be audited locally. Engine-coupled functions take objectApi as a parameter (the engine injects it, never imports it), so the signature alone decides: no api parameter and no engine-only require means the function is pure and runnable in plain Node. Run this BEFORE writing an audit manifest — it tells you what there is to check. No browser, no room, no credentials.

spawn_audit_mathA

Run declared numeric invariants over the game's pure functions, locally: no browser, no live room, no push, no credentials. Sweeps each function across its declared input domain and reports the exact arguments that broke a rule. Catches what playing the game catches slowly and unreliably — NaN and Infinity, divide-by-zero at boundary inputs, difficulty curves that flatten or invert, values escaping their declared bounds. Reads audit/math.json by default; pass manifest for another path or checks to try one inline without writing a file. Use spawn_audit_scan first to see what is auditable.

spawn_audit_uiA

Locally count which of the 21 Interface In Game UI surfaces this Spawn game project has: no browser, no live room, no push, no credentials. This is a text scan, not a look at the screen, so it can only tell you found or missing, never whether a surface is actually built or styled — a missing verdict means go build that surface: load the skills the report names with spawn_skill, then re-run this tool to confirm it. found means only that the surface's name turned up in a path or identifier; it is not a verdict on completeness or appearance, and spawn_play_screenshot is the only authority on how a surface actually looks. Reads audit/ui.json's expect list by default, falling back to a 6-surface baseline (main-menu, in-game, settings, overlay, game-over, loading) when the file is absent; pass expect to try a different surface set without writing the file. Every finding also carries an interfaceingame.com reference link for a human to open — this tool never fetches that site itself. An unknown surface id, in expect here or in audit/ui.json's expect/ignore, fails with the full 21-slug menu instead of silently scoring it as missing.

Prompts

Interactive templates invoked by user choice

NameDescription
spawn_sessionHow to work on a Spawn game via this MCP: bootstrap → game → init → edit → push → play/screenshot → fix. Covers both engine lanes (6.0 git worlds and pre-6.0 document worlds) and multi-agent.

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.7/5.0

Scored across 40 tools

Disambiguation4/5

The 40 tools are mostly distinguishable by domain prefix and explicit descriptions, but several clusters can be confused: spawn_exec vs spawn_play_eval vs spawn_client (read-only JS vs browser JS vs client verbs), and spawn_logs vs spawn_play_console (room script logs vs browser console). Status tools also overlap across domains (spawn_status, spawn_play_status, spawn_client_status, spawn_savi_status). Descriptions mitigate but do not fully remove ambiguity.

Naming Consistency4/5

All names use a consistent spawn_ prefix and snake_case, making grouping predictable. However, the token pattern is not uniformly verb_noun: some are domain_action (spawn_play_open, spawn_asset_sync), others are verb_noun (spawn_create_game, spawn_list_games), and a few are bare nouns or phrases (spawn_me, spawn_getting_started). This is mostly consistent with minor deviations.

Tool Count2/5

40 tools is well above the 3–15 sweet spot and exceeds the 25-tool threshold for 'too many', even for a complex development platform. The surface covers many sub-domains (auth, project, play, client, audit, asset, Savi), each adding tools that could have been consolidated under fewer multiplexed commands. The count feels heavy and increases selection cost.

Completeness4/5

The surface covers the major lifecycle stages: auth, game creation/selection, project provisioning, push/pull/validate, live-room interaction, play-browser control, skills, audits, asset bank, and Savi delegation. However, a referenced tool (spawn_team_status) is absent, and there is no explicit game/variant deletion or team-management surface, leaving minor dead ends. Otherwise coverage is strong.

Maintenance

ActivityMaintained
ResponsivenessWithin a week