Code mode · for Claude Code and Codex

One script instead of forty tool calls.

A second endpoint with three tools. The assistant reads a typed API for your world, writes a short TypeScript script and runs it in a sandbox. Bulk edits, filters and multi-step tasks finish in one round trip, and you get a trace of every call.

docsread

The API index for your session: 19 domains, 118 methods, typed signatures. Locked methods are marked 🔒 with the tier that unlocks them, so the assistant knows before it writes a line.

queryread-only

Runs a script that only reads. Writes are refused before the script starts, with the line number.

executeread · write · delete

Runs a script with the full API. Budgets per script: 150 calls, 150 writes, 30 deletions, 60 seconds of wall time, 15 seconds of CPU.

A real run

From a sentence to an imported encounter

// "Build a goblin warren encounter for four level-5 characters"
const folder = await foundry.folders.create({ name: "Encounter: Goblin Warren", type: "Actor" });
const picks = await foundry.dnd5e.filterCompendiumActors({ packIds: ["dnd5e.monsters"], crMin: 1, crMax: 3 });
const chosen = picks.results.filter(m => ["Bugbear","Dire Wolf","Ogre","Green Hag"].includes(m.name));
for (const m of chosen) await foundry.actors.createFromCompendium({ uuid: m.uuid, folder: folder.id });
return { imported: chosen.map(m => m.name), xp: chosen.reduce((s, m) => s + m.xp, 0) };

--- 6 calls, 2.9 s, execution 063b3918 ---
 folders.create 38 ms  id=kQ2…
 dnd5e.filterCompendiumActors 640 ms
 actors.createFromCompendium ≈120 ms  id=…  ×4
→ { imported: [Bugbear, Dire Wolf, Ogre, Green Hag], xp: 1550 }

What tool mode would do

Eight to twelve separate calls, each result read back into the context before the next one. Same outcome, several times the tokens and a minute of waiting.

Nothing is hidden

The trace lists every call with its timing, category and the ids it touched. A script that fails half-way tells you exactly what already happened.

Guarded by design

The sandbox holds

Checked before it runs

Every foundry.* call is found statically. A locked method, an unknown one or dynamic access stops the script with the line number, and nothing has touched the world.

Isolated while it runs

Each script gets a fresh QuickJS isolate inside a worker: no network, no filesystem, no timers, CPU and memory limits, and only the API you see in docs.

Bounded when it writes

150 calls, 150 writes and 30 deletions per script; results over 48 KB are cut with a warning. Calls that fail carry a category, never a stack trace.

[tier] The script was not started: the static check found calls it cannot make.

Locked calls:
  🔒 foundry.tokens.move (line 2) — requires the Dungeon Master tier

Tiers are unlocked on Patreon (free trial available): https://www.patreon.com/c/nitromoon

Who gets it

Every tier, with a daily quota

The tier of your key applies inside a script exactly as it does to tools: a Free key can read actors and roll dice in a script, and hits the same 🔒 on tokens as it would in tool mode.

Guest10 runs a day
Free30 runs a day
Adventurer100 runs a day
Dungeon MasterNo daily limit

Quotas reset at midnight UTC. One script at a time per world; Dungeon Masters go first in the queue.

Connect

Same key, second endpoint

Claude Code

claude mcp add --transport http foundry-code https://foundry-mcp.com/mcp/code
# then /mcp → Authenticate, sign in with Patreon

Codex CLI

codex mcp add foundry-code --url https://foundry-mcp.com/mcp/code
codex mcp login foundry-code

Claude connector (web or desktop)

Settings → Connectors → Add custom connector, paste the URL, leave client id and secret empty, connect.

https://foundry-mcp.com/mcp/code

Keep /mcp too

Code mode does not replace the 121 tools. Keep both connected: the assistant picks tools for one-step asks and a script for the rest.