Skip to content

Latest commit

 

History

History
329 lines (229 loc) · 8.85 KB

File metadata and controls

329 lines (229 loc) · 8.85 KB

AGENTS.md - just-bash

Instructions for AI agents using just-bash in projects.

What is just-bash?

A sandboxed bash interpreter with an in-memory virtual filesystem. Use it when you need to:

  • Execute shell commands without real filesystem access
  • Run untrusted scripts safely
  • Process text with standard Unix tools (grep, sed, awk, jq, etc.)

For AI Agents

If you're building an AI agent that needs a bash tool, use bash-tool which is optimized for just-bash:

npm install bash-tool
import { createBashTool } from "bash-tool";
import { generateText } from "ai";

const bashTool = createBashTool({
  files: { "/data/users.json": '[{"name": "Alice"}, {"name": "Bob"}]' },
});

const result = await generateText({
  model: "anthropic/claude-sonnet-4",
  tools: { bash: bashTool },
  prompt: "Count the users in /data/users.json",
});

See the bash-tool documentation for more details.

Quick Reference

import { Bash } from "just-bash";

const bash = new Bash({
  files: { "/data/input.txt": "content" }, // Initial files
  cwd: "/data", // Working directory
});

const result = await bash.exec("cat input.txt | grep pattern");
// result.stdout  - command output
// result.stderr  - error output
// result.exitCode - 0 = success, non-zero = failure

Key Behaviors

  1. Isolation: Each exec() call is isolated. Environment variables, functions, and cwd changes don't persist between calls. Only filesystem changes persist.

  2. No real filesystem: By default, commands only see the virtual filesystem. Use OverlayFs to read from a real directory (writes stay in memory).

  3. No network by default: curl doesn't exist unless you configure network options with URL allowlists.

  4. No binaries/WASM: Only built-in commands work. You cannot run node, python, or other binaries.

Available Commands

Text processing: awk, cat, column, comm, cut, egrep, expand, fgrep, fold, grep, head, join, nl, paste, rev, rg, sed, sort, strings, tac, tail, tr, unexpand, uniq, wc, xargs

Data processing: jq (JSON), python3/python (Python via Pyodide), sqlite3 (SQLite), xan (CSV), yq (YAML/XML/TOML/CSV)

File operations: basename, chmod, cp, dirname, du, file, find, ln, ls, mkdir, mv, od, pwd, readlink, rm, rmdir, split, stat, touch, tree

Utilities: alias, base64, bash, clear, curl, date, diff, echo, env, expr, false, gzip, gunzip, help, history, hostname, html-to-markdown, md5sum, printenv, printf, seq, sh, sha1sum, sha256sum, sleep, tar, tee, time, timeout, true, unalias, which, whoami, zcat

All commands support --help for usage details.

Tools by File Format

JSON - jq

# Extract field
jq '.name' data.json

# Filter array
jq '.users[] | select(.active == true)' data.json

# Transform structure
jq '[.items[] | {id, name}]' data.json

# From stdin
echo '{"x":1}' | jq '.x'

YAML - yq

# Extract value
yq '.config.database.host' config.yaml

# Output as JSON
yq -o json '.' config.yaml

# Filter with jq syntax
yq '.users[] | select(.role == "admin")' users.yaml

# Modify file in-place
yq -i '.version = "2.0"' config.yaml

TOML - yq

# Read TOML (auto-detected from .toml extension)
yq '.package.name' Cargo.toml
yq '.tool.poetry.version' pyproject.toml

# Convert TOML to JSON
yq -o json '.' config.toml

# Convert YAML to TOML
yq -o toml '.' config.yaml

CSV/TSV - yq -p csv

# Read CSV (auto-detects from .csv/.tsv extension)
yq '.[0].name' data.csv
yq '.[0].name' data.tsv

# Filter rows
yq '[.[] | select(.status == "active")]' data.csv

# Convert CSV to JSON
yq -o json '.' data.csv

Front-matter - yq --front-matter

# Extract YAML front-matter from markdown
yq --front-matter '.title' post.md
yq -f '.tags[]' blog-post.md

# Works with TOML front-matter (+++) too
yq -f '.date' hugo-post.md

XML - yq -p xml

# Extract element
yq '.root.users.user[0].name' data.xml

# Access attributes (use +@ prefix)
yq '.root.item["+@id"]' data.xml

# Convert XML to JSON
yq -p xml -o json '.' data.xml

INI - yq -p ini

# Read INI section value
yq '.database.host' config.ini

# Convert INI to JSON
yq -p ini -o json '.' config.ini

HTML - html-to-markdown

# Convert HTML to markdown
html-to-markdown page.html

# From stdin
echo '<h1>Title</h1><p>Text</p>' | html-to-markdown

Format Conversion with yq

# JSON to YAML
yq -p json '.' data.json

# YAML to JSON
yq -o json '.' data.yaml

# YAML to TOML
yq -o toml '.' config.yaml

# TOML to JSON
yq -o json '.' Cargo.toml

# CSV to JSON
yq -p csv -o json '.' data.csv

# XML to YAML
yq -p xml '.' data.xml

Common Patterns

Process JSON with jq

cat data.json | jq '.items[] | select(.active) | .name'

Find and process files

find . -name "*.ts" -type f | xargs grep -l "TODO"

Text transformation pipeline

cat input.txt | grep -v "^#" | sort | uniq -c | sort -rn | head -10

AWK for columnar data

cat data.csv | awk -F',' '{sum += $3} END {print sum}'

Limitations

  • 32-bit integers only: Arithmetic operations use 32-bit signed integers
  • No job control: No &, bg, fg, or process suspension
  • No external binaries: Only built-in commands are available
  • Execution limits: Loops, recursion, command counts, and output sizes have configurable limits to prevent runaway execution (exit code 126 when exceeded)

Error Handling

Always check exitCode:

import { Bash } from "just-bash";

const bash = new Bash({ files: { "/file.txt": "some content" } });
const result = await bash.exec("grep pattern file.txt");
if (result.exitCode !== 0) {
  // Command failed - check result.stderr for details
}

Common exit codes:

  • 0 - Success
  • 1 - General error or no matches (grep)
  • 2 - Misuse of command (invalid options)
  • 126 - Execution limit exceeded (loops, output size, string length)
  • 127 - Command not found

Debugging Tips

  1. Check stderr: Error messages go to result.stderr
  2. Use --help: All commands support --help for usage
  3. Test incrementally: Build pipelines step by step
  4. Quote variables: Use "$var" to handle spaces in values

Security Model

  • Virtual filesystem is isolated from the real system
  • Network access requires explicit URL allowlists
  • Execution limits prevent infinite loops and resource exhaustion
  • No shell injection possible (commands are parsed, not eval'd)

Execution Limits

All limits are configurable via executionLimits in BashOptions:

const bash = new Bash({
  executionLimits: {
    maxCommandCount: 10000,      // Max commands per exec()
    maxLoopIterations: 10000,    // Max bash loop iterations
    maxCallDepth: 100,           // Max function recursion depth
    maxStringLength: 10485760,   // Max string size (10MB)
    maxArrayElements: 100000,    // Max array elements
    maxGlobOperations: 100000,   // Max glob filesystem operations
    maxAwkIterations: 10000,     // Max AWK loop iterations
    maxSedIterations: 10000,     // Max sed branch loop iterations
    maxJqIterations: 10000,      // Max jq loop iterations
    maxSubstitutionDepth: 50,    // Max $() nesting depth
    maxHeredocSize: 10485760,    // Max heredoc size (10MB)
  },
});

Output size limits: AWK, sed, jq, and printf enforce maxStringLength on their output buffers. Commands that exceed the limit exit with code 126.

File read size limits: OverlayFs and ReadWriteFs default to a 10MB max file read size. Override with maxFileReadSize in filesystem options (set to 0 to disable).

Network response size: maxResponseSize in NetworkConfig caps HTTP response bodies (default: 10MB).

Discovering Types

TypeScript types are available in the .d.ts files. Use JSDoc-style exploration to understand the API:

# Find all type definition files
find node_modules/just-bash/dist -name "*.d.ts" | head -20

# View main exports and their types
cat node_modules/just-bash/dist/index.d.ts

# View Bash class options
grep -A 30 "interface BashOptions" node_modules/just-bash/dist/Bash.d.ts

# Search for specific types
grep -r "interface.*Options" node_modules/just-bash/dist/*.d.ts

Key types to explore:

  • BashOptions - Constructor options for new Bash()
  • ExecResult - Return type of bash.exec()
  • InitialFiles - File specification format