boxer

Go package

Every exported identifier in pkg/boxer, for opening, running and managing sandboxes from Go.

import "github.com/BarakChamo/boxer/pkg/boxer"

pkg/boxer is the module's only importable package. Everything else is under internal/. It calls the same code the CLI does, so a Box reads the worktree's boxer.toml and behaves as boxer run would there. The stability contract covers its exported functions, types and fields from 1.0.

b, err := boxer.Open("/Users/me/src/app-wt1", boxer.Options{})
if err != nil {
    return err
}
if _, err := b.Ensure(true, false); err != nil {
    return err
}
code, err := b.Run([]string{"sh", "-c", "npm test"}, boxer.RunOpts{Stdout: os.Stdout, Stderr: os.Stderr})

examples/go-embed runs one shell line in several worktrees at once through this package and reports each exit code. Build on boxer covers when to use it and what to check before you ship.

Index

IdentifierKind
Openfunc
List, ListAll, Stop, Delete, LastUsedfunc
Ports, URLsfunc
Boxtype, with Scope, Warnings, Ensure, Run, Status, Down
Optionstype
RunOptstype alias
Machinetype alias
Scopetype alias
Errortype alias

Open

func Open(cwd string, o Options) (*Box, error)

Resolves the sandbox for cwd, or for the process working directory when cwd is empty. It reads configuration and does not create anything. The error is a *Error when boxer refused, with cause NO_REPOSITORY, WORKTREE_REQUIRED or SCOPE_UNRESOLVED, and a plain error when boxer.toml is invalid.

Options

type Options struct {
    Harness   string
    SessionID string
    AgentID   string
}

Every field may be empty.

Field
HarnessSelects the [harness.<name>] override layer
SessionIDThe session id for isolation = "session"
AgentIDThe subagent id for isolation = "subagent"

Box

type Box struct { /* unexported */ }

The sandbox resolved for one working directory. Its methods are safe to call on a running sandbox.

Box.Scope

func (b *Box) Scope() Scope

The resolved scope.

Box.Warnings

func (b *Box) Warnings() []string

Non-fatal findings from resolution, such as running in the main checkout or degraded isolation.

Box.Ensure

func (b *Box) Ensure(allowCreate, recreate bool) (created bool, err error)

Makes the machine exist and run. When it starts one, it runs setup and start and waits for ready; a machine already running is returned as it is. It creates a machine only when allowCreate is set. Otherwise a missing sandbox fails with cause NO_SANDBOX. recreate deletes an existing machine first. created reports whether a machine was created.

Box.Run

func (b *Box) Run(argv []string, o RunOpts) (int, error)

Executes argv in the guest and returns its exit code. It provisions first when create_on includes run. A non-nil error means the command did not run. -1 with an error means on_sandbox_unavailable = "passthrough" applies and you may run argv on the host.

Box.Status

func (b *Box) Status() (Machine, bool, error)

The machine, and whether it exists.

Box.Down

func (b *Box) Down() error

Deletes the machine. Absence is not an error.

List

func List() ([]Machine, error)

Every boxer-owned machine on the host backend.

ListAll

func ListAll() ([]Machine, error)

Every boxer-owned machine on every backend installed on this host, with Machine.Backend set to the backend's name. A backend that is installed and not answering is skipped. Its error is returned beside the machines the other backends listed, so check both. Same as boxer ls -A.

Ports

func Ports(m Machine) map[string]string

A machine's forwarded ports, guest port to host port, read from its boxer.port.<guest> labels. Empty when it forwards none.

URLs

func URLs(m Machine) map[string]string

A URL for each forwarded port, keyed by guest port: the portless name when [urls] is on and the route is registered, otherwise http://127.0.0.1:<host port>. Same as boxer url --all.

ms, _ := boxer.ListAll()
for _, m := range ms {
    if m.Running() {
        fmt.Println(m.Backend, m.Name, boxer.URLs(m)["3000"])
    }
}

Stop

func Stop(name string) error

Stops one machine by name without deleting it. boxer status reports a stopped machine as exit 3. Stopping a stopped machine is not an error. Same as boxer stop NAME.

Delete

func Delete(name string) error

Removes one machine by name, and what boxer kept about it: its run record, last-used stamp, lock and URLs, as boxer rm NAME does. Its volumes are kept.

LastUsed

func LastUsed(name string) time.Time

When the scope last ran a command, or the zero time when unknown.

List, Stop, Delete and LastUsed take a machine name instead of a directory because the worktree may be gone. List, Stop and Delete act on the backend the CLI would use from the process's working directory. That is BOXER_BACKEND if set, else the backend boxer.toml names, else smolvm.

RunOpts

type RunOpts = box.RunOpts

type RunOpts struct {
    Stdin   io.Reader
    Stdout  io.Writer
    Stderr  io.Writer
    TTY     bool
    Timeout time.Duration
    Task    string
}

The fields set the streams, whether to request a terminal, a timeout (zero for none), and the [tasks] name to record in the run record. Pass the same writer as Stdout and Stderr to get one interleaved stream.

Machine

type Machine = vm.Machine

type Machine struct {
    Name      string
    State     string
    Image     string
    Labels    map[string]string
    CreatedAt int64
    PID       int
    CPUs      int
    MemoryMiB int
    Backend   string
}

func (m Machine) Running() bool

One sandbox on any backend. Name is the scope key. CreatedAt is Unix seconds. Backend is set only by ListAll. Labels carry boxer's boxer.* keys, which are stable:

LabelValue
boxer.rootthe worktree
boxer.isolationthe isolation it was created with
boxer.port.<guest>the host port a guest port is forwarded to
boxer.harness, boxer.session, boxer.agentthe identity it was created for, when set

Scope

type Scope = scope.Scope

type Scope struct {
    Key       string
    Isolation string
    Root      string
    Degraded  bool
    Reason    string
}

func (s Scope) Slug() string
func (s Scope) Names() string

Key is sb- plus twelve hex characters and is the machine name. Isolation is the isolation used after degradation, and Reason says why when Degraded is set. Root is the mounted worktree. Slug is the two-word name (swift-crab). Names is swift-crab (sb-7e1852e4a3c3).

Error

type Error = box.Error

type Error struct {
    Reason string
    Cause  string
    Fix    string
    Scope  Scope
}

func (e *Error) Error() string

The error boxer returns when it refuses. Error() returns the same multi-line text the CLI prints.

var be *boxer.Error
if errors.As(err, &be) {
    log.Printf("%s (%s)\n  fix: %s", be.Reason, be.Cause, be.Fix)
}

Match on Cause, which is stable. Do not match on the message. The full list is on the JSON page. The same causes appear in --json output and in failed MCP tool calls.

On this page