Configuration
Four TOML files, later ones winning. See How it works for how they merge. The comments in the shipped defaults.toml and in the files the wizard writes are the long-form documentation of every key; this page is the map.
Files and directories#
| Path | What |
|---|---|
<install>/defaults.toml | the shipped defaults. Never edit; an upgrade replaces it |
~/.config/msb/config.toml | your overrides |
~/.config/msb/CLAUDE.local.md | your additions to every sandbox's CLAUDE.md |
~/.config/msb/sandboxes/<name>.toml | one registry entry per sandbox |
~/.config/msb/secrets/global.env | the Claude token, and an optional GH_TOKEN for version checks (0600) |
~/.config/msb/secrets/<name>.env | that sandbox's tokens (0600) |
<project>/.msb/sandbox.toml | the project's portable policy |
<project>/.msb/dev.yaml | the file passed to msb --conf: image, cpus, memory |
~/.local/state/msb/claude/<name>/ | that sandbox's ~/.claude |
~/.local/state/msb/profile/ | the assembled CLAUDE.md, mounted read-only |
~/.local/state/msb/agent/ | the SSH-agent filters' sockets and logs |
~/.local/state/msb/versions.json | the cached version checks |
MSB_CONFIG_DIR and MSB_STATE_DIR move the two roots.
config.toml#
Keep it short: a value copied here from defaults.toml stops following the shipped one. Tables merge with the shipped ones key by key; anything else, including a whole egress group, replaces the shipped value.
[defaults]#
| Key | Default | Meaning |
|---|---|---|
workspaces | "~/workspaces" | where a bare name given to msbctl add resolves. "" resolves against the current directory |
image | a pinned devcontainers Ubuntu digest | the image a new sandbox starts from |
cpus | 4 | |
memory | "8G" | a ceiling, not a reservation |
root_disk | "16G" | the writable root disk |
rule_groups | ["github", "claude"] | groups a new sandbox gets on top of base |
egress_mode | "enforce" | "observe" stops blocking (per sandbox is better: msbctl observe) |
private_dns_groups | [] | groups whose names resolve to private addresses; projects using one get allow_private_dns |
claude_auth | "secret" | "mount" shares the host's real ~/.claude instead. A fallback only |
identity | "" | the [identities] entry new sandboxes use |
[identities.<name>]#
[identities.public]
name = "yourhandle"
email = "12345+yourhandle@users.noreply.github.com"
signing_key = "ssh-ed25519 AAAA..." # optional: sign commits with this keyApplied inside the guest with git config --system, the lowest of git's three layers, so a repo's own identity still wins. See commit signing.
[rules]#
Egress groups, name = [rule, …]. Yours are added to the shipped ones; a shipped name redefined here replaces that group entirely. See Network & egress.
[env]#
Environment variables every sandbox gets. The shipped set turns off telemetry, error reporting and feedback prompts, and sets EDITOR = "nano". Projects merge their own over these. Fixed at create time.
[versions]#
Component pins for the bootstrap: node (major), gh, gitleaks, bun. A sandbox's own [versions] overrides these.
[version_check]#
| Key | Default | Meaning |
|---|---|---|
ttl_hours | 6 | how long upstream version checks are cached |
use_global_token | true | use GH_TOKEN from secrets/global.env for them, if present |
[secret_presets.<name>]#
What msbctl secret add offers. Shipped: npm, dockerhub, ghcr, pypi, crates.
[secret_presets.mytool]
env = "MYTOOL_TOKEN"
hosts = ["api.mytool.example"]
help = "https://mytool.example/settings/tokens"
usage = "mytool login --token \"$MYTOOL_TOKEN\"".msb/sandbox.toml#
The project's policy. It never contains a host path, a token or a sandbox name, so it's safe to commit.
| Key | Meaning |
|---|---|
rule_groups | egress groups, on top of base |
extra_rules | one-off rules, emitted last |
allow_private_dns | accept DNS answers that point at private addresses |
secret_binds | extra secrets, as ENV[:OPTIONS]@HOST[,HOST]; values live in secrets/<name>.env |
cpus, memory, root_disk | resources; omit to use the defaults |
containers_disk | a disk for /var/lib/containers, kept across rebuilds |
identity | an [identities] name this project commits as |
[env] | extra environment variables, merged over the machine-wide set |
[caches] | key = "size" per package manager: npm, bun, python, rust, go |
[secrets] github | bind this project's GH_TOKEN (default: true when it has a GitHub repo) |
[bootstrap]#
| Key | Meaning |
|---|---|
packages | extra apt packages |
claude | install Claude Code (default true) |
bun, gitleaks | install these (default false) |
containers_storage | "fuse-overlayfs" for podman without a container disk |
script | a project script run last, inside the guest, from /work |
The registry entry#
~/.config/msb/sandboxes/<name>.toml is machine-local and never committed. Any key it sets overrides the project's file.
| Key | Meaning |
|---|---|
name, project | the sandbox's name and the absolute path of its project folder |
repo | owner/name on GitHub, for the token binding and the picker |
identity | an [identities] name; applied at every start |
autostart | started when the picker opens |
ssh_keys | key fingerprints this sandbox may use. Absent means all, [] means none |
mounts | extra folders, as "HOST[:GUEST][:ro|rw]" |
egress_mode | "observe" while measuring; only ever set here, never in the project |
volumes | the disk-volume prefix, set by msbctl rename to keep the old disks |
image, cpus, memory, root_disk, conf, rule_groups, extra_rules | per-machine overrides |
[versions] | what msbctl update installed, so a rebuild reproduces it |