interpretthis 0.3.0

Sandboxed Python AST interpreter for untrusted and LLM-generated code
Documentation
# interpretthis

Sandboxed Python AST interpreter for Rust.

Runs untrusted or LLM-generated Python by evaluating a
[`rustpython-parser`](https://crates.io/crates/rustpython-parser) AST under
resource limits and an allowlisted language surface. It is **not** CPython
embedded via the C API: there is no filesystem, network, or process access
unless the host injects those as tools.

## Why

You need to execute model-written Python for structured work (transforms,
scoring, tool-orchestrated agents) without giving the model a real Python
process. `interpretthis` is the evaluator: host code owns tools, limits, and
what happens with the result.

## Quick start

```rust
use std::collections::HashMap;

use interpretthis::{
    Interpreter, InterpreterConfig, InterpreterDeps, KwargsExt, ToolDefinition, Tools, Value,
};

#[tokio::main]
async fn main() {
    let tools = Tools::new().with(
        "double",
        ToolDefinition::from_fn(|kwargs| async move {
            let n = kwargs.require_int("n")?;
            Ok(Value::Int(n * 2))
        }),
    );

    let interp = Interpreter::new(
        InterpreterDeps { tools },
        InterpreterConfig::default(),
    );

    // Per-call tools merge with registered tools (per-call wins on name clash).
    let resp = interp
        .execute(
            "result = double(n=x)\nprint(result)",
            &Tools::new(),
            HashMap::from([("x".to_string(), Value::Int(42))]),
        )
        .await;

    match resp.result() {
        Ok(()) => println!("{}", resp.stdout),
        Err(e) => eprintln!("{e}"),
    }
}
```

Requires Rust 1.85+ and Tokio.

## Limits (honest)

- **Language subset** — large, but not full CPython. See
  [`CONFORMANCE.md`]./CONFORMANCE.md.
- **Sandbox** — dangerous names/attrs and non-allowlisted imports are rejected.
  See [`THREAT_MODEL.md`]./THREAT_MODEL.md.
- **Tools are trusted** — a host tool with side effects extends the trust
  boundary. Tool failures become a generic Python `Exception` (catchable);
  uncaught they fail the host `execute` call.
- **State export** is a versioned byte blob (4-byte version + JSON) for
  host-owned resume; signing/encryption is the host’s job.

## Docs

| | |
| --- | --- |
| [docs.rs/interpretthis]https://docs.rs/interpretthis | API reference (after crates.io publish) |
| [`CONFORMANCE.md`]./CONFORMANCE.md | CPython divergences |
| [`STATUS.md`]./STATUS.md | Parity track status |
| [`THREAT_MODEL.md`]./THREAT_MODEL.md | Security boundary |
| [`CHANGELOG.md`]./CHANGELOG.md | Release notes |
| [`CONTRIBUTING.md`]./CONTRIBUTING.md | Contribution policy (outreach first) |
| [`RELEASING.md`]./RELEASING.md | Tag and crates.io publish |
| [`MODULE_TEMPLATE.md`]./MODULE_TEMPLATE.md | Adding a stdlib module |
| [`SECURITY.md`]./.github/SECURITY.md | Vulnerability reporting |

## Development

```bash
cargo nextest run --all-targets   # preferred; cargo test also works
cargo clippy --all-targets -- -D warnings
scripts/license-headers.sh check
```

Parity tests compare against host `python3.12` when available
(`tests/integration/parity_corpus/`).

## License

Licensed under either of

- Apache License, Version 2.0 ([`LICENSE-APACHE`]./LICENSE-APACHE or
  http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([`LICENSE-MIT`]./LICENSE-MIT or
  http://opensource.org/licenses/MIT)

at your option.

### Contribution policy

We do **not** accept unsolicited outside contributions. If you are interested
in working on this project, email
[opensource@moderately.ai](mailto:opensource@moderately.ai) and explain why —
see [`CONTRIBUTING.md`](./CONTRIBUTING.md).

If a contribution is later accepted, unless you explicitly state otherwise it
is dual-licensed under MIT OR Apache-2.0 as above, without additional terms.