multiplayer-publish 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. Ship a hosted Summer multiplayer game: the bundle, server preset, pre-upload checks, a new Build.
When your agent uses it
- Publishing a hosted Summer multiplayer game online so other players can join it
- Making the summer.games bundle of a hosted game: client.pck, server.pck and the Linux server preset
- A summer.games export error mentions summer.build.json, WorldDefinitions, the server preset, the composition or the source graph
Install
summer setup installs every skill for your agent. To add only this one:
claude-code for your agent, such as codex or cursor. See Skills for every option.
The skill
Step 5 of the multiplayer sequence. It assumes the layout frommultiplayer-project: summer.build.json, world.json,
runtime-manifest.json, source-domains.json, and the client/,
authority/ and network/ folders.
1. What gets built
Project > Export, preset summer.games, Export Project to a.zip
gives one file, the bundle, which becomes one Build:
Players get
client.pck on iOS, macOS or Windows (targetPlatforms in
summer.build.json). Summer runs server.pck on Linux for every World.
2. The two export presets
Every project has a built-in summer.games preset. The server needs a second, Linux dedicated-server preset, named exactly asserver.exportPreset in summer.build.json. export_presets.cfg:
- summer.games: tick the platforms the game supports; leave encryption
off. It needs no exclude filters, because the source graph decides what
stays out of
client.pck. - Server: Add… > Linux, named exactly as
server.exportPreset. Resources: Export Mode Export as dedicated server, and exclude the client folder (client/*). Features: Customsummer_authority.
summer_authority custom feature is what makes the server start the
authority. Summer starts server.pck with no scene argument, so the pack’s
own main scene decides what runs: run/main_scene.summer_authority from
project.godot (multiplayer-project), which applies only to a pack whose
preset carries that feature. Without it, the server runs the client’s main
scene, usually the title. It never restores the World or reports ready, and
every online join fails with world_start_timeout. Local Play and the upload
checks name the scene themselves, so they can’t catch this; step 4d can.
Textures: iOS and macOS read ETC2/ASTC (textures/vram_compression/import_etc2_astc=true
in project.godot), and Windows reads S3TC/BPTC (import_s3tc_bptc=true).
Enable the ones for the platforms you tick. The exporter’s Fix Import
button does it.
3. Export
In the editor: Project > Export, select summer.games, Export Project, save asbuild/<game>.summer.zip. Or from a terminal (<summer>
is the Summer editor executable):
server.pck and your config/ files are listed, and that the
“Left N server-only files” count covers your authority/ files. The
Server: … mainScene … line names the scene the Build declares, not the
scene the pack will start; step 4d checks that. The Exported by Summer
line must name a released Summer: export with the released editor from the
download page, never a development build, and export again after you update
Summer. Players’ apps run the packs on the released Summer of that version;
step 4e checks it. The Summer Games apps for iPhone and Android start only
exports on their own MAJOR.MINOR, so export with the current Summer release
(release-readiness check 9). Every
result message and every export error, with its fix, is in
export-errors.md.
4. Check before uploading
Do all five. Each catches problems the export doesn’t. Run them on the.zip you will upload, not on a pack exported separately with the server
preset (--export-pack): that pack differs from the bundle’s server.pck,
for example it keeps gameId, and can pass where the upload fails.
a. Local Play passes (multiplayer-testing): every process has
script_errors 0, there’s no cannot attach, and your ready lines appear.
b. The source graph is clean. Save this script outside the project,
for example as ~/check_graph.gd:
ok=true. SUMMER_COMPOSITION_DOMAIN_LEAK means a
client file loads a server file; move the shared part into network/.
SUMMER_COMPOSITION_DYNAMIC_PATH_UNDECLARED flags any call whose name ends
in load( without a string literal inside. That includes
request.get_payload(): read request.payload instead. For a file that
really loads a computed path, add a
{ "from": "<file>", "to": "<loaded file>" } entry to dependencies in
source-domains.json.
c. Both packs load the way Summer loads them. In a scratch folder
outside the project:
"sceneLoaded": true, and
their compositionManifest objects are identical. On failure the probe
writes rejection.json; its codes are in export-errors.md.
The probe names the scene to load, so it does not show which scene the
server starts on its own.
d. The server pack starts the authority scene. Start the bundle’s
server.pck the way Summer does, with no scene argument, and stop it after
a few seconds:
Completed load for: 'res://….tscn' line must be the authority
scene (res://authority/main.tscn here). If it is the client or title
scene, add summer_authority to the server preset’s custom features and
export again. Later lines may complain that there is no hosted World; that
is expected locally.
e. The client compiles on the released Summer. Run the bundle’s
client.pck with the released Summer of the version the export names (see
release-readiness check 7 for how to confirm the stamp), and fail on any
compile error:
Static function "party_queue()" not found, means the scripts use an API the released version lacks, usually
because a development build made the export. Every player would see an
empty window. Re-export with the current Summer release.
5. Upload the Build
- The game must exist in Summer Studio, and
gameIdinsummer.build.jsonmust be its id. The export leavesgameIdout of the bundle, and the game code callsSummer.initialize()with no ID: a literal or fallback ID fails hosted withgame_identity_mismatch. - Open the game’s Builds page:
studio.openwith targetgame,gameIdand sectionbuilds, or summerengine.com → Studio → your game → Builds. - Upload the
.zipas a new Build. Summer checks it again: unknown fields, queue rules, both packs, and the composition match. From an agent:summer_export_game, thenstore.upload_filewithgameIdandclientVersion; it asks for confirmation first and needssummer login --store. If the store refuses this machine’s sign-in, upload in Studio. - Release the Build to an environment (
store.releasereleases the Build the owner approved withstore.publish). Its queues go live there, and clients join them withSummer.client.join(SummerJoinTarget.queue(...)). The code is the same as in Local Play.
.pck path instead
of .zip. That writes client.pck alone.
6. Join it for real
Right after the Build is released, open the game in a Summer Games app, join online and play until you are in the game, before players hear about the update. A wrong Game ID only fails under a real hosted launch, so nothing before this step catches it. Keep playing, signed in, for at least 3 minutes: the game must not close and the player must stay signed in (release-readiness check 10). An agent can’t do this; ask the user and
record the result. The whole list of checks before a release is
release-readiness, and the creator docs have it at
https://docs.summerengine.com/publishing/release-readiness.
When online joins fail
Every join ends inworld_start_timeout, but Local Play works:
- The server starts the wrong scene: run step 4d.
- The game passes a fixed Game ID to
Summer.initialize: pass none.
Checklist
-
summer.build.json:gameId,targetPlatforms,server.exportPreset, every WorldDefinition selected by a queue. -
world.json: every field frommultiplayer-project, includingnetwork_compositionsandsource_graph. - Two presets: summer.games (platforms ticked, no encryption) and the Linux dedicated server named in
server.exportPreset. - The export ends with
Publish uploads this one file as a new Build. - The analyzer prints
ok=truetwice. - Both probes load their scene, with identical composition manifests.
- The bundle’s
server.pck, run with no scene, loads the authority scene first. -
Exported by Summernames a released Summer, and the bundle’sclient.pckrun on that release prints noSCRIPT ERROR,Parse ErrororFailed to load script. - Every
Summer.initializecall passes no Game ID. - After release: a real online join reaches the game, and a signed-in player keeps playing for 3 minutes (
release-readinesschecks 2 and 10). - Local Play passed with the same project.
Common mistakes
From a shell
No Summer MCP tools in this session? Run each one as a command; whensummer --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.
Files in this skill
Related skills
multiplayer: Start here for Summer multiplayer: how authority, clients, Worlds and Sessions fit, and what comes next.multiplayer-project: Set up a Summer multiplayer project: entry scenes, World and queue files, joining, a first Local Play.multiplayer-testing: Test a Summer multiplayer game with Local Play: several players, bad network, bots, a passing run.release-readiness: Before releasing a Summer game version, prove players can play it: server, online join, progress, files.
Source:
library/skills/multiplayer-publish/SKILL.md, rendered from summer-engine@4.3.0 on npm.
