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
Metadata
Release files for deepagents-monty 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| deepagents_monty-0.2.0.tar.gz | 15.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| deepagents_monty-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.9 kB
Release files / deepagents_monty-0.2.0.tar.gz
| Download URL | deepagents_monty-0.2.0.tar.gz |
|---|---|
| Size | 15.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9b285d3bd65af1bf485ca5ec66143fee7590bb3b6543ef93345f33f1be9d1d64
|
|
BLAKE2b-256 checksum How to use checksums |
ef2689e0e43d3dfcb105ad786852c7138d62281c36bb857fa32acad79b02952f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / deepagents_monty-0.2.0-py3-none-any.whl
| Download URL | deepagents_monty-0.2.0-py3-none-any.whl |
|---|---|
| Size | 17.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
239a7c6a872b201006de729b74f14df936517e65a0c94996a4bbaa8471b95e53
|
|
BLAKE2b-256 checksum How to use checksums |
6a0ad122fae4e6090124f29b85badac1aa82ea0696a010ded974e4b958911300
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|