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

agentic-bash-tool

v0.1.0

Published

Harness-neutral agentic Bash execution with streaming, background sessions, persistence, and permissions

Readme

agentic-bash-tool

A standalone, harness-neutral Bash tool for Node agent runtimes. It provides advanced the agent-facing behaviors for small harnesses.

Features include streamed progress, foreground and background execution, task/session control, wall-clock timeouts, output persistence, image attachments, semantic command metadata, permission analysis, approvals, and injectable execution backends.

Install

npm install agentic-bash-tool

Node 22 or newer is required.

Minimal usage

Execution is fail-closed unless a security mode is chosen explicitly:

import { createBashRuntime } from "agentic-bash-tool";

const bash = createBashRuntime({
  security: "full",
  ask: "off",
  cwd: process.cwd(),
});

const result = await bash.execute(
  { command: "git status", description: "Inspect repository status" },
  { onEvent: (event) => console.log(event.type) },
);

console.log(result.content);
await bash.dispose();

security: "full" permits local host execution. Use it only when the surrounding harness has already established the appropriate trust boundary.

Generic function-tool wrapper

createBashTool returns an SDK-independent object with a plain JSON Schema and a familiar four-argument execute method:

import { createBashTool } from "agentic-bash-tool";

const tool = createBashTool({ security: "full", ask: "off" });

registerWithYourHarness({
  name: tool.name,
  description: tool.description,
  inputSchema: tool.parameters,
  execute: (args, context) =>
    tool.execute(context.callId, args, context.signal, context.onUpdate),
});

There is no dependency on Anthropic, OpenAI, TypeBox, Pi, or OpenClaw.

Approvals

Use allowlist mode with a callback provider when a harness can ask its operator for permission:

const bash = createBashRuntime({
  security: "allowlist",
  ask: "on-miss",
  allowlist: ["git status", "rg *"],
  permissionProvider: {
    async decide(request, signal) {
      // Render request.analysis.riskText however your harness prefers.
      return await askOperator(request, signal);
      // "allow-once" | "allow-always" | "deny"
    },
  },
});

Allow-always creates only a narrowed command-prefix suggestion. Empty and universal wildcard rules are rejected.

The built-in semantic analyzer:

  • distinguishes read-only, mutating, neutral, and sed commands;
  • analyzes compound commands with quote and parenthesis awareness;
  • detects dangerous wrappers, process substitution, redirects, redirect expansion, network paths, and out-of-root writes;
  • caps compound-command work and fails safely when parsing is uncertain;
  • produces structured reason codes, risk text, and audit records.

For higher-assurance environments, use an external policy engine through permissionProvider and an isolated ExecutionBackend.

Background commands

const result = await bash.execute({
  command: "long-running-command",
  runInBackground: true,
});

const sessionId = result.details.backgroundTaskId;

await bash.tasks.execute({ action: "poll", sessionId, timeout: 10_000 });
await bash.tasks.execute({ action: "log", sessionId, offset: 0, limit: 200 });
await bash.tasks.execute({ action: "write", sessionId, data: "yes\n" });
await bash.tasks.execute({ action: "send-keys", sessionId, keys: ["CTRL_C"] });
await bash.tasks.execute({ action: "stop", sessionId });

Supported task actions are list, get, poll, wait, output, log, write, send-keys, submit, paste, kill, stop, clear, and remove.

Commands also auto-background after backgroundMs. A wall-clock timeoutMs is separate: yielding never kills a command, while timeout always requests process-tree termination.

Execution events

Pass onEvent globally or per invocation. Events are JSON-serializable discriminated objects:

  • execution.started
  • execution.output
  • execution.progress
  • execution.backgrounded
  • permission.requested, permission.resolved, permission.denied
  • execution.completed, execution.failed, execution.timed-out
  • session.expired

Callbacks are isolated: a telemetry or harness callback exception cannot break the command.

Output behavior

  • stdout and stderr are retained separately and in arrival-order aggregate output.
  • In-memory output, pending output, and tails are bounded.
  • Character, UTF-8 byte, and line counts remain accurate after truncation.
  • Output over the persistence threshold is written to a mode-0600 file and replaced in model-facing content by a short preview plus path and size.
  • Emitted PNG, JPEG, GIF, and WebP paths are loaded best-effort as harness-neutral image blocks.

All thresholds and the OutputStore/ImageLoader implementations are configurable.

Backends and sandboxes

The bundled LocalExecutionBackend uses Node child processes and process-group termination. An execution backend implements:

interface ExecutionBackend {
  id: string;
  capabilities: {
    sandboxed: boolean;
    pty: boolean;
    stdin: boolean;
    remote: boolean;
  };
  start(request, hooks): Promise<RunningCommand>;
}

Inject a container, hosted sandbox, SSH, remote-node, or PTY backend with backend. Optionally provide hostBackend and set allowDangerouslyDisableSandbox: true to let the model-facing compatibility field request that backend. The core never pretends a backend is sandboxed and contains no OpenClaw host routing.

Standalone safety helpers

The package also exports:

  • analyzeBashPermission and policy/allowlist helpers;
  • hardened environment merging;
  • root-bounded, no-follow script reads and variable-injection preflight;
  • ReadStateTracker for read-before-write integration;
  • previewSedEdit and applySedPreview, which bind approval to original and proposed hashes and refuse stale/tampered applies;
  • terminal key, control-key, and hex-byte encoding.

These helpers are public so a harness can compose them with its own file tools and approval interface without importing OpenClaw.

Lifecycle

Create one runtime per desired security/session scope. Always call dispose() during shutdown. Disposal stops the TTL sweeper, terminates running processes, removes tracked persisted output, and clears session state.

The package does not use a process-global runtime singleton.