Monty-backed Python REPL middleware for Deep Agents, with a shared filesystem between the sandbox and the agent's file tools.
Project description
deepagents-monty
deepagents-monty adds a secure python_repl tool to
Deep Agents using Pydantic's
Monty sandboxed Python interpreter.
Agent-generated Python can inspect and transform the same virtual files used by
read_file, write_file, ls, glob, grep, and edit_file, without giving
that code host filesystem or network access.
Why use it?
- Run model-written Python in a sandbox instead of on the host.
- Let the model use loops, parsing, aggregation, and data transforms when file tools would be awkward.
- Share one Deep Agents backend between the normal file tools and Monty code.
- Expose carefully scoped host capabilities with
external_functions.
Install
uv add deepagents-monty
Or with pip:
pip install deepagents-monty
Until the package is published on PyPI, install from this repository:
uv add 'deepagents-monty @ git+https://github.com/yesh0907/deepagents-monty'
Quickstart
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents_monty import MontyCodeMiddleware
backend = StateBackend()
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
backend=backend,
middleware=[MontyCodeMiddleware(backend=backend)],
)
result = await agent.ainvoke({
"messages": [{
"role": "user",
"content": "Find all Python files larger than 1000 bytes and list their sizes.",
}]
})
The model can now call python_repl with code like:
from pathlib import Path
sizes = []
for p in Path("/").iterdir():
if str(p).endswith(".py"):
content = p.read_text()
if len(content) > 1000:
sizes.append((str(p), len(content)))
sorted(sizes, key=lambda x: -x[1])
The files visible to Path("/") are the same files visible to the Deep Agents
filesystem tools. python_repl preserves variables, imports, and function
definitions between calls; pass restart=True to reset the REPL.
Security Model
Monty code runs in a restricted interpreter. By default, it has:
- no host filesystem access
- no network access
- no arbitrary third-party imports
- no access to environment variables
- only the virtual filesystem backed by the Deep Agents backend you provide
Host capabilities must be explicitly exposed through external_functions. Treat
those functions as part of the trusted boundary: validate inputs, keep return
values simple, and expose only the operations the model should be allowed to use.
Limitations
deepagents-monty inherits Monty's current Python subset:
- no class definitions
- no match statements, generators, or context managers
- no third-party libraries such as
pandas,requests, ornumpy - only a small standard-library subset
- no wall-clock or timing primitives
- no file deletes or renames through
pathlib - filesystem bridging expects sync Deep Agents backend methods
See docs/limitations.md for the detailed list.
External Functions
Use external_functions when sandboxed code needs a carefully scoped host
capability, such as CSV parsing, an API client, or a domain-specific helper.
from typing import Any
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents_monty import MontyCodeMiddleware
def read_csv(path: str) -> list[dict[str, Any]]:
...
backend = StateBackend()
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
backend=backend,
middleware=[
MontyCodeMiddleware(
backend=backend,
external_functions={"read_csv": read_csv},
)
],
)
The model can call the function from python_repl:
rows = read_csv("/transactions.csv")
sum(row["Amount"] for row in rows if row["Category"] == "Groceries")
Async external functions are supported. Sandbox code must call them with
await:
data = await fetch_json("https://example.com/data.json")
Function signatures are inferred from Python annotations and added to Monty's
type checker. Pass type_check_stubs when the public sandbox contract should be
more precise than the host function signature.
Customizing the system prompt
MontyCodeMiddleware injects a default system prompt (the public
MONTY_SYSTEM_PROMPT) that describes python_repl's mechanics and limitations
to the model. There are two ways to customize it:
-
append_system_prompt— add guidance after the default prompt. Use this when you want the built-in mechanics doc plus your own instructions (e.g. when to reach forpython_repl):from deepagents_monty import MontyCodeMiddleware middleware = MontyCodeMiddleware( backend=backend, append_system_prompt=( "Reach for python_repl whenever a task involves loops, aggregation, " "or parsing JSON across many files — it is cheaper than a long chain " "of read_file calls." ), )
-
system_prompt— replace the default prompt entirely. You lose the built-in mechanics/limitations doc, so only do this if you intend to describe the tool yourself.
The two compose independently: pass both to replace the base and append to it.
The default prompt is exported as MONTY_SYSTEM_PROMPT if you want to
introspect or compose against it:
from deepagents_monty import MONTY_SYSTEM_PROMPT
API
MontyCodeMiddleware(
*,
backend,
system_prompt=None,
append_system_prompt=None,
external_functions=None,
type_check_stubs=None,
max_duration_secs=10.0,
type_check=True,
)
backend: required Deep Agents backend. Pass the same backend you pass tocreate_deep_agent(backend=...).system_prompt: optional replacement for the default prompt that describespython_replto the model. Using this drops the built-in mechanics and limitations doc — preferappend_system_promptwhen you just want to add guidance.append_system_prompt: optional extra guidance appended after the base prompt (separated by a blank line). The base issystem_promptif provided, else the default. Composes independently ofsystem_prompt. See Customizing the system prompt.external_functions: optional host functions exposed as global names inside Monty code.type_check_stubs: optional Python stub text for external functions and model-facing types.max_duration_secs: per-call wall-clock cap for sandbox execution.type_check: enables Monty's parse-time type checker. Defaults toTrue.
Advanced users can also build the standalone python_repl tool with
make_execute_python(...).
Examples
Analyze Agent Files
from pathlib import Path
import json
records = []
for path in Path("/").iterdir():
if str(path).endswith(".json"):
records.append(json.loads(path.read_text()))
len(records)
Expose a Safe Reader
def read_transactions() -> list[dict[str, str]]:
...
middleware = MontyCodeMiddleware(
backend=backend,
external_functions={"read_transactions": read_transactions},
)
Use an Async Helper
async def lookup_customer(customer_id: str) -> dict[str, str]:
...
middleware = MontyCodeMiddleware(
backend=backend,
external_functions={"lookup_customer": lookup_customer},
)
Sandbox code:
customer = await lookup_customer("cust_123")
customer["segment"]
Development
uv sync --all-extras
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run pyright
Build the package locally:
uv build
uvx twine check dist/*
More Documentation
Credits
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 Distribution
Built Distribution
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 deepagents_monty-0.2.0.tar.gz.
File metadata
- Download URL: deepagents_monty-0.2.0.tar.gz
- Upload date:
- Size: 15.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","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":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9b285d3bd65af1bf485ca5ec66143fee7590bb3b6543ef93345f33f1be9d1d64
|
|
| MD5 |
ba98e8b3657856da242e2013a5e33b6a
|
|
| BLAKE2b-256 |
ef2689e0e43d3dfcb105ad786852c7138d62281c36bb857fa32acad79b02952f
|
File details
Details for the file deepagents_monty-0.2.0-py3-none-any.whl.
File metadata
- Download URL: deepagents_monty-0.2.0-py3-none-any.whl
- Upload date:
- Size: 17.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","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":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
239a7c6a872b201006de729b74f14df936517e65a0c94996a4bbaa8471b95e53
|
|
| MD5 |
8c7b56f38d376a1a3a38ec4a4b5bf3ba
|
|
| BLAKE2b-256 |
6a0ad122fae4e6090124f29b85badac1aa82ea0696a010ded974e4b958911300
|