Skip to content

Files and directories

Registering a repository from a parent directory creates:

<parent>/<repository>.project/
├── <repository>/ # host-side clone
└── .sbxm/ # metadata, Dockerfile, lock, and cache
└── incoming/ # copies received from the sandbox by files pull

.sbxm/incoming/ is a private area that only sbxm writes. A copy received from the sandbox lands there first, never over a file of yours, and is removed once you have decided whether to adopt it.

What sbxm saves from the sandbox lives in the host-side clone under refs/sbx/<sandbox>/:

refs/sbx/<sandbox>/
├── heads/<branch> # the sandbox's branches
├── tags/<tag> # the sandbox's tags
├── worktrees/<worktree> # each worktree's HEAD
└── archive/<time>/... # earlier tips of rewritten or deleted refs

sbxm writes nothing outside this namespace in your clone, and it never removes archive/.

A project added with --local has no <repository>/ clone inside the project directory: the registered repository plays that role, and refs/sbx/<sandbox>/ is written there.

~/.sbxm/
├── registry.yaml # registered project IDs and locations
└── config.yaml # identity, language, and declared files when configured

The registry is the only place that knows where a project lives. Moving the project directory makes sbxm ls report missing; it does not adopt a matching directory by name.

Every sandbox mounts one directory from the host:

/tmp/docker-sandboxes/<sandbox-name>/

The path is derived from the project ID alone, so it carries neither the project directory nor your home directory into the sandbox. It is an empty mount point: the repository and the managed worktrees live inside the sandbox, not here.

The runtime records this path when the sandbox is created, and it refuses to start a sandbox whose recorded directory is no longer on the host. This host-side /tmp path is volatile: it can disappear after a reboot, OS cleanup, or other external/manual removal while the sandbox record remains. It is separate from the sandbox’s own /tmp, which is inside the writable layer and is lost when that layer is recreated.

That is a missing start-up condition rather than lost data. sbxm ls reports the affected stopped project as open-blocked, and sbxm status <project-id> reports the directory as the workspace item with value missing. The status or open diagnostic gives the recovery action; the list does not expose the host directory as a separate column.

A running sandbox can lose the same directory the same way, without being stopped first. The runtime does not refuse an existing session’s commands just because the host-side source of a live mount vanished, and a command that then fails reports the same exit status whether the sandbox holds a repository or the directory is simply gone. Because of that, sbxm destroy and sbxm rebuild confirm the directory is on the host before trusting anything a running sandbox reports about what is inside it, and refuse rather than guess when it is not.

When a sandbox is full, use this order:

  1. Delete unnecessary files inside the sandbox; the space returns immediately.
  2. Understand what a rebuild discards. If recreating the writable layer is necessary, use the normal protected sbxm rebuild flow and review its plan.
  3. Save or resolve every Layer A blocker before retrying, including unpublished commits, dirty or untracked work, in-progress Git operations, active sessions, and repository-level refs.

Inside a built sandbox, managed worktrees look like:

/home/agent/work/<repository>/<repository>.tree-1
/home/agent/work/<repository>/<repository>.tree-2

The exact count and attached/detached mode come from the project registration and later apply changes.

For a project added with --local, the sandbox’s origin is sbxm-host::<project-id>. Nothing in the sandbox can reach it; the host repository writes refs/remotes/origin/* and tags into the sandbox over SSH, and they disappear with the sandbox.