msb run, msb create, or msb install; explicit CLI arguments are applied on top. The file may have any name when passed with --conf.
Sparse configuration
Every config file may provide only the fields it owns. Required fields are checked after root config, scoped config, and command-line inputs are merged, so a positional image can complete a network-only file:Scoped config files
Scoped flags accept the contents of one field or field group without its root wrapper. They are useful for focused policies that should fail on unrelated fields.
For example,
--net-conf expects this unwrapped document:
network: {...} to --net-conf is an error; use --conf for a root-shaped document. Every root and scoped config flag is repeatable, and different config flag kinds may be interleaved freely.
Precedence and merging
Configuration resolves from lower to higher precedence:- Built-in and global
config.jsondefaults - Every
--confand scoped config occurrence, from left to right on the command line - Explicit non-config CLI flags and positional arguments
init, network.dns, network.tls, and secret definitions. A list supplied by a higher-precedence config file replaces the lower list. Network policy is atomic: when a higher config source supplies any of policy, allow, or deny, those values replace the complete lower-layer policy while sibling network fields continue to merge. Repeating the same config flag works exactly like interleaving different config flags: each file overlays everything to its left.
--net-conf cannot be combined with --net, --no-net, --net-rule, or --net-default*. When network policy is loaded through a root --conf file instead, a policy CLI flag replaces it, while --net-rule remains additive and is evaluated before rules loaded from the file.
patch_files are resolved against that patch file.
Rust SDK patches
SandboxConfigPatch is the typed sparse representation for per-sandbox configuration. Its nested patch types are generated from the canonical sandbox configuration, compose with right-hand-side precedence, and are applied by SandboxBuilder::overlay before later fluent builder calls:
${ENV}, or carry registry credentials and snapshot-selection state; those remain file-adapter or explicit builder responsibilities. SandboxConfig remains the complete durable configuration.
Collection fields are atomic unless their canonical field declares a merge strategy. Environment variables merge by variable name, labels and scripts merge by map key, and secret entries merge by environment-variable name; higher values win when keys match. Their normal setters merge, while generated replace_* methods replace the complete collection. Calling clear_* removes that field from the patch, so applying the patch leaves the lower-layer value unchanged.
The generated model replaces the earlier handwritten patch hierarchy. Use SandboxResourcesPatch, SandboxRuntimeOptionsPatch, NetworkSpecPatch, SandboxPolicyPatch, and SecretsConfigPatch in place of the former resource, runtime, network, network-policy, and secret patch types. Filesystem, script, image, and init changes are now expressed directly through SandboxConfigPatch and its canonical nested patches. The old LocalConfig name remains as a deprecated alias of GlobalConfig.
Schema
Image and registry
The common image form is a string. Local paths beginning with., .., or / are resolved as bind roots or disk images; other strings are OCI references.
Resources and lifecycle
hard is omitted it equals soft.
Runtime
cmd is the default workload for msb run. msb create stores it without launching it.
Mounts
A string mount is a config-relative bind mount using the sameSOURCE:TARGET[:OPTIONS] option grammar as a bind passed to -v/--volume. Options include ro, rw, noexec, nosuid, nodev, follow-root-symlinks, stat-virt=strict|relaxed|off, host-perms=private|mirror, quota=<size>, and paired uid=<N>,gid=<N>:
target:
readonly, noexec, nosuid, and nodev. stat_virtualization, host_permissions, and paired uid/gid apply only to bind and directory-backed named mounts. Ownership changes only the guest fallback for files without a per-file stat override; it does not change host inode ownership. Duplicate guest targets are rejected.
Rootfs patches
Patch files run first in listed order, followed by inline patches:patches list using the same operations. File modes must be quoted four-digit octal strings.
Network
Use a preset string for the common cases:public, the default, permits public internet access while blocking private, loopback, link-local, and metadata destinations. none denies ingress and egress. open is unrestricted.
The object form adds rules and network services:
allow list implies deny-by-default egress. Top-level ports is shorthand for network.ports; when both are present, the lists are combined and duplicate host ports are rejected.
Secrets
Every secret requires a non-empty destination allowlist. Whenvalue is omitted, the host environment variable with the same name is used. An exact ${NAME} value records NAME as the host-side source instead of copying its plaintext into durable config.
inject accepts headers, basic_auth, and query_params; it defaults to headers. Declaring a secret enables TLS interception and DNS-rebind protection.
Scripts
Scripts are named shell snippets installed as executables in/.msb/scripts, which is on PATH. The sandbox configuration’s shell selects their shebang and defaults to /bin/sh.
Strict YAML and environment substitution
Sandbox configuration is data, not a templating language. The loader rejects unknown fields, duplicate keys, multiple YAML documents, anchors, aliases, merge keys, and custom tags. Bare YAML 1.1 booleans such asyes, no, on, and off are rejected. Quote modes, sizes, durations, ports, domains, image references, and other typed strings.
Only ${NAME} environment substitution is supported. Substituted variables must exist when the config is loaded; an exact secret value: "${NAME}" is the exception because it records a host-side source that is resolved when the sandbox starts. Shell-style operators such as ${NAME:-fallback}, includes, templates, loops, and expressions are not supported.
Project envelope fields such as sandboxes, volumes, and layers, plus per-project fields such as depends_on, are rejected in single-sandbox configuration.