byre

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: MIT

README

byre

--dangerously-skip-permissions, without risking the farm.

byre runs your coding agent in a local container. It gets the current folder, the tools you choose, and nothing else. Zero setup out of the box. Over time, you and your agent build up rich, reusable environments. Bring your toolkit and your favourite skills through the airlock.

$ brew install --cask pjlsergeant/tap/byre
$ cd ~/my-project && byre develop

  byre: ~/my-project -> /workspace (rw) · extra host mounts: none · network: open
  ╭──────────────────────────────────╮
  │ ✻ Claude Code                    │
  │   /workspace                     │
  ╰──────────────────────────────────╯

Good to know:

  • Single, self-contained, MIT-licensed binary
  • Ships with agent skills for Claude Code, Codex, Gemini, and Grok, or bring your own
  • Low magic: the Dockerfiles it generates are right there to read
  • Grant more access from the TUI in seconds, relaunch and /resume

⚠️ byre is a young project. I spend all day, every day inside it, for literally all of my work, but features are liable to change quickly.

Install

byre is a single Go binary. With Go 1.22+ on your machine:

go install github.com/pjlsergeant/byre/cmd/byre@latest

(that puts byre in $(go env GOPATH)/bin -- make sure it's on your PATH). Or, no Go toolchain needed, a checksum-verified download of the latest release binary:

curl -fsSL https://raw.githubusercontent.com/pjlsergeant/byre/main/install.sh | sh

Or on macOS, via Homebrew:

brew install --cask pjlsergeant/tap/byre

Or build from a checkout:

go build -o ~/bin/byre ./cmd/byre

You need Docker (or Podman) running on the host.

Quickstart

The first byre develop in a project asks a few quick questions (template, agent, and -- for agents that support it -- whether this box shares a machine-wide login) and remembers your answers: your favourites become the pre-selected defaults. Log the agent in once; the login persists, per project, across rebuilds. To skip the questions:

byre develop --template go --agent claude

Ask the box what it can touch, any time:

$ byre status
Project id:   my-project-pjl-069d95
Agent:        byre/claude
Template:     byre/go                 bundled 0.2.0
Engine:       docker
Project:      ~/my-project -> /workspace  (rw)
Network:      open
Ports:        none
Host mounts:  none
Skills:       byre/claude             bundled 0.2.0
State vols:   .claude
Cache vols:   node_modules
Container:    running (0d95f3a2c1b4)

Your toolkit, every folder

byre ships templates for go, node, and python, and agent skills for Claude, Codex, Gemini, and Grok; the first byre develop asks which you want, and that's the setup.

But you and your agent can build powerful templates and skills, and add them in seconds to any of your projects, or stick them in the defaults to always have them available: mounts, volumes, packages, agent contexts.

The first time you want a postgres client, it's a line in one project's config. When it belongs everywhere you write node, it moves into your node template. After a while, byre develop in a brand-new directory lands you somewhere familiar: your tools installed, your agent launching, nothing to set up.

What's boxed, what isn't

  • Boxed: your host filesystem, environment, and credentials. The agent sees only what you mount or pass.
  • Not boxed, by design: the network (open by default -- enable the default-deny firewall skill to close it) and the project itself (mounted read-write -- it's the agent's job to edit it).
  • Not a security product: a container is not a microVM. If you need the strongest isolation story, use one. byre is meant to protect you from over-eager and reckless agents, not from state-sponsored malware.
  • Not your nanny: the box is locked against the agent, not against you. Every protection is one config edit away from off, and skills can widen the box as far as you like -- you can hang yourself with skills, and that's intentional. byre's promise is that byre status always tells you where the rope is.

Configuration

byre config opens an interactive editor in your terminal (keyboard-driven, works over SSH): grants first (mounts, env), then build choices, in the same vocabulary byre status prints. Adding a package or mounting another repo read-only takes a couple of seconds. --self-edit (a per-session develop flag, announced at launch) lets the agent edit its own box config; edits apply on the next develop.

Underneath, it's a cascade of three TOML files that are always yours to edit by hand -- last layer wins (scalars override, lists union, and a later layer can remove an inherited entry: !name for named lists, remove = true for ports):

~/.byre/default.config              your personal baseline
~/.byre/templates/<name>/           template config (+ optional files)
~/.byre/projects/<id>/byre.config   this project's overrides (host-side)

The vocabulary covers packages, env, mounts, volumes, and skills; raw Dockerfile lines and docker run args cover the rest. Full reference: docs/ARCHITECTURE.md. One sharp edge to know: env values are baked into the image (docker history shows them, and they outlive byre reset), so don't put secrets there -- agent logins belong to the agents' own auth flows.

byre reads config only from its host-side store, never from inside the project -- the project mount is read-write, so the agent could edit a config that lived there. A repo can ship a byre.preset -- a saved answer to setup's questions -- but cloning gives you a file, not a prompt: nothing takes effect until you run byre preset apply, which walks you through any missing package installs, shows the composed box's grants, and writes the project's config on your confirm.

Commands

Command What it does
byre develop Generate, build on cache-miss, and run in the foreground. The main entry point.
byre shell A second shell in the running session -- for logins, tests, poking around.
byre worktree <name> New linked worktree on branch <name> + a session in it -- a parallel agent in one step.
byre status What can this thing touch? Resolved config, mounts, skills, volumes, session.
byre config [--global] Interactive config editor -- packages, mounts, agents, in seconds.
byre dockerfile Print the generated Dockerfile. Your exit, whenever you want it.
byre ejectfirewall Print the firewall sidecar as a standalone script -- the exit's last piece.
byre reset [--force] Wipe this project's volumes. Names what dies first.
byre forget [--force] Remove all of byre's host-side state for this directory. Never touches your project tree.
byre rebuild Rebuild with --no-cache to pull fresh upstream versions.
byre rehome <old-id> Re-point a moved/renamed directory's identity onto its new path.
byre skill list / inspect / fork Discover, inspect, and fork skill packages.
byre preset apply / inspect Review and apply a repo's byre.preset (or any path/URI) as this project's config.
byre skill install <uri> / uninstall Fetch, hash-verify, and snapshot a skill package — grants nothing until enabled in a box.
byre skill pack <name> Emit a local skill's distribution manifest (payload hashes + digest).
byre skill update Transitional: bundled packages update with byre itself.
byre template list / inspect / fork / install / pack Same verbs for template packages.
byre version Which byre is this? Release tag, module version, or build info.

Worktrees: parallel agents, the git way

byre worktree fix-flaky-tests

creates a linked git worktree on branch fix-flaky-tests (existing or new) and starts a session in it. The worktree inherits the repo's config, image, and volumes -- the agent is already logged in -- but runs in its own container against its own checkout, so sessions run side by side. Worktrees you made yourself with git worktree add inherit the same way: just byre develop in them. You pick once where new worktrees live (byre config --global). Commits land in the shared object store, byre status shows every worktree session in the project, and reset/forget name their blast radius before touching anything shared.

Volumes & state

Cache volumes (node_modules, …) are disposable. State volumes (.claude, …) hold the agent's login and history, per project, and survive rebuilds. Machine volumes let you share volumes between different byre boxes. byre never reads or copies host credentials; nothing crosses unless you enable it, and what you enable, byre status shows.

By default agents log in once per project, inside the box, and maintain their own context. See "How do I?" for enabling shared LLM credentials.

Why not…?

byre is a thin layer over the Docker or Podman you already run. The alternatives:

…raw Docker? Nothing -- and byre never takes it away. You'd just be hand-rolling what it generates: host-matched file ownership, per-project agent login that survives rebuilds, templates, a clean reset. If you want to stop using byre, byre dockerfile prints your exit.

…Docker Sandboxes™? Commercial product with a hosted control plane (you sign in) and paid tiers. Not open source. (But it gives you kernel-level microVM isolation, and we don't.)

…your agent's built-in sandbox? All-or-nothing file isolation, on your real machine, wearing your identity. Env vars and credentials come along by default, so a stray git push goes out as you. byre's box contains nothing that you didn't put in it.

…nothing -- just keep YOLOing on the host? The host is the incumbent: zero setup, and nothing bad has happened yet. But the agent works as you, in your real home dir -- byre exists because Claude went editing a sibling repository and did things with an ssh key it shouldn't have. The box costs one command, so the host's convenience argument is gone. (If you've never had the scare, you may not feel the need -- byre is for after your first one.)

…devcontainers? You hand-write the Dockerfile and JSON per project, and wire up agent credentials yourself. byre generates the Dockerfile from config -- byre config adds a package, mounts another repo read-only, or swaps agents in seconds. (But it's the mature industry spec, and we're young.)

…container-use? Explicitly experimental, and MCP-shaped: your agent manages a fleet of environments; you don't sit inside one. byre does parallel the git way -- one boxed session per worktree, sharing the repo's image, volumes, and agent login.

…a cloud sandbox (e2b, Daytona, your agent's web offering)? Account, usage billing, your code in their cloud -- and they're repo-shaped, built for shipping agent products or driving a GitHub repo. byre is for dropping into whatever folder you're standing in.

…a cheap VPS (a Hetzner box)? A box per project doesn't scale across many repos -- and half of what you'd point an agent at isn't a repo, just a folder. byre is a throwaway box per folder, on the machine you're already sitting at, with your toolkit already inside. (But a remote box is real hardware isolation -- if the agent must never share a kernel with your machine, rent one.)

How do I...?

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 byre config and enable the relevant x-shared-auth skill(s) by hand.

By default agents log in once per project, inside the box. The shared-auth skills (claude-shared-auth, codex-shared-auth, gemini-shared-auth) move that to once per machine. For claude and codex every project's first run asks: "Opt this box into shared credentials?" -- 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 by hand in ~/.byre/default.config is the machine-wide route -- then the question stops.) On an install that predates the offer, run byre skill update once so the companion skills carry the offer metadata. The login lives in a shared volume that reset/forget deliberately never touch. See docs/SECURITY.md for the implications of this. (Grok has no shared-auth: its token rotation can't be file-shared, so it logs in per project -- ADR 0023.)

Paste images and files into the box?

tldr: byre deliver <file> — or just byre deliver and paste.

Anything you deliver lands in the box's /inbox and the in-box path comes back on your clipboard, ready to Cmd-V into the agent prompt. With no arguments byre reads your clipboard — so screenshot, byre deliver, paste, done. Works from any directory (it finds your running box), over SSH, and with whole directories. See docs/DELIVER.md.

Get tab completion for byre commands?

tldr: eval "$(byre completion bash)" in your shell's startup file.

Completions cover every command and flag — bash, zsh, fish, and powershell. One line in your rc file regenerates the script at shell startup (~3ms), so it never goes stale across byre upgrades and needs no extra packages:

eval "$(byre completion bash)"        # ~/.bashrc
source <(byre completion zsh)         # ~/.zshrc, after compinit
byre completion fish | source         # ~/.config/fish/config.fish

byre completion --help has the powershell line and the details.

Stop using byre?

byre dockerfile prints the image, byre dockerrun prints the exact run command -- that's the whole exit. The firewall is the one thing that doesn't travel automatically (its rules are applied from outside the box, by byre); byre ejectfirewall prints that step as a standalone script. See docs/EJECTING.md.

Restrict network access?

tldr: byre config and enable the firewall skill. Under "Egress" choose what to open. We automatically open the ports your selected agent needs, and there may be more suggestions based on your selected skills (eg Github) but those you'll need to manually open and then relaunch.

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.

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 docs/SECURITY.md.

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.

Mount other folders from the host?

tldr: byre config -> Mounts

Run other Docker containers from inside the byre environment?

Today this is possible rather than ergonomic. You can mount the host's Docker daemon socket using byre config -> Mounts. It's worth remembering that anything that can run Docker on the host also has effective root on the host. I plan to make this even easier and also support nested Podman in the very near future.

Get the coding agent to edit its own byre config?

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.

Platform

Linux and macOS, over Docker or Podman (rootful; rootless Podman coming soon). byre bakes your UID/GID into the image so the agent runs unprivileged as you and files land correctly owned. Debian-derived base images only.

Design: docs/ARCHITECTURE.md.

Directories

Path Synopsis
cmd
byre command
Command byre runs an AI coding agent in a throwaway, project-scoped container.
Command byre runs an AI coding agent in a throwaway, project-scoped container.
internal
build
Package build assembles the docker build context for a project: the generated Dockerfile, the launcher script, and any skill/agent files COPYed by the generated build.
Package build assembles the docker build context for a project: the generated Dockerfile, the launcher script, and any skill/agent files COPYed by the generated build.
builtins
Package builtins ships byre's built-in skills and templates embedded in the binary.
Package builtins ships byre's built-in skills and templates embedded in the binary.
commands
Package commands implements the byre subcommands.
Package commands implements the byre subcommands.
config
Package config loads and resolves byre's configuration cascade:
Package config loads and resolves byre's configuration cascade:
configui
complete.go owns the flows that finish an editing session: save/assemble, dirty tracking behind the quit confirm, and the $EDITOR round-trip.
complete.go owns the flows that finish an editing session: save/assemble, dirty tracking behind the quit confirm, and the $EDITOR round-trip.
deliver
Package deliver implements `byre deliver`: getting files from the host into a running box's /inbox over an exec stream (no mount, no host-side state).
Package deliver implements `byre deliver`: getting files from the host into a running box's /inbox over an exec stream (no mount, no host-side state).
gen
Package gen renders the byre Dockerfile from a resolved configuration.
Package gen renders the byre Dockerfile from a resolved configuration.
lock
Package lock provides a per-project setup mutex via an advisory file lock.
Package lock provides a per-project setup mutex via an advisory file lock.
onboard
Package onboard implements byre's first-run picker: when `byre develop` runs in a project with no byre.config, it lets the user choose a template × agent (with their favourites pre-selected) and writes the choice to byre.config — and, optionally, saves it as their default (favourites) in default.config.
Package onboard implements byre's first-run picker: when `byre develop` runs in a project with no byre.config, it lets the user choose a template × agent (with their favourites pre-selected) and writes the choice to byre.config — and, optionally, saves it as their default (favourites) in default.config.
packages
Package packages is the skill/template package model: identity, manifests, the multi-provider catalog, and the store-ensure path (bundled mirror + legacy migration).
Package packages is the skill/template package model: identity, manifests, the multi-provider catalog, and the store-ensure path (bundled mirror + legacy migration).
project
Package project derives byre's per-project identity and on-disk locations.
Package project derives byre's per-project identity and on-disk locations.
runner
Package runner drives a container engine (Docker or Podman) via its CLI.
Package runner drives a container engine (Docker or Podman) via its CLI.
skills
Package skills loads skill packages from the multi-provider catalog and resolves their contributions to the layers byre controls: build (per-skill Dockerfile block), runtime (mounts/env/caps/run_args), state (named volumes), agent context, and — for agent skills — the launch command.
Package skills loads skill packages from the multi-provider catalog and resolves their contributions to the layers byre controls: build (per-skill Dockerfile block), runtime (mounts/env/caps/run_args), state (named volumes), agent context, and — for agent skills — the launch command.
version
Package version reports the byre executable's version string.
Package version reports the byre executable's version string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL