JustBash
View SourceA simulated bash environment with an in-memory virtual filesystem, written in Elixir.
Designed for AI agents that need a secure, sandboxed bash environment.
Supports optional network access via curl with secure-by-default URL filtering.
Note: This is an Elixir port of just-bash by Vercel. The entire codebase was generated through conversational prompting with Claude Opus 4.5 via OpenCode.
Security Model
- The shell only has access to the provided virtual filesystem
- No access to the real filesystem by default
- No network access by default
- Network access can be enabled with URL allowlists
Installation
def deps do
[{:just_bash, "~> 0.1.0"}]
endUsage
Basic API
bash = JustBash.new()
{result, _} = JustBash.exec(bash, ~s(echo "Hello" > greeting.txt))
{result, _} = JustBash.exec(bash, "cat greeting.txt")
result.stdout #=> "Hello\n"
result.exit_code #=> 0Configuration
bash = JustBash.new(
files: %{"/data/file.txt" => "content"}, # Initial files
env: %{"MY_VAR" => "value"}, # Environment variables
cwd: "/app" # Starting directory
)Network Access
Network access is disabled by default. Enable it with allowlists:
# Allow specific hosts
bash = JustBash.new(
network: %{
enabled: true,
allow_list: ["api.github.com", "*.example.com"]
}
)
# Custom HTTP client for testing
bash = JustBash.new(
network: %{enabled: true},
http_client: MyMockHttpClient
)Execute Script Files
# Run a script from the real filesystem in the sandbox
{result, bash} = JustBash.exec_file("script.sh")
# With options
JustBash.exec_file("script.sh",
files: %{"/data/input.txt" => "hello"},
network: %{enabled: true}
)Sigil
import JustBash.Sigil
result = ~b"echo hello"
result.stdout #=> "hello\n"
# Modifiers
~b"echo hello"t # trimmed output
~b"echo hello"s # stdout only
~b"exit 42"e # exit codeSupported Commands
File Operations
cat, cp, file, find, ln, ls, mkdir, mv, readlink, rm, stat, touch, tree, du
Text Processing
awk, base64, comm, cut, diff, expand, fold, grep, head, md5sum, nl, paste, rev, sed, sort, tac, tail, tr, uniq, wc, xargs
Data Processing
jq (JSON), markdown (Markdown → HTML)
Network
curl
Shell Builtins
echo, printf, cd, pwd, export, unset, set, test, [, [[, true, false, :, source, ., read, exit, return, local, declare, break, continue, shift, getopts, trap
Utilities
basename, dirname, date, env, hostname, printenv, seq, sleep, tee, which
Shell Features
Pipes:
cmd1 | cmd2- Redirections:
>,>>,2>,&>,<,<<<, heredocs - Command chaining:
&&,||,; - Variables:
$VAR,${VAR},${VAR:-default},${VAR:=value},${#VAR},${VAR:start:len},${VAR#pattern},${VAR%pattern},${VAR/old/new},${VAR^^},${VAR,,} - Brace expansion:
{a,b,c},{1..10},{a..z} - Arithmetic:
$((expr))with full operators - Glob patterns:
*,?,[...] - Control flow:
if/elif/else/fi,for/while/until,case/esac - Functions:
function name { ... }orname() { ... } - Arrays:
arr=(...),${arr[0]},${arr[@]},${#arr[@]} - Subshells:
(cmd)and command groups{ cmd; }
Default Layout
When created without options, JustBash provides a Unix-like directory structure:
/home/user- Default working directory (and$HOME)/bin,/usr/bin- Binary directories/tmp- Temporary files
API Reference
# Create environment
bash = JustBash.new(opts)
# Execute command
{result, bash} = JustBash.exec(bash, "command")
result.stdout # String
result.stderr # String
result.exit_code # Integer
result.env # Updated environment
# Parse without executing
{:ok, ast} = JustBash.parse("echo hello")
# Format script
{:ok, formatted} = JustBash.format("if true;then echo yes;fi")Development
mix deps.get
mix test # 2400+ tests
mix dialyzer # Type checking
mix credo # Linting
License
MIT