everruns/bashkit
Virtual Bash interpreter with a virtual file system for multi-tenant environments.
Bashkit is a Rust library that reimplements the bash shell from scratch inside a virtual sandbox, so you can run shell commands safely in-process without ever forking real processes. It's built specifically as a tool for LLM agents: an agent can execute bash commands, get streaming output, and have its state (files, variables, git repos, even Python/TypeScript/SQLite) isolated and resettable.
Key capabilities
- No real OS access by default — all 167 built-in commands (echo, grep, tar, jq, etc.) are implemented in Rust and run against a virtual filesystem; no
fork/exec, no network unless allowlisted. - Full shell semantics — POSIX-compliant, plus bashisms like arrays,
[[ ]], process substitution, globs, here-docs. - Resource limits — cap command count, loop iterations, output size, etc.
- LLM tool contract —
BashToolexposes discovery metadata, a system prompt, and streaming output;analyze()statically inspects a script before running it so hosts can decide whether to ask the user for approval. - Virtual filesystem — in-memory, overlay, and mountable layers; optional real-fs backend.
- Extensibility — register custom builtins in Rust, JS, or Python.
- Embedded language runtimes (experimental) — Python (Monty or real CPython in WASM), TypeScript (ZapCode), SQLite (Turso), virtual git.
- Snapshots — serialize shell state + VFS to bytes for checkpoints/resume.
- Bindings — Python (PyO3) and JS/TS (NAPI-RS), plus a CLI.
How it works Every command runs against an in-process interpreter with its own virtual filesystem and environment. No host processes are spawned; even background jobs and pipelines are emulated. The VFS makes it easy to give an agent a disposable workspace.
Use cases
- Giving LLM agents a bash tool with hard isolation and permission checks.
- Multi-tenant execution of user-provided shell code.
- Training/evals — measuring how well models use bash (the project includes an eval suite with published results).
Quick start
use bashkit::Bash;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut bash = Bash::new();
let result = bash.exec("echo hello world").await?;
println!("{}", result.stdout); // "hello world\n"
Ok(())
}
Install with cargo add bashkit (optional features: git, python, cpython, typescript, sqlite, realfs). A separate crate bashkit-scripted-tool helps compose tool definitions.
Related
- Project
- Project
- Project
- Project