Package Exports
- @everruns/bashkit
- @everruns/bashkit/ai
- @everruns/bashkit/anthropic
- @everruns/bashkit/langchain
- @everruns/bashkit/openai
Readme
@everruns/bashkit
Sandboxed bash interpreter for JavaScript and TypeScript. Native NAPI-RS bindings to the bashkit Rust core for Node.js, Bun, and Deno.
Features
- Sandboxed, in-process execution with a virtual filesystem
- Full bash syntax: variables, pipelines, redirects, loops, functions, and arrays
- 160 built-in commands including
grep,sed,awk,jq,curl, andfind - Sync and async execution APIs
- Direct VFS helpers, constructor mounts, and live host mounts
- Cancellation support via
cancel() - Snapshot and restore support on
Bash - AI framework adapters for OpenAI, Anthropic, Vercel AI SDK, and LangChain
Install
npm install @everruns/bashkit # Node.js
bun add @everruns/bashkit # Bun
deno add npm:@everruns/bashkit # DenoQuick Start
Sync Execution
import { Bash } from "@everruns/bashkit";
const bash = new Bash();
const result = bash.executeSync('echo "Hello, World!"');
console.log(result.stdout); // Hello, World!\n
bash.executeSync("X=42");
console.log(bash.executeSync("echo $X").stdout); // 42\nAsync Execution
import { Bash } from "@everruns/bashkit";
const bash = new Bash();
const result = await bash.execute('echo -e "banana\\napple\\ncherry" | sort');
console.log(result.stdout); // apple\nbanana\ncherry\n
await bash.execute('printf "data\\n" > /tmp/file.txt');
console.log((await bash.execute("cat /tmp/file.txt")).stdout); // data\nConfiguration
BashOptions
import { Bash } from "@everruns/bashkit";
const bash = new Bash({
username: "agent",
hostname: "sandbox",
maxCommands: 1000,
maxLoopIterations: 10000,
maxMemory: 10 * 1024 * 1024,
timeoutMs: 30_000,
mounts: [{ path: "/workspace", root: "./src", writable: true }],
python: false,
});Virtual Filesystem
Direct Methods on Bash and BashTool
import { Bash } from "@everruns/bashkit";
const bash = new Bash();
bash.mkdir("/data", true);
bash.writeFile("/data/config.json", '{"debug":true}');
bash.appendFile("/data/config.json", "\n");
console.log(bash.readFile("/data/config.json"));
console.log(bash.exists("/data/config.json"));
console.log(bash.ls("/data"));
console.log(bash.glob("/data/*.json"));BashTool exposes the same direct filesystem helpers.
FileSystem Accessor
Call bash.fs() or tool.fs() when you need the underlying filesystem handle directly. For most applications, the convenience methods on Bash and BashTool are simpler and more explicit.
Pre-Initialized Files
import { Bash } from "@everruns/bashkit";
const bash = new Bash({
files: {
"/config.json": '{"key":"value"}',
"/lazy.txt": () => "computed on first read",
},
});
console.log(bash.readFile("/config.json"));
const asyncBash = await Bash.create({
files: {
"/async.txt": async () => "loaded asynchronously",
},
});Real Filesystem Mounts
import { Bash } from "@everruns/bashkit";
const bash = new Bash({
mounts: [
{ path: "/docs", root: "./docs" },
{ path: "/workspace", root: "./src", writable: true },
],
});
console.log(bash.executeSync("ls /workspace").stdout);Live Mounts
import { Bash } from "@everruns/bashkit";
const bash = new Bash();
bash.mount("./src", "/workspace", true);
console.log(bash.executeSync("ls /workspace").stdout);
bash.unmount("/workspace");Error Handling
import { Bash, BashError } from "@everruns/bashkit";
const bash = new Bash();
try {
bash.executeSyncOrThrow("exit 1");
} catch (err) {
if (err instanceof BashError) {
console.log(err.exitCode);
console.log(err.stderr);
}
}Cancellation
import { Bash } from "@everruns/bashkit";
const bash = new Bash();
const running = bash.execute("sleep 60");
bash.cancel();
await running;
bash.reset(); // reset before reusing the instanceBashTool exposes the same cancel() and reset() methods. For synchronous execution, executeSync(...) and executeSyncOrThrow(...) also accept { signal }.
BashTool
BashTool wraps the interpreter with tool-contract metadata for agent frameworks:
nameversionshortDescriptiondescription()help()systemPrompt()inputSchema()outputSchema()
import { BashTool } from "@everruns/bashkit";
const tool = new BashTool();
console.log(tool.name);
console.log(tool.inputSchema());
const result = tool.executeSync("echo hello");
console.log(result.stdout);ScriptedTool
Use ScriptedTool to register JavaScript callbacks as bash-callable tools:
import { ScriptedTool } from "@everruns/bashkit";
const tool = new ScriptedTool({ name: "api" });
tool.addTool("get_user", "Fetch user by ID", (params) => {
return JSON.stringify({ id: params.id, name: "Alice" });
});
const result = tool.executeSync("get_user --id 1 | jq -r '.name'");
console.log(result.stdout); // AliceSnapshot / Restore
State snapshots are currently available on Bash instances:
import { Bash } from "@everruns/bashkit";
const bash = new Bash({ username: "agent", maxCommands: 100 });
await bash.execute("export BUILD_ID=42; mkdir -p /workspace && cd /workspace && echo ready > state.txt");
const snapshot = bash.snapshot();
const restored = Bash.fromSnapshot(snapshot);
console.log((await restored.execute("echo $BUILD_ID")).stdout); // 42\n
restored.reset();
restored.restoreSnapshot(snapshot);
console.log(restored.executeSync("pwd").stdout); // /workspace\nFramework Integrations
OpenAI
import { bashTool } from "@everruns/bashkit/openai";
const bash = bashTool();Anthropic
import { bashTool } from "@everruns/bashkit/anthropic";
const bash = bashTool();Vercel AI SDK
import { bashTool } from "@everruns/bashkit/ai";
const bash = bashTool();LangChain
import { createBashTool, createScriptedTool } from "@everruns/bashkit/langchain";API Reference
Bash
new Bash(options?)Bash.create(options?)executeSync(commands, { signal? })execute(commands)executeSyncOrThrow(commands, { signal? })executeOrThrow(commands)cancel()reset()snapshot()restoreSnapshot(data)Bash.fromSnapshot(data)- Direct VFS helpers:
readFile,writeFile,appendFile,mkdir,remove,exists,stat,readDir,ls,glob,mount,unmount,fs
BashTool
- All execution, cancellation, reset, and direct VFS helpers from
Bash - Tool metadata:
name,version,shortDescription description()help()systemPrompt()inputSchema()outputSchema()
ScriptedTool
new ScriptedTool(options)addTool(name, description, callback, schema?)executeSync(script)execute(script)executeSyncOrThrow(script)executeOrThrow(script)env(key, value)toolCount()
BashOptions
username?: stringhostname?: stringmaxCommands?: numbermaxLoopIterations?: numbermaxMemory?: numbertimeoutMs?: numberfiles?: Record<string, string | (() => string) | (() => Promise<string>)>mounts?: Array<{ path: string; root: string; writable?: boolean }>python?: booleanexternalFunctions?: string[]
ExecResult and BashError
ExecResult.stdoutExecResult.stderrExecResult.exitCodeExecResult.errorExecResult.successExecResult.stdoutTruncatedExecResult.stderrTruncatedBashError.exitCodeBashError.stderr
Platform Support
| OS | Architecture |
|---|---|
| macOS | x86_64, aarch64 |
| Linux | x86_64, aarch64 |
| Windows | x86_64 |
| WASM | wasm32-wasip1-threads |
How It Works
The JavaScript package wraps the Rust bashkit interpreter through NAPI-RS bindings. Commands execute in-process against a virtual filesystem, with the Rust core enforcing parsing, execution, and resource limits while the JS wrapper exposes a TypeScript-friendly API and framework adapters.
Part of Everruns
Bashkit is part of the Everruns ecosystem. See the bashkit monorepo for the Rust core, the Python package (bashkit), and related tooling.
License
MIT