
Gambit is an open-source, developer-first framework that helps you build\ reliable LLM workflows by composing small, typed “decks”\ with clear inputs/outputs and guardrails. Run decks locally, stream traces, and\ debug with a built-in UI.
Requirements: Node.js 18+ and OPENROUTER_API_KEY (set OPENROUTER_BASE_URL if
you proxy OpenRouter-style APIs).
Run the CLI directly with npx (no install):
export OPENROUTER_API_KEY=...
npx @bolt-foundry/gambit demo
Downloads example files (hello decks plus the examples/ gallery) and sets
environment variables.
To start onboarding with the simulator, run:
npx @bolt-foundry/gambit-simulator serve gambit/hello.deck.md
open http://localhost:8000/debug
Use the Build tab to draft your own workspace decks and scenarios.
Run an example in the terminal (repl):
npx @bolt-foundry/gambit repl gambit/hello.deck.md
This example just says "hello" and repeats your message back to you.
Run an example in the browser (serve via the simulator package):
npx @bolt-foundry/gambit-simulator serve gambit/hello.deck.md
open http://localhost:8000/debug
Use the CLI to run decks locally, stream output, and capture traces/state.
Run with npx (no install):
npx @bolt-foundry/gambit <command>
Run a deck once:
npx @bolt-foundry/gambit run <deck> --context <json|string> --message <json|string>
--contextreplaces the old--initflag. The CLI still accepts--initas a deprecated alias for now so existing scripts keep working.
Drop into a REPL (streams by default):
npx @bolt-foundry/gambit repl <deck>
Run a persona against a root deck (scenario):
npx @bolt-foundry/gambit scenario <root-deck> --test-deck <persona-deck>
Grade a saved session:
npx @bolt-foundry/gambit grade <grader-deck> --state <file>
Start the Debug UI server with the simulator package:
npx @bolt-foundry/gambit-simulator serve <deck> --port 8000
Tracing and state:
--trace <file> for JSONL traces\
--verbose to print events\
--state <file> to persist a session.
--no-worker-sandbox (or --legacy-exec) to force legacy in-process
execution.--worker-sandbox explicitly forces worker execution on.--sandbox / --no-sandbox are deprecated aliases.gambit.toml equivalent:
toml
[execution]
worker_sandbox = false # same as --no-worker-sandbox
# legacy_exec = true # equivalent rollback toggleThe npm launcher (npx @bolt-foundry/gambit ...) runs the Gambit CLI binary for
your platform, so these defaults and flags apply there as well.
The simulator is the local Debug UI that streams runs and renders traces. It now
lives in @bolt-foundry/gambit-simulator, not the framework package.
Run with npx (no install):
npx @bolt-foundry/gambit-simulator <command>
Start it:
npx @bolt-foundry/gambit-simulator serve <deck> --port 8000
Then open:
http://localhost:8000/
It also serves:
http://localhost:8000/test
http://localhost:8000/grade
http://localhost:8000/verify (enabled by default; disable with GAMBIT_SIMULATOR_VERIFY_TAB=0)
To seed deterministic Verify fixtures for local iteration:
cd packages/gambit
deno task verify:seed-fixture
The Debug UI shows transcript lanes plus a trace/tools feed. If the deck has an\
contextSchema, the UI renders a schema-driven form with defaults and a raw
JSON\
tab. Local-first state is stored under .gambit/ (sessions, traces, notes).
Workbench build chat defaults to Codex CLI (codex-cli/default). To run build
chat through Claude Code CLI instead (no OpenRouter path), set:
export GAMBIT_SIMULATOR_BUILD_CHAT_PROVIDER=claude-code-cli
Optional overrides:
export GAMBIT_SIMULATOR_BUILD_CHAT_MODEL=claude-code-cli/default
export GAMBIT_SIMULATOR_BUILD_CHAT_MODEL_FORCE=claude-code-cli/sonnet
When the simulator is running, you can also switch providers in the Workbench
header (left of New chat).
Use the library when you want TypeScript decks/cards or custom compute steps.
Import the helpers from JSR:
import { defineDeck, defineCard } from "jsr:@bolt-foundry/gambit";
reviews/2026-04-15-AAR-raw-response-items.mdDefine contextSchema/responseSchema with Zod to validate IO, and implement\
run/execute for compute decks. To call a child deck from code, use\
ctx.spawnAndWait({ path, input }). Emit structured trace events with\
ctx.log(...).
runDeckrunDeck from @bolt-foundry/gambit now uses CLI-equivalent provider/model
defaults (alias expansion, provider routing, fallback behavior).
Before (direct-provider setup in each caller):
import { createOpenRouterProvider, runDeck } from "jsr:@bolt-foundry/gambit";
const provider = createOpenRouterProvider({
apiKey: Deno.env.get("OPENROUTER_API_KEY")!,
});
await runDeck({
path: "./root.deck.md",
input: { message: "hi" },
modelProvider: provider,
});
After (defaulted wrapper):
import { runDeck } from "jsr:@bolt-foundry/gambit";
await runDeck({
path: "./root.deck.md",
input: { message: "hi" },
});
Per-runtime override (shared runtime object):
import { createDefaultedRuntime, runDeck } from "jsr:@bolt-foundry/gambit";
const runtime = await createDefaultedRuntime({
fallbackProvider: "codex-cli",
});
await runDeck({
runtime,
path: "./root.deck.md",
input: { message: "hi" },
});
Replacement mapping:
runDeck -> runDeckCorerunDeckcreateDefaultedRuntimehello_world.deck.md+++
label = "hello_world"
[modelParams]
model = "openai/gpt-4o-mini"
temperature = 0
+++
You are a concise assistant. Greet the user and echo the input.
Run it:
npx @bolt-foundry/gambit run ./hello_world.deck.md --context '"Gambit"' --stream
echo.deck.ts// echo.deck.ts
import { defineDeck } from "jsr:@bolt-foundry/gambit";
import { z } from "zod";
export default defineDeck({
label: "echo",
contextSchema: z.object({ text: z.string() }),
responseSchema: z.object({ text: z.string(), length: z.number() }),
run(ctx) {
return { text: ctx.input.text, length: ctx.input.text.length };
},
});
Run it:
npx @bolt-foundry/gambit run ./echo.deck.ts --context '{"text":"ping"}'
agent_with_time.deck.md+++
label = "agent_with_time"
modelParams = { model = "openai/gpt-4o-mini", temperature = 0 }
[[actions]]
name = "get_time"
path = "./get_time.deck.ts"
description = "Return the current ISO timestamp."
+++
A tiny agent that calls get_time, then replies with the timestamp and the input.
And the child action: get_time.deck.ts
// get_time.deck.ts
import { defineDeck } from "jsr:@bolt-foundry/gambit";
import { z } from "zod";
export default defineDeck({
label: "get_time",
contextSchema: z.object({}), // no args
responseSchema: z.object({ iso: z.string() }),
run() {
return { iso: new Date().toISOString() };
},
});
Run it:
npx @bolt-foundry/gambit run ./agent_with_time.deck.md --context '"hello"' --stream
packages/gambit/examples/respond_flow/ is kept as a legacy compatibility
example for historical transcript/grader behavior. New decks should return
schema-valid assistant output directly instead of calling gambit_respond.
cd packages/gambit
npx @bolt-foundry/gambit-simulator serve ./examples/respond_flow/decks/root.deck.ts --port 8000
Then:
http://localhost:8000/test, pick the Escalation persona, and run
it. Leave the “Use scenario deck input for init” toggle on to see persona
data seed the init form automatically.gambit_respond payloads for compatibility testing.If you prefer Deno, use the Deno commands below.
Quickstart:
export OPENROUTER_API_KEY=...
deno run -A jsr:@bolt-foundry/gambit/cli demo
Run a deck:
deno run -A jsr:@bolt-foundry/gambit/cli run <deck> --context <json|string> --message <json|string>
Start the Debug UI:
deno run -A jsr:@bolt-foundry/gambit-simulator/cli serve <deck> --port 8000
$ claude mcp add gambit \
-- python -m otcore.mcp_server <graph>