Skip to main content

Generative AI/UI sandbox for Python

Project description

Belgie: Generative AI/UI Sandbox for Python

Belgie is a sandboxed TypeScript environment for Python that lets you build React MCP Apps and have agents write code in a sandbox.

  • MCP Apps: Attach React widgets to Python MCP tools in one project.
  • AI agents: Sandboxed run_code so Pydantic AI and LangChain can run TypeScript and TSX.
  • Inline React widgets: Return self-contained HTML from run_code with @belgie/render.
  • Sandbox: Deno is bundled, so you do not need to install 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]"

MCP Apps

Skip the second package manager. 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 an npm package, a browser-style API, or a JS-side transform, give it run_code. Belgie executes the TypeScript, JavaScript, or TSX in the embedded Deno sandbox. No 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 BelgieCapability

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

result = agent.run_sync(
    "Convert 'foo-bar' to camelCase using TypeScript and the camelcase npm package.",
)
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 JS/TS in a Deno sandbox with run_code.",
)

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

See examples/ai/langchain.

Under the hood: Deno in Python

MCP Apps and agent run_code both use Belgie’s embedded Deno runtime. Call it directly when you need JS/TS 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.
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 same run_code tool. The agent writes one TSX module and imports the standalone renderer:

import { render } from "npm:@belgie/render";

function Widget() {
  return <main>Hello from Belgie</main>;
}

export default function run() {
  return render({
    widget: <Widget />,
    plugins: [],
  });
}

render() requests HTML from a Belgie-owned renderer side-channel (not from 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 FFI/sys/write, no host path grants) and returns one self-contained HTML string with inline JavaScript, CSS, and assets. Package imports are supported. Relative host-file imports are intentionally unavailable, and Vite plugins run only during the server build before their expressions and plugin-only imports are removed from the browser bundle. 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 BelgieCapability() 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

belgie-0.38.0.tar.gz (818.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

belgie-0.38.0-cp312-abi3-win_amd64.whl (54.2 MB view details)

Uploaded CPython 3.12+Windows x86-64

belgie-0.38.0-cp312-abi3-manylinux_2_28_x86_64.whl (61.3 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.28+ x86-64

belgie-0.38.0-cp312-abi3-manylinux_2_28_aarch64.whl (64.9 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.28+ ARM64

belgie-0.38.0-cp312-abi3-macosx_11_0_arm64.whl (55.3 MB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

belgie-0.38.0-cp312-abi3-macosx_10_12_x86_64.whl (57.4 MB view details)

Uploaded CPython 3.12+macOS 10.12+ x86-64

File details

Details for the file belgie-0.38.0.tar.gz.

File metadata

  • Download URL: belgie-0.38.0.tar.gz
  • Upload date:
  • Size: 818.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for belgie-0.38.0.tar.gz
Algorithm Hash digest
SHA256 951194929ff076f7ece68a5a452ab36574bf792ba046360fa93440e27616b006
MD5 b9d7856f55f06b709fdab75a3f6bfeb9
BLAKE2b-256 ba2dd28fecfe868769e21d3313d41828f130c00b856b757f50fc3f3224d73070

See more details on using hashes here.

File details

Details for the file belgie-0.38.0-cp312-abi3-win_amd64.whl.

File metadata

  • Download URL: belgie-0.38.0-cp312-abi3-win_amd64.whl
  • Upload date:
  • Size: 54.2 MB
  • Tags: CPython 3.12+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for belgie-0.38.0-cp312-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ae5b91dcc4e1cb23c0eebc0513ea76629637b7c80e2d08e281806f3925ac4cea
MD5 0c7eff6cc4d2153dd6fe030854b8aa6f
BLAKE2b-256 713e4639e3045b7cbad2cc0a108c03257cdfb98bd9611e2126940a8c8ca19fb8

See more details on using hashes here.

File details

Details for the file belgie-0.38.0-cp312-abi3-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: belgie-0.38.0-cp312-abi3-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 61.3 MB
  • Tags: CPython 3.12+, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for belgie-0.38.0-cp312-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d9006a4a887d152cd75ff03a76045ce9937f923f559a079544971b1e7cf66e7f
MD5 4f9dc23276e3d435e90902914b6fbbaa
BLAKE2b-256 b5da3fc6a96b35e61a40bd349b1ec98b71bcdd6023e1e5f106eaed9e7859a810

See more details on using hashes here.

File details

Details for the file belgie-0.38.0-cp312-abi3-manylinux_2_28_aarch64.whl.

File metadata

  • Download URL: belgie-0.38.0-cp312-abi3-manylinux_2_28_aarch64.whl
  • Upload date:
  • Size: 64.9 MB
  • Tags: CPython 3.12+, manylinux: glibc 2.28+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for belgie-0.38.0-cp312-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 93fec6e341efb013a2b2b22226fc64a1070f416db43de6781fefaa20f2311ae5
MD5 abc94b4bbd4857514125618d55d523a2
BLAKE2b-256 72e742d270c20abf8799c8febcd008ade8f48d056c21575cb5bf37597ef459ee

See more details on using hashes here.

File details

Details for the file belgie-0.38.0-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

  • Download URL: belgie-0.38.0-cp312-abi3-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 55.3 MB
  • Tags: CPython 3.12+, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for belgie-0.38.0-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ded8b95fea67e1bdde7c796f3745407d445da645cbd2d9b7853a6a6ab6638739
MD5 ab310fc4f517086c58a69d36e6e3e1db
BLAKE2b-256 722a63cb0bf559153b349b4803be5b8b352397b8eeb7b9630bccd2843c96fc8d

See more details on using hashes here.

File details

Details for the file belgie-0.38.0-cp312-abi3-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: belgie-0.38.0-cp312-abi3-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 57.4 MB
  • Tags: CPython 3.12+, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for belgie-0.38.0-cp312-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 0f531e1fc3bcab00b4b695e48289c926a6121d4860f65d208ff40c93f26dc190
MD5 44008281a4568dee8c444298ecee8bee
BLAKE2b-256 0625f6c003ffa3771b3ff9d36db3e1f511287e46f377e450b0dcf6915aef259c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page