Skip to main content

Belgie: Run JavaScript and TypeScript from Python

CI PyPI versions


Documentation: mplemay.github.io/belgie


Belgie gives AI agents and Python applications a permissioned way to run JavaScript, TypeScript, and TSX. Use the embedded Deno runtime to add sandbox tools to Pydantic AI and LangChain, build React MCP Apps, or execute scripts directly from Python.

  • AI agents: Add sandboxed run_typescript for Pydantic AI or run_code for LangChain.
  • Inline React widgets: Return self-contained HTML from either agent integration with render_widget (@belgie/vite).
  • MCP Apps: Connect Python MCP tools to React widgets and typed tool callers.
  • Direct runtime: Run scripts, resolve JavaScript dependencies, and invoke package binaries from Python.
  • Embedded runtime: Deno is bundled, so the Python runtime does not require Node.js.

Installation

uv add belgie
uvx library-skills install  # optional: install the use-belgie skill for Cursor, Codex, Claude, etc.

For MCP Apps, install the MCP and CLI extras:

uv add "belgie[mcp,cli]"

Build MCP Apps

Keep the Python and JavaScript dependency workflow in one project. Attach a React widget to a Python MCP tool. BelgieExtension starts Vite in the background for development and runs a one-time production build.

from datetime import UTC, datetime
from pathlib import Path

from mcp.server import MCPServer

from belgie.mcp import BelgieExtension

belgie = BelgieExtension(project=".")


@belgie.tool(
    widget=Path("src/widgets/get-time/widget.tsx"),
    name="get-time",
    title="Get Time",
    description="Get the current server time in ISO 8601 format.",
)
def get_time() -> dict[str, str]:
    return {"time": datetime.now(tz=UTC).isoformat()}


mcp = MCPServer(name="Get Time Server", extensions=[belgie])

The widget is a normal React entry. @belgie/mcp connects the MCP Apps host and surfaces the opening tool result:

import { Widget, useToolResult } from "@belgie/mcp";
import { getTime } from "@widgets/tools";

function AppView() {
  const { data, isLoading, execute } = useToolResult(getTime);
  return (
    <main>
      <p>{data?.time ?? (isLoading ? "Waiting..." : "No time returned.")}</p>
      <button onClick={() => void execute()}>Refresh</button>
    </main>
  );
}

export default function GetTime() {
  return (
    <Widget metadata={{ name: "Get Time", version: "1.0.0" }}>
      <AppView />
    </Widget>
  );
}

Declare JS deps under [tool.belgie.dependencies], then:

uv run belgie lock
uv run belgie install
# start your MCP server; Belgie starts Vite with widget HMR

Pass build=False to BelgieExtension when Vite is managed separately or production assets are already built.

Runnable projects:

  • mcp: Minimal MCP Apps widget.
  • shadcn: Same pattern with Tailwind CSS and shadcn/ui.
  • tanstack: TanStack Start SPA and MCP widget served together through FastAPI.

AI agents

When an agent needs a browser-style API or a JavaScript transformation, give it the Belgie sandbox tool. Pydantic AI uses run_typescript; LangChain uses run_code. Belgie executes JavaScript, TypeScript, or TSX in the embedded Deno sandbox. The Python runtime does not require a separate Node install.

Pydantic AI

Install with uv add "belgie[pydantic-ai]", set OPENAI_API_KEY, then:

from pydantic_ai import Agent

from belgie.pydantic_ai import BelgieSandbox

agent = Agent("openai:gpt-5", capabilities=[BelgieSandbox()])

result = agent.run_sync(
    "Convert 'foo-bar' to camelCase using TypeScript.",
)
print(result.output)

See examples/ai/pydantic-ai.

LangChain

Install with uv add "belgie[langchain]", set OPENAI_API_KEY, then:

from langchain.agents import create_agent

from belgie.langchain import BelgieMiddleware

agent = create_agent(
    model="openai:gpt-5",
    tools=[],
    middleware=[BelgieMiddleware()],
    system_prompt="You can execute JavaScript or TypeScript in a Deno sandbox with run_code.",
)

result = agent.invoke(
    {
        "messages": [
            (
                "user",
                "Convert 'foo-bar' to camelCase using TypeScript.",
            ),
        ],
    },
)
print(result["messages"][-1].content)

See examples/ai/langchain.

Under the hood: Deno in Python

MCP Apps and both agent sandbox integrations use Belgie's embedded Deno runtime. Call it directly when you need JavaScript or TypeScript from Python without MCP or an agent framework:

  • Scripts: Inline or file-based JS/TS with Runtime and Script, sync or async.
  • Inline dependencies: Import npm, JSR, and URL modules from source.
  • Environments: Lockfiles, custom cache/options, local packages, and Command for npm binaries (Vite, esbuild, etc.).
  • Data bridge: Pass JSON-safe dicts, lists, and primitives across the boundary.

Runtime permissions

RuntimePermissions gates Deno APIs and every host-backed module read, including static and dynamic imports, JSON modules, and Node require(). File entrypoints created with Script.from_file and command entrypoints must be covered by allow_read; inline and in-memory sources do not need a host read grant. Belgie-managed npm packages are available to the module loader without adding their node_modules or cache roots to the runtime's general read grants. Package imports therefore work in restricted runtimes, while Deno.readFile, arbitrary absolute file: URLs, and other direct host reads remain subject to the caller's allow_read and deny_read settings.

import asyncio

from belgie import Runtime, Script

script = Script[[str], str](
    """
import camelcase from "npm:camelcase@8.0.0";

export default function run(input: string): string {
  return camelcase(input);
}
"""
)


async def main() -> None:
    async with Runtime() as run:
        print(await run(script)("foo-bar"))  # prints: fooBar


asyncio.run(main())

Inline widget rendering

Pydantic AI and LangChain agents can return a complete inline React widget through the render_widget tool (alongside run_typescript / run_code). Enable rendering on the sandbox or middleware and pass a default-export TSX module — do not call render():

export default function Widget() {
  return <main>Hello from Belgie</main>;
}
from belgie.pydantic_ai import BelgieSandbox

capability = BelgieSandbox(enable_rendering=True, plugins=[])

render_widget builds HTML with @belgie/vite on a Belgie-owned renderer side-channel (not in the model-visible Deno worker). The agent Script stays workspace-restricted — no host /etc//proc, allow_sys, or allow_ffi — while Vite runs only in that host-mediated worker (workspace read/write, FFI under node_modules, localhost network, limited allow_sys; host env denied) and returns one self-contained HTML string with inline JavaScript, CSS, and assets. Host-configured Vite plugins run only during the server build; treat them as reviewed application code and use plugins=() for untrusted agents. This API is independent from @belgie/mcp and its path-based widget.tsx development and production flow.

Examples

Small, runnable projects. Each focuses on one capability.

UI

  • mcp: MCP Apps extension with a React widget built through Belgie.
  • shadcn: MCP Apps widget styled with Tailwind CSS and shadcn/ui.
  • tanstack: TanStack Start SPA and MCP widget served together through FastAPI.

AI

  • pydantic-ai: Pydantic AI agent with BelgieSandbox() for sandboxed JS/TS/TSX execution.
  • langchain: LangChain agent with BelgieMiddleware() for sandboxed JS/TS/TSX execution.

Basic

  • simple: Async Runtime with a TypeScript file on disk.
  • inline-deps: Direct npm:, jsr:, and URL imports in a script.
  • jsr-deps: JSR packages declared through an explicit Environment.
  • pyproject: Manage project package dependencies with belgie[cli] and [tool.belgie.dependencies].
  • environment: Sync and async Environment setup with path.
  • commands: npm package binaries via Runtime and Command.

For deeper integration guidance, optionally install the use-belgie skill with uvx library-skills install.

Metadata

Release files for belgie 0.41.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for belgie 0.41.1
File Size Uploaded
belgie-0.41.1.tar.gz 970.3 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for belgie 0.41.1
File
belgie-0.41.1-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details
belgie-0.41.1-cp312-abi3-manylinux_2_28_x86_64.whl CPython 3.12 abi3 Linux glibc 2.28+ x86-64 Details
belgie-0.41.1-cp312-abi3-manylinux_2_28_aarch64.whl CPython 3.12 abi3 Linux glibc 2.28+ ARM64 Details
belgie-0.41.1-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details
belgie-0.41.1-cp312-abi3-macosx_10_12_x86_64.whl CPython 3.12 abi3 macOS 10.12+ x86-64 Details

Total release size: 294.6 MB

Release files / belgie-0.41.1.tar.gz

Download URL belgie-0.41.1.tar.gz
Size 970.3 kB
Tags Source
SHA-256 checksum
How to use checksums
400f101df855df6026fadd6e83cd06f75ea7225c8429a171ccdab7f6107c51e8
BLAKE2b-256 checksum
How to use checksums
b0d5533c52e83def92e9627888631670e19fc6a7e3a05edfd80044d0e99a3d24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / belgie-0.41.1-cp312-abi3-win_amd64.whl

Download URL belgie-0.41.1-cp312-abi3-win_amd64.whl
Size 54.3 MB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
931f4ad9ce8449dcaa254195d89fd15c8cb19e580e69aee6e402de2dab983543
BLAKE2b-256 checksum
How to use checksums
dfc102bb7df9e474abfa485fbaff1d7b5c186dff4754fed934192909a723009a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / belgie-0.41.1-cp312-abi3-manylinux_2_28_x86_64.whl

Download URL belgie-0.41.1-cp312-abi3-manylinux_2_28_x86_64.whl
Size 61.4 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
d784ea967f45cd5d97be10f5a22857414e342cf08792d7dcb279b392ea21664f
BLAKE2b-256 checksum
How to use checksums
443f625f3ef583ae05a4dce923ba723c8ece026f96cd3441745c50d14c136cad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / belgie-0.41.1-cp312-abi3-manylinux_2_28_aarch64.whl

Download URL belgie-0.41.1-cp312-abi3-manylinux_2_28_aarch64.whl
Size 65.0 MB
Tags CPython 3.12 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
024a33ecd5c3595b06bde7260e9f9f86f91d79af8da867d8eac9f42c6c2377d7
BLAKE2b-256 checksum
How to use checksums
96970b38938a4f1416f8e8891d745e8b98bda8515e6a0f0ee12f8292c59db2c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / belgie-0.41.1-cp312-abi3-macosx_11_0_arm64.whl

Download URL belgie-0.41.1-cp312-abi3-macosx_11_0_arm64.whl
Size 55.4 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
752acfc94fd11f6bc3eef05bd6f9e918ddb6310c689344d0f68a1bbe0390400b
BLAKE2b-256 checksum
How to use checksums
a6cd349271175a0743062f7359300ebd68f605e8a9125be53a28b58471f9f800
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / belgie-0.41.1-cp312-abi3-macosx_10_12_x86_64.whl

Download URL belgie-0.41.1-cp312-abi3-macosx_10_12_x86_64.whl
Size 57.5 MB
Tags CPython 3.12 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
0a4d897b283416b049c97b2cf33d7780c1fbff3592ba60f9a266bfc81447b5e7
BLAKE2b-256 checksum
How to use checksums
a00d0427d9592fe932dfc5e6c1284aa6bde8d3d8d0eb0c756d67363b85d3521f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.42.0

6 release files

This release

0.41.1 This release

6 release files

0.41.0

6 release files

0.37.0

6 release files

0.36.0

6 release files

0.35.0

6 release files

0.34.0

6 release files

0.33.0

6 release files

0.32.0

6 release files

0.27.1

6 release files

0.27.0

6 release files

0.26.0

6 release files

0.25.1

6 release files

0.25.0

6 release files

0.24.0

6 release files

0.23.2

6 release files

0.22.0

6 release files

0.21.0

6 release files

0.20.0

6 release files

0.3.0

5 release files

0.2.3

6 release files

0.1.1

2 release files

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page