Instructions for AI agents using just-bash in projects.
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.)
If you're building an AI agent that needs a bash tool, use bash-tool which is optimized for just-bash:
npm install bash-toolimport { 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.
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-
Isolation: Each
exec()call is isolated. Environment variables, functions, and cwd changes don't persist between calls. Only filesystem changes persist. -
No real filesystem: By default, commands only see the virtual filesystem. Use
OverlayFsto read from a real directory (writes stay in memory). -
No network by default:
curldoesn't exist unless you configurenetworkoptions with URL allowlists. -
No binaries/WASM: Only built-in commands work. You cannot run node, python, or other binaries.
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.
# 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'# 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# 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# 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# 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# 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# Read INI section value
yq '.database.host' config.ini
# Convert INI to JSON
yq -p ini -o json '.' config.ini# Convert HTML to markdown
html-to-markdown page.html
# From stdin
echo '<h1>Title</h1><p>Text</p>' | html-to-markdown# 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.xmlcat data.json | jq '.items[] | select(.active) | .name'find . -name "*.ts" -type f | xargs grep -l "TODO"cat input.txt | grep -v "^#" | sort | uniq -c | sort -rn | head -10cat data.csv | awk -F',' '{sum += $3} END {print sum}'- 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)
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- Success1- 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
- Check stderr: Error messages go to
result.stderr - Use --help: All commands support
--helpfor usage - Test incrementally: Build pipelines step by step
- Quote variables: Use
"$var"to handle spaces in values
- 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)
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).
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.tsKey types to explore:
BashOptions- Constructor options fornew Bash()ExecResult- Return type ofbash.exec()InitialFiles- File specification format