Configuration keys

User config keys and how the layers resolve

AgentBox reads layered defaults at the start of every command. The same key shape lives in three files plus a runtime CLI-flag layer, so a preference can be a one-off flag, sticky for one project, or shared with your whole team.

You rarely need to touch config — every key has a built-in default and most surfaces also expose a one-off CLI flag. Config is for making a preference stick.

TIP

Don't memorize keys. agentbox config list prints every key with its current value and where it came from, and agentbox config list --include-advanced adds the advanced ones.

Config layers

AgentBox merges four layers on top of the built-in defaults. Highest layer that sets a key wins:

CLI flag > workspace defaults: > per-project > global > built-in default
LayerWhere it livesScope
CLI flagthe command you typethis invocation only, never persists
workspacethe defaults: block in agentbox.yamlcommitted, shared with the team
per-project~/.agentbox/projects/<hash>/config.yamlper machine, per user, not committed
global~/.agentbox/config.yamlevery project on this machine
built-inBUILT_IN_DEFAULTS in the CLIthe fallback for any unset key

The per-project <hash> is the first 16 hex chars of the SHA-1 of the project's absolute path. The workspace layer is found by walking up from the current directory to the nearest agentbox.yaml.

config set/unset/edit only write the --global or --project files (project is the default). The committed defaults: block is hand-edited — see agentbox.yaml for its full schema. engine.kind is read by the engine detection itself, so it applies in every process that touches docker — the CLI, the hub, the relay.

Config resolution order: the highest layer that sets a key wins; unset keys fall through to the built-in default.

The config command

Seven subcommands: get, set, unset, list, path, edit, list-projects. The default write scope is --project. Pass at most one scope flag.

# Read the effective value of a key (and where it came from)
agentbox config get box.provider

# Set a key (default scope is --project)
agentbox config set box.withPlaywright true

# Set a key globally for all projects
agentbox config set box.provider hetzner --global

# Remove a key from a scope (default --project)
agentbox config unset box.image --project

# List effective config; advanced keys hidden unless you ask
agentbox config list
agentbox config list --include-advanced

# List one layer's raw values
agentbox config list --scope global
agentbox config list --scope workspace

# Print or open a scope's file
agentbox config path --workspace
agentbox config edit --global

# Show directories that have per-project config recorded
agentbox config list-projects

config get --all shows every layer's value with its source — the fastest way to see why a key resolved the way it did:

$ agentbox config get box.provider --all
box.provider:
  effective: hetzner   (global ~/.agentbox/config.yaml)
  cli:       <unset>
  workspace: <unset>
  project:   <unset>   ~/.agentbox/projects/3f2a…/config.yaml
  global:    hetzner   ~/.agentbox/config.yaml
  default:   docker

<unset> is the literal token the CLI prints for an absent value. get, set, list, path, and list-projects all accept --json. set coerces the value to the key's declared type (bool/int/enum/string) and errors on an invalid enum or non-int. There is no config set --workspace; to change the committed defaults:, edit agentbox.yaml (or run config edit --workspace, which just opens that file).

WHY

agentbox config get <key> validates the key — an unknown key errors. Use it to sanity-check spelling before set.

HEADS UP

box.snapshot was renamed to box.hostSnapshot. The old name now errors with a migration hint — update any config or agentbox.yaml still using it. AgentBox is pre-1.0, so there are no compatibility aliases.

box.* — the box keys

The largest group. A pattern runs through it: a generic key plus per-provider overrides of the form <key><Provider> (e.g. box.sizeHetzner). The provider-specific form wins over the generic one for that provider. This applies to box.size*, box.image*, and box.defaultCheckpoint*.

Provider

KeyTypeDefaultMeaning
box.providerenum docker/daytona/hetzner/vercel/e2b/digitalocean/remote-docker, or a docker:<alias> engine specdockerbackend new boxes are created on

This is what plain agentbox claude (or create, codex, opencode, pi) uses when you don't pass --provider. agentbox install offers to set it for you at the end of the wizard, so the provider you just logged in to and prepared becomes the one new boxes go to. Set it yourself at any time:

agentbox config set box.provider hetzner --global    # every project on this machine
agentbox config set box.provider hetzner             # this project only

A per-run --provider docker (or the agentbox docker claude prefix) still overrides it.

It also accepts a host-qualified engine specdocker:<alias> — naming a registered Remote Docker host rather than a provider:

agentbox config set box.provider docker:hub --global      # your control box's own engine
agentbox config set box.provider docker:buildbox          # a machine of yours

That form is shorthand for two keys, and it is stored as two:

box:
  provider: remote-docker
  remoteDockerHost: hub

So agentbox config get box.provider answers remote-docker, with the engine in box.remoteDockerHost. Both spellings work in a hand-written config file — provider: docker:hub is split on read — and each key layers on its own, so a project can point at a different engine without repeating the provider.

Setting up a control box does the first one for you when your default was still plain docker, since a control box turns local docker boxes off.

See local Docker, Remote Docker, Hetzner, Daytona, Vercel, and core concepts.

Resource limits (Docker)

KeyTypeDefaultMeaning
box.memoryint (MiB)0 (unlimited)hard memory ceiling; use --memory on create for byte/k/m/g strings
box.cpusint0 (unlimited)whole-core cap; use --cpus for fractional like 1.5
box.pidsLimitint0 (unlimited)max PID count
box.diskstring (advanced)emptybest-effort writable-layer size; no-op on overlay2 / macOS engines

VM size (cloud)

KeyTypeDefaultMeaning
box.sizestringemptygeneric cloud size, provider-interpreted: hetzner = server type (cx33), digitalocean = Droplet size slug (s-4vcpu-8gb), daytona = cpu-memory-disk GB (4-8-20), vercel = vCPU count (1/2/4/8), e2b = cpu-memory GB (4-8, baked at prepare time); docker ignores it
box.sizeDaytona / box.sizeHetzner / box.sizeDigitalocean / box.sizeVercel / box.sizeE2b / box.sizeRemoteDockerstring (advanced)emptyper-provider override of box.size. Daytona and E2B fix resources when the base image is baked, so a size that disagrees with the bake is ignored at create time — agentbox config set and -i submits now say so, and agentbox prepare --provider <name> --size <spec> --force re-bakes
box.sizeDockerstring (advanced)emptyreserved — docker uses box.memory / box.cpus / box.disk
box.daytonaClassstringcontainerDaytona sandbox class: container builds its base from the Dockerfile and runs in any region, so it works on every account. linux-vm gives a true pause (CPU + memory frozen, running processes survive) and a ~1 min base bake, but runs only in us-east-1 — a dedicated region Daytona enables per organization, so set it only if yours is authorized. Changing it needs agentbox prepare --provider daytona --force. Daytona-only
box.daytonaRegionstringemptyDaytona region (us, eu, us-east-1). Empty derives it from the class — linux-vmus-east-1 (the only region with VM runners), container ⇒ the account default. Daytona-only
box.daytonaTimeoutMsint1500000 (25 min)how long a box may sit idle before it's paused; 0 disables. The host enforces this (and holds the box open while the agent is working): Daytona's own timer is an inactivity window that the relay's polling keeps resetting, so it only fires as a backstop when the relay isn't running. See Daytona → idle boxes. Daytona-only
box.daytonaVmBaseImagestring (advanced)emptyregistry image the linux-vm base is baked from. Empty uses the box image AgentBox publishes. Set it when there's no published image for your build context — a locally modified Dockerfile.box — or to bake from a private mirror. Must be amd64 with an explicit tag. Daytona-only
box.hetznerLocationstringnbg1Hetzner datacenter new boxes are created in (nbg1, fsn1, hel1, ash); override per box with --location. Hetzner-only
box.digitaloceanRegionstringnyc3DigitalOcean region new boxes are created in (nyc3, sfo3, ams3, fra1, …); override per box with --location. DigitalOcean-only
box.remoteDockerHoststringemptydefault SSH destination whose Docker engine runs new boxes — an ~/.ssh/config alias or [user@]host[:port]. Also where box.provider: docker:<alias> stores its host. Override per box with agentbox docker:<host> … or --remote-host. See Remote Docker. remote-docker-only
box.digitaloceanProjectstringemptythe DigitalOcean Project new boxes are placed in — a project name or its UUID. Empty leaves them in the account's default project. Pick it at agentbox digitalocean login, or set it per repo in agentbox.yaml. DigitalOcean-only
box.inboundstringlockedinbound-access policy for the VPS per-box firewall. locked = SSH from your host egress IP only; open = SSH from anywhere (0.0.0.0/0, key-only — reach a box from a phone with the laptop off); a CIDR list (e.g. 203.0.113.5/32) = host egress plus those. Override per box with --inbound or after create with agentbox inbound <box>. Hetzner/DigitalOcean-only. See remote access

Box image

KeyTypeDefaultMeaning
box.imagestring (advanced)agentbox/box:devgeneric image ref; the default is a sentinel cloud backends read as "boot from the prepared base snapshot"
box.imageDocker / box.imageDaytona / box.imageHetzner / box.imageDigitalocean / box.imageVercel / box.imageRemoteDockerstring (advanced)emptyper-provider override; the cloud ones are written by agentbox prepare --provider <name>. box.imageVercel and box.imageE2b are written but never read — those two resolve from their prepared state, so setting them has no effect. Leave box.imageRemoteDocker empty — that provider derives a fingerprint-tagged ref and ensures it on the remote engine itself
box.imageRegistrystring (advanced, docker only)ghcr.io/madarco/agentbox/boxregistry to pull the prebuilt base from before building locally; empty = always build

HEADS UP

Setting the generic box.image to a provider-native snapshot id breaks creates on other providers. Prefer the per-provider box.image<Provider> keys (which is what prepare writes). If a stale box.image blocks creates, clear it with agentbox config unset box.image --project.

Default checkpoint per project

KeyTypeDefaultMeaning
box.defaultCheckpointstringemptycheckpoint new boxes start from when --snapshot isn't given; set via agentbox checkpoint set-default
box.defaultCheckpointDocker / …Daytona / …Hetzner / …Digitalocean / …Vercel / …E2b / …RemoteDockerstring (advanced)emptyper-provider overrides; set via checkpoint set-default --provider <name>

See checkpoints and pausing.

Create-time toggles

KeyTypeDefaultMeaning
box.hostSnapshotboolpromptuse a frozen APFS clone of the host workspace as overlay lower (renamed from box.snapshot)
box.withEnvboolfalsecopy host env/config files (.env*, secrets.toml, agentbox.yaml, …) into /workspace, bypassing gitignore
box.withPlaywrightboolfalseinstall @playwright/cli@latest in the box at create
box.vncbooltruerun the per-box Xvnc + noVNC stack
box.autoApproveSafeHostActionsbooltrueauto-approve the safe subset of host actions without a prompt: opening a PR, PR/review comments, re-running CI, pushing to the box's scratch or host-sanctioned branch, checkpoints, calls to a granted host tool, and file copy/download that stays inside the box project folder (non-secret). Uncontained/secret transfers, non-sanctioned-branch pushes, and PR merge/checkout still prompt. Set false to prompt for every host action. Each bypass is logged as a relay event. See sync & git
box.autoApproveHostActionsboolfalseauto-approve all host-action confirms (the superset: git push, cp, gh PR writes incl. merge/checkout, checkpoint) for this box without a prompt; for unattended orchestration of trusted boxes. Each bypass is logged as a relay event. See orchestration
box.resyncOnStartbooltrueon starting a session, merge the host's current branch + overlay changes (box wins on conflict, warns the agent)
box.bundleDepthintadaptivecap git-bundle history shipped to cloud sandboxes; 0 = full history; ignored for docker
box.dockerCacheSharedboolfalseshare the in-box docker image cache across boxes; only one box can run at a time when set
box.credentialSyncbooltrueautomatically sync refreshed agent credentials from boxes to the host backup and out to all other running boxes (Claude's OAuth refresh rotates the refresh token, killing every other copy). --no-credential-sync at create disables the in-box watcher for that box. See run an agent

See teleport a project, environment, browser and screen, sync and git, and Docker in Docker.

Config-volume isolation

KeyTypeDefaultMeaning
box.isolateClaudeConfig / box.isolateCodexConfig / box.isolateOpencodeConfig / box.isolatePiConfigboolfalsegive the box its own agent config volume instead of the shared one

Vercel only

KeyTypeDefaultMeaning
box.vercelTimeoutMsint2700000 (45 min)max session length before auto-snapshot; persistent mode auto-resumes
box.vercelNetworkPolicystringempty (allow-all)egress lock: allow-all, deny-all, or a comma-separated domain allowlist (github.com,*.npmjs.org)
box.e2bTimeoutMsint2700000 (45 min)session window a --provider e2b box is created with and re-armed with on resume; the host keepalive holds it open while the agent works, and pauses the box once the agent has been idle that long. Boxes pause rather than die at the window — and at E2B's own cap (~1 h Hobby, 24 h Pro) — keeping filesystem and memory

See Vercel.

checkpoint.*

KeyTypeDefaultMeaning
checkpoint.maxLayersint (advanced)3max stacked checkpoint layers before a new checkpoint is materialized flattened instead of layered

See checkpoints and pausing.

Agent sessions — claude / codex / opencode / pi

KeyTypeDefaultMeaning
claude.sessionNamestringclaudetmux session name for the claude agent
codex.sessionNamestringcodextmux session name for the codex agent
opencode.sessionNamestringopencodetmux session name for the opencode agent
pi.sessionNamestringpitmux session name for the pi agent
claude.dangerouslySkipPermissionsbooltruelaunch claude with --dangerously-skip-permissions (auto-accept tool use)
codex.dangerouslySkipPermissionsbooltruelaunch codex with --dangerously-bypass-approvals-and-sandbox

These keys are generated per agent, so every agent AgentBox ships gets the same set — <agent>.sessionName always, and <agent>.dangerouslySkipPermissions only where that agent actually has such a launch flag (OpenCode and Pi have none — Pi ships with no permission prompts at all).

Agent settings

An agent can also declare settings of its own, and those become config keys in the same block. Claude declares two:

KeyTypeDefaultMeaning
claude.installenum native/npmnativehow Claude Code is installed into a box: native runs Anthropic's installer, npm installs @anthropic-ai/claude-code. A fallback for cloud egress IPs the native installer's CDN 403s. Bake-time — changing it re-derives the agent layer (the agentless base is unaffected). Override per-bake with prepare --agent-setting claude.install=npm
claude.tuienum default/fullscreen/autodefaultterminal renderer Claude Code uses inside a box. Claude's fullscreen renderer repaints differentially and leaves stale characters in the blank areas of the screen over a network transport — visible while scrolling, cleared only by resizing the terminal. Boxes pin the classic renderer; set fullscreen to opt back in, or auto to let Claude decide. Rides the agent's next launch

These are deliberately not generic keys. Which installer Claude Code uses and which of its two renderers it picks are facts about Claude, not about agents in general — so the names stay Claude's. What is generic is the mechanism: an agent declares its settings, AgentBox generates the keys, and the values reach that agent's own install recipe and launch. An agent installed with agentbox agent add gets real config keys the same way, with no change to AgentBox — run agentbox config list to see what an agent declares.

Renamed

These were box.claudeInstall and box.claudeTui. The old spellings are refused with a message naming the new one; move them into a claude: block in your config.

WHY

The permission-skip defaults are on precisely because each box is a throwaway sandbox the agent can't escape — that's the whole point of AgentBox. Turn them off per-box with --no-dangerously-skip-permissions if you want approval prompts. See core concepts and run an agent.

attach

KeyTypeDefaultMeaning
attach.openInenum split/window/tab/samesplitwhere agentbox claude|codex|opencode|pi opens the attached session under tmux, cmux, Herdr, or iTerm2
attach.cmuxStatusbooltruewhen attached inside cmux, reflect the box agent's activity on its cmux workspace (colour + description)
attach.herdrStatusbooltruewhen attached inside Herdr, report the box agent's activity to its Herdr pane (so it looks like a normal agent) and highlight AgentBox's own approval prompts

split uses a tmux split-window / cmux new-split / Herdr pane.split / iTerm2 vertical split (same workspace). tab opens a new tmux window / a new cmux surface (a tab in the current pane, same workspace) / a new Herdr tab / a new iTerm2 tab. window opens a new tmux window / a separate cmux workspace / a new Herdr workspace / a new iTerm2 window. Outside tmux/cmux/Herdr/iTerm2 every value behaves like same. Under Herdr the default is a new tab (rather than a split) — set attach.openIn (or pass --attach-in) explicitly to override. See access your box.

attach.cmuxStatus surfaces a box's agent state in the cmux sidebar. While you're attached inside a cmux surface, AgentBox reflects the agent's live activity on the box's cmux workspace via its colour and description — blue/"working" while the agent runs, amber/"needs input" when it asks a question or is waiting, and the tint clears when idle. The workspace's original colour and description are restored when you detach. When you open several boxes from one project as tabs in the same workspace (--attach-in tab), AgentBox also flags the individual tab whose agent needs input via a cmux notification (tab badge + reorder + a desktop notification), so you can tell which box is waiting; the flag clears when you focus that tab. (cmux only renders its status pills for workspaces running an agent it recognizes; a box runs the agent inside the container, so AgentBox drives the always-visible workspace colour/description and the per-tab highlight instead.) No effect outside cmux; set to false to disable.

attach.herdrStatus makes a box look like a normal agent inside Herdr. While you're attached inside a Herdr pane, AgentBox reports the box agent's live activity to that pane (working / blocked / idle), so Herdr applies its native agent treatment — including its own needs-input handling. The one thing Herdr can't see is AgentBox's own host-relay approval prompts (git push, PR, checkpoint, …), so those get an explicit Herdr notification. No effect outside Herdr; set to false to disable. See Herdr integration.

code / shell

KeyTypeDefaultMeaning
code.ideenum vscode/cursor/autoautowhich IDE agentbox code launches; auto prefers code, falls back to cursor
code.waitbooltrueblock on agentbox-ctl wait-ready before opening the IDE
code.timeoutMsint120000wait-ready timeout
code.autoTerminalsbooltruegenerate /workspace/.vscode/tasks.json so the IDE auto-opens log panels
shell.userstringvscodedefault in-container user for agentbox shell
shell.loginbooltruepass -l to bash (load login profile)
shell.tmuxbooltruerun inside a detachable tmux session (Ctrl+a d to detach)

See access your box.

ssh

KeyTypeDefaultMeaning
ssh.autoConfigbooltrueauto-maintain ~/.agentbox/ssh/config (Include'd from ~/.ssh/config) for SSH-capable cloud boxes

For providers that reach a box over plain SSH with a persistent per-box key (Hetzner, and DigitalOcean once wired), AgentBox writes one Host <box-name> entry per box into its own ~/.agentbox/ssh/config file and adds a single Include ~/.agentbox/ssh/config line to the top of your ~/.ssh/config — so ssh <box-name> (and VS Code Remote-SSH, Codex, Claude desktop) just works without touching the rest of your config. The file is regenerated from box state on create and on start/resume (a cloud box's public IP can change across stop/start), and a box's entry is dropped on destroy. Set ssh.autoConfig to false if you manage ~/.ssh/config yourself; the explicit agentbox shell <box> --ssh-config, agentbox code, and agentbox open commands still write the entry on demand. Docker boxes (no SSH) and Daytona (60-minute token auth, no persistent key) are never auto-added.

The same file also gets a Host agentbox-hub entry for a deployed control box, pointing at its VPS and the per-deploy key under ~/.agentbox/control-plane/ssh/<stamp>/ — so ssh agentbox-hub reaches the machine running your hub. A box you happen to name agentbox-hub wins the alias.

browser

KeyTypeDefaultMeaning
browser.defaultenum agent-browser/playwright/bothagent-browserdefault browser stack in the box; playwright or both implies box.withPlaywright

See browser and screen.

tools

Policy for the host-tool proxy. The list of granted tools is not config — it is written by agentbox tools add and by approved in-box requests, and lives in a host-only grant file. These two keys are the policy around it.

KeyTypeDefaultMeaning
tools.gh.enabledbooltruekeep the built-in gh grant active, so the in-box gh routes GitHub calls through the host's authenticated gh
tools.request.enabledbooltruelet a box ask for a new host CLI (agentbox-ctl tool request <bin>), which raises an approval prompt on the host
agentbox tools add terraform                     # grant a tool
agentbox config set tools.gh.enabled false       # revoke the built-in gh grant
agentbox config set --project tools.request.enabled false   # boxes may not ask

Whether a granted tool prompts on every call is controlled by box.autoApproveSafeHostActions (default true — granted tools run quietly, and every call is still audited).

agentbox doctor reports one row per granted tool in a tools: group, probing whether the host binary actually resolves.

queue & autopause

queue.* schedules background -i jobs; autopause.* pauses idle boxes.

KeyTypeDefaultMeaning
queue.enabledbooltruerun agentbox claude|codex|opencode|pi -i <prompt> jobs through the host-wide FIFO queue
queue.maxConcurrentint5max simultaneously-running boxes before -i jobs queue; override with --max-running <n>
queue.maxWorkingint0 (off)max agents actively working at once before -i jobs queue; override with --max-working <n>
queue.idleGraceSecondsint15debounce before an agent frees its working slot; only used when maxWorking > 0
queue.openInenum none/split/window/tabnonewhen a background -i job's box becomes ready, open an attached terminal onto it (a tmux/cmux/Herdr split, window, or tab); none opens nothing
autopause.enabledbooltruelet the relay periodically pause idle boxes when more than maxRunningBoxes run
autopause.maxRunningBoxesint5target ceiling of running boxes before idle ones get paused
autopause.idleMinutesint5minutes a box must be continuously idle before it's eligible for auto-pause
agentbox config set queue.maxConcurrent 3 --global
agentbox config set autopause.idleMinutes 10 --global
agentbox config set queue.openIn split --global

By default a background -i run just queues and prints its job line. Set queue.openIn to split, window, or tab and the host relay opens an attached terminal onto the box the moment its worker finishes creating it — no need to find the box and attach by hand. It only fires when the submitting shell is inside tmux, cmux, Herdr, or iTerm2. Under cmux, split splits the pane you submitted from (falling back to the parent workspace, then a new workspace), tab adds a tab in the parent workspace, and window opens a separate workspace; under Herdr, split splits the pane you submitted from, tab adds a tab in the parent workspace, and window opens a separate workspace; iTerm2 opens relative to the frontmost window. Unlike attach.openIn there is no same mode (the box is created asynchronously, so it is always a fresh terminal).

cmux: allow socket control

The box is opened by the relay's queue worker, a detached host process — not a cmux-initiated one. cmux's default socketControlMode: cmuxOnly only trusts processes cmux itself started, so it blocks the worker and nothing opens. To use queue.openIn under cmux, set socketControlMode to automation (or password) in ~/.config/cmux/cmux.json and run cmux reload-config. tmux and iTerm2 need no such change.

Auto-pause only ever targets a box whose live agent has settled to idle for idleMinutes. A box where any agent (Claude, Codex, or OpenCode) is working, compacting, or waiting on you is never auto-paused. If a box does get paused while you still need it, agentbox drive …, agentbox shell, and agentbox unpause all resume it on demand (drive auto-unpauses before it reaches the session).

See background and parallel and checkpoints and pausing.

cloud / engine / portless / relay / vnc / maintenance

The remaining infrastructure knobs — mostly advanced.

KeyTypeDefaultMeaning
cloud.useCurrentBranchboolfalseon daytona/hetzner, start boxes on the host's current branch instead of forking agentbox/<box-name>; overridden by --use-branch / --from-branch
cloud.viaHubbooltruewhen a control box is configured (relay.controlPlaneUrl), build cloud boxes on it by default (so they keep running with the laptop off) instead of on this machine; overridden per-command by --via-hub / --local. Docker and remote-docker always build locally. Cloud base bakes (agentbox prepare) follow the same routing, and this machine's hub UI mirrors the control box's provider state. See deployed hub
engine.kindenum orbstack/docker-desktop/other/autoautooverride docker-engine auto-detection (which otherwise reads docker info once per process — restart the hub/relay after switching engines)
portless.enabledboolpromptmap each box web app to https://<box-name>.localhost via the Portless proxy (Docker Desktop only)
portless.stateDirstring (advanced)emptyhost Portless state dir to share into boxes
relay.portint (advanced)8787TCP port the host daemon binds. Governs the lean relay and the hub — the hub is the same relay plus the Web UI in one process, and the two are mutually exclusive on the port, so they always move together. Machine-wide (~/.agentbox/relay.pid and relay.log are single), so set it --global and run agentbox relay restart (plus agentbox hub restart if a hub is running). Docker boxes get it baked in at create time via host.docker.internal:<port>, and container env is immutable — so boxes created before the change keep dialling the OLD port and their host actions (git push, cp, checkpoint) fail with relay returned 502. Recreate those boxes; agentbox doctor names any that are stranded. Cloud boxes are unaffected (the host polls them). 8788 is refused — every box binds that internally for its own in-box relay.
relay.controlPlaneUrlstringemptyURL of a deployed control plane; cloud boxes point at it for git-token leasing, permission state, and the registry/events so they keep working with the laptop off. Set via agentbox hub set-url
hub.gitAuthenum gh/appghwhich git credential a deployed control box uses: gh (the hub holds a GitHub token taken from your own gh login and does the git work itself, so boxes never receive a credential and nothing needs installing on GitHub) or app (the hub holds a GitHub App key and leases a 1-hour, single-repo token to each box — tighter, but the repo owner must install the App). Deploy intent: it selects what agentbox hub setup / hub deploy provisions and which push mode a cloud box gets; it can't reconfigure a hub that's already running
git.pushModeenum auto/relay/lease/directautohow a cloud box's git push reaches GitHub (docker always uses relay): relay (the host relay pushes with your host credentials — they never enter the box), lease (the relay/plane leases a short-lived GitHub-App token and the box pushes directly, so it works with the laptop off), direct (the box holds a copy of your git credentials and pushes on its own — set via --with-credentials), or auto (lease when relay.controlPlaneUrl is set, else relay). direct is refused when a control box is configured — use leasing (the auto default) instead, which does the same job without copying the credential into the box and its snapshots
hub.modeenum auto/thin/localautowhether the local docker engine is offered on this machine. auto gates docker/remote-docker off once a control box is configured (relay.controlPlaneUrl) — a docker box built on your laptop can't run with the laptop off, so create --provider docker is refused, docker rows drop out of the provider pickers / doctor / prepare, and docker boxes show as inactive in ls. thin forces that even with no control box; local keeps docker on regardless (the escape hatch every "docker is hidden here" message names)
relay.custodyMaxBodyBytesint (advanced)33554432 (32 MiB)per-request body cap for the custody JSON API — the simple base64-in-JSON surface used for small values (credentials, .env, SSH keys). Large payloads use the streaming blob API instead (see below). Applies only to custody, so every other route keeps the 1 MiB cap. A control box enforces its own via AGENTBOX_CUSTODY_MAX_BODY_BYTES, so raise both
relay.custodyMaxBlobBytesint (advanced)104857600 (100 MiB)per-request cap for the streaming custody blob API, which carries payloads too large to buffer as base64 — chiefly a project's carry: material. Defaults to the same value as box.cpMaxBytes so an entry the carry prompt accepted can actually be stored on a control box; if the two disagree, AgentBox would offer to copy a file the transport then refuses. Enforced mid-upload. A control box enforces its own via AGENTBOX_CUSTODY_MAX_BLOB_BYTES, so raise both
relay.hostReachTimeoutMsint (advanced)60000 (60s)how long a control box waits for your machine to pick up a copy between a box and your files before treating it as offline — and how long a silence must last before a machine that already took one is presumed gone. Your machine long-polls the hub while its relay runs, so this is a missed-heartbeat window, not a per-copy timeout: once the copy reaches your machine it can wait on your approval indefinitely. Only meaningful with relay.controlPlaneUrl set; lower it to fall back to the hub's cache sooner on a flaky link, raise it if your machine sleeps often
vnc.containerPortint (advanced)6080container-side noVNC port
maintenance.pruneProjectConfigsbooltrueperiodically delete ~/.agentbox/projects/<hash>/ dirs whose source folder is gone
maintenance.pruneProjectConfigsEveryint50run the orphan sweep every N successful agentbox create
update.checkbooltruedaily background check for a newer published CLI (npm) and menu-bar app (release checksum), plus the "newer version available" nudge; at most one network probe per 24h — false disables both
update.channelenumautorelease channel self-update and install app follow: auto follows the installed build, nightly opts into pre-release builds, stable opts back out. Nightly installs the newest build of either channel, so a stable release supersedes the nightlies before it
update.registrystringhttps://registry.npmjs.orgnpm registry provider-plugin updates are resolved against, for agentbox self-update and agentbox plugin update. Point it at a mirror or a private registry when your plugins are not on the public one

See web apps and tunnels, local Docker, sync and git, and browser and screen.

Where the files live

$ agentbox config path --global
/Users/you/.agentbox/config.yaml
$ agentbox config path --project
/Users/you/.agentbox/projects/3f2a8c1d9e0b4a76/config.yaml
$ agentbox config list-projects
3f2a8c1d9e0b4a76  /Users/you/Projects/myapp
  • Global: ~/.agentbox/config.yaml
  • Per-project user: ~/.agentbox/projects/<sha1-16-of-abs-path>/config.yaml
  • Workspace (committed): the defaults: block in agentbox.yaml

For the defaults: block and the full agentbox.yaml schema, see agentbox.yaml; for secrets and env files, see environment. The served JSON schema lives at /schema/user-config.schema.json.

On this page