Skip to content

Configuring Zones

zones.toml sits beside config.toml in the machine config directory (/etc/wardcell), not in the policy root — the policy root holds only .sbx fragments. It is a machine setting, like the rest of config.toml: root-owned, and the switch that turns zones on cannot be introduced or dropped by pointing --policy-root elsewhere.

/etc/wardcell/zones.toml
[zones.anonymous]
profile = "anonymous" # resolved exactly like `--profile anonymous`
default = true # used when no --zone is given
enter_from = ["*"] # reachable from any zone
[zones.user]
profile = "developer"
description = "Signed in to the company registry"
authenticated = true # turn on credential injection
enter_from = ["anonymous"]
requires_approval = true # every entry must be approved first

TOML rather than .sbx on purpose: zones are identity and topology, not filesystem and network rules, and they are not resolved by the merge algorithm at all. A separate concern gets a separate file.

profilerequired. The fragment to resolve for this zone’s reach.
defaultthis zone is used when run/draft gets no --zone. At most one zone may set it.
descriptionwhat the zone is for, shown by wardcell zone list. An agent inside a sandbox chooses a zone by it.
enter_fromwhich zones may enter this one with wardcell zone enter. ["*"] means any.
authenticatedturn on credential injection. Default false.
requires_approvalevery entry into this zone must be approved, after enter_from has allowed it. Default false. See Entry Approval.
approval_timeouthow long such an entry waits for its answer — 90s, 30m, 4h. Omit it and the entry waits as long as the approver takes.

enter_from defaults to [] — no zone may enter this one. Fail closed, like everything else.

authenticated and requires_approval say what a zone needs. Which program answers is named once on the machine, in /etc/wardcell/config.toml:

/etc/wardcell/config.toml
[plugin]
path = "/usr/local/libexec/wardcell/wardcell-plugin"

That split is what makes a policy root portable. It is the artifact an organisation distributes and versions; which secret store holds its tokens and where its approvals go belong to the fleet it is deployed to, and one root then serves machines wired to entirely different programs.

A run whose policy needs something the machine’s plugin cannot answer fails before it starts, naming the zone, the setting, and the method:

error: zone 'release' sets requires_approval = true, needing 'approvals.zone',
which the plugin '/usr/local/libexec/wardcell/wardcell-plugin' does not
implement.
It implements: credentials.resolve.

See Writing Plugins for the protocol, and two examples that implement all of it.

Note default and enter_from are independent: a zone can be the default entry point and also reachable by escalation, or neither.

Terminal window
wardcell run --zone user -- git push
wardcell policy draft --zone user -- git push
# explain and render take --zone as a convenience — they resolve the zone's
# profile for display and never execute anything, so identity is not involved
wardcell policy explain --zone user

Omit --zone and the default = true zone is used.

Not silently overridden — a usage error.

Without this, anyone could bypass enter_from and default by passing a wider --profile alongside --zone, which would make every guarantee here meaningless. A zone’s profile field is the only source of its reach.

/etc/wardcell is root-owned machine config an org controls. Shipping a zones.toml there makes every run on that machine go through a zone, with no flag or environment variable to opt back out — and because it lives outside the policy root, pointing --policy-root at a different fragment tree does not escape it.

An org that wants this ships a default = true zone tight enough for everyday work and gates anything wider behind enter_from:

[zones.work]
profile = "developer-readonly"
default = true
enter_from = [] # nothing escalates into the default zone
[zones.release]
profile = "release"
authenticated = true
enter_from = ["work"] # and only from there

The same trust boundary already makes base.sbx non-overridable: escaping it means pointing wardcell at a different policy root entirely. Close that too with policy_root.allow_override = false in /etc/wardcell/config.toml, and consider workspace_policy.mode = "off": in the default extend mode, a workspace’s .wardcell.sbx applies in every zone and can add to any of them.