npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@everruns/bashkit

v0.6.0

Published

Sandboxed bash interpreter for JavaScript/TypeScript

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.

Homepage: bashkit.sh

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, and find
  • Sync and async execution APIs
  • Direct VFS helpers, standalone FileSystem handles, and live mounts
  • Cancellation support via cancel()
  • Sticky cancellation recovery via clearCancel()
  • 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  # Deno

Quick 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\n

Async 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\n

Live Output

const bash = new Bash();

const result = await bash.execute(
  "for i in 1 2 3; do echo out-$i; echo err-$i >&2; done",
  {
    onOutput({ stdout, stderr }) {
      if (stdout) process.stdout.write(stdout);
      if (stderr) process.stderr.write(stderr);
    },
  },
);

onOutput is optional and fires during execution with chunk objects shaped like { stdout, stderr }. Chunks are not line-aligned or exact terminal interleaving, but concatenating all callback chunks matches the final ExecResult.stdout and ExecResult.stderr. The handler must be synchronous; Promise-returning handlers are rejected. Do not call back into the same Bash / BashTool instance from onOutput via execute*, readFile, fs(), or similar same-instance APIs.

Configuration

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

import { Bash, FileSystem } from "@everruns/bashkit";

const source = new FileSystem();
source.writeFile("/org/repo/README.md", "hello\n");

const bash = new Bash();
bash.mount("/workspace", source);

console.log(bash.executeSync("cat /workspace/org/repo/README.md").stdout);

Call bash.fs() or tool.fs() when you need a live handle to the current interpreter filesystem. Use new FileSystem() or FileSystem.real(...) when you need a standalone mountable filesystem.

Native Addon Interop

import { Bash, FileSystem } from "@everruns/bashkit";
import { createFilesystem } from "filesystem-addon";

const imported = FileSystem.fromExternal(createFilesystem());

const bash = new Bash();
bash.mount("/workspace", imported);
console.log(bash.executeSync("ls /workspace").stdout);

toExternal() / fromExternal() exchange an opaque native External token for the versioned stable ABI handle, so JavaScript cannot inspect or mutate native handle bytes. Native addons should depend on bashkit with the interop feature and use bashkit::interop::fs.

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, FileSystem } from "@everruns/bashkit";

const bash = new Bash();
const workspace = FileSystem.real("./src", {
  writable: true,
  allowedMountPaths: ["./src"],
});

bash.mount("/workspace", workspace);
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.clearCancel(); // preserve session/VFS state before reusing the instance

cancel() sets a sticky flag that causes future executions to fail with "execution cancelled". Call clearCancel() after the cancelled execution has finished to reuse the same instance without losing shell or VFS state. Use reset() only when you want to discard state entirely.

BashTool exposes the same cancel(), clearCancel(), and reset() methods. For synchronous execution, executeSync(...) and executeSyncOrThrow(...) also accept { signal }.

BashTool

BashTool wraps the interpreter with tool-contract metadata for agent frameworks:

  • name
  • version
  • shortDescription
  • description()
  • 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); // Alice

Snapshot / Restore

State snapshots are available on both Bash and BashTool instances:

import { Bash, BashTool } 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 shellOnly = bash.snapshot({ excludeFilesystem: true });
const promptOnly = bash.snapshot({
  excludeFilesystem: true,
  excludeFunctions: true,
});

const restored = Bash.fromSnapshot(snapshot);
console.log((await restored.execute("echo $BUILD_ID")).stdout); // 42\n

restored.reset();
restored.restoreSnapshot(snapshot);
restored.restoreSnapshot(shellOnly);
console.log(restored.executeSync("pwd").stdout); // /workspace\n

const tool = new BashTool({ username: "agent", maxCommands: 5 });
tool.executeSync("export TOOL_STATE=ready");

const toolSnapshot = tool.snapshot();
const toolShellOnly = tool.snapshot({ excludeFilesystem: true });
const restoredTool = BashTool.fromSnapshot(toolSnapshot, {
  username: "agent",
  maxCommands: 5,
});

console.log(restoredTool.executeSync("echo $TOOL_STATE").stdout); // ready\n
restoredTool.restoreSnapshot(toolShellOnly);

Framework 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, options?)
  • execute(commands, options?)
  • executeSyncOrThrow(commands, options?)
  • executeOrThrow(commands, options?)
  • cancel()
  • clearCancel()
  • 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 (cancel(), clearCancel()), reset, snapshot, restore, and direct VFS helpers from Bash
  • Tool metadata: name, version, shortDescription
  • snapshot()
  • restoreSnapshot(data)
  • BashTool.fromSnapshot(data, options?)
  • 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?: string
  • hostname?: string
  • maxCommands?: number
  • maxLoopIterations?: number
  • maxMemory?: number
  • timeoutMs?: number
  • files?: Record<string, string | (() => string) | (() => Promise<string>)>
  • mounts?: Array<{ path: string; root: string; writable?: boolean }>
  • python?: boolean
  • externalFunctions?: string[]

ExecuteOptions

  • signal?: AbortSignal
  • onOutput?: (chunk: { stdout: string; stderr: string }) => void

ExecResult and BashError

  • ExecResult.stdout
  • ExecResult.stderr
  • ExecResult.exitCode
  • ExecResult.error
  • ExecResult.success
  • ExecResult.stdoutTruncated
  • ExecResult.stderrTruncated
  • BashError.exitCode
  • BashError.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