A minimal, secure Python sandbox for AI agents
Project description
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 uncatchable — try/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 stdout —
print()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. Noos,sys,json,re, or anything else - Use third-party libraries — no
pip install, nonumpy, norequests - Define classes —
classdefinitions are not supported - Use async/await — no coroutines, no
asyncio - Use closures (functions cannot capture variables from enclosing scopes)
- Use
finallyblocks — onlytry/except/else - Use
matchstatements - 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/elseforloops over lists, strings, ranges,dict.items(), etc. — withbreak/continuewhileloops withbreak/continue- Ternary expressions:
x if condition else y - List comprehensions with filters:
[x*2 for x in items if x > 0]
Functions
defwith positional parameters, default values,*args,**kwargslambdaexpressions:lambda x, y: x + y- Keyword arguments at call sites:
f(x=1, y=2) - Recursive and nested function definitions
- Implicit
return Nonefor functions without a return statement
Error Handling
try/exceptwith typed handlers:except ValueError as e:- Bare
except:to catch all exceptions elseclause on try blocksraise ValueError("message")and bareraiseto 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file littrs-0.5.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: littrs-0.5.0-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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
434e5273c81d2a5d870bd07ad148bbf9f3fcb7a98d821e5ff9422fdb29e7a7a7
|
|
| MD5 |
5536c8f82b023857bb9e99b5abb9eda3
|
|
| BLAKE2b-256 |
1a100c4e8797cccd4892c06b9772530e269d78cde1263baa53bd4af88c460c9d
|
File details
Details for the file littrs-0.5.0-cp312-cp312-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: littrs-0.5.0-cp312-cp312-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 8.9 MB
- Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c8e65033cab6a73aaeed56aa3250954a612850583181d9945f125f37554c3d7
|
|
| MD5 |
442fa74405b11241220e568f310f53c2
|
|
| BLAKE2b-256 |
cd9ac30d74d9554978616b853e2e828f016ec275f3f6c18c26a342bfee808483
|
File details
Details for the file littrs-0.5.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: littrs-0.5.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 7.7 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b83be9b2aa0b7f343855d52480d8255a557ab35c42511f2cda8ef1d58647aeed
|
|
| MD5 |
30e4a22bebdabdb2cfe52c47fe142924
|
|
| BLAKE2b-256 |
c361ef67ba58217d369293e6e31288b52727c16b95a6d1a6362b0b5b2993e04f
|