A box has open OUTBOUND network BY DEFAULT
A box gets a network namespace of its own, but a recipe that says nothing aboutegress gets full outbound access through it — so an unconfined box can phone
home, and code you do not trust must not be run in one on the strength of the
filesystem boundary alone. What the namespace does give you is separation from
your host: the box cannot reach a service on your host’s loopback, and a port it
binds is its own.
Confine the outbound side in the recipe: egress: none (no network at all), or
an egress: mapping with allow/deny (a CONNECT gate for every protocol) and
an optional http_proxy content chain. See Egress.
Each mode has its own host dependencies. egress: none needs nothing. Proxy
egress needs bun and openssl on the host PATH and a forwarder binary —
embedded in the CLI, or supplied by a program embedding dabs as a module
(recipe schema). On Linux (the bwrap driver)
egress: open needs pasta — install the passt package — and dabs running
as an unprivileged user; a boot that can have neither refuses and says so rather
than handing the box your host’s network. pasta must be snapshot 2025_05_03 or newer, for the address flags dabs passes: Debian trixie+ and Fedora 41+ package a new enough one, Ubuntu’s and Alpine’s current packages refuse those flags, and there you build from passt.top at the version contrib/recipes/dabseption.Dockerfile pins.
Boxes accumulate
Everydabs recipe … --no-command is a new box, and nothing reaps it for you.
Agents are the worst offenders: a driver that boots a box per task — or aborts
mid-task before its own dabs rm — leaves live boxes (and their processes)
piling up behind it. Hundreds of leftover boxes will eventually destabilize
whatever they run on.
If you are wiring an agent to dabs, make cleanup structural, not polite:
- reap in a teardown path that runs even when the task fails
(
dabs rm <box> -y), never only at the happy end of a script; - sweep periodically:
dabs lsand reap what nothing points at,dabs rm --clean-worktreesfor reviewed worktrees,dabs rm --inactivefor empty markers; - one box per agent, and the spawner owns the reap.
copy:/scratchbox recipes have the same shape with workdir nodes: every
boot snapshots the cwd into a new node that deliberately survives the box.
There is no --clean-workdirs sweep; list and reap them by name.
Pristine again means a NEW box
Writes inside a box persist for that instance’s lifetime. Re-running a recipe does not reset an old box — boot a new one and reap the old.Boxes are copies, not mounts, of their image
The image froze the program at the lastdabs build. Edited your Dockerfile’s
inputs? A boot auto-rebuilds only when the Dockerfile or a bundled image’s
files change — a change only in COPY . context files is not detected.
Run dabs prune, then build.
The box only contains what the Dockerfile installed
Slim images lack tools you may assume (ps, clear, pagers). If a job needs
one, it belongs in the Dockerfile, not worked around. Two consequences seen in
practice:
git loginside a minimal box opens a pager and appears to hang a driven terminal — usegit --no-pager.- A box left up (
--no-command,--detach) has a PID 1 that never reaps children, so processes killed inside it — and a--detachcommand that exits on its own — linger as zombies until the box itself is reaped.
Appending to a recipe is literal
dabs recipe <name> <cmd…> and dabs recipe -- <cmd…> append your tokens
to the recipe’s command argv. Against command: [sh], -- echo hi runs
sh echo hi (sh tries to open a file named echo). The confirmation shows
the exact final command — read it before you say yes. And a default: naming
an agent turns a bare append into arguments to that agent; set no default
unless one recipe is the obvious choice.
--detach does not mean “boot and run nothing”
--no-command boots a box and runs nothing. --detach boots one and STARTS the
recipe’s command in the background, with its output going to the node’s own
tmp/detached.log rather than your terminal. They are different asks, and passing both is
an error.
--detach also needs a driver whose box carries a process of its own (docker,
apple). dabs ASKS the driver before it provisions anything, so a driver that
cannot hold one refuses with its own reason and points at the pair that does
work everywhere:
The
--detach screens are verified by walkthroughs/test_detach.py.Instance names don’t say which recipe made them
The instance is named after the recipe’s image. Recipes sharing an image share a name prefix (claude, fresh-claude both boot a claude-… box), so
dabs ls cannot tell you which recipe made a box. Name your images
distinctively if the distinction matters.
Ambiguity errors speak two vocabularies
For the same ambiguous prefix,rm lists node ids while exec lists
instance names — they refer to the same boxes. Cross-reference with
dabs ls, which shows both.
Places dabs won’t work
dabs reciperefuses to make a project, worktree, or scratch node from inside~/.dabs— marking dabs’s own node store as a project would re-render dabs’s tree inside itself. The exception is a dabs worktree’s checkout: a boot from in there parents the box on that worktree (and mounts its parent.git), so working inside one is a supported place to run from.- Keep build contexts under your home directory; contexts under system temp
dirs have failed
dabs buildon macOS with cache-key errors. - (Nested/bwrap setups) dabs’s state cannot sit on overlayfs — bwrap cannot
stack an overlay on one. In docker, put
$HOMEon a non-overlay volume.
Warning noise on staged images
A box booting from a pre-staged image (no builder present) printsimage shell: no build record — rebuilding / no builder here to refresh it — serving it as-is on every boot. It means “serving the image as-is” —
everything is fine.
Before 1.0, vocabulary moves
No backwards-compatibility guarantees before 1.0. Deprecations are docs-first (the old word keeps working while new work avoids it): fleet → drivers, consent → confirmation, ephemeral → held (with permanent$…_EPHEMERAL
aliases), gone/no place/boxes with no node marked unstable. Agents
migrating across versions should read the project’s GLOSSARY and CHANGELOG.