{"id":49026154,"url":"https://github.com/TheUncharted/zapcode","last_synced_at":"2026-05-05T10:01:34.610Z","repository":{"id":343662442,"uuid":"1178630544","full_name":"TheUncharted/zapcode","owner":"TheUncharted","description":"TypeScript interpreter for AI agents. Written in Rust. 2µs cold start. Sandboxed. Alternative to MCP tool calling.","archived":false,"fork":false,"pushed_at":"2026-03-21T16:40:10.000Z","size":673,"stargazers_count":47,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-22T06:15:37.779Z","etag":null,"topics":["agent","ai","ai-agents","code-execution","interpreter","llm","mcp","python","rust","sandbox","tool-calling","tool-calling-agent","typescript","wasm"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheUncharted.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-11T07:57:08.000Z","updated_at":"2026-03-21T16:40:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/TheUncharted/zapcode","commit_stats":null,"previous_names":["theuncharted/zapcode"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/TheUncharted/zapcode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheUncharted%2Fzapcode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheUncharted%2Fzapcode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheUncharted%2Fzapcode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheUncharted%2Fzapcode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheUncharted","download_url":"https://codeload.github.com/TheUncharted/zapcode/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheUncharted%2Fzapcode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32644188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"online","status_checked_at":"2026-05-05T02:00:06.033Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","ai","ai-agents","code-execution","interpreter","llm","mcp","python","rust","sandbox","tool-calling","tool-calling-agent","typescript","wasm"],"created_at":"2026-04-19T07:00:20.155Z","updated_at":"2026-05-05T10:01:34.599Z","avatar_url":"https://github.com/TheUncharted.png","language":"Rust","funding_links":[],"categories":["Adjacent agent systems and specialized experiments"],"sub_categories":["Multiplatform"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/TheUncharted/zapcode/master/assets/logo.png\" alt=\"Zapcode\" width=\"160\" /\u003e\n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003eZapcode\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eRun AI-generated code. Safely. Instantly.\u003c/strong\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003eA minimal, secure TypeScript interpreter written in Rust for use by AI agents\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/TheUncharted/zapcode/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/TheUncharted/zapcode/ci.yml?branch=master\u0026label=CI\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://crates.io/crates/zapcode-core\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/zapcode-core\" alt=\"crates.io\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@unchartedfr/zapcode\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/@unchartedfr/zapcode\" alt=\"npm\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/zapcode/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/zapcode\" alt=\"PyPI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/TheUncharted/zapcode/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/TheUncharted/zapcode\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n\u003e **Experimental** — Zapcode is under active development. APIs may change.\n\n## Why agents should write code\n\nAI agents are more capable when they **write code** instead of chaining tool calls. Code gives agents loops, conditionals, variables, and composition — things that tool chains simulate poorly.\n\n- [Codemode](https://blog.cloudflare.com/code-mode/) from Cloudflare\n- [Programmatic Tool Calling](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling) from Anthropic\n- [Code Execution with MCP](https://www.anthropic.com/engineering/code-execution-with-mcp) from Anthropic\n- [Smol Agents](https://github.com/huggingface/smolagents) from Hugging Face\n\n**But running AI-generated code is dangerous and slow.**\n\nDocker adds 200-500ms of cold-start latency and requires a container runtime. V8 isolates bring ~20MB of binary and millisecond startup. Neither supports snapshotting execution mid-function.\n\nZapcode takes a different approach: a purpose-built TypeScript interpreter that starts in **2 microseconds**, enforces a security sandbox at the language level, and can snapshot execution state to bytes for later resumption — all in a single, embeddable library with zero dependencies on Node.js or V8.\n\nInspired by [Monty](https://github.com/pydantic/monty), Pydantic's Python subset interpreter that takes the same approach for Python.\n\n## Alternatives\n\n| | Language completeness | Security | Startup | Snapshots | Setup |\n|---|---|---|---|---|---|\n| **Zapcode** | TypeScript subset | Language-level sandbox | **~2 µs** | Built-in, \u003c 2 KB | `npm install` / `pip install` |\n| Docker + Node.js | Full Node.js | Container isolation | ~200-500 ms | No | Container runtime |\n| V8 Isolates | Full JS/TS | Isolate boundary | ~5-50 ms | No | V8 (~20 MB) |\n| Deno Deploy | Full TS | Isolate + permissions | ~10-50 ms | No | Cloud service |\n| QuickJS | Full ES2023 | Process isolation | ~1-5 ms | No | C library |\n| WASI/Wasmer | Depends on guest | Wasm sandbox | ~1-10 ms | Possible | Wasm runtime |\n\n### Why not Docker?\n\nDocker provides strong isolation but adds hundreds of milliseconds of cold-start latency, requires a container runtime, and doesn't support snapshotting execution state mid-function. For AI agent loops that execute thousands of small code snippets, the overhead dominates.\n\n### Why not V8?\n\nV8 is the gold standard for JavaScript execution. But it brings ~20 MB of binary size, millisecond startup times, and a vast API surface that must be carefully restricted for sandboxing. If you need full ECMAScript compliance, use V8. If you need microsecond startup, byte-sized snapshots, and a security model where \"blocked by default\" is the foundation rather than an afterthought, use Zapcode.\n\n## Benchmarks\n\nAll benchmarks run the full pipeline: parse → compile → execute. No caching, no warm-up.\n\n| Benchmark | Zapcode | Docker + Node.js | V8 Isolate |\n|---|---|---|---|\n| Simple expression (`1 + 2 * 3`) | **2.1 µs** | ~200-500 ms | ~5-50 ms |\n| Variable arithmetic | **2.8 µs** | — | — |\n| String concatenation | **2.6 µs** | — | — |\n| Template literal | **2.9 µs** | — | — |\n| Array creation | **2.4 µs** | — | — |\n| Object creation | **5.2 µs** | — | — |\n| Function call | **4.6 µs** | — | — |\n| Promise.resolve + await | **3.1 µs** | — | — |\n| Promise.then (single) | **5.6 µs** | — | — |\n| Promise.then chain (×3) | **9.9 µs** | — | — |\n| Promise.all (3 promises) | **7.4 µs** | — | — |\n| Async `.map()` (3 elements) | **11.6 µs** | — | — |\n| Loop (100 iterations) | **77.8 µs** | — | — |\n| Fibonacci (n=10, 177 calls) | **138.4 µs** | — | — |\n| Snapshot size (typical agent) | **\u003c 2 KB** | N/A | N/A |\n| Memory per execution | **~10 KB** | ~50+ MB | ~20+ MB |\n| Cold start | **~2 µs** | ~200-500 ms | ~5-50 ms |\n\nNo background thread, no GC, no runtime — CPU usage is exactly proportional to the instructions executed.\n\n```bash\ncargo bench   # run benchmarks yourself\n```\n\n## Installation\n\n**TypeScript / JavaScript**\n```bash\nnpm install @unchartedfr/zapcode        # npm / yarn / pnpm / bun\n```\n\n**Python**\n```bash\npip install zapcode                     # pip / uv\n```\n\n**Rust**\n```toml\n# Cargo.toml\n[dependencies]\nzapcode-core = \"1.0.0\"\n```\n\n**WebAssembly**\n```bash\nwasm-pack build crates/zapcode-wasm --target web\n```\n\n## Basic Usage\n\n### TypeScript / JavaScript\n\n```typescript\nimport { Zapcode, ZapcodeSnapshotHandle } from '@unchartedfr/zapcode';\n\n// Simple expression\nconst b = new Zapcode('1 + 2 * 3');\nconsole.log(b.run().output);  // 7\n\n// With inputs\nconst greeter = new Zapcode(\n    '`Hello, ${name}! You are ${age} years old.`',\n    { inputs: ['name', 'age'] },\n);\nconsole.log(greeter.run({ name: 'Zapcode', age: 30 }).output);\n\n// Data processing\nconst processor = new Zapcode(`\n    const items = [\n        { name: \"Widget\", price: 25.99, qty: 3 },\n        { name: \"Gadget\", price: 49.99, qty: 1 },\n    ];\n    const total = items.reduce((sum, i) =\u003e sum + i.price * i.qty, 0);\n    ({ total, names: items.map(i =\u003e i.name) })\n`);\nconsole.log(processor.run().output);\n// { total: 127.96, names: [\"Widget\", \"Gadget\"] }\n\n// External function (snapshot/resume)\nconst app = new Zapcode(`const data = await fetch(url); data`, {\n    inputs: ['url'],\n    externalFunctions: ['fetch'],\n});\nconst state = app.start({ url: 'https://api.example.com' });\nif (!state.completed) {\n    console.log(state.functionName);  // \"fetch\"\n    const snapshot = ZapcodeSnapshotHandle.load(state.snapshot);\n    const final_ = snapshot.resume({ status: 'ok' });\n    console.log(final_.output);  // { status: \"ok\" }\n}\n```\n\nSee [`examples/typescript/basic/main.ts`](examples/typescript/basic/main.ts) for more.\n\n### Python\n\n```python\nfrom zapcode import Zapcode, ZapcodeSnapshot\n\n# Simple expression\nb = Zapcode(\"1 + 2 * 3\")\nprint(b.run()[\"output\"])  # 7\n\n# With inputs\nb = Zapcode(\n    '`Hello, ${name}!`',\n    inputs=[\"name\"],\n)\nprint(b.run({\"name\": \"Zapcode\"})[\"output\"])  # \"Hello, Zapcode!\"\n\n# External function (snapshot/resume)\nb = Zapcode(\n    \"const w = await getWeather(city); `${city}: ${w.temp}°C`\",\n    inputs=[\"city\"],\n    external_functions=[\"getWeather\"],\n)\nstate = b.start({\"city\": \"London\"})\nif state.get(\"suspended\"):\n    result = state[\"snapshot\"].resume({\"condition\": \"Cloudy\", \"temp\": 12})\n    print(result[\"output\"])  # \"London: 12°C\"\n\n# Snapshot persistence\nstate = b.start({\"city\": \"Tokyo\"})\nif state.get(\"suspended\"):\n    bytes_ = state[\"snapshot\"].dump()          # serialize to bytes\n    restored = ZapcodeSnapshot.load(bytes_)    # load from bytes\n    result = restored.resume({\"condition\": \"Clear\", \"temp\": 26})\n```\n\nSee [`examples/python/basic/main.py`](examples/python/basic/main.py) for more.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eRust\u003c/strong\u003e\u003c/summary\u003e\n\n```rust\nuse zapcode_core::{ZapcodeRun, Value, ResourceLimits, VmState};\n\n// Simple expression\nlet runner = ZapcodeRun::new(\n    \"1 + 2 * 3\".to_string(), vec![], vec![],\n    ResourceLimits::default(),\n)?;\nassert_eq!(runner.run_simple()?, Value::Int(7));\n\n// With inputs and external functions (snapshot/resume)\nlet runner = ZapcodeRun::new(\n    r#\"const weather = await getWeather(city);\n       `${city}: ${weather.condition}, ${weather.temp}°C`\"#.to_string(),\n    vec![\"city\".to_string()],\n    vec![\"getWeather\".to_string()],\n    ResourceLimits::default(),\n)?;\n\nlet state = runner.start(vec![\n    (\"city\".to_string(), Value::String(\"London\".into())),\n])?;\n\nif let VmState::Suspended { snapshot, .. } = state {\n    let weather = Value::Object(indexmap::indexmap! {\n        \"condition\".into() =\u003e Value::String(\"Cloudy\".into()),\n        \"temp\".into() =\u003e Value::Int(12),\n    });\n    let final_state = snapshot.resume(weather)?;\n    // VmState::Complete(\"London: Cloudy, 12°C\")\n}\n```\n\nSee [`examples/rust/basic/basic.rs`](examples/rust/basic/basic.rs) for more.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eWebAssembly (browser)\u003c/strong\u003e\u003c/summary\u003e\n\n```html\n\u003cscript type=\"module\"\u003e\nimport init, { Zapcode } from './zapcode-wasm/zapcode_wasm.js';\n\nawait init();\n\nconst b = new Zapcode(`\n    const items = [10, 20, 30];\n    items.map(x =\u003e x * 2).reduce((a, b) =\u003e a + b, 0)\n`);\nconst result = b.run();\nconsole.log(result.output);  // 120\n\u003c/script\u003e\n```\n\nSee [`examples/wasm/basic/index.html`](examples/wasm/basic/index.html) for a full playground.\n\u003c/details\u003e\n\n## AI Agent Usage\n\n### Vercel AI SDK (@unchartedfr/zapcode-ai)\n\n```bash\nnpm install @unchartedfr/zapcode-ai ai @ai-sdk/anthropic  # or @ai-sdk/amazon-bedrock, @ai-sdk/openai\n```\n\nThe recommended way — one call gives you `{ system, tools }` that plug directly into `generateText` / `streamText`:\n\n```typescript\nimport { zapcode } from \"@unchartedfr/zapcode-ai\";\nimport { generateText } from \"ai\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\n\nconst { system, tools } = zapcode({\n  system: \"You are a helpful travel assistant.\",\n  tools: {\n    getWeather: {\n      description: \"Get current weather for a city\",\n      parameters: { city: { type: \"string\", description: \"City name\" } },\n      execute: async ({ city }) =\u003e {\n        const res = await fetch(`https://api.weather.com/${city}`);\n        return res.json();\n      },\n    },\n    searchFlights: {\n      description: \"Search flights between two cities\",\n      parameters: {\n        from: { type: \"string\" },\n        to: { type: \"string\" },\n        date: { type: \"string\" },\n      },\n      execute: async ({ from, to, date }) =\u003e {\n        return flightAPI.search(from, to, date);\n      },\n    },\n  },\n});\n\n// Works with any AI SDK model — Anthropic, OpenAI, Google, etc.\nconst { text } = await generateText({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n  system,\n  tools,\n  messages: [{ role: \"user\", content: \"Weather in Tokyo and cheapest flight from London?\" }],\n});\n```\n\nUnder the hood: the LLM writes TypeScript code that calls your tools → Zapcode executes it in a sandbox → tool calls suspend the VM → your `execute` functions run on the host → results flow back in. All in ~2µs startup + tool execution time.\n\nSee [`examples/typescript/ai-agent/ai-agent-zapcode-ai.ts`](examples/typescript/ai-agent/ai-agent-zapcode-ai.ts) for the full working example.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eAnthropic SDK\u003c/strong\u003e\u003c/summary\u003e\n\n**TypeScript:**\n\n```typescript\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport { Zapcode, ZapcodeSnapshotHandle } from \"@unchartedfr/zapcode\";\n\nconst tools = {\n  getWeather: async (city: string) =\u003e {\n    const res = await fetch(`https://api.weather.com/${city}`);\n    return res.json();\n  },\n};\n\nconst client = new Anthropic();\nconst response = await client.messages.create({\n  model: \"claude-sonnet-4-20250514\",\n  max_tokens: 1024,\n  system: `Write TypeScript to answer the user's question.\nAvailable functions (use await): getWeather(city: string) → { condition, temp }\nLast expression = output. No markdown fences.`,\n  messages: [{ role: \"user\", content: \"What's the weather in Tokyo?\" }],\n});\n\nconst code = response.content[0].type === \"text\" ? response.content[0].text : \"\";\n\n// Execute + resolve tool calls via snapshot/resume\nconst sandbox = new Zapcode(code, { externalFunctions: [\"getWeather\"] });\nlet state = sandbox.start();\nwhile (!state.completed) {\n  const result = await tools[state.functionName](...state.args);\n  state = ZapcodeSnapshotHandle.load(state.snapshot).resume(result);\n}\nconsole.log(state.output);\n```\n\n**Python:**\n\n```python\nimport anthropic\nfrom zapcode import Zapcode\n\nclient = anthropic.Anthropic()\nresponse = client.messages.create(\n    model=\"claude-sonnet-4-20250514\",\n    max_tokens=1024,\n    system=\"\"\"Write TypeScript to answer the user's question.\nAvailable functions (use await): getWeather(city: string) → { condition, temp }\nLast expression = output. No markdown fences.\"\"\",\n    messages=[{\"role\": \"user\", \"content\": \"What's the weather in Tokyo?\"}],\n)\ncode = response.content[0].text\n\nsandbox = Zapcode(code, external_functions=[\"getWeather\"])\nstate = sandbox.start()\nwhile state.get(\"suspended\"):\n    result = get_weather(*state[\"args\"])\n    state = state[\"snapshot\"].resume(result)\nprint(state[\"output\"])\n```\n\nSee [`examples/typescript/ai-agent/ai-agent-anthropic.ts`](examples/typescript/ai-agent/ai-agent-anthropic.ts) and [`examples/python/ai-agent/ai_agent_anthropic.py`](examples/python/ai-agent/ai_agent_anthropic.py).\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eMulti-SDK support\u003c/strong\u003e\u003c/summary\u003e\n\n`zapcode()` returns adapters for all major AI SDKs from a single call:\n\n```typescript\nconst { system, tools, openaiTools, anthropicTools, handleToolCall } = zapcode({\n  tools: { getWeather: { ... } },\n});\n\n// Vercel AI SDK\nawait generateText({ model: anthropic(\"claude-sonnet-4-20250514\"), system, tools, messages });\n\n// OpenAI SDK\nawait openai.chat.completions.create({\n  messages: [{ role: \"system\", content: system }, ...userMessages],\n  tools: openaiTools,\n});\n\n// Anthropic SDK\nawait anthropic.messages.create({ system, tools: anthropicTools, messages });\n\n// Any SDK — just extract the code from the tool call and pass it to handleToolCall\nconst result = await handleToolCall(codeFromToolCall);\n```\n\n```python\nb = zapcode(tools={...})\nb.anthropic_tools  # → Anthropic SDK format\nb.openai_tools     # → OpenAI SDK format\nb.handle_tool_call(code)  # → Universal handler\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCustom adapters\u003c/strong\u003e\u003c/summary\u003e\n\nBuild a custom adapter for any AI SDK without forking Zapcode:\n\n```typescript\nimport { zapcode, createAdapter } from \"@unchartedfr/zapcode-ai\";\n\nconst myAdapter = createAdapter(\"my-sdk\", (ctx) =\u003e {\n  return {\n    systemMessage: ctx.system,\n    actions: [{\n      id: ctx.toolName,\n      schema: ctx.toolSchema,\n      run: async (input: { code: string }) =\u003e {\n        return ctx.handleToolCall(input.code);\n      },\n    }],\n  };\n});\n\nconst { custom } = zapcode({\n  tools: { ... },\n  adapters: [myAdapter],\n});\n\nconst myConfig = custom[\"my-sdk\"];\n```\n\n```python\nfrom zapcode_ai import zapcode, Adapter, AdapterContext\n\nclass LangChainAdapter(Adapter):\n    name = \"langchain\"\n\n    def adapt(self, ctx: AdapterContext):\n        from langchain_core.tools import StructuredTool\n        return StructuredTool.from_function(\n            func=lambda code: ctx.handle_tool_call(code),\n            name=ctx.tool_name,\n            description=ctx.tool_description,\n        )\n\nb = zapcode(tools={...}, adapters=[LangChainAdapter()])\nlangchain_tool = b.custom[\"langchain\"]\n```\n\nThe adapter receives an `AdapterContext` with everything needed: system prompt, tool name, tool JSON schema, and a `handleToolCall` function. Return whatever shape your SDK expects.\n\u003c/details\u003e\n\n## Auto-Fix, Debug \u0026 Execution Tracing\n\n### Auto-fix (`autoFix`)\n\nWhen enabled, execution errors are returned as tool results instead of throwing — letting the LLM see the error and self-correct on the next step.\n\n**TypeScript:**\n```typescript\nconst { system, tools } = zapcode({\n  autoFix: true,\n  tools: { /* ... */ },\n});\n```\n\n**Python:**\n```python\nzap = zapcode(auto_fix=True, tools={...})\n```\n\n### Execution Trace\n\nEvery execution produces a trace tree with timing for each phase (parse → compile → execute). Use `printTrace()` / `print_trace()` to display the full session trace, or `getTrace()` / `get_trace()` to access the trace programmatically.\n\n**TypeScript:**\n```typescript\nconst { system, tools, printTrace, getTrace } = zapcode({\n  autoFix: true,\n  tools: { /* ... */ },\n});\n\n// After running...\nprintTrace();\n// ✓ zapcode.session  12.3ms\n//   ✓ execute_code    8.1ms\n//     ✓ parse          0.2ms\n//     ✓ compile        0.1ms\n//     ✓ execute        7.8ms\n\nconst trace = getTrace(); // TraceSpan tree\n```\n\n**Python:**\n```python\nzap = zapcode(auto_fix=True, tools={...})\n\n# After running...\nzap.print_trace()\ntrace = zap.get_trace()  # TraceSpan tree\n```\n\n### Debug Logging\n\nFor detailed logging of generated code, tool calls, and output, see the debug-tracing examples which show how to inspect each execution step:\n\n- [TypeScript debug-tracing example](examples/typescript/debug-tracing/main.ts)\n- [Python debug-tracing example](examples/python/debug-tracing/main.py)\n\n## What Zapcode Can and Cannot Do\n\n**Can do:**\n\n- Execute a useful subset of TypeScript — variables, functions, classes, generators, async/await, closures, destructuring, spread/rest, optional chaining, nullish coalescing, template literals, try/catch\n- Strip TypeScript types at parse time via [oxc](https://oxc.rs) — no `tsc` needed\n- Snapshot execution to bytes and resume later, even in a different process or machine\n- Call from Rust, Node.js, Python, or WebAssembly\n- Track and limit resources — memory, allocations, stack depth, and wall-clock time\n- 30+ string methods, 25+ array methods, plus Math, JSON, Object, and Promise builtins\n- Async callbacks in `.map()` and `.forEach()` — each `await` suspends and resumes the VM sequentially\n\n**Cannot do:**\n\n- Run arbitrary npm packages or the full Node.js standard library\n- Execute regular expressions (parsing supported, execution is a no-op)\n- Provide full `Promise` semantics (`Promise.race`, etc.) — `.then()`, `.catch()`, `.finally()`, and `Promise.all` are supported\n- Run code that requires `this` in non-class contexts\n\nThese are intentional constraints, not bugs. Zapcode targets one use case: **running code written by AI agents** inside a secure, embeddable sandbox.\n\n## Supported Syntax\n\n| Feature | Status |\n|---|---|\n| Variables (`const`, `let`) | Supported |\n| Functions (declarations, arrows, expressions) | Supported |\n| Classes (`constructor`, methods, `extends`, `super`, `static`) | Supported |\n| Generators (`function*`, `yield`, `.next()`) | Supported |\n| Async/await | Supported |\n| Control flow (`if`, `for`, `while`, `do-while`, `switch`, `for-of`) | Supported |\n| Try/catch/finally, `throw` | Supported |\n| Closures with mutable capture | Supported |\n| Destructuring (object and array) | Supported |\n| Spread/rest operators | Supported |\n| Optional chaining (`?.`) | Supported |\n| Nullish coalescing (`??`) | Supported |\n| Template literals | Supported |\n| Type annotations, interfaces, type aliases | Stripped at parse time |\n| String methods (30+) | Supported |\n| Array methods (25+, including `map`, `filter`, `reduce`) | Supported |\n| Async callbacks in `.map()`, `.forEach()` | Supported |\n| Math, JSON, Object, Promise | Supported |\n| `import` / `require` / `eval` | Blocked (sandbox) |\n| Regular expressions | Parsed, not executed |\n| `var` declarations | Not supported (use `let`/`const`) |\n| Decorators | Not supported |\n| `Symbol`, `WeakMap`, `WeakSet` | Not supported |\n\n## Security\n\nRunning AI-generated code is inherently dangerous. Unlike Docker, which isolates at the OS level, Zapcode isolates at the **language level** — no container, no process boundary, no syscall filter. The sandbox must be correct by construction, not by configuration.\n\n### Deny-by-default sandbox\n\nGuest code runs inside a bytecode VM with no access to the host:\n\n| Blocked | How |\n|---|---|\n| Filesystem (`fs`, `path`) | No `std::fs` in the core crate |\n| Network (`net`, `http`, `fetch`) | No `std::net` in the core crate |\n| Environment (`process.env`, `os`) | No `std::env` in the core crate |\n| `eval`, `Function()`, dynamic import | Blocked at parse time |\n| `import`, `require` | Blocked at parse time |\n| `globalThis`, `global` | Blocked at parse time |\n| Prototype pollution | Not applicable — objects are plain `IndexMap` values |\n\nThe **only** escape hatch is external functions that you explicitly register. When guest code calls one, the VM suspends and returns a snapshot — your code resolves the call, not the guest.\n\n### Resource limits\n\n| Limit | Default | Configurable |\n|---|---|---|\n| Memory | 32 MB | `memory_limit_bytes` |\n| Execution time | 5 seconds | `time_limit_ms` |\n| Call stack depth | 512 frames | `max_stack_depth` |\n| Heap allocations | 100,000 | `max_allocations` |\n\n### Zero `unsafe` code\n\nThe `zapcode-core` crate contains **zero `unsafe` blocks**. Memory safety is guaranteed by the Rust compiler.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eAdversarial test suite — 65 tests across 19 attack categories\u003c/strong\u003e\u003c/summary\u003e\n\n| Attack category | Tests | Result |\n|---|---|---|\n| Prototype pollution (`Object.prototype`, `__proto__`) | 4 | Blocked |\n| Constructor chain escapes (`({}).constructor.constructor(...)`) | 3 | Blocked |\n| `eval`, `Function()`, indirect eval, dynamic import | 5 | Blocked at parse time |\n| `globalThis`, `process`, `require`, `import` | 6 | Blocked at parse time |\n| Stack overflow (direct + mutual recursion) | 2 | Caught by stack depth limit |\n| Memory exhaustion (huge arrays, string doubling) | 4 | Caught by allocation limit |\n| Infinite loops (`while(true)`, `for(;;)`) | 2 | Caught by time/allocation limit |\n| JSON bombs (deep nesting, huge payloads) | 2 | Depth-limited (max 64) |\n| Sparse array attacks (`arr[1e9]`, `arr[MAX_SAFE_INTEGER]`) | 3 | Capped growth (max +1024) |\n| toString/valueOf hijacking during coercion | 3 | Not invoked (by design) |\n| Unicode escapes for blocked keywords | 2 | Blocked |\n| Computed property access tricks | 2 | Returns undefined |\n| Timing side channels (`performance.now`) | 1 | Blocked |\n| Error message information leakage | 3 | No host paths/env exposed |\n| Type confusion attacks | 4 | Proper TypeError |\n| Promise/Generator internal abuse | 4 | No escape |\n| Negative array indices | 2 | Returns undefined |\n| `setTimeout`, `setInterval`, `Proxy`, `Reflect` | 6 | Blocked |\n| `with` statement, `arguments.callee` | 3 | Blocked |\n\n```bash\ncargo test -p zapcode-core --test security   # run the security tests\n```\n\n**Known limitations:**\n- `Object.freeze()` is not yet implemented — frozen objects can still be mutated (correctness gap, not a sandbox escape)\n- User-defined `toString()`/`valueOf()` are not called during implicit type coercion (intentional — prevents injection)\n\u003c/details\u003e\n\n## Architecture\n\n```\nTypeScript source\n    │\n    ▼\n┌─────────┐   oxc_parser (fastest TS parser in Rust)\n│  Parse  │──────────────────────────────────────────►  Strip types\n└────┬────┘\n     ▼\n┌─────────┐\n│   IR    │   ZapcodeIR (statements, expressions, operators)\n└────┬────┘\n     ▼\n┌─────────┐\n│ Compile │   Stack-based bytecode (~50 instructions)\n└────┬────┘\n     ▼\n┌─────────┐\n│   VM    │   Execute, snapshot at external calls, resume later\n└────┬────┘\n     ▼\n  Result / Suspended { snapshot }\n```\n\n## Contributing\n\n```bash\ngit clone https://github.com/TheUncharted/zapcode.git\ncd zapcode\n./scripts/dev-setup.sh   # installs toolchain, builds, runs tests\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheUncharted%2Fzapcode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTheUncharted%2Fzapcode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheUncharted%2Fzapcode/lists"}