Skip to main content

A minimal, secure Python sandbox for AI agents

Project description

Littrs Logo

Littrs

A minimal, secure Python sandbox written in Rust for use by AI agents.

PyPI version Crates.io License CI GitHub stars


A minimal, secure Python sandbox written in Rust for use by AI agents.

Littrs avoids the cost, latency, and complexity of using full container-based sandboxes for running LLM-generated code. Instead, it lets you safely run Python code written by an LLM embedded directly in your agent, with startup times measured in milliseconds and zero external dependencies.

The core idea is simple: LLMs work faster, cheaper, and more reliably when they write Python code instead of relying on traditional structured tool calling. Littrs makes that possible without spinning up containers or risking arbitrary code execution on the host. You register Python functions as callable tools, hand the sandbox some LLM-generated code, and get back a result — safely.

Installation

pip install littrs

Quick Start

from littrs import Sandbox

sandbox = Sandbox()

@sandbox.tool
def get_weather(city: str, units: str = "celsius") -> dict:
    """Get current weather for a city."""
    return {"city": city, "temp": 22, "units": units}

result = sandbox("get_weather('London')")
# result == {"city": "London", "temp": 22, "units": "celsius"}

The @sandbox.tool decorator registers your function with its full signature — the LLM code calls it like a normal Python function. The sandbox is also callable: sandbox(code) is shorthand for sandbox.run(code).

Variables persist across calls, and you can inject values directly:

sandbox["user_id"] = 42
sandbox("name = get_weather('London')['city']")
sandbox("name")  # "London"

Resource Limits

Prevent runaway code from consuming unbounded resources:

sandbox.limit(max_instructions=10_000, max_recursion_depth=50)

try:
    sandbox.run("while True: pass")
except RuntimeError as e:
    print(e)  # "Instruction limit exceeded (limit: 10000)"

Resource limit errors are uncatchabletry/except in the sandbox code cannot suppress them. This is by design: the host must always be able to regain control.

Capturing Print Output

capture() returns both the result and everything that was print()-ed:

result, printed = sandbox.capture("""
for i in range(5):
    print(i)
"done"
""")
# result  == "done"
# printed == ["0", "1", "2", "3", "4"]

Tool Documentation for LLM Prompts

describe() auto-generates Python-style signatures and docstrings from registered tools, ready to embed in a system prompt:

print(sandbox.describe())
# def get_weather(city: str, units: str = 'celsius') -> dict:
#     """Get current weather for a city."""

Low-level Registration

If you need to bypass the decorator (e.g. registering a function that takes raw positional args):

def fetch_data(args):
    return {"id": args[0], "name": "Example"}

sandbox.register("fetch_data", fetch_data)

WASM Sandbox (Stronger Isolation)

For stronger isolation, Littrs can run the interpreter inside a WebAssembly guest module with memory isolation and fuel-based computation limits:

from littrs import WasmSandbox, WasmSandboxConfig

config = WasmSandboxConfig().with_fuel(1_000_000).with_max_memory(32 * 1024 * 1024)
sandbox = WasmSandbox(config)

result = sandbox.run("sum(range(100))")
assert result == 4950

What Littrs Can Do

  • Run a reasonable subset of Python — variables, control flow, functions (with defaults, *args, **kwargs), lambdas, list comprehensions, f-strings, try/except, and all the built-in types an LLM needs
  • Completely block access to the host environment — no filesystem, no network, no environment variables, no import, no standard library. The sandbox has zero ambient capabilities
  • Call functions on the host — only functions you explicitly register as tools. The LLM code calls them like normal Python functions, and you handle them in Python
  • Control resource usage — set instruction limits and recursion depth limits per run call. Resource limit violations are uncatchable (they bypass try/except)
  • Capture stdoutprint() output is collected and returned to the caller
  • Start up fast — no interpreter boot, no WASM runtime to load (unless you want it). Create a Sandbox, register tools, run code

What Littrs Cannot Do

  • Use the standard library — there is no import. No os, sys, json, re, or anything else
  • Use third-party libraries — no pip install, no numpy, no requests
  • Define classes — class definitions are not supported
  • Use async/await — no coroutines, no asyncio
  • Use closures (functions cannot capture variables from enclosing scopes)
  • Use finally blocks — only try/except/else
  • Use match statements
  • Snapshot/resume execution state — execution runs to completion in a single call

Supported Python Features

Types

None, bool, int, float, str, list, tuple, dict, set

Operators

Category Operators
Arithmetic +, -, *, /, //, %, **
Comparison ==, !=, <, <=, >, >=, in, not in, is, is not
Boolean and, or, not
Bitwise |, ^, &, <<, >>, ~
Assignment =, +=, -=, *=, /=, //=, %=, **=

Control Flow

  • if/elif/else
  • for loops over lists, strings, ranges, dict.items(), etc. — with break/continue
  • while loops with break/continue
  • Ternary expressions: x if condition else y
  • List comprehensions with filters: [x*2 for x in items if x > 0]

Functions

  • def with positional parameters, default values, *args, **kwargs
  • lambda expressions: lambda x, y: x + y
  • Keyword arguments at call sites: f(x=1, y=2)
  • Recursive and nested function definitions
  • Implicit return None for functions without a return statement

Error Handling

  • try/except with typed handlers: except ValueError as e:
  • Bare except: to catch all exceptions
  • else clause on try blocks
  • raise ValueError("message") and bare raise to re-raise

F-strings

name = "world"
f"hello {name}!"  # "hello world!"

String Methods

.upper(), .lower(), .strip(), .lstrip(), .rstrip(), .split(), .join(), .replace(), .startswith(), .endswith(), .find(), .count(), .title(), .capitalize(), .isdigit(), .isalpha(), .isalnum()

List/Dict/Set Methods

.append(), .pop(), .extend(), .insert(), .remove(), .index(), .count(), .keys(), .values(), .items(), .get(), .update(), .clear(), .add(), .discard(), .union(), .intersection(), .difference()

Slicing

items = [1, 2, 3, 4, 5]
items[1:3]    # [2, 3]
items[::2]    # [1, 3, 5]
items[::-1]   # [5, 4, 3, 2, 1]

Built-in Functions

len(), str(), int(), float(), bool(), list(), range(), abs(), min(), max(), sum(), print(), type(), isinstance(), enumerate(), zip(), sorted(), reversed(), dict(), tuple(), set(), round(), map(), filter(), any(), all(), chr(), ord()

Citation

If you use Littrs in your research, please cite it as:

@software{littrs,
  title = {Littrs: A Minimal, Secure Python Sandbox for AI Agents},
  author = {Chonkie Inc.},
  url = {https://github.com/chonkie-inc/littrs},
  license = {Apache-2.0},
  year = {2025}
}

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

littrs-0.5.1-cp312-cp312-win_amd64.whl (7.7 MB view details)

Uploaded CPython 3.12Windows x86-64

littrs-0.5.1-cp312-cp312-manylinux_2_34_x86_64.whl (8.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

littrs-0.5.1-cp312-cp312-macosx_11_0_arm64.whl (7.7 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file littrs-0.5.1-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: littrs-0.5.1-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 7.7 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for littrs-0.5.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 ebdb5058188b9b6813a7c6156fa52c93c6c80980068f3224c2df12e70cd22a7b
MD5 863d240d5c5f873014db5d18920c3ff9
BLAKE2b-256 fb9abca4c2629b386ab8dbbde34b7934a6ef25ca3a67f49c8450a27d03d433e6

See more details on using hashes here.

File details

Details for the file littrs-0.5.1-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for littrs-0.5.1-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 982d103ff5bfeabec75c4c3b379073b2c6fac9cf7f9e339f0a064a67dcf35d24
MD5 2e06b08ef0faca282eab3e3a9e3483ad
BLAKE2b-256 66b66691c96aa1d0102aeb4ffd8e188cfeb7c79a056baad2012e85639f69ceb6

See more details on using hashes here.

File details

Details for the file littrs-0.5.1-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for littrs-0.5.1-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1cc6047d7b880908e1dec17caea0f4ad238ea39a55aef0bcc7bd5595f872ac2e
MD5 9d5c415f82d9cdffa71a21a9ef95b23d
BLAKE2b-256 cf165c736b41eff1e290597dcf6d22df0ec8b5c13cce4370370ceb085b279fc0

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