Releases: streamingfast/sbox
v1.9.0
Fixed
-
Fix
sbox runhanging on startup when stdin is not a terminal but no data is piped to it (e.g. when launched from certain IDEs, shells, or CI environments). The command now uses a zero-timeoutselectcall to check if stdin data is immediately available before attempting to read it, preventing the indefinite block. -
Fix
sbox runprompt argument being rejected when it starts with---(e.g. YAML front-matter): dashes-only strings are no longer treated as CLI flags. -
Fix extra blank lines in markdown rendering for both
claudeandopencodestream printers. Glamour pads rendered lines with ANSI-colored spaces thatstrings.TrimSpacecannot detect as blank, causing those padding lines to appear as blank lines in the output. The fix applies ANSI-aware blank detection usingansi.Stripbefore trimming, and switches glamour word wrap to 0 to prevent trailing-space padding entirely. -
Fix
Labeloutput for long values (e.g.Prompt,Goal): values are now collapsed to a single line and truncated to 100 characters with a trailing...to prevent multi-line or excessively long terminal output.
Added
-
Add
--watch <regex>flag tosbox run. When specified (can be given multiple times), after the interactive session exits the command stays alive and watches for changes to workspace files whose relative path matches any of the given regex patterns. Any matching write or create event triggers a new session. Watches are inactive while the agent is running. -
Add stdin support to
sbox run. When stdin is not a terminal (i.e., piped), its content is automatically used as the prompt. For example:cat TASK.md | sbox run. If a prompt argument is also provided, the argument takes precedence over stdin. -
Add optional prompt argument to
sbox run. Runningsbox run "<prompt>"launches the agent interactively with the given prompt pre-seeded. For Claude, the prompt is passed as a positional argument; for OpenCode, it is passed via--prompt. The session remains interactive after the prompt is processed. Extra agent args via--continue to work alongside the prompt. -
Add timing summary to
sbox loopcompletion report. When a loop finishes (goal confirmed or max iterations reached), the output now includes a "Timing Summary" section showing the total elapsed time for the entire loop and the duration of each individual iteration. -
Add
--watch <regex>flag tosbox loop. When specified (can be given multiple times), after the loop completes the command stays alive and watches for changes to workspace files whose relative path matches any of the given regex patterns. Any matching write or create event triggers a new loop run with the same prompt. Watches are inactive while the loop is running. The sandbox/container is kept warm between watch-triggered runs and only stopped on exit (Ctrl+C or error). -
Add git worktree support for all three isolation backends (container, sandbox, sbx). When the workspace is a git linked worktree (has a
.gitfile instead of a.git/directory), sbox automatically makes the main repository root accessible inside the sandbox at the same absolute path. This allows git operations to resolve the gitdir path embedded in the worktree's.gitfile. Container backend uses a bind mount; sandbox and sbx backends pass it as an extra workspace todocker sandbox create/sbx create. -
Add
sbox stop all,sbox stop sandbox, andsbox stop containersubcommands for globally stopping least-recently-used sandboxes and containers without removing them. Each subcommand supports--keep N(default 3) to keep the N most recently used running, and--forceto actually stop (dry-run by default). Useful to free file descriptor limits when many sandboxes/containers are running simultaneously. -
Add disk size information to
sbox infooutput. For container backend, shows the container's writable layer size and, if present, the associated named volume size (e.g.234 MB (container) + 1.1 GB (volume)). For sandbox backend, attempts to retrieve the sandbox VM disk size viadocker sandbox inspect. Size is omitted silently if unavailable. -
Add
sbxbackend for Docker Sandbox MicroVMs managed by the top-levelsbxCLI tool. Sandbox names follow the<agent>-<workspace>convention (nosbox-prefix). Select it via--backend sbx,sbox.yaml, or project/global config. -
Add
sbox stop sbxsubcommand for LRU-based stopping of sbx sandboxes (mirrorssbox stop sandbox).
v1.8.0
Added
-
Add
libclang-devto therustprofile, required by crates that usebindgenor link against LLVM/Clang. -
Install
cargo-nextestin therustprofile via the official pre-built binary fromget.nexte.st. Architecture-aware (amd64→linux,arm64→linux-arm). -
Add
exclude_dirsconfig option tosbox.yamland per-project config. Lists workspace-relative directories to shadow with anonymous Docker volumes, preventing them from being synced to the host. Solves "too many open files" on macOS when working with large build output trees (e.g.target/for Rust,node_modules/for Node). Only applies to the container backend. Anonymous volumes are cleaned up automatically when the container is removed (docker rm -v). -
Add
--backend=hostsupport. The host backend runs the AI agent directly on the host machine with no Docker or MicroVM isolation. Supports interactive mode, single-prompt mode, and loop mode (sbox loop). The.sbox/directory is still written for CLAUDE.md injection and env vars.sbox shellandsbox infoprint a clear unsupported message with exit code 1 when the host backend is active. Using--profilewith the host backend shows a warning that profiles are ignored. -
Add support for forwarding extra arguments to the agent binary via
--onsbox run(e.g.sbox run -- --resume <session-id>). Arguments after--are passed verbatim to the agent. -
Add
sbox prune <all|sandbox>command to reclaim disk space by removing old and stale sandboxes. Sandboxes whose workspace directory no longer exists are always pruned; the rest are kept based on a--keep N(default 5) most-recently-used policy. Dry-run by default; use--forceto actually delete. Each pruned sandbox removes the Docker sandbox, its.sbox/directory, and the project config entry in~/.config/sbox/projects/. Projects are inspected concurrently (2×CPU) usingdestel/rillfor faster scanning on large project lists or slow filesystems. -
Add
sbox stopsupport for the host backend. When the host backend starts an agent, its PID is recorded in.sbox/host.pid.sbox stopreads this file, sends SIGTERM to the process, and escalates to SIGKILL after 5 seconds if needed. The PID file is removed after the process exits. -
Add
load_claude_skillssetting insbox.yaml(opt-in, default off). When enabled for OpenCode sessions, installed Claude Code pluginSKILL.mdfiles are automatically converted to OpenCode rules at startup and written to~/.config/opencode/rules/. This bridges Claude Code's on-demand skill concept to OpenCode's always-on rules system.!commandinterpolation in skill bodies is preserved as-is for the agent to handle. -
Forward host git identity (
user.name,user.email) into the sandbox automatically. Values are read from the host's global git config and injected viaGIT_CONFIG_COUNT/GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_nenv vars (git 2.31+), making them available to the agent without touching~/.gitconfig. Skipped silently if not set on the host, or ifGIT_CONFIG_COUNTis already present in the environment.
Added
- Add
sbox prune containersubcommand to find and prune orphan Docker containers whose name starts withsbox-and whose workspace no longer exists or that have not been used recently. On prune: stops the container, removes it, then removes its associated namedsbox-volume. Supports the same--keep,--force, and--protect/-pflags assbox prune sandbox. Renders candidates in lipgloss tables with Container, Workspace, and Last Used columns. - Add
ContainerPruneCandidatetype,FindContainerPruneCandidates,PruneOneContainer, andgetContainerVolumeNameto thesboxpackage to support container-level pruning.
Changed
- Update
sbox prune allto run both sandbox pruning and container pruning, displaying results in separate=== Sandboxes ===and=== Containers ===sections. Previouslyallwas equivalent tosandbox. - Remove plugin forwarding from the host backend. When running with
--backend=hostthe agent is already on the host where plugins live natively in its own config directory (e.g.~/.claude/plugins). Passing redundant--plugin-dirflags is no longer needed and has been removed. - Rework
sbox pruneoutput into three styled lipgloss table sections — "Pruning N sandbox(es) | Missing", "Pruning N sandbox(es) | Too old", and "Keeping N sandbox(es)" — each only shown when non-empty. Uses the newstylex/package andgithub.com/charmbracelet/lipgloss/tablefor consistent terminal styling. - Add blank line between each prune table section for readability.
- Add named-sandbox targeting to
sbox prune sandbox: pass one or more sandbox names as arguments to target them specifically for deletion. Matched sandboxes are shown in a "Pruning N sandbox(es) | Named" table; unrecognised names appear in a separate "Unknown N sandbox(es)" table. Dry-run and--forcebehaviour are preserved. - Add
--protect/-pflag tosbox prune allandsbox prune sandboxto exempt specific sandboxes from deletion. Accepts comma-separated names per flag value and can be repeated (-p a,b -p c). Protected candidates that would otherwise have been pruned appear in a "Protected N sandbox(es)" table instead.
Fixed
- Fix
sbox pruneorphan detection including Docker sandboxes created by unrelated tools. Orphan candidates are now limited to sandboxes whose name starts withsbox-. - Fix
sbox pruneincorrectly associating a live Docker sandbox with a stale project entry when both share the same sandbox name but different workspaces (e.g. tworethdirectories). The name-based fallback lookup now verifies that the sandbox's recorded workspace matches the project before claiming it; if it differs the sandbox is considered unrelated and is left untouched. - Fix terminal env vars (
TERM,COLORTERM,TERM_PROGRAM,TERM_PROGRAM_VERSION) not being forwarded to existing containers, causing broken TUI rendering and non-functional OSC 8 hyperlinks (Cmd+click on URLs). The previous approach set them viadocker run -eflags which only apply at container creation time. They are now written to.sbox/envon every run and loaded by the entrypoint vialoadEntrypointEnv, making them available to both Claude and OpenCode regardless of whether the container is new or pre-existing. - Fix sandbox firewall instructions inside the sandbox injecting the wrong sandbox name (e.g.
firehose-coreinstead ofsbox-opencode-firehose-core). The sandbox context MD now uses a{{SBOX_SANDBOX_NAME}}placeholder that is substituted with the actual Docker sandbox name at prep time. The command is also wrapped in backticks for clean copy-paste.
v1.7.1
v1.7.0
Added
- Add
sbox backendcommand group (list,set,show) to manage the default container backend globally, mirroring the existingsbox agentcommand group. - Add
default_backendanddefault_agentkeys tosbox configfor viewing and setting defaults via the config command.
Changed
- Clarify
.sbox/directory purpose in both backend instruction files: it is a bidirectional host↔sandbox exchange directory, not read-only. Document what belongs there (user uploads, dependency repos being fixed) vs what does not (temporary logs, reference clones, scratch files). - Replace direct bind-mounts of
settings.json/settings.local.json(both container and sandbox backends) with a copy-merge approach: host settings are copied to.sbox/with bypass-permissions enforced, then merged into the sandbox agent home on startup. Sandbox-side changes (e.g. model, theme) are preserved across restarts while host-side updates (e.g. MCP servers) are applied on each run.
Fixed
- Fix
sbox infoshowingclaudein docker sandbox create command regardless of the configured agent. Now correctly displays the resolved agent binary (e.g.opencode). - Fix container backend not forwarding
TERMandCOLORTERMenv vars from host, causing incorrect colors and broken ANSI links compared to sandbox mode. - Fix container backend mounting
settings.jsonandsettings.local.jsonas read-only, causingEROFSerrors when the agent tries to modify settings (e.g. setting effort level).
v1.6.0
Added
sbox loopand prompt mode now support OpenCode agent (--agent=opencode). OpenCode JSON stream output (opencode run --format=json) is parsed and displayed with the same visual style as Claude stream output.- Add
opencodepackage withStreamPrinterfor parsing OpenCode's JSON stream format (step_start,tool_use,text,step_finishevents). - Add
PromptArgs()andNewStreamPrinter()toAgentSpecinterface, making prompt/loop mode agent-agnostic.
Changed
- Remove prompt file indirection in loop/prompt mode — prompt is now passed directly as a CLI argument instead of writing to a file and asking the agent to read it.
Fixed
- Claude stream printer now displays context for many more tools:
ToolSearch,WebSearch,WebFetch,Skill,TaskCreate,TaskUpdate,TaskOutput,NotebookEdit. Unknown tools fall back to extracting common field names (query,description,prompt, etc.) from their input.
v1.5.1
Added
- Background agent auto-updater: sbox entrypoint now wraps the agent as a child process instead of exec'ing, runs a background update check every 15 minutes, and updates the agent binary if the last update was more than 24 hours ago. After each update, the shim wrapper is automatically repaired so the sbox entrypoint remains the entry point.
- Disable agent's built-in auto-updater (
DISABLE_AUTOUPDATER=1) to prevent it from overwriting the sbox shim wrapper. Updates are now managed by sbox itself.
v1.5.0
Added
sbox run --startup-delayflag to delay agent startup inside the sandbox. If set to0, waits forever without starting the agent (useful for attaching a shell and debugging). Otherwise accepts a Go duration (e.g.30s,5m).sbox loop --confirmationsflag to configure the number of consecutive goal completions required (default: 2). Also configurable vialoop_confirmationsin global config (~/.config/sbox/config.yaml) orsbox.yaml.sbox loop <prompt>command: runs the agent in a loop until the goal described by the prompt is completed- Same
--backendand--agentsupport assbox run - Augments the prompt with loop instructions so the agent knows to assess and work toward the goal
- Agent writes
.sbox/loop.completionwhen the goal is reached - Loop stops after the agent confirms completion the required number of consecutive times
- Same
Fixed
sbox loopnow stops immediately when the agent exits with an error or is killed, instead of continuing to loopsbox loopnow stops the sandbox when the loop exits (completion, error, or Ctrl+C), preventing the container from running in the background- Fix container backend not producing output in loop/prompt mode due to TTY allocation (
-it) mangling stream-json output - Transfer
tui.jsonfrom~/.config/opencode/tui.jsonto.sbox/(host→sandbox) and from.sbox/tui.jsonto agent home (sandbox entrypoint) for OpenCode - OpenCode state persistence across
sbox stopandsbox run --recreate~/.config/opencodesynced to.sbox/opencode-cache/on stop/recreate; restored on next run~/.local/share/opencodesynced to.sbox/opencode-share-cache/on stop/recreate; restored after initial file seeding so cached auth/session data takes precedence
v1.4.0
Added
- OpenCode support as an alternative AI agent to Claude
--agentflag forsbox runto select the AI agent type (claudeoropencode)agentfield insbox.yamlto configure agent per-projectagentfield in project config (persisted when using--agentflag)default_agentfield in global config (~/.config/sbox/config.yaml)sbox agentcommand group for managing the default AI agentsbox agent list— show available agentssbox agent set <agent>— set default agent globallysbox agent show— show current default agent
- Agent resolution priority: CLI flag > sbox.yaml > project config > global config > default (claude)
- Entrypoint automatically detects and launches the configured agent (claude or opencode)
- Sandbox/container names now include agent type:
sbox-<agent>-<workspace>(e.g.,sbox-opencode-myproject)- This allows running different agents for the same workspace
- Sandbox name is automatically regenerated when switching agents
- Previous sandboxes named
sbox-claude-<workspace>will be automatically detected for Claude agent
- Agent-specific Docker sandbox templates:
- Claude agent uses
docker/sandbox-templates:claude-code - OpenCode agent uses
docker/sandbox-templates:opencode - Template is automatically selected based on the configured agent
- Claude agent uses
- Agent abstraction via
AgentSpecinterface for extensibility- Encapsulates agent-specific behavior (binary name, wrapper name, template image, config directory, binary discovery, exec args)
- Template builder generates agent-specific wrapper scripts (e.g.,
claude-wrapperoropencode-wrapper) - Wrapper script automatically renames agent binary to
<name>-realand symlinks to wrapper for proper initialization - Template hash includes agent type to ensure separate template images for different agents
- Entrypoint uses agent-specific config directories (
.claudefor Claude,.config/opencodefor OpenCode) - Agent setup (CLAUDE.md/AGENTS.md, agents, plugins) works with appropriate config directory per agent
- Container backend uses agent-specific volume names (
sbox-claude-*vssbox-opencode-*) - Container backend mounts agent config directory based on agent type (
.claudeor.opencode) - Settings.json mount location is agent-aware
- Template build pre-creates agent config directory with proper ownership to avoid permission issues with volume mounts
- OpenCode agent uses appropriate command-line arguments (no
--dangerously-skip-permissionsflag) - Entrypoint passes workspace path to OpenCode when no arguments provided
- Config now supports agent-specific home directories (
opencode_homedefaults to~/.config/opencode,claude_homedefaults to~/.claude) - Plugins and agents are loaded from agent-specific home directories (
~/.config/opencodefor OpenCode,~/.claudefor Claude) - Settings.json files mounted from appropriate agent home directory
- Container config directory matches host XDG conventions (
.config/opencodefor OpenCode) - OpenCode config file (
~/.config/opencode/opencode.json) is automatically prepared via.sbox/directory:- If no config exists, a default one is created with full permissions
- Existing config is loaded and permissions are automatically set to
{"*": "allow"}for sandbox/container environment - All other user config fields (like
model, preferences, etc.) are preserved - Ensures OpenCode runs with full permissions in the isolated environment
- OpenCode authentication file (
~/.local/share/opencode/auth.json) is automatically copied if present:- Shares local authentication credentials with the sandbox/container
- Enables seamless OpenCode usage without re-authentication
- Copied to
/home/agent/.local/share/opencode/auth.jsonin the container
- CLAUDE.md/AGENTS.md concatenation works for both agents:
- Same walking and concatenation logic for all agents
- Claude: Final file placed at
~/.claude/CLAUDE.md - OpenCode: Final file placed at
~/.config/opencode/AGENTS.md - Discovers and merges all CLAUDE.md and AGENTS.md files from parent directories
- Includes backend-specific context (sandbox vs container)
- Symlink deduplication: If CLAUDE.md is a symlink to AGENTS.md (or vice versa), only includes the file once
- Renamed functions for clarity:
setupCLAUDEMD→setupRules,prepareCLAUDEMD→prepareRules
Fixed
- OpenCode config file preparation now correctly preserves all user fields (like
model, preferences, etc.) while only adding/overriding thepermissionfield for sandbox safety
v1.3.3
v1.3.2
Added
cppprofile for C/C++ development (Boost, libc++, libstdc++, autoconf, automake, libtool, ninja-build, libzstd-dev, zlib1g-dev)
Changed
- Sensitive environment variables (KEY, TOKEN, SECRET, PASSWORD, etc.) are now masked in
sbox infoandsbox env listoutput
Fixed
- Fix Docker image tag format to include
vprefix for semantic versions (e.g.,v1.3.1instead of1.3.1) to match published image tags