just-bash Runtime
Why the first local Little Harness runtime can build on just-bash.
Little Harness: published on npm as little-harness@0.2.0-alpha.0 (2026-10-05). Sections labeled UNRELEASED describe source-only changes. Release status
just-bash is a TypeScript virtual bash environment with an in-memory filesystem. It is a strong first substrate for Little Harness because agents naturally benefit from file and shell workflows.
The alpha runtime uses just-bash for:
- virtual filesystems
- mountable filesystems
- copy-on-write overlays
- standard shell commands
- text and data tools such as
rg,jq,sqlite3, andxan - optional Python and JavaScript execution
- network disabled by default
- Runtime Tool Bridge exposure for configured Little Harness tools inside
js-exec
Runtime Shape
Little Harness session
-> just-bash Bash instance
-> /session
-> /artifacts
-> .agents/skills
-> /persistent
-> configured tools via Runtime Tool BridgeThis gives the runtime a familiar command surface and per-session file isolation without requiring Docker, microVMs, or cloud sandboxes in the happy path.
Where It Runs
The same just-bash runtime can run in two places, chosen by localHost({ sandbox }):
- In a child process (
subprocessSandbox()) — the default for any turn that can run Python or JavaScript or reach the network, under the default"auto"mode. - In the host process (
justBashSandbox()) — under"auto"only whenruntime.pythonandruntime.javascriptare bothfalseand network is off, or always with"in-process".
Runtime Tool Bridge
When JavaScript is enabled, the default just-bash runtime exposes configured
tools inside js-exec as tools.<name>(args).
js-exec -c 'const result = await tools.queryCustomers({ plan: "enterprise" }); console.log(result.path ?? JSON.stringify(result))'This is the default path for complex, batched, or programmatically assembled tool inputs. The model can still call the same tools directly through the provider; the bridge simply gives it a scriptable route when emitting many large tool-call JSON payloads would be brittle or token-heavy.
Bridge calls use the same configured tool definitions, execution context,
spooling policy, abort signal, traces, and durability replay as ordinary tool
calls. Trace and durable events use caller: "runtime" and scope replay by the
parent bash tool call id so repeated identical bridge calls in different bash
commands do not collide.
The bridge is available only when bash is model-visible and JavaScript is
enabled. It is not advertised when runtime.bash === false,
runtime.javascript === false, runtime.toolBridge === false, or per-call
activeTools / prepareStep settings hide bash.
createHarness({
host: localHost(),
model,
tools,
runtime: { toolBridge: false },
});Security Boundary
just-bash is Tier-0: a compatibility layer for trusted tool patterns, not an isolation boundary.
Commands never touch the real filesystem, processes, or sockets, but the containment is a library's
parser and virtual filesystem, not the OS. js-exec and Python execute guest code inside whichever
process hosts just-bash, which is why the default "auto" mode moves code-running turns into the
subprocess sandbox (empty environment, SIGKILL watchdog, and just-bash's defense-in-depth layer, on only
there — see defenseInDepthForAdapter). Neither placement confines native code; see
Isolation And Security.
Whatever the sandbox, these still run in the host app's trust boundary:
- tool handlers
- storage callbacks
- export callbacks
- custom runtime hooks
Little Harness should treat those as explicit capabilities and make their side effects visible in trace events.
Beyond Tier-0
just-bash has no git, containers, compilers, or package managers. A command that needs one can be
escalated to a real sandbox you provide with tieredSandbox({ nextTier }),
which classifies each script before it runs; see Execution Tiers.
Containers, microVMs, or hosted execution pools plug in as that nextTier (or as the whole
sandbox) through the same HarnessSandboxFactory port — the
developer-facing harness config does not change.