9.7 KiB
Configuration
Read when:
- adding a new config key, env override, or flag;
- debugging "why is Crabbox using value X here?";
- onboarding a repo and choosing what belongs in repo config vs user config;
- reviewing the YAML schema that
crabbox config showandcrabbox initemit.
Crabbox configuration is layered. The CLI loads values from five sources and merges them in a deterministic order. Each source is optional - the binary boots with sane defaults for everything.
Precedence
flags > env > repo-local crabbox.yaml/.crabbox.yaml > user config > defaults
Reading order is the lowest precedence first: defaults are applied, then overridden by user config, then repo config, then env vars, then flags. Every override only replaces fields that are explicitly set; unset fields fall through.
crabbox config show prints the merged configuration as the CLI sees it after
all five layers run. --json is stable enough to diff in scripts.
crabbox config path prints the user config file path so other tools can
edit it without parsing prose.
File Locations
macOS user: ~/Library/Application Support/crabbox/config.yaml
Linux user: ~/.config/crabbox/config.yaml
XDG override: $XDG_CONFIG_HOME/crabbox/config.yaml
repo: ./crabbox.yaml or ./.crabbox.yaml at repo root
explicit: $CRABBOX_CONFIG (any path)
If CRABBOX_CONFIG is set, it overrides the repo-local search and replaces
the effective repo config. User config is never replaced by the env override.
State that does not belong in either YAML file:
- live lease records (those are coordinator-owned);
- per-lease SSH private keys (those live under the user config dir but not in
config.yaml); - provider secrets (those live in the broker environment, your shell env, or a credential manager).
YAML Schema
The full schema below merges what crabbox init emits and what advanced
operators set in user config. Most repos only need a small subset.
Top-level
broker:
url: https://crabbox.openclaw.ai
provider: aws
token: <signed-github-token-or-shared-token>
access:
clientId: <cloudflare-access-service-token-id>
clientSecret: <cloudflare-access-service-token-secret>
provider: aws # default provider when --provider is not set
target: linux # default target OS
windows:
mode: normal # normal or wsl2 when target=windows
profile: project-check
class: beast # standard | fast | large | beast
type: c7a.48xlarge # explicit provider type, overrides class fallback
network: auto # auto | tailscale | public
lease:
idleTimeout: 30m
ttl: 90m
Capacity
capacity:
market: spot # spot | on-demand
strategy: most-available
fallback: on-demand-after-120s
hints: true
regions:
- eu-west-1
- us-east-1
availabilityZones:
- eu-west-1a
- eu-west-1b
largeClasses:
- large
- beast
AWS
aws:
region: eu-west-1
ami: ami-0123456789abcdef0
securityGroupId: sg-0abcdef0123456789
subnetId: subnet-0abcdef0123456789
instanceProfile: crabbox-runner
rootGB: 400
sshCidrs:
- 203.0.113.0/24
macHostId: h-0123456789abcdef0
Hetzner
Hetzner credentials and image come from broker-side config. Repos do not need
a hetzner: block unless they pin a class or location.
Static SSH
provider: ssh
target: macos
static:
host: mac-studio.local
user: steipete
port: "22"
workRoot: /Users/steipete/crabbox
Blacksmith Testbox
provider: blacksmith-testbox
blacksmith:
org: openclaw
workflow: .github/workflows/ci-check-testbox.yml
job: test
ref: main
idleTimeout: 90m
debug: false
Daytona
provider: daytona
daytona:
snapshot: openclaw-crabbox
apiKey: <daytona-api-key> # prefer DAYTONA_API_KEY env
Sync
sync:
delete: true
checksum: false
gitSeed: true
fingerprint: true
baseRef: main
timeout: 15m
warnFiles: 50000
warnBytes: 5368709120
failFiles: 150000
failBytes: 21474836480
allowLarge: false
exclude:
- node_modules
- .turbo
- dist
A .crabboxignore file at the repo root appends to sync.exclude. See
Sync for the matcher rules.
Env Forwarding
env:
allow:
- CI
- NODE_OPTIONS
- PROJECT_*
env.allow is name-based and supports trailing wildcards. Crabbox forwards
matching local env vars to the remote command. Secrets do not belong in
env.allow; pass them through provider-side mechanisms.
Actions
actions:
workflow: .github/workflows/crabbox.yml
job: test
ref: main
fields:
- crabbox_docker_cache=true
runnerLabels:
- crabbox
ephemeral: true
runnerVersion: latest
Cache
cache:
pnpm: true
npm: true
docker: true
git: true
maxGB: 80
purgeOnRelease: false
Results
results:
junit:
- junit.xml
- reports/junit.xml
SSH
ssh:
key: ~/.ssh/id_ed25519
user: crabbox
port: "2222"
fallbackPorts:
- "22"
Tailscale
tailscale:
enabled: false
tags:
- tag:crabbox
hostnameTemplate: crabbox-{slug}
authKeyEnv: CRABBOX_TAILSCALE_AUTH_KEY
exitNode: ""
exitNodeAllowLanAccess: false
Mediated Egress
Mediated egress is a browser/app QA feature where a lease exits to the internet through an operator machine over the Cloudflare Worker mediator. The first implementation is opt-in and profile-based.
egress:
enabled: false
listen: 127.0.0.1:3128
browserProxy: true
profiles:
discord:
allow:
- discord.com
- "*.discord.com"
- discordcdn.com
- "*.discordcdn.com"
slack:
allow:
- slack.com
- "*.slack.com"
- slack-edge.com
- "*.slack-edge.com"
See Mediated egress for the design, security model, and command
surface. The current CLI ships built-in discord and slack profiles; the
YAML shape is the intended config surface for making those profiles
user-configurable.
Profiles
Profiles are named bundles of config that get applied as a layer on top of
user/repo config. They live under a profiles: map and are selected by
--profile or profile: in repo config.
profiles:
project-check:
class: beast
sync:
baseRef: main
env:
allow:
- PROJECT_*
smoke:
class: standard
lease:
ttl: 30m
Use profiles when one repo has multiple test lanes with different machine classes, sync rules, or env allowlists. A repo without profiles never needs the block.
Machine Classes
A machine class is a provider-agnostic name for "standard", "fast", "large", or "beast" capacity. Each provider maps the class to a list of concrete instance/server types and falls back through the list when the first candidate cannot be provisioned.
| Class | Intent |
|---|---|
standard |
typical CI lane |
fast |
~2x more cores than standard for parallel-friendly suites |
large |
memory-heavy or many-process workloads |
beast |
maximum capacity within the provider's burstable family |
Class-to-type mappings live in Providers. When you set
type:, that exact provider type wins and the class is ignored. The
--type and type: paths intentionally do not fall back; they fail loud
if the provider rejects the type.
Environment Variables
Every YAML key has a CRABBOX_* env override. The full list is in
CLI. Common ones:
CRABBOX_COORDINATOR
CRABBOX_COORDINATOR_TOKEN
CRABBOX_PROVIDER
CRABBOX_TARGET
CRABBOX_PROFILE
CRABBOX_DEFAULT_CLASS
CRABBOX_IDLE_TIMEOUT
CRABBOX_TTL
CRABBOX_NETWORK
CRABBOX_OWNER
CRABBOX_ORG
Provider credentials live outside the Crabbox env namespace because they are provider-native:
HCLOUD_TOKEN / HETZNER_TOKEN
AWS_PROFILE / AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN
DAYTONA_API_KEY / DAYTONA_JWT_TOKEN
BLACKSMITH_* (read by the Blacksmith CLI)
ISLO_API_KEY (read by the Islo SDK)
What Belongs Where
| Setting | User config | Repo config | Profile | Notes |
|---|---|---|---|---|
broker.url and broker.token |
yes | no | no | Per-machine identity. |
provider, class, type |
optional default | yes | yes | Per-repo defaults; profiles for lanes. |
sync.exclude, sync.fingerprint, sync.baseRef |
no | yes | yes | Lives with the repo. |
env.allow |
no | yes | yes | Repo decides what is safe to forward. |
| Per-user SSH key path | yes | no | no | Personal preference. |
aws.region, aws.ami |
optional | yes | yes | Repos can pin region. |
| Tailscale tags and template | yes | yes | yes | Both layers can set this. |
| Profiles | yes | yes | n/a | Either layer can define profiles. |
The rule of thumb: anything other repos should inherit when they clone goes in repo config; anything tied to one operator's machine goes in user config.
Validation
The CLI validates config eagerly:
parseNetworkModerejects--networkvalues outsideauto|tailscale|public;validateNetworkConfigrequirestailscale.tagswhentailscale.enabledis true and rejects Tailscale on Blacksmith and static providers;validateRequestedCapabilitiesrejects--desktop,--browser, or--codefor providers whoseSpec.Featuresdoes not list the matching feature flag;crabbox doctorruns a richer set of checks against config, network reachability, and SSH keys.
When validation fails, crabbox exits with code 2 and a message that names
the offending field.
Related docs: