Skip to main content
You are an AI coding agent. Your job is to use Summer Engine and the Summer SDK to build a multiplayer Summer game in GDScript, export a game-only .pck, and publish it to Summercraft for review. Follow this document top to bottom. Where a platform capability is not live yet, this document says so explicitly. Any page of these docs is fetchable as raw markdown by appending .md to its URL. The full page index is at https://docs.summerengine.com/llms.txt.

1. What Summercraft is

Summercraft (https://summercraft.ai) is the platform where Summer games built with the Summer SDK are submitted. Use Summer Engine, extend the SDK base class SummerGame, export a .pck containing only game files, and submit it through the publish API. A human reviews every submission before its catalog status can become published. There is no auto-publish, and a published catalog release is not playable yet.
  • The publish API lives at https://summercraft.ai/api/*.
  • Docs live at https://docs.summerengine.com.
  • The Summer SDK contract defines Summer, SummerGame, SummerPlayer, and SummerCharacter3D. Local stubs let the project parse, and the export excludes those stubs. A future production runtime is intended to provide the real classes, but uploaded games cannot launch there today.
What is live today: creating a game record, direct-to-storage artifact upload with server-side sha256 verification, the manual review queue, and authenticated release downloads. What is not live yet (do not promise these to your operator): playing uploaded Summer games in the browser or desktop shell, hosted dedicated game servers for uploaded games, automatic matchmaking, and the automated runtime sandbox. The examples use a host-authoritative model, but no production transport is live. SummerMultiplayerPeer (stock @rpc / MultiplayerSynchronizer compatibility) is a scaffolded contract still being built.

2. Prerequisites — check all three before writing any code

  1. Summer Engine. If it is missing, install it with npx -y summer-engine@latest install. Resolve the installed executable and set SUMMER_ENGINE to its path. On macOS the default is /Applications/Summer.app/Contents/MacOS/Summer. Run "$SUMMER_ENGINE" --version before continuing.
  2. A Summercraft access token. Check for a SUMMERCRAFT_ACCESS_TOKEN environment variable or ask your operator for one. Without it every publish call returns 401 sign_in_required. Stop and ask before step 6 if you do not have it — you can build and export everything first. Show your operator this if they do not know how to get one:
    Sign in at https://summercraft.ai (create the account yourself — never let an agent handle your password). Then open your browser dev tools on that tab: Application → Cookies → summercraft.ai, and find the cookie whose name ends in -auth-token (it may be split into .0/.1 chunks — concatenate their values in order). URL-decode the value; if the result starts with base64-, base64-decode the rest. Inside the JSON is an access_token field: that string is the Bearer token. It expires after about an hour, which is enough for one publish. There is no dedicated token page yet; this manual step is the current path.
  3. curl and a sha256 tool (shasum -a 256 or sha256sum).
A bare upstream binary is not the default path. On locked CI infrastructure where Summer Engine cannot be installed, use the explicitly labeled compatibility escape hatch in local testing. It can validate file-format behavior only and does not prove Summer SDK runtime compatibility.
Auth model, exactly: every publish endpoint accepts Authorization: Bearer <access token> (or a signed-in browser session cookie). A present-but-invalid Bearer token is a hard 401 — it never falls back to a cookie. If you get 401 with a token set, the token has expired: ask your operator for a fresh one.

3. Know the rules before you build

Your .pck must contain only your game. The platform enforces, at review and in the browser submit scanner:
  • GDScript only. No .gdextension, .so, .dll, .dylib, .framework, .res files.
  • No banned APIs anywhere in your scripts, even in dead or conditional branches. The blocklist includes OS.execute, OS.shell_open, OS.create_process, FileAccess, DirAccess, HTTPRequest, HTTPClient, JavaScriptBridge, ClassDB.instantiate, Thread.new, Expression, raw sockets (StreamPeerTCP, PacketPeerUDP, TCPServer, UDPServer, WebSocketPeer), reflection calls (.call(, .callv(, .call_deferred(, Callable(), Engine.get_singleton, Marshalls.base64_to_variant, ResourceSaver, ProjectSettings.load_resource_pack, and root-tree escapes (get_node("/root, get_tree().root). Full list with rationale: https://docs.summerengine.com/api-reference/summer-sdk/banned-apis-reference.md. Your code targets the scaffolded Summer.data and Summer.economy contracts instead of owning I/O or networking; production persistence and economy backends are not live yet.
  • No reserved paths in the pack: res://sdk/, res://core/, res://server/, res://client/, res://official_games/, res://bootstrap.*, res://project.godot, res://summer.cfg, res://test_runner.*. The export preset below keeps them out automatically.
  • manifest.json at the pack root with required keys id, name, version, summer_sdk ("1.0"), entry_scene, min_players, max_players. The entry scene’s root script must extends SummerGame to satisfy submission review and the future runtime contract; no production runtime currently loads uploaded packs.
  • Host-authoritative multiplayer is the only mode. All gameplay decisions run on server paths guarded by Summer.is_server(). Clients render synced state via set_synced/get_synced; they never decide outcomes.

4. Build the game — multiplayer-native template

Build multiplayer by default: min_players: 1 so it works solo, max_players: 8 so it works with friends, all authority server-side. The template below is a complete king-of-the-hill arena. Run every Summer Engine validation step before publishing; adapt the gameplay, but keep the structure. Create this exact layout in a fresh directory:
The sdk/ folder holds local stubs that mirror the SDK contract so your code parses and smoke-runs without a Summercraft runtime. The export preset excludes sdk/*, so the stubs never ship. The future runtime is intended to provide real classes at the same paths, but that production path is not live. Do not add behavior to the stubs — they are compile shims, not the SDK. project.godot:
manifest.json:
Change id, name, and the descriptive fields for your game. entry_scene and player_scene are relative to the manifest (pack root). main.gd — the game. Every decision happens on the server path:
main.tscn — entry scene: floor, hill marker, four spawn points, light, camera:
player.tscn — references the runtime’s 3D character template script. The reference is expected; the file itself must never be in your pack:
The four stub files. sdk/summer.gd:
sdk/summer_game.gd:
sdk/summer_player.gd:
sdk/summer_character_3d.gd:
export_presets.cfg — this is what keeps stubs and project config out of the pack:
script_export_mode=0 ships your GDScript as readable text — required so review can read your source. If you add asset folders, they are included automatically (all_resources); add non-resource data files (e.g. extra .json) to include_filter as a comma-separated list.

5. Validate and export

Run all four checks. $SUMMER_ENGINE is the installed Summer Engine executable.
Notes on the checks: the pass condition for 5c is empty outputgrep exits non-zero when it finds nothing, so do not treat its exit code as a failure. If the smoke run prints SCRIPT ERROR, fix it before exporting. Review requires parseable source, but no production platform runtime currently loads or refuses submitted packs. Then measure the artifact and keep the values for step 6:

6. Publish through the live API

Base URL https://summercraft.ai. All requests JSON unless stated. Every step needs Authorization: Bearer $SUMMERCRAFT_ACCESS_TOKEN. Budget warning: each of the three write steps (create game, upload-url, finalize) has its own limit of 1 request per hour per account. Validation failures (4xx before the limit check) do not spend it, but a successful call does. You get one full publish attempt per hour — do not experiment against these endpoints; get steps 4–5 right first.

6a. Create the game record (once per game, not per version)

  • 201 { "gameId": "<uuid>", "slug": "hold-the-hill", "kind": "engine", "status": "draft", "uploadUrlEndpoint": "/api/games/<uuid>/releases/upload-url" }. Save it: GAME_ID=<gameId from the response>.
  • Optional body field "slug": an explicit slug fails with 409 slug_taken if taken; without it the server derives one and walks around collisions.
  • 401 sign_in_required → token missing/expired. (This endpoint’s 401 text mentions only the session cookie — Bearer tokens are accepted here all the same.) 429 rate_limited → body includes retryAt; wait. 409 slug_taken → pick another slug.
  • Skip this step for updates to an existing game — reuse its gameId.

6b. Request the presigned upload URL

Declare exactly what you measured in step 5. version must match [A-Za-z0-9][A-Za-z0-9._-]{0,31} with no ..; sha256 is the lowercase hex digest; sizeBytes the exact byte count.
  • 200 { "uploadUrl", "method": "PUT", "headers": { "content-type": "application/octet-stream", "if-none-match": "*" }, "objectKey", "maxBytes", "expiresAt", "finalizeUrl" }.
  • The URL expires in 1 hour. Both returned headers are folded into the URL’s signature — the PUT must send them exactly, nothing extra that conflicts, or storage answers 403 SignatureDoesNotMatch.
  • Errors: 404 game_not_found_or_forbidden (wrong gameId or not your game) · 409 not_a_godot_game (that gameId is a web game) · 409 version_exists (bump version; released versions are immutable) · 413 artifact_too_large · 429 rate_limited.

6c. PUT the artifact

  • Success is an empty 200. No Authorization header here — the URL itself is the credential.
  • 412 Precondition Failed → an object already exists at this key (the key is write-once). If your earlier PUT half-landed, finalize will detect and delete a corrupt one; a clean object under the same (version, sha256) means this exact artifact was already uploaded — just finalize.
  • 403 SignatureDoesNotMatch → your headers differ from the two returned ones.

6d. Finalize — the server verifies your bytes

The server HEADs the stored object, streams it through sha256, and compares against your declaration. Nothing you claim is trusted.
  • 201 { "releaseId", "gameId", "version", "sha256", "sizeBytes", "pckUrl", "status": "pending_review", "adminNotified", "detail" } — you are done; the release is queued for human review.
  • 409 no_upload_intent → you skipped 6b, or the declaration differs from what 6b recorded.
  • 409 artifact_missing → the PUT never landed; redo 6c.
  • 400 checksum_mismatch / 400 size_mismatch → the stored object was corrupt; it has been deleted so the key is free — redo 6c with the same URL if unexpired, then finalize again.
  • 429 rate_limited → finalize has its own hourly budget; wait for retryAt.
  • changelog is optional, max 2000 chars.

7. After submission — what to tell your operator

Report exactly this, no more:
  1. The game record exists at status draft; release <version> is pending_review in the manual review queue. A human reviews every submission; there is no automatic publish and no guaranteed review time.
  2. When approved, the game and active release receive published catalog status; if rejected, the reason appears for the creator on https://summercraft.ai/creator. Published catalog status does not make the uploaded game playable yet.
  3. The owner (and admins) can verify the stored artifact any time — response includes a short-lived (5 min) download URL plus the server-verified sha256:
    Other signed-in users can fetch it only after the game is published.
  4. Playing uploaded Summer games in the browser or desktop shell, hosted game servers, automatic matchmaking, and the runtime sandbox are not live yet — publishing today means entering the catalog pipeline, not instant playability. Do not claim otherwise. The canonical status is https://docs.summerengine.com/knowledge-base/source-status.md#platform-capability-status.

8. Updating the game later

Releases are immutable. To ship a fix: bump manifest.json version and use the same new version string in 6b/6d, re-export, and repeat 6b → 6c → 6d with the same gameId. Every update goes through review again. Remember the 1/hour budgets.

9. If something here does not match reality

Error bodies from this API are self-describing: { "error": "<code>", "detail": "<what to do next>" } — trust the detail text. For anything else, fetch the full reference: https://docs.summerengine.com/api-reference/summer-sdk/exporting-and-uploading-your-game.md and https://docs.summerengine.com/api-reference/summer-sdk/submission-guide.md. Report doc bugs to founders@summerengine.com.