$_ bashkit

Embedded Python (Monty)

Experimental. Monty is an early-stage Python interpreter that may have undiscovered crash or security bugs. Resource limits are enforced by Monty’s runtime. The integration should be treated as experimental.

Bashkit embeds the Monty Python interpreter, a pure-Rust implementation of Python 3.12. Python runs entirely in-memory with configurable resource limits and no host access.

See also:

Quick Start

Enable the python feature and register via builder:

use bashkit::Bash;

# #[tokio::main]
# async fn main() -> bashkit::Result<()> {
let mut bash = Bash::builder()
    .python()
    .env("BASHKIT_ALLOW_INPROCESS_PYTHON", "1")
    .build();

let result = bash.exec("python3 -c \"print('hello from Monty')\"").await?;
assert_eq!(result.stdout, "hello from Monty\n");
# Ok(())
# }

Usage Patterns

Inline Code

python3 -c "print(2 ** 10)"
# Output: 1024

Expression Evaluation

When no print() is called, the last expression is displayed (REPL behavior):

python3 -c "2 + 2"
# Output: 4

Script Files (from VFS)

cat > /tmp/script.py << 'EOF'
data = [1, 2, 3, 4, 5]
print(f"sum={sum(data)}, avg={sum(data)/len(data)}")
EOF
python3 /tmp/script.py

Pipelines and Command Substitution

result=$(python3 -c "print(42 * 3)")
echo "Result: $result"

echo "print('piped')" | python3

Virtual Filesystem (VFS) Bridging

Python pathlib.Path operations are bridged to Bashkit’s virtual filesystem. Files created by bash are readable from Python and vice versa.

Bash → Python

echo "important data" > /tmp/shared.txt
python3 -c "
from pathlib import Path
content = Path('/tmp/shared.txt').read_text()
print(f'Got: {content.strip()}')
"

Python → Bash

python3 -c "
from pathlib import Path
_ = Path('/tmp/result.txt').write_text('computed by python\n')
"
cat /tmp/result.txt

Supported Path Operations

OperationExample
Read textPath('f.txt').read_text()
Read bytesPath('f.txt').read_bytes()
Write textPath('f.txt').write_text('data')
Write bytesPath('f.txt').write_bytes(b'data')
ExistsPath('f.txt').exists()
Is file/dirPath('f.txt').is_file(), .is_dir()
MkdirPath('d').mkdir(parents=True, exist_ok=True)
DeletePath('f.txt').unlink()
List dirPath('.').iterdir()
StatPath('f.txt').stat().st_size
RenamePath('old').rename('new')
Env varsos.getenv('KEY'), os.environ

Architecture

Python code → Monty VM → OsCall(ReadText, path) → Bashkit VFS → resume

Monty pauses at filesystem operations, Bashkit bridges them to the VFS, then resumes execution with the result (or a Python exception like FileNotFoundError).

Resource Limits

Default limits prevent runaway Python code. Customize via PythonLimits:

use bashkit::{Bash, PythonLimits};
use std::time::Duration;

# fn main() {
let bash = Bash::builder()
    .python_with_limits(
        PythonLimits::default()
            .max_duration(Duration::from_secs(5))
            .max_memory(16 * 1024 * 1024)   // 16 MB
            .max_allocations(100_000)
            .max_recursion(50)
    )
    .build();
# }
LimitDefaultPurpose
Allocations1,000,000Heap allocation cap
Duration30 secondsExecution timeout
Memory64 MBHeap memory cap
Recursion200Call stack depth

LLM Tool Integration

When using BashTool for AI agents, call .python() on the tool builder:

use bashkit::{BashTool, Tool};

# fn main() {
let tool = BashTool::builder()
    .python()
    .build();

// help() and system_prompt() automatically document Python limitations
let help = tool.help();  // Includes a Markdown Notes section with Python hints
# }

The builtin’s llm_hint() is automatically included in the tool’s documentation, so LLMs know not to generate code using open(), HTTP requests, or classes.

Limitations

No open() builtin. Monty does not implement Python’s open(). Use pathlib.Path instead:

# Won't work:
# f = open('data.txt')

# Use instead:
from pathlib import Path
content = Path('data.txt').read_text()

No HTTP/network. No socket, urllib, requests, or http.client modules. Monty has no network primitives and no OsCall variants for network operations.

No classes. Class definitions are not yet supported by Monty (planned upstream).

No third-party imports. Only builtin modules (sys, typing, os, pathlib, math, json, datetime) are available. No pip install, no import numpy.

No re module. Disabled due to catastrophic backtracking DoS risk in untrusted code execution.

No str.format(). Use f-strings instead: f"value={x}" not "value={}".format(x).

Security

All Python execution runs in a virtual environment:

  • No host filesystem access — all paths resolve through the VFS
  • No network access — no sockets, HTTP, or DNS
  • No process spawning — no os.system(), subprocess, or __import__('os')
  • Resource limited — allocation, time, memory, and recursion caps
  • Path traversal safe../.. is resolved by VFS path normalization

See threat IDs TM-PY-001 through TM-PY-029 in the threat model.