summer-router 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. AI characters for games on Summer Games: Summer Router replies, tools, speech, images.
When your agent uses it
- A talking NPC (shopkeeper, guard, companion) players chat with, in a single-player or multiplayer game on Summer Games
- A game should speak a line in a character’s voice, or make an image, while people play
- About to put a model name, a provider SDK or a provider key into a game project
- Choosing between Summer.client.router and Summer.authority.router in a single-player or multiplayer game
- Handling Summer Router refusals (limit_reached, credits_required, router_disabled, not_on_summer_games, unavailable) or changing its caps
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
A shopkeeper who haggles, a guard who opens the gate when convinced, a narrator who says the player’s name. With Summer Router, a game calls AI while people play. The game names a character and sends what the player said. Summer holds the instructions, the model, the voice, the caps and the provider keys, and meters each call from the creator’s paid Summer credits. Players never pay, and nothing secret is in the build.What works today (early preview)
In the editor and in Local Play, every call answers
unavailable, so the game uses its offline lines. Test the character with the test conversation (step 2) and play the real thing on Summer Games.
1. Plan: who calls
Ask the person one question if it is not clear: is the game single-player or multiplayer?
In a multiplayer game, the server owns the world. Anything a character does that changes the game (sell an item, give gold, open a shared door) runs on the server. A player’s game may also talk to a character itself and tell the server what happened; then the server checks the exchange with
verify_exchange before it acts (step 4).
2. Make the character
A character lives on Summer, not in the build. Make it in Summer Studio (the game’s Grow > Summer Router tab), or with the Summer MCP:- Over MCP, call it with
summer_call({ op: "router.save_character", input: {...} }), or from a shell:summer router save-character --input '<json>'. Find the game id withgames.list. On a game that is live, the person approves the change with one link. - Test it before you write game code:
router.test_character({ gameId, characterId: "shopkeeper", messages: ["Do you have anything for my wounds?", "Fine, 25 gold for the health potion."], toolOutputs: { sell_item: { ok: true } }, expectTools: ["sell_item"] }). Test turns count toward a developer cap of their own. router.modelslists the text models, voices and the full character schema (include: ["schema"]). Pickmodelandvoice.idfrom it, or leave them out for the game’s defaults.- The tool
namein the character is the name your game handles. Tool arguments come from the model: check every one in game code.
3. Single-player: call from the player’s game
toolsmaps each tool name to aCallable. The SDK runs the handler, sends what it returns back to the character, and the character goes on, up to 8 rounds in one call. Return{"error": "..."}when the action fails (not enough gold, out of stock); the character then says so.Shop.sellchecks the price against your own price list, the stock and the gold. The model’s word is never the price.conversation_id: Summer keeps the history. Send the one the last result named. Without it, each call starts a new conversation.- For a whole conversation in one node, add a
SummerRouterCharacter, set Character ID, turn on Show UI, and give ittools. It shows a bar with the character’s words and a text field.
has_voice of each entry in status().characters), and consider voicing on tap: speech costs more than text.
await Summer.client.router.status() asks Summer what this player can use now: available (and reason, an error tag, when it is not), characters (each id, name, has_voice, client_tools), kinds (the capabilities Summer serves) and voice (realtime voice, false during the early preview). report(exchange_id, reason) answers report_id and status; it takes one of this player’s replies from the last 30 days.
4. Multiplayer: call from the server
The player’s game sends what the player typed to the server as a Command (themultiplayer-state skill sets up Commands and shared State). The server answers the Command at once, asks the character for that player’s session, runs the tool calls itself, and publishes the line in shared State so every player sees it.
- The server has
reply(session, character, text, options),speak(session, text, {"character": id})andgenerate(session, "image", {...}). Options are the client’s withouttools: the server readsr.tool_callsand answers them withtool_resultson the next call, with the sameconversation_id. speakandgenerateon the server returndataandmime_type. Audio and images are too big for shared State: to voice a line, each player’s game callsSummer.client.router.speak(line, {"character": "shopkeeper"})for the line it shows (it counts toward that player’s caps).- Server calls count toward the game’s caps, not the player’s. Keep your own pace per player on the server: one line in flight per player, a short gap between lines, and a length cap on the text, so one player cannot spend the whole game’s daily cap.
Shop.sell_toon the server is the only place an item or gold changes hands. Never apply an effect a client reports.
Summer.client.router itself and tells the server “the shopkeeper agreed to sell”, the server checks the exchange first:
5. Every refusal keeps the game running
Every call returns aSummerRouterResult. Read ok first. On a refusal, error is a stable tag, fix says what to do (for you), and message is a plain line you may show players. Show message or your own offline line, and go on. Treat a tag you do not know as unavailable.
retryable is true when the same call can work later (unavailable, limit_reached, provider_unavailable, rate_limited). Never retry in a loop: a cap is the product working.
6. Caps and money
Every game starts on, with caps on from day one:- The creator changes them per game in Grow > Summer Router, or an agent asks with
router.set_settings(the person approves with one link).router.set_account_limitchanges the account cap.router.usageshows calls, units, how much of each cap is used and which calls a cap stopped. - A character can carry its own daily caps per player and per game (
limitsin the character). - Calls are paid from the creator’s paid Summer credits (plan credits and top-ups), the same balance as the Summer API. A result never carries a price.
7. Ship it safely
- No provider key, provider SDK, model id or character instructions in the project. The build holds character ids only.
- Every character keeps an offline line set that is good on its own. Most refusals happen in normal play.
- Label AI lines as AI in the game (a small tag on the bubble), and offer a report button:
Summer.client.router.report(exchange_id, "inappropriate"). - Never ask players for personal details, and keep characters off romance, self-harm and medical advice. Write it into the instructions.
- In a multiplayer game, a reply never changes shared state on a client. The server applies every effect and checks every tool argument.
Summer.client.router.is_available()says, without a network call, whether this run can call Summer Router.status()asks Summer which characters and kinds it serves for this player.
Verify
grepthe project for provider names, model ids and anything key-shaped: none.- In the editor every character answers with its offline line, and no error is shown.
router.test_characterwithexpectToolspasses for each tool the game handles.- Every tool handler refuses bad arguments (an unknown item, a wrong price, not enough gold).
- In multiplayer, the server is the only code that sells, gives or opens anything, and it checks a relayed exchange with
verify_exchange. - On Summer Games, signed in, the character answers, its tool works, and
router.usageshows the calls.
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.
Related skills
design-npc: Design enemy, NPC, boss or companion behavior: perception, state machine, telegraphs, script stub.multiplayer-state: Authority-owned state in Summer multiplayer: shared and private State groups, Commands, Events.summer-api: Summer API game assets: models, estimate, one job or a batch, download the files.
Source:
library/skills/summer-router/SKILL.md, rendered from summer-engine@4.8.0 on npm.
