Skip to main content

Code Mode: use LLMs to generate executable code that performs tool calls.

Project description

codemode

Instead of making tool calls one at a time, let the LLM write code that orchestrates your Python tools in a single, more token-efficient pass.

Codemode runs that code in an in-process V8 isolate via jsrun. Isolates spin up in under 5ms with the same runtime performance as Node.js, have no network or filesystem access by default, and cannot reach the host except through functions you explicitly provide.

Experimental: this project is in early development

Install

pip install py-codemode[mcp]
# or
uv add py-codemode[mcp]

For the core executor without MCP: pip install py-codemode

Quick start

Create an MCP server with built-in capabilities and custom tools:

from codemode import EnvCapability, FsCapability, HttpCapability
from codemode.mcp import CodeModeServer

server = CodeModeServer(
    name="example",
    capabilities=[
        EnvCapability(allowed_keys=["USER"]),
        FsCapability(allowed_paths=["./examples"]),
        HttpCapability(allowed_hosts=["httpbin.org"]),
    ],
    enable_search=True,
)


@server.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b


if __name__ == "__main__":
    server.mcp.run(transport="streamable-http")

Run with uv run python examples/mcp_server.py and connect any MCP client.

The codemode[mcp] extra wraps the executor as an MCP server, exposing:

  • execute -- runs JavaScript that calls your Python functions. TypeScript declarations are auto-generated from your type hints and embedded in the tool description so the LLM knows what is callable.
  • search (optional, via enable_search=True) -- searches registered capabilities and tools by name or description.

How it works

┌─────────────────────┐         ┌──────────────────────┐
│  V8 isolate (jsrun) │         │  Python host         │
│                     │         │                      │
│  LLM-generated JS   │         │  Executor            │
│  runs in async IIFE │         │                      │
│                     │  bridge │                      │
│  codemode.fn({...}) ├────────►│  _dispatch()         │
│                     │◄────────┤  -> your_fn(**kwargs)│
│                     │  result │                      │
└─────────────────────┘         └──────────────────────┘

The executor wraps your code in a harness that captures console output and sets up a codemode proxy object. The proxy intercepts every codemode.*() call, serializes it to JSON, and bridges back to Python where _dispatch() routes it to the matching host function. The MCP server uses Executor under the hood.

Host functions

Host functions use keyword-only parameters with type hints:

async def read(*, path: str) -> str:
    return open(path).read()

Called from JavaScript as await codemode.read({ path: "/tmp/f" }). The type hints are used to generate TypeScript stubs (str becomes string, int/float becomes number, list[T] becomes T[], etc.).

Built-in capabilities

Capabilities are namespaced host functions with allowlist-based security. The sandbox has no filesystem, network, or environment access by default.

Capability Namespace Description
FsCapability(allowed_paths=[...]) codemode.fs Sandboxed read/write within allowed paths
EnvCapability(allowed_keys=[...]) codemode.env Read environment variables from an allowlist
HttpCapability(allowed_hosts=[...]) codemode.http HTTP requests to allowed hosts only

Limitations

  • V8 runtime, not Node, so no Node built-in modules. JavaScript only.
  • No top-level import or require in sandbox code

Advanced

For step-by-step control over host calls, use the session API directly:

import asyncio
from codemode import Executor, HostCallRequest, RunCompleted, RunFailed

async def main():
    executor = Executor(timeout_s=5)
    session = await executor.start("""
        async () => {
          const a = await codemode.double({ n: 3 });
          const b = await codemode.double({ n: a });
          return b;
        }
    """)

    while True:
        event = await session.next_event()
        if isinstance(event, HostCallRequest):
            result = event.input["n"] * 2
            await session.submit_result(event.call_id, result)
        elif isinstance(event, (RunCompleted, RunFailed)):
            break

    await session.cancel()
    executor.close()

asyncio.run(main())

This gives you full control over each host call, useful for logging, approval flows, or routing to external services.

jsrun also supports loading additional JavaScript libraries into the isolate via Runtime.add_static_module() or custom module loaders, V8 heap snapshots for faster cold starts, heap size limits, and per-call execution timeouts. See the jsrun documentation for details.

Further reading

License

MIT

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

py_codemode-0.1.1.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

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

py_codemode-0.1.1-py3-none-any.whl (14.8 kB view details)

Uploaded Python 3

File details

Details for the file py_codemode-0.1.1.tar.gz.

File metadata

  • Download URL: py_codemode-0.1.1.tar.gz
  • Upload date:
  • Size: 11.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for py_codemode-0.1.1.tar.gz
Algorithm Hash digest
SHA256 910fda43c87a2c9a6f8e26dd1c4b9defea8681fe9ee0973dfb82e49292d19933
MD5 0a0b3d8685c833009bb20bb2e8f10be4
BLAKE2b-256 aa723d9cd3679415864dcb1ad94796d48902cadc5658e477f4be788cbe24ce1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_codemode-0.1.1.tar.gz:

Publisher: ci.yml on imfing/codemode

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_codemode-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: py_codemode-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 14.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for py_codemode-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 84c1c7385dad6fb2cbedea4bb32324468103bd4dcf7bbe8f1cb4f666b7b91006
MD5 cb38beacf154ebf93ecf4884cb43be9b
BLAKE2b-256 fdf4b25633df4ab586f63d2b016f5d7c530108fe8086324a3690e9b63f32601c

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_codemode-0.1.1-py3-none-any.whl:

Publisher: ci.yml on imfing/codemode

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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