Configuring the box
Save my LLM credentials so I don’t need to re-auth for each box?
tldr: say y when the first-run picker offers shared auth for your
agent – or enable the relevant x-shared-auth skill(s) in
byre config.
By default agents log in once per project, inside the box. The shared-auth
skills (claude-shared-auth, codex-shared-auth, gemini-shared-auth,
opencode-shared-auth) move that to once per machine. For claude, codex,
and opencode every project’s first run asks: “Use machine-wide credentials
to log in to <agent>?” – yes enables the skill for that project
(its byre.config), and only for it. Saying yes to “Save these as your
default?” remembers your answer like the template/agent favourites: the
next box’s question just defaults to it, one Enter to accept. (Enabling the
skill in byre config --global is the machine-wide route – then the
question stops.) The login lives in a shared volume that
reset/forget deliberately never touch. See the
security model for the implications of this.
(Grok’s shared auth works differently – its token rotation can’t be
file-shared, so a broker mediates instead, and until its field gate passes
the skill is hand-enabled rather than offered –
ADR 0036.)
Enable a skill in this box?
tldr: the Skills section of byre config.
Bundled skills toggle on the spot; installed and local ones appear once
they exist on the machine. Everything a skill grants shows up in
byre status the moment it’s enabled –
what a skill is.
Add an MCP server to my agent’s session?
tldr: byre mcp add <name> <url> – or byre mcp add <name> -- <command...> for a local server; --global for every project.
--bearer TOKEN_NAME wires static-token auth (the header carries
${TOKEN_NAME}, expanded from the box env at launch – names travel,
values don’t). byre mcp list shows the effective set with every entry
attributed to the layer or skill that declared it; byre mcp remove is
closure-smart, so removing a skill-declared server writes a !name
entry instead of failing. Declarations bake into the image and inject
into the agent session; a remote server’s host is attributed egress in
byre status. The full story:
MCP & Claude Skills.
Add a package to this box – and promote it to my template?
tldr: add it under Packages in byre config; when it belongs
everywhere, move it into your template (fork the bundled one first:
byre template fork byre/node my-node).
The first time you want a postgres client, it’s one entry under
Packages in that project’s byre config. When it belongs everywhere you write node, fork the
bundled template into an editable local one, add the package there, and
set template = "my-node" – every project on that template gets it on
its next develop. For literally-everywhere, byre config --global puts
it in your personal baseline.
Set my defaults so every new box starts right?
tldr: byre config --global – your personal baseline, the bottom
layer of every project’s cascade.
Anything a config can carry can live there: packages, mounts, skills, env, egress. The first-run picker’s favourites (template, agent, shared auth) are remembered separately, as preferences – your most-used answers become the pre-selected defaults.
Switch agents for one project?
tldr: the Agent section of byre config, then relaunch.
The agent key decides which enabled agent skill’s command launches in
the foreground. Each agent keeps its login in its own state volume, so
switching to codex for a week and back to claude costs no re-auth.
Expose a port to see the box’s dev server?
tldr: the Ports section of byre config.
Published ports bind 127.0.0.1 by default – your browser reaches the
box, your LAN doesn’t; opening a wider interface is an explicit,
louder choice. Every published port shows in byre status.
Pass env vars into the box?
tldr: [env] for plain config values – never secrets – and
[env_from_host] to pass host values at runtime.
[env] literals are baked into the image: docker history shows
them and they outlive byre reset, so they’re for configuration, not
credentials. [env_from_host] is the runtime channel and a legible
grant: KEY = "env:HOST_VAR" passes a host env var at launch,
"git:user.email" reads git config, "tz:" passes your timezone –
values resolve at launch and never land in a layer. Git identity,
TERM, and TZ already pass through by default.
Use my API key instead of an agent login?
tldr: pass it at runtime – [env_from_host] with
OPENAI_API_KEY = "env:OPENAI_API_KEY" – never [env], which bakes
it into the image.
The agents’ own login flows are still the better default: the
credential lands in the agent’s state volume, per project, and the
shared-auth skills make one login serve every box. But where an API key
is the workflow, env_from_host keeps it out of the image, resolves it
fresh at every launch, and shows as a named grant in byre status.
Use Podman instead of Docker?
tldr: nothing – engine = "auto" (the default) picks docker if
present, else podman.
Force it with engine = "podman" per project or globally. Rootful and
rootless both work; rootless Podman 4.3+ runs under --userns=keep-id
so files still land correctly owned. Everything else – volumes,
images, status – reads identically across engines.
Mount other folders from the host?
tldr: the Mounts section of byre config.
Each mount is a host path, an in-box path, and a read-only/read-write
choice (read-only is the default); every mount shows up in byre status under “Host mounts”.
Bring my dotfiles and shell setup into every box?
tldr: mount them read-only under Mounts in byre config --global
– the box’s target mirrors your home path, so they land where the
agent looks.
A home-relative host path (~/.config/starship.toml) suggests the
matching /home/dev/... target automatically. Symlinks into a dotfiles
repo work – byre reads through them. For dotfiles that should be baked
in rather than live-mounted, a template’s [files] copies them into
the image (one caveat: files baked under a state volume’s mountpoint,
like ~/.claude, are masked by the volume at runtime).
Give my agent standing instructions in every box?
tldr: a tiny local skill with a [context] block – every box that
enables it injects the text into the agent’s memory file.
byre skill init my-conventions, point its skill.toml at a
context.md ([context] file = "context.md"), and enable it in
byre config --global so every box gets it. byre concatenates enabled
skills’ contexts into the agent’s own memory path (Claude’s
CLAUDE.md, Codex’s AGENTS.md), additive with whatever the project
carries. It’s how byre’s own dev box enforces its diary and review
habits.
Stop re-downloading dependencies on every rebuild?
tldr: a [[volumes]] entry with role = "cache" on the dependency
directory.
Templates ship the obvious ones (node_modules for node); add your own
for anything regenerable that’s slow to fetch. Cache volumes survive
rebuilds and relaunches, and losing one only costs a re-download.
Volumes & state has the model.
Run project setup automatically?
tldr: build-time setup goes in dockerfile_post; per-launch setup is a
small skill’s hook script.
dockerfile_post lines run at image build and cache like any Dockerfile
step – the right home for installs and fetches that shouldn’t repeat
every session. For something that must run at every launch (or once per
fresh box), a skill’s [build] files can place a script into
/etc/byre/firstrun.d/ (first run) or /etc/byre/env.d/ (sourced at
every launch, just before the agent starts). There’s deliberately no
config-level launch hook – launch behavior is a skill’s job, so it’s
attributable.
Cap the box’s CPU or RAM?
tldr: run_args = ["--cpus=2", "--memory=4g"].
run_args is raw docker run passthrough, appended after byre’s own
flags so yours win. byre never parses inside it; byre status degrades
its posture claims honestly when it’s present. (Identity-changing flags
– --user, --userns – are the one documented footgun: they break
the baked-UID ownership model.)
Restrict network access?
tldr: enable the firewall skill in byre config, then pick what to
open under Egress.
By default, we don’t restrict network access. The firewall skill flips that to deny-by-default: your container starts but runs nothing while a privileged one-shot helper joins its network namespace, installs the allowlist rules, and verifies them. Only then does the agent launch behind the wall – and if any of that fails, the box dies closed rather than running open.
Under “Egress” you choose what to open. The ports your selected agent needs open automatically, and your other skills may suggest more (eg GitHub) – those you open by hand, then relaunch.
One honest limit worth knowing: hostname grants are pinned to the IPs they resolved to at launch, so on DNS that rotates (CDNs, some cloud resolvers) a granted host can start failing – closed, never open – until a relaunch re-resolves it. Details in the security model.
Just want to block telemetry, not the internet? The firewall-open skill
keeps the network open and drops only the hosts you block:
egress = ["!statsig.anthropic.com"]. The same !host entries subtract
from the full firewall’s allowlist too, skill-declared endpoints included.
Run other Docker containers from inside the byre environment?
tldr: enable the docker-host skill in byre config.
The skill installs the Docker CLI (plus compose and buildx) in the box and
mounts the host daemon’s socket. It’s worth being clear-eyed about what
you’re granting: anything that can run Docker on the host also has
effective root on the host, and byre status disclaims that hole for as
long as the skill is enabled.
docs/DOCKER-HOST.md
covers what the grant really means and when to prefer something narrower.
Nested Podman (a daemon inside the box, granting nothing on the host) is
possible future work; there’s no support for it today.
Get the coding agent to edit its own byre config?
tldr: byre develop --self-edit – the box gets its own config mounted,
and changes are shown on exit.
byre develop --self-edit will mount the box’s configuration directory on
/home/dev/.byre-self and will also ship contextual documentation to your
box telling your agent how to make edits. There are (of course!) some
security implications to this, so it’s probably best not to always run in
this mode. Changes to the configuration will be shown on exit.