StudioHow-toFor authorsApplies from 4.2.1
The Assistant: bring your own key
Cette page en françaisThis page on the GitHub wiki
The Assistant is a chat drawer in the Studio where you ask a model of your choice (OpenAI, Anthropic, Ollama, Mistral, or any OpenAI-compatible endpoint) to help complete the game. It has the same tools as the MCP server and knows what you have selected. You bring the key; without one, your request becomes a task for an AI agent connected through MCP.
What you get
A model that reads the room or the panel you are on, writes look lines, topics or hints into the game files with the Studio's tools, and runs validate and solve; the Studio reloads what it wrote.
Context and versions
The local Studio (npm run studio, engine repository or created project), where the Studio's server relays the call,
and the demo Studio, where the page calls the provider itself. True from 4.2.1.
Prerequisites
- The Studio running (overview).
- An API key of a provider (with a spending limit), or Ollama on your machine with a model that supports tools, or an MCP agent for the no-key route (Local MCP: setting up each client).
Where to run the commands
In the browser: the Assistant button in the top bar, or the a key when no field has focus. For Ollama, the
ollama commands run on your machine.
Steps
-
Pick a provider (gear icon). Presets:
Preset Base URL Models offered Key OpenAI https://api.openai.comgpt-5,gpt-5-mini,gpt-4.1yes Anthropic (default) https://api.anthropic.comclaude-sonnet-5(default),claude-opus-5,claude-haiku-4-5yes Ollama (local) http://localhost:11434llama3.1,qwen3,mistral-smallno Mistral https://api.mistral.aimistral-large-latest,mistral-small-latestyes Custom any OpenAI-compatible base URL typed by you as the endpoint needs For Ollama, pull the model first (
ollama pull llama3.1) and pick one that supports tools.
- Paste your key. It is kept in this browser tab only (sessionStorage) and sent with each request; the other settings (preset, URL, model) are remembered in localStorage, never the key. Forget the key removes it. Use a key with a spending limit, and forget it on a shared computer.
- Ask. The composer shows what the request is about:
house › pantry (prop)(the room and the entity selected in Rooms),storyboard › <board> › <panel> (panel)(the selected panel, as edited, even unsaved), or the whole game. Quick actions use it: Write 3 look lines, Suggest a puzzle for this room, Write the talk topics for this character, Find what's missing (validate + solve), Draft the hint chain, Generate the art prompts for this sheet.
- Read the answer. Answers are light markdown (paragraphs, lists, code). Each tool call is a chip you unfold to see its arguments and result. Stop aborts the request (the server aborts the provider call too); New chat starts over. After a turn that wrote something, the Studio reloads the room, the storyboard (a banner when it has unsaved edits) or the notes, and runs Check.
How it works
- One tool registry.
tools/studio/tools.tsdefines every tool (name, description, schema, handler over a backend); the MCP server and the Assistant both use it, so the Assistant has the MCP server's tools:list_rooms,get_room,set_text,set_value,add_entity,set_layout,get_storyboard,set_storyboard,get_notes,add_note,validate,solve,screenshot,read_doc,run_tests,asset_promptsand the others (MCP tools). - The relay (local Studio). The page posts the conversation to
POST /__studio/api/assistant/chatwith{ provider: { kind, baseUrl, model, apiKey? }, messages: [{ role, content }], context }(a body of 4 MB at most). The relay (tools/studio/assistant.ts, loop intools/studio/assistant-loop.ts) builds a system prompt fromAGENTS.md, the game (rooms, characters, items, checkpoints) and the current selection with its texts. It calls the model, runs the tool calls on the game files, and streams server-sent events back:{ type: 'text', delta },{ type: 'tool_call', id, name, args },{ type: 'tool_result', id, name, result, isError? }(result cut at 4 KB in the event; the model gets up to 32 KB),{ type: 'error', message }, then{ type: 'done', usage?, wrote?, stopped? }. The model is told to ask before destructive changes and to keep the game's voice. Earlier turns are sent back as text only. - Two wire formats, no SDK. OpenAI-compatible
POST <base>/v1/chat/completionswithtoolsandstream: true(OpenAI, Mistral, Ollama, most others), and Anthropic'sPOST <base>/v1/messageswithtools,x-api-keyandanthropic-version: 2023-06-01. Streaming answers are read as server-sent events; a provider that answers plain JSON works too. A base URL may or may not end in/v1.
Limits
| Limit | Value | When it is reached |
|---|---|---|
| Tool rounds per request | 12 | Stopped after 12 tool rounds: ask again to continue. |
| One provider call | 60 s | <url> did not answer within 60 s |
| A provider's answer | 8 MB | the provider's answer exceeds 8 MB |
| Redirects | none followed | <url> answered with a redirect (…): refused, a provider must answer at its own address |
Custom providers and WEB_SCUMM_ALLOW_CUSTOM_PROVIDER
The relay accepts the presets' addresses (OpenAI, Anthropic, Mistral) and Ollama on this machine (localhost,
127.0.0.1, [::1]). Any other base URL is refused unless the Studio was started with the opt-in:
# in the engine repository or the created project
WEB_SCUMM_ALLOW_CUSTOM_PROVIDER=1 npm run studioEven then, a custom provider must use HTTPS and cannot target a local or private network host (loopback, unspecified,
private and link-local addresses in both IP families, .local, .internal), and a provider URL cannot carry
credentials. See Local and LAN security and
WEB_SCUMM_ALLOW_CUSTOM_PROVIDER.
Key safety
The key stays in this browser tab (sessionStorage) and goes with each request. On the local Studio, the relay keeps it
in memory for that request only: never written to disk, never logged, and removed from error messages (replaced by
***). In the demo Studio it goes from the page straight to the provider.
No key: tasks for an MCP agent
Without a key (and not on Ollama), the composer offers Send as a task to the AI agent. The page posts
POST /__studio/api/assistant/task with { about, text }, which appends a note with author: "you" and task: true
to notes.json, about the current selection. An agent connected through MCP (Claude Code, Cursor, Codex, Gemini
CLI…) reads it with get_notes and does the work; the Studio shows its edits live, and the Notes tab tags these notes
"task" (Notes).
In the demo Studio
There is no relay on a static host: the page runs the same loop itself, with the tools on the browser backend (edits
kept as demo patches, Demo mode). screenshot, run_tests and asset_prompts are not
available, set_value answers that it needs the dev server, and read_doc has only CONTENT_GUIDE. The browser
calls the provider directly: Anthropic gets its anthropic-dangerous-direct-browser-access header; OpenAI refuses
browser calls from unknown origins for some keys, and the error says so. Use Ollama on your machine, allowing the
page's origin, or the local Studio, whose server relays the call:
# on your machine, for the demo Studio's page
OLLAMA_ORIGINS=<the page's origin> ollama serveTasks go into the demo's notes, and its patch.
Applies from 4.5.0 to …
Documentation in the demo
A demo built from 4.5.0 also carries the wiki's ready pages in its snapshot: the demo's Assistant can use
search_docs, list_docs and read_doc by id on them.
Expected result, and how to check it
The answer streams in; a tool chip shows validate returning { ok: true … }; after a write, the room or the
storyboard shows the change and git diff holds it.
Common errors
| Symptom | Cause | Fix |
|---|---|---|
custom provider URLs are disabled (set WEB_SCUMM_ALLOW_CUSTOM_PROVIDER=1 to opt in) | A base URL that is no preset | Restart the Studio with the opt-in, or use a preset |
custom providers must use HTTPS and cannot target local or private network hosts | http://, or a private address | Use an HTTPS public endpoint; for a local model, the Ollama preset |
`provider.kind` must be openai, anthropic or ollama | A hand-made request | Use the settings dialog |
The browser could not reach <url> … (CORS) | Demo Studio, provider refusing browser calls | Ollama with OLLAMA_ORIGINS, or the local Studio |
Stopped after 12 tool rounds | The task needs more rounds | Ask again to continue |
More: Studio troubleshooting.
Files or data changed
Whatever the tools write (room files, layouts, storyboard.json, notes.json), as the Studio would. The key is never
written; the settings without the key are in the browser's localStorage under web-scumm.studio-assistant.
Recovery or going back
The model's writes go through the Studio's operations: undo them from the header during the session, or with git.
References
src/studio/assistant.ts(the drawer),tools/studio/assistant.ts(the relay),tools/studio/assistant-loop.ts(the loop, shared with the demo).- Working with an AI, Local and LAN security.