- An environment is reusable desired configuration: provider, image, resources, network, lifecycle, labels, and environment variables.
- A sandbox is the concrete runtime instance Fabro creates for a run from the selected environment.
workflow.toml
/api/v1/environments REST API. Install seeds default as an ordinary persisted environment; users can replace or delete it. local is reserved, synthetic, and unpersisted: it appears only when the local sandbox provider is enabled, and it cannot be created, replaced, or deleted through the environments API. Workflow and project TOML can additionally define [environments.<slug>] catalog entries that merge with the server catalog through the normal settings precedence.
Defining Server Environments
Create server-managed environments through the REST API. Stored environments use inline Dockerfile content; local Dockerfile paths are rejected by the API because the server cannot safely resolve client-side paths.POST /api/v1/environments
cwd, an optional runtime
command working directory:
POST /api/v1/environments
cwd is owned by the server environment and is only honored by the local
provider. It is not a replacement for run.working_dir. Docker and Daytona
ignore cwd and report a preflight warning because those clone-based providers
own their workspace layout. Workflow, project, user, and direct-run
[environments.<slug>] catalogs cannot set cwd; configure it in the
server-managed environment through the environments API.
The same fields nest under [environments.<slug>] when defined in workflow or project TOML instead:
workflow.toml
workflow.toml
env and labels merge by key.
Environment value interpolation
Environmentenv values can mix literal text with {{ vars.NAME }} and {{ secrets.NAME }} tokens:
workflow.toml
{{ env.* }} reference: the process environment is not a configuration source.
Selecting an environment from the CLI
Use--environment with an environment slug:
--preserve-sandbox still controls the concrete runtime instance lifecycle for a run. Runtime commands such as fabro sandbox ssh keep the word “sandbox” because they operate on an already-created runtime instance.
Seeded Environments
Install seeds adefault environment into SQLite. It is a normal persisted environment, so deleting it removes the default run target until you recreate it. The standard Docker default is:
GET /api/v1/environments/default
local is not stored in SQLite. It is synthesized at runtime when the local sandbox provider is enabled.
Provider mappings
Local
local runs tools directly in the resolved working directory. It offers no filesystem or network isolation, so use it only for trusted workflows.
Create a server-managed local-provider environment through the environments API when you need a host cwd.
A version-backed run intent can submit
{ "kind": "folder", "path": "/absolute/server/path" } to run in an existing
server directory. Fabro accepts this target only with a Local environment,
resolves symlinks and .., requires an existing directory, and persists the
canonical UTF-8 path. The target path takes precedence over the environment’s
cwd. Because the run executes in place with the Local provider’s unrestricted
host access, use folder targets only in trusted single-tenant deployments.
Docker and Daytona always reject folder targets. This does not add Local Git
cloning or Local scratch workspaces for the none target. Local folder runs
execute in place without Fabro Git checkpoints: retries retain the canonical
folder target, but fork and rewind are unavailable for these runs.
When cwd is set, local runs execute commands from that absolute server-side
path. When it is unset, Fabro keeps same-host compatibility by using the
submitted source directory only if that path exists on the server. If neither is
available, the run fails before execution with a remediation to configure
cwd.
Fabro hard-errors if a local environment asks for blocked or CIDR-restricted networking because the provider cannot enforce it.
Docker
Docker runs tools inside a container created fromimage.docker. Docker is the built-in default provider.
workflow.toml
[run.clone] enabled = false to start a manifest-backed run with an empty workspace. Set [run.clone] depth = 0 to clone full history. A version-backed run intent can instead submit the explicit { "kind": "none" } target, which forces an empty provider workspace regardless of the workflow’s clone setting. Its Git target may select a branch, an optional bare tag, an optional exact commit SHA, or both tag and SHA. Both providers attach the selected revision to the target’s working branch; an exact SHA wins over a tag, and unavailable tags or commits fail without branch fallback. The none target is not supported by Local environments, while the Local-only folder target is rejected by Docker and Daytona. Docker and Daytona ignore cwd; use the provider-owned workspace layout and run.working_dir for repository-relative commands.
The image must provide /bin/bash; Fabro evaluates every sandbox command with it and has no sh fallback. Commands run in a non-login shell, so login profiles (/etc/profile.d/*.sh, ~/.bash_profile, and nvm/rbenv/sdkman initializers) are not sourced — put anything they set into the Dockerfile’s ENV instead. Fabro verifies Bash during initialization and again on resume, and fails with remediation rather than reporting the sandbox ready.
Daytona
Daytona runs tools in a cloud sandbox. Set eitherimage.docker to use an existing Docker image or image.dockerfile to build a custom image. Fabro computes a deterministic internal snapshot name from the selected image source, resource hints, a single-tenant scope, and the Daytona API key. If neither field is set, Fabro uses Daytona’s built-in daytona-medium snapshot.
workflow.toml