{
  "markdown": "# Bashkit\n\n[![CI](https://github.com/everruns/bashkit/actions/workflows/ci.yml/badge.svg)](https://github.com/everruns/bashkit/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Crates.io](https://img.shields.io/crates/v/bashkit.svg)](https://crates.io/crates/bashkit)\n[![docs.rs](https://img.shields.io/docsrs/bashkit)](https://docs.rs/bashkit)\n[![Repo: Agent Friendly](https://img.shields.io/badge/Repo-Agent%20Friendly-blue)](https://github.com/everruns/bashkit/blob/main/AGENTS.md)\n\nAwesomely fast virtual sandbox with bash and file system. Written in Rust.\n\nHomepage: [bashkit.sh](https://bashkit.sh)\n\n## Features\n\n- **Secure by default** - No process spawning, no filesystem access, no network access unless explicitly enabled. [280+ threats](knowledge/security/threat-model.md) analyzed and mitigated\n- **POSIX compliant** - Substantial IEEE 1003.1-2024 Shell Command Language compliance\n- **Sandboxed, in-process execution** - All 167 commands reimplemented in Rust, no `fork`/`exec`\n- **Virtual filesystem** - InMemoryFs, OverlayFs, MountableFs with optional RealFs backend (`realfs` feature)\n- **Resource limits** - Command count, loop iterations, function depth, output size, filesystem size, parser fuel\n- **Network allowlist** - HTTP access denied by default, per-domain control\n- **Multi-tenant isolation** - Each interpreter instance is fully independent\n- **Custom builtins** - Extend with domain-specific commands\n- **LLM tool contract** - `BashTool` with discovery metadata, streaming output, and system prompts\n- **Script analysis** - Inspect commands, arguments, and file writes *before* running, to drive permission prompts ([guide](docs/script-analysis.md))\n- **Snapshotting** - Serialize shell state and VFS contents for checkpoint/resume workflows\n- **Scripted tool orchestration** - Compose ToolDef+callback pairs into multi-tool bash scripts (`scripted_tool` feature)\n- **Async-first** - Built on tokio\n- **Language bindings** - Python (PyO3) and JavaScript/TypeScript (NAPI-RS) for Node.js, Bun, and Deno\n- **Experimental: Git support** - Virtual git operations on the virtual filesystem (`git` feature)\n- **Experimental: Python support** - Embedded Python interpreter via [Monty](https://github.com/pydantic/monty) (`python` feature)\n- **Experimental: TypeScript support** - Embedded TypeScript interpreter via [ZapCode](https://github.com/TheUncharted/zapcode) (`typescript` feature)\n- **Experimental: SQLite support** - Embedded SQLite-compatible engine via [Turso](https://github.com/tursodatabase/turso) (`sqlite` feature)\n\n## Install\n\n```bash\ncargo add bashkit\n```\n\nOptional features:\n\n```bash\ncargo add bashkit --features git              # Virtual git operations\ncargo add bashkit --features python           # Embedded Python interpreter\ncargo add bashkit --features typescript       # Embedded TypeScript interpreter\ncargo add bashkit --features sqlite           # Embedded SQLite engine (Turso)\ncargo add bashkit --features realfs           # Real filesystem backend\ncargo add bashkit --features scripted_tool    # Tool orchestration framework\n```\n\n## Agent Development\n\nInstall the Bashkit skill before asking a coding agent to build against the\nruntime:\n\n```bash\nnpx skills add everruns/bashkit\n```\n\nThen ask your coding agent to wire Bashkit into the host project:\n\n```bash\nUsing bashkit, add support for a bash tool\n```\n\nEnjoy :)\n\n## Quick Start\n\n```rust\nuse bashkit::Bash;\n\n#[tokio::main]\nasync fn main() -> anyhow::Result<()> {\n    let mut bash = Bash::new();\n    let result = bash.exec(\"echo hello world\").await?;\n    println!(\"{}\", result.stdout); // \"hello world\\n\"\n    Ok(())\n}\n```\n\n## LLM Tool Contract\n\n`BashTool` follows the toolkit-library contract: builder for reusable config,\nimmutable tool metadata for discovery, and single-use executions for each call.\n\n```rust\nuse bashkit::{BashTool, Tool};\nuse futures::StreamExt;\n\n# #[tokio::main]\n# async fn main() -> anyhow::Result<()> {\nlet tool = BashTool::builder()\n    .username(\"agent\")\n    .hostname(\"sandbox\")\n    .build();\n\nprintln!(\"{}\", tool.description());\nprintln!(\"{}\", tool.system_prompt());\n\nlet execution = tool.execution(serde_json::json!({\n    \"commands\": \"printf 'hello\\nworld\\n'\"\n}))?;\nlet mut stream = execution.output_stream().expect(\"stream available\");\n\nlet handle = tokio::spawn(async move { execution.execute().await });\nwhile let Some(chunk) = stream.next().await {\n    println!(\"{}: {}\", chunk.kind, chunk.data);\n}\n\nlet output = handle.await??;\nassert_eq!(output.result[\"stdout\"], \"hello\\nworld\\n\");\n# Ok(())\n# }\n```\n\n## Script Analysis\n\n`analyze()` reports what a script statically refers to, commands, arguments,\nredirect targets, functions, without running it. Hosts use it to decide whether\na model-produced command needs user approval.\n\n```rust\nuse bashkit::Bash;\n\n# fn main() -> bashkit::Result<()> {\nlet bash = Bash::new();\nlet analysis = bash.analyze(\"cat notes.txt | grep -i todo > out.txt\")?;\n\nassert_eq!(analysis.command_names(), [\"cat\", \"grep\"]);\nassert_eq!(analysis.redirects[0].path.as_deref(), Some(\"out.txt\"));\nassert!(analysis.redirects[0].mode.is_write());\nassert!(!analysis.is_opaque());\n# Ok(())\n# }\n```\n\nAdvisory only: names built at runtime (`$cmd`, `$(echo rm)`), `eval`/`source`,\nand truncated walks report as *unknown* and set `is_opaque()`, an allowlist\ncheck must consult it. Available in Rust, Node (`bash.analyze()`), and Python\n(`bash.analyze()`). See [docs/script-analysis.md](docs/script-analysis.md).\n\n## Overview\n\n<div align=\"center\">\n  <a href=\"https://www.youtube.com/watch?v=0rIGX7mSlMg\">\n    <img src=\"assets/overview-thumb.jpg\" alt=\"Watch the overview video\" width=\"600\">\n    <br>\n    <strong>▶ Watch the 10-minute overview</strong>\n  </a>\n</div>\n\n## Built-in Commands (167)\n\n| Category | Commands |\n|----------|----------|\n| Core | `echo`, `printf`, `cat`, `nl`, `read`, `mapfile`, `readarray` |\n| Navigation | `cd`, `pwd`, `ls`, `tree`, `find`, `pushd`, `popd`, `dirs` |\n| Flow control | `true`, `false`, `exit`, `return`, `break`, `continue`, `test`, `[` |\n| Variables | `export`, `set`, `unset`, `local`, `shift`, `source`, `.`, `eval`, `readonly`, `times`, `declare`, `typeset`, `let`, `alias`, `unalias` |\n| Shell | `bash`, `sh` (virtual re-invocation), `exec`, `:`, `trap`, `caller`, `getopts`, `shopt`, `command`, `type`, `which`, `hash`, `compgen`, `fc`, `help` |\n| Text processing | `grep`, `rg`, `sed`, `awk`, `jq` (requires `jq` feature), `head`, `tail`, `sort`, `uniq`, `cut`, `tr`, `wc`, `paste`, `column`, `diff`, `comm`, `strings`, `tac`, `rev`, `seq`, `expr`, `fold`, `expand`, `unexpand`, `join`, `iconv`, `shuf` |\n| File operations | `mkdir`, `mktemp`, `mkfifo`, `rm`, `cp`, `mv`, `touch`, `chmod`, `chown`, `ln`, `rmdir`, `realpath`, `readlink`, `split`, `truncate` |\n| File inspection | `file`, `stat`, `less` |\n| Archives | `tar`, `gzip`, `gunzip`, `zip`, `unzip` |\n| Byte tools | `od`, `xxd`, `hexdump`, `base64` |\n| Checksums | `md5sum`, `sha1sum`, `sha256sum` |\n| Utilities | `sleep`, `date`, `basename`, `dirname`, `timeout`, `wait`, `watch`, `yes`, `kill`, `bc`, `clear`, `numfmt` |\n| Disk | `df`, `du` |\n| Pipeline | `xargs`, `tee` |\n| System info | `whoami`, `hostname`, `uname`, `id`, `env`, `printenv`, `history` |\n| Data formats | `csv`, `json`, `yaml`, `tomlq`, `template`, `envsubst` |\n| Network | `curl`, `wget` (requires allowlist), `http` |\n| DevOps | `assert`, `dotenv`, `glob`, `log`, `retry`, `semver`, `verify`, `parallel`, `patch` |\n| Experimental | `python`, `python3` (requires `python` feature), `ts`, `typescript`, `node`, `deno`, `bun` (requires `typescript` feature), `git` (requires `git` feature), `ssh`, `scp`, `sftp` (requires `ssh` feature), `sqlite`, `sqlite3` (requires `sqlite` feature) |\n\n## Shell Features\n\n- Variables and parameter expansion (`$VAR`, `${VAR:-default}`, `${#VAR}`, `${var@Q}`, case conversion `${var^^}`)\n- Command substitution (`$(cmd)`, `` `cmd` ``)\n- Arithmetic expansion (`$((1 + 2))`, `declare -i`, `let`)\n- Pipelines and redirections (`|`, `>`, `>>`, `<`, `<<<`, `2>&1`, `&>`)\n- Control flow (`if`/`elif`/`else`, `for`, `while`, `until`, `case` with `;;`/`;&`/`;;&`, `select`)\n- Functions (POSIX and bash-style) with dynamic scoping, FUNCNAME stack, `caller`\n- Indexed arrays (`arr=(a b c)`, `${arr[@]}`, `${#arr[@]}`, slicing, `+=`)\n- Associative arrays (`declare -A map=([key]=val)`)\n- Nameref variables (`declare -n`)\n- Brace expansion (`{a,b,c}`, `{1..10}`, `{01..05}`)\n- Glob expansion (`*`, `?`) and extended globs (`@()`, `?()`, `*()`, `+()`, `!()`)\n- Glob options (`dotglob`, `nullglob`, `failglob`, `nocaseglob`, `globstar`)\n- Here documents (`<<EOF`, `<<-EOF` with tab stripping, `<<<` here-strings)\n- Process substitution (`<(cmd)`, `>(cmd)`)\n- Coprocesses (`coproc`)\n- Background execution (`&`) with `wait`\n- Shell options (`set -euxo pipefail`, `shopt`)\n- Alias expansion\n- Trap handling (`trap cmd EXIT`, `trap cmd ERR`)\n- `[[ ]]` conditionals with regex matching (`=~`, BASH_REMATCH)\n\n## Configuration\n\n```rust\nuse bashkit::{Bash, ExecutionLimits, InMemoryFs};\nuse std::sync::Arc;\n\nlet limits = ExecutionLimits::new()\n    .max_commands(1000)\n    .max_loop_iterations(10000)\n    .max_function_depth(100);\n\nlet mut bash = Bash::builder()\n    .fs(Arc::new(InMemoryFs::new()))\n    .env(\"HOME\", \"/home/user\")\n    .cwd(\"/home/user\")\n    .limits(limits)\n    .build();\n```\n\n### Virtual Identity\n\nConfigure the virtual username and hostname for `whoami`, `hostname`, `id`, and `uname`:\n\n```rust\nlet mut bash = Bash::builder()\n    .username(\"deploy\")      // Sets whoami, id, and $USER env var\n    .hostname(\"my-server\")   // Sets hostname, uname -n\n    .build();\n\n// whoami → \"deploy\"\n// hostname → \"my-server\"\n// id → \"uid=1000(deploy) gid=1000(deploy)...\"\n// echo $USER → \"deploy\"\n```\n\n## Snapshotting\n\nCheckpoint an interpreter to bytes, then restore it later:\n\n```rust\nuse bashkit::{Bash, SnapshotOptions};\n\n# #[tokio::main]\n# async fn main() -> bashkit::Result<()> {\nlet mut bash = Bash::new();\nbash.exec(\"export BUILD_ID=42; echo ready > /tmp/state.txt\").await?;\n\nlet snapshot = bash.snapshot()?;\nlet shell_only = bash.snapshot_with_options(SnapshotOptions {\n    exclude_filesystem: true,\n})?;\nlet mut restored = Bash::from_snapshot(&snapshot)?;\nassert_eq!(restored.exec(\"echo $BUILD_ID\").await?.stdout.trim(), \"42\");\nrestored.restore_snapshot(&shell_only)?;\n# Ok(())\n# }\n```\n\nSee [docs/snapshotting.md](docs/snapshotting.md) for Rust, Python, and Node examples,\nplus snapshot security notes.\n\n## Custom Builtins\n\nRegister your own commands as bash builtins. They share the interpreter's VFS\nand shell state, so `mybuiltin > /scratch/out.json` writes through and the\nnext call sees the file.\n\nRust (any embedder):\n\n```rust\nuse bashkit::{Bash, Builtin, BuiltinContext, BuiltinRegistry, ExecResult, async_trait};\nuse std::sync::Arc;\n\nstruct Greet;\n\n#[async_trait]\nimpl Builtin for Greet {\n    async fn execute(&self, ctx: BuiltinContext<'_>) -> bashkit::Result<ExecResult> {\n        let who = ctx.args.first().map(String::as_str).unwrap_or(\"world\");\n        Ok(ExecResult::ok(format!(\"hello {}\\n\", who)))\n    }\n}\n\n# #[tokio::main]\n# async fn main() -> bashkit::Result<()> {\nlet registry = BuiltinRegistry::new();\nlet mut bash = Bash::builder().builtin_registry(registry.clone()).build();\n\n// Register after construction — visible immediately, VFS untouched.\nregistry.insert(\"greet\", Arc::new(Greet));\nassert_eq!(bash.exec(\"greet Alice\").await?.stdout, \"hello Alice\\n\");\n# Ok(())\n# }\n```\n\nRegistry builtins get execution-scoped VFS/request handles by default. Only\ntrusted host code that intentionally needs a session-lived VFS handle should\nuse `registry.insert_trusted(...)`.\n\nNode (`@everruns/bashkit`):\n\n```typescript\nimport { Bash } from \"@everruns/bashkit\";\n\nconst bash = new Bash({\n  customBuiltins: {\n    \"get-order\": (ctx) =>\n      JSON.stringify({ id: ctx.argv[0], status: \"shipped\" }) + \"\\n\",\n  },\n});\n\nawait bash.execute(\"mkdir -p /scratch\");\nawait bash.execute(\"get-order 42 > /scratch/order.json\");\nconsole.log((await bash.execute(\"cat /scratch/order.json\")).stdout);\n// {\"id\":\"42\",\"status\":\"shipped\"}\n\n// Post-construction registration / removal too:\nbash.addBuiltin(\"greet\", (ctx) => `hello ${ctx.argv[0] ?? \"world\"}\\n`);\nbash.removeBuiltin(\"greet\");\n```\n\nResolution order: shell function → POSIX special builtin → custom builtin →\nbaked-in builtin → `$PATH`, so custom builtins can override baked-ins\n(e.g. wrap `cat` with tracing) but a shell function defined in the script\nstill wins.\n\nSee [docs/custom_builtins_js.md](docs/custom_builtins_js.md) for the full JS guide\n(sync vs async, `BashTool`, error handling, snapshot/restore behavior).\nWorking example: [`examples/custom_builtins.mjs`](examples/custom_builtins.mjs).\n\n## Experimental: Git Support\n\nEnable the `git` feature for virtual git operations on the virtual filesystem.\nAll git data lives in the VFS, no host filesystem access.\n\n```bash\ncargo add bashkit --features git\n```\n\n```rust\nuse bashkit::{Bash, GitConfig};\n\nlet mut bash = Bash::builder()\n    .git(GitConfig::new()\n        .author(\"Deploy Bot\", \"deploy@example.com\"))\n    .build();\n\n// Local operations: init, add, commit, status, log\n// Branch operations: branch, checkout, diff, reset\n// Remote operations: remote add/remove, clone/push/pull/fetch (virtual mode)\n```\n\nSee [knowledge/integrations/git-support.md](knowledge/integrations/git-support.md) for the full specification.\n\n## Experimental: Python Support\n\nEnable the `python` feature to embed the [Monty](https://github.com/pydantic/monty) Python interpreter (pure Rust, Python 3.12).\nPython code runs in-memory with configurable resource limits and VFS bridging, files created\nby bash are readable from Python and vice versa.\n\n```bash\ncargo add bashkit --features python\n```\n\n```rust\nuse bashkit::Bash;\n\nlet mut bash = Bash::builder().python().build();\n\n// Inline code\nbash.exec(\"python3 -c \\\"print(2 ** 10)\\\"\").await?;\n\n// Script files from VFS\nbash.exec(\"python3 /tmp/script.py\").await?;\n\n// VFS bridging: open() and pathlib.Path work with the virtual filesystem\nbash.exec(r#\"python3 -c \"\nwith open('/tmp/data.txt', 'w') as f:\n    f.write('hello from python')\n\"\"#).await?;\nbash.exec(\"cat /tmp/data.txt\").await?; // \"hello from python\"\n```\n\nStdlib modules: `math`, `pathlib`, `os` (getenv/environ), `sys`, `typing`.\nSecurity note: `re` is intentionally disabled due to regex backtracking DoS risk.\nLimitations: file I/O is VFS-scoped, no network, no classes, no third-party imports.\nSee [crates/bashkit/docs/python.md](crates/bashkit/docs/python.md) for the full guide.\n\n## Experimental: TypeScript Support\n\nEnable the `typescript` feature to embed the [ZapCode](https://github.com/TheUncharted/zapcode) TypeScript interpreter (pure Rust, no V8).\nTypeScript code runs in-memory with configurable resource limits and VFS bridging via external function suspend/resume.\n\n```bash\ncargo add bashkit --features typescript\n```\n\n```rust\nuse bashkit::Bash;\n\nlet mut bash = Bash::builder().typescript().build();\n\n// Inline code (ts, node, deno, bun aliases all work)\nbash.exec(\"ts -c \\\"console.log(2 ** 10)\\\"\").await?;\nbash.exec(\"node -e \\\"console.log('hello')\\\"\").await?;\n\n// Script files from VFS\nbash.exec(\"ts /tmp/script.ts\").await?;\n\n// VFS bridging: readFile/writeFile async functions\nbash.exec(r#\"ts -c \"await writeFile('/tmp/data.txt', 'hello from ts')\"#).await?;\nbash.exec(\"cat /tmp/data.txt\").await?; // \"hello from ts\"\n```\n\nCompat aliases (`node`, `deno`, `bun`) and unsupported-mode hints are configurable:\n\n```rust\nuse bashkit::{Bash, TypeScriptConfig};\n\n// Only ts/typescript, no compat aliases\nlet bash = Bash::builder()\n    .typescript_with_config(TypeScriptConfig::default().compat_aliases(false))\n    .build();\n```\n\nLimitations: no `import`/`require`, no `eval()`, no network, no `process`/`Deno`/`Bun` globals.\nSee [crates/bashkit/docs/typescript.md](crates/bashkit/docs/typescript.md) for the full guide.\n\n## Experimental: SQLite Support\n\nEnable the `sqlite` feature to embed [Turso](https://github.com/tursodatabase/turso), a pure-Rust, SQLite-compatible engine, backed by the bashkit virtual filesystem. Turso is BETA upstream, so the builtin is opt-in at both the cargo and runtime layer.\n\n```toml\n[dependencies]\nbashkit = { version = \"0.17.1\", features = [\"sqlite\"] }\n```\n\n```rust\nuse bashkit::Bash;\n\nlet mut bash = Bash::builder()\n    .sqlite()\n    .env(\"BASHKIT_ALLOW_INPROCESS_SQLITE\", \"1\")\n    .build();\n\n// In-memory query\nbash.exec(\"sqlite :memory: 'SELECT 1 + 2'\").await?;\n\n// VFS-backed database — persists across invocations\nbash.exec(r#\"sqlite /tmp/notes.sqlite '\n  CREATE TABLE IF NOT EXISTS notes(id INTEGER PRIMARY KEY, body TEXT);\n  INSERT INTO notes(body) VALUES (\"hello\");\n'\"#).await?;\nbash.exec(\"sqlite -header /tmp/notes.sqlite 'SELECT * FROM notes'\").await?;\n```\n\nSqlite3-shell-compatible flags (`-csv`, `-json`, `-markdown`, `-header`, `-separator`, `-nullvalue`, `-cmd`) and dot-commands (`.tables`, `.schema`, `.dump`, `.read`, `.headers`, `.mode`) are supported. Two IO backends are available: `Memory` (default, load/flush against the VFS at command boundaries) and `Vfs` (custom turso `IO` impl).\n\nLimits via [`SqliteLimits`](crates/bashkit/src/builtins/sqlite/mod.rs) cap script size, result-set rows, DB file size, wall-clock duration, and statement count. See [crates/bashkit/docs/sqlite.md](crates/bashkit/docs/sqlite.md) for the full guide.\n\n## Virtual Filesystem\n\n```rust\nuse bashkit::{InMemoryFs, OverlayFs, MountableFs, FileSystem};\nuse std::sync::Arc;\n\n// Layer filesystems\nlet base = Arc::new(InMemoryFs::new());\nlet overlay = Arc::new(OverlayFs::new(base));\n\n// Mount points\nlet mut mountable = MountableFs::new(Arc::new(InMemoryFs::new()));\nmountable.mount(\"/data\", Arc::new(InMemoryFs::new()));\n```\n\n## CLI Usage\n\n```bash\n# Run a script\nbashkit script.sh\n\n# Interactive REPL\nbashkit\n\n\n# Mount real filesystem (read-only or read-write)\nbashkit --mount-ro /data script.sh\nbashkit --mount-rw /workspace script.sh\n```\n\n## Development\n\n```bash\njust build        # Build project\njust test         # Run tests\njust check        # fmt + clippy + test\njust pre-pr       # Pre-PR checks\n```\n\n## LLM Eval Results\n\nBashkit includes a [mira eval study](crates/bashkit-eval/) that measures how well LLMs use bashkit as a bash tool in agentic workloads, 58 tasks across 15 categories.\n\n_Latest run: 2026-06-27, on the mira eval framework (58 tasks)._\n\n| Model | Score | Tasks Passed | Tool Call Success | Duration |\n|-------|-------|-------------|-------------------|----------|\n| Claude Opus 4.8 | **95%** | **55/58** | **96%** | 12.8 min |\n| Claude Haiku 4.5 | **95%** | **55/58** | 94% | **7.4 min** |\n| GPT-5.3-Codex | 93% | 54/58 | 85% | 12.1 min |\n| GPT-5.5 | 88% | 51/58 | 90% | 8.2 min |\n| Claude Sonnet 4.6 | 84% | 49/58 | 93% | 19.9 min |\n\nOpus 4.8 and Haiku 4.5 lead at 55/58, Haiku matches Opus in ~⅗ the wall-clock\ntime. Two tasks trip every model (`file_path_organizer`, `script_getopts_parser`).\nSee the [detailed analysis](crates/bashkit-eval/README.md#results).\n\n```bash\ncargo install mira-cli       # one-time: the `mira` host CLI\njust eval-list               # list evals, samples, scorers, targets\njust eval                    # run the bash eval across the model matrix\njust eval-scripting          # run the scripting-tool eval\n```\n\n## Benchmarks\n\nBashkit includes a benchmark tool to compare performance against bash and just-bash.\n\n```bash\njust bench              # Quick benchmark run\njust bench --save       # Save results with system identifier\njust bench-verbose      # Detailed output\njust bench-list         # List all benchmarks\n```\n\nSee [crates/bashkit-bench/README.md](crates/bashkit-bench/README.md) for methodology and assumptions.\n\n## Language Bindings\n\n### C API\n\nThe experimental `libbashkit` native C ABI exposes opaque handles, synchronous\nexecution, and binary-safe virtual filesystem access. See\n[`crates/bashkit-capi`](crates/bashkit-capi/README.md), including two runnable C\nexamples.\n\n### Python\n\nPython bindings with LangChain integration are available in [crates/bashkit-python](crates/bashkit-python/README.md).\n\n```python\nfrom bashkit import BashTool\n\ntool = BashTool()\nprint(tool.description())\nprint(tool.help())\nresult = await tool.execute(\"echo 'Hello, World!'\")\nprint(result.stdout)\n```\n\n### JavaScript / TypeScript\n\nNAPI-RS bindings for Node.js, Bun, and Deno. Available as `@everruns/bashkit` on npm.\n\n```typescript\nimport { BashTool } from '@everruns/bashkit';\n\nconst tool = new BashTool({ username: 'agent', hostname: 'sandbox' });\nconst result = await tool.execute(\"echo 'Hello, World!'\");\nconsole.log(result.stdout);\n\n// Direct VFS access\nawait tool.writeFile('/tmp/data.txt', 'hello');\nconst content = await tool.readFile('/tmp/data.txt');\n```\n\nPlatform matrix: macOS (x86_64, aarch64), Linux (x86_64, aarch64), Windows (x86_64), WASM.\nSee [crates/bashkit-js](crates/bashkit-js/) for details.\n\n### Browser / edge (WebAssembly)\n\nA slim, single-threaded WebAssembly build for the browser and any other\nJavaScript runtime, edge/serverless workers (Cloudflare Workers, Vercel Edge,\nDeno Deploy), Node, Deno, and Bun. Available as `@everruns/bashkit-wasm` on npm.\nIt needs **no `SharedArrayBuffer` and no `COOP`/`COEP` headers**, so it drops\ninto any web app (including iframes) and into thread-less edge runtimes.\n\n```js\nimport { initBashkit, Bash } from \"@everruns/bashkit-wasm\";\n\nawait initBashkit();\nconst bash = new Bash();\nconsole.log(bash.executeSync('echo \"Hello, browser!\" | tr a-z A-Z').stdout); // HELLO, BROWSER!\n```\n\nUse this when a native addon can't load (browsers, edge); for a native\nNode.js / Bun / Deno addon use `@everruns/bashkit` above. See\n[crates/bashkit-wasm](crates/bashkit-wasm/README.md) for details.\n\n## Security\n\nBashkit is built for running untrusted scripts from AI agents and users. Security is a core design goal, not an afterthought.\n\n### Defense in Depth\n\n| Layer | Protection |\n|-------|------------|\n| **No process spawning** | All 167 commands are reimplemented in Rust, no `fork`, `exec`, or shell escape |\n| **Virtual filesystem** | Scripts see an in-memory FS by default; no host filesystem access unless explicitly mounted |\n| **Network allowlist** | HTTP access is denied by default; each domain must be explicitly allowed |\n| **Resource limits** | Configurable caps on commands (10K), loop iterations (10K per loop, 1M total), function depth (100), stdout/stderr (1MiB each), input (10MB) |\n| **Filesystem limits** | Max total bytes (100MB), max file size (10MB), max file count (10K), prevents zip bombs, tar bombs, and append floods |\n| **Parser limits** | Timeout (5s), fuel budget (100K ops), AST depth (100), prevents pathological input from hanging the interpreter |\n| **Multi-tenant isolation** | Each `Bash` instance is fully isolated, no shared state between tenants |\n| **Panic recovery** | All builtins wrapped in `catch_unwind`, a panic in one command doesn't crash the host |\n| **Path traversal prevention** | RealFs backend canonicalizes paths to prevent `../../etc/passwd` escapes |\n| **Unicode security** | 68 byte-boundary tests across builtins; zero-width character rejection in VFS paths |\n\n### Threat Model\n\n280+ identified threats across 17 categories (DoS, sandbox escape, info disclosure, injection, network, isolation, internal errors, git, SSH, logging, crypto, Python, TypeScript, SQLite, Unicode, filesystem, snapshots), each with a stable ID, mitigation status, and test coverage.\n\nSee the [threat model](knowledge/security/threat-model.md) for the full analysis and [security policy](SECURITY.md) for reporting vulnerabilities.\n\n## Other Virtual Bash Implementations\n\n- **[just-bash](https://github.com/vercel-labs/just-bash)** (TypeScript, Apache-2.0), Virtual bash interpreter for AI agents by Vercel Labs. Custom recursive descent parser, 75+ reimplemented commands (including full awk/sed/jq), in-memory VFS, defense-in-depth sandboxing, AST transform plugins. Runs in Node.js and browser.\n- **[gbash](https://github.com/ewhauser/gbash)** (Go, Apache-2.0), Deterministic, sandbox-only bash runtime for AI agents. Delegates parsing to `mvdan/sh`. Registry-backed commands, policy enforcement, structured tracing, JSON-RPC server mode.\n\n## Acknowledgments\n\nBashkit is an independent implementation that draws design inspiration from several open source projects:\n\n- **[just-bash](https://github.com/vercel-labs/just-bash)** (Vercel Labs, Apache-2.0), Pioneered the idea of a virtual bash interpreter for AI-powered environments. Bashkit's sandboxing architecture and multi-tenant design was inspired by their approach.\n- **[Oils](https://github.com/oilshell/oil)** (Andy Chu, Apache-2.0), Comprehensive bash compatibility testing approach inspired our spec test methodology.\n- **[One True AWK](https://github.com/onetrueawk/awk)** (Lucent Technologies), AWK language semantics reference for our awk builtin.\n- **[jq](https://github.com/jqlang/jq)** (Stephen Dolan, MIT), jq query syntax and behavior reference. Our implementation uses the [jaq](https://github.com/01mf02/jaq) Rust crates.\n\nNo code was copied from any of these projects. See [NOTICE](NOTICE) for full details.\n\n## Contributing\n\nThe best way to contribute is to [open an issue](https://github.com/everruns/bashkit/issues), bug reports, feature requests, and questions all help improve bashkit. If you'd like to contribute code, see [CONTRIBUTING.md](CONTRIBUTING.md) for setup and workflow details.\n\n## Ecosystem\n\nBashkit is part of the [Everruns](https://everruns.com) ecosystem.\n\n## License\n\nMIT\n",
  "bytes": 25543,
  "sha": "078a9fdbde8fa8aee9e311f597628345fe85b39065981bc01a58437bcb4502c5",
  "repo_slug": "everruns/bashkit",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_everruns_bashkit_knowledge_index_md_0c2e60e0/readme"
}