Skip to main content

JailBee

CI License: GPL v3

JailBee runs isolated, per-branch development environments in Incus system containers. Spin up multiple full stacks in parallel on one host — each with its own services, Docker daemon, IDE, and browser — without port conflicts, Docker name clashes, or shared-database collisions.

The CLI is jailbee, or jb for short.

JailBee is project-agnostic: every repo supplies its own .jailbee/config.yaml. The golden image ships stack-neutral by default — language toolchains (JDK, Node, Python venv/pip, Docker) are bundled but opt-in, enabled per repo via golden.stacks / golden.enable_snippets. It was built at GISGRO, which is its origin, not its scope.

See it work

A terminal recording: jb ls shows one container, jb new feat/health-endpoint clones a second from the golden image and provisions it — dependencies, database, dev server, agent — and jb ls shows it running.

▶ Watch the whole flow

What the full clip shows, end to end. A branch gets a container of its own, cloned from the golden image with the app's dependencies synced, its database seeded and its dev server already listening on port 8080. A coding agent gets a window inside it and is asked for a /health endpoint with a test; the human detaches, checks the running service from outside, and comes back to find the work committed. jb git pull brings that commit onto the host as a merge — asking before it destroys anything — and jb destroy throws the container away as its own deliberate step.

Every command and every line of output is real. Two stretches of the clip are sped up and say so on screen; nothing else is edited.

Key features

  • Per-branch isolation — one full-stack container per git branch, running in parallel without port or Docker-name collisions.
  • Host↔container git bridge — the container acts as a git remote; move commits with jailbee git push/pull/checkout instead of round-tripping through GitHub.
  • Submodules that travel — sub-repos are initialised offline on jailbee new and their objects move with the superproject on every push/pull, so a repo with submodules needs no manual setup on either side.
  • Nested Dockersecurity.nesting=true out of the box on Ubuntu 26.04.
  • GUI passthrough — launch a JetBrains IDE (jailbee ide) and Chrome (jailbee chrome) from inside a container onto your Wayland session.
  • Host sockets, shared — Wayland, PulseAudio, D-Bus and the gpg-agent are attached to every container, so git commit -S and ssh work inside while the private key never leaves the host (a smartcard still asks for its touch). Mount any other host socket the same way and use it from inside.
  • Host services, forwarded in — declare host_ports: [{ name: adb, port: 5037 }] and every container of the repo reaches that host service on its own localhost, so plain adb devices works inside with no ADB_SERVER_SOCKET juggling. jailbee port adds or removes a forward on one container without touching the config, in either direction — to-host for the rarer case where you do want a container's service on the host.
  • Network modes — per-container egress allowlist with strict and loose policies (jailbee net), safe for unattended agent runs. Entries are hostnames and ports (api.example.com:443), not IP addresses: JailBee resolves them into the kernel ACL, keeps a cumulative pool as CDN addresses rotate, and pins the container's /etc/hosts to match. Any protocol, not just HTTP — ssh, git+ssh and a database client work under the same list. jailbee net egress add widens one container's copy of that list — or this machine's copy of the repo's — without editing the committed config, so a host only you need never lands in git; see Egress overrides.
  • First-class Claude Code — opt in with claude.enabled: true and every container gets Claude Code installed, sharing one login and one settings directory across the repo's containers while your host ~/.claude is never read. The Anthropic hosts are added to the strict-mode allowlist automatically, JailBee's own skills teach the in-container Claude to drive jailbee, and jailbee pr writes the PR title and body — to your repo's own standard, if you state one in claude.pr_prompt. Start it automatically in a tmux window and the container is ready for an unattended run the moment it boots — with permission prompts turned off (--dangerously-skip-permissions), because the boundary is the container rather than the agent's own judgement. You size that boundary once in the repo's config; see Running an agent without prompts for what it does and doesn't cover.
  • Generic agent supportagents: {codex: {enabled: true}} wires any terminal coding agent into the same mount/egress/install/autostart pipeline Claude Code uses, via a shipped preset or one you write yourself. Five presets beyond Claude (codex, gemini, aider, opencode, grok) ship as untested starting points — see Generic agent support.
  • One shared state layer per repo — package-manager caches, the JetBrains config, ~/.ssh and Claude's login live in a shared dir outside the containers, set up once per repo instead of once per branch. Most of it is one mount every container shares live — pnpm's store, JetBrains, ~/.ssh, Claude's login. Gradle, Maven and the Chrome profile instead give each container its own private slot seeded from the warmest one: a warm cache without the lock contention one shared ~/.gradle used to cause. Either way the state outlives jailbee destroy / jailbee new — while nothing a container does reaches your host's own dotfiles.
  • Fast, cheap containers — copy-on-write clones of one golden image; a live TUI dashboard (jailbee dashboard) or Qt GUI dashboard (jailbee gui) spans every repo, and acts on what it shows: attach a shell or tmux, open the IDE, create or update the PR, update a container from its base, read its diff — without leaving the view that told you it was needed.

Getting started

JailBee needs a Linux host running Incus. Install the CLI with uv or pipx — JailBee is an ordinary PyPI package and needs neither at runtime, but Ubuntu 24.04+ refuses a bare pip install into its system Python:

uv tool install jailbee      # or: pipx install jailbee

For the optional Qt GUI dashboard (jailbee gui), add the gui extra:

uv tool install 'jailbee[gui]'      # or: pipx install 'jailbee[gui]'

Host setup — Incus, firewall, UID mapping, kernel keyring limits — is a one-time job with a few moving parts. Follow Installation end-to-end first. Then, from the repo you want to manage:

jailbee config init          # write .jailbee/config.yaml
jailbee doctor               # sanity-check host + config
jailbee init                 # create Incus profiles, ACL, bridge
jailbee base build           # build the golden image (one-time, ~10–15 min)
jailbee new feat/my-branch   # spin up an isolated env for a branch

See Getting started for the full first-run walkthrough.

Post-install setup

Installing the package puts jailbee and jb on your PATH and nothing else. One command installs the rest:

jailbee setup

It asks about three steps, each idempotent — re-run it after upgrading:

  • shell completions for both jailbee and jb (bash, zsh or fish),
  • the jailbee-net-refresh user timer, which keeps strict-mode egress allowlists current and expires jailbee net loose --for TTLs,
  • JailBee's Claude Code skills in ~/.claude/skills, so Claude on your host knows how to drive jailbee.

jailbee doctor reports any step that is missing. Host prerequisites — Incus, the firewall, UID delegation — are separate; see Installation.

Shell completion

Restart the shell after jailbee setup, and TAB completes commands, options, and:

  • container names on every command that takes one (jailbee shell, jailbee destroy, jailbee git push, jailbee ide, …) — short names, from the containers that exist in the current repo
  • branch names on jailbee new and jailbee retarget, from the host repo's local branches
  • snapshot tags on jailbee snapshot restore and jailbee snapshot delete, from the container already named on the command line
  • fixed values for --format, --layer, --attach and --user

Completion looks for .jailbee/config.yaml in the current directory, the same default the commands themselves use; elsewhere it offers nothing. Unlike the commands, it does not honor --config/-c, so e.g. jailbee shell -c /other/repo/.jailbee/config.yaml <TAB> still completes against the current directory's containers, not the repo the flag points at.

Documentation

Setup — get JailBee running:

Doc What's inside
Installation One-time host setup: Incus, UID delegation, installing the CLI (plus conditional firewall / kernel-keyring steps)
Getting started Concepts, configure a repo, build the image, and a "typical day" walkthrough
Running on macOS Using JailBee from an Apple Silicon Mac via a Linux VM (Colima/Lima) with the repo shared from macOS (experimental)

Daily use — working with containers:

Doc What's inside
FAQ Short answers to the common questions, each linking to the page that covers it in full
Commands Full command + flag reference table
Git bridge and branch workflows Host↔container git bridge, stacked PRs, mount vs clone, PR review, gh inside containers
Setting up JailBee in your own project Tutorial for adapting JailBee to your own repo and stack
Troubleshooting Common failures by symptom, and how to remove JailBee

Reference — the details:

Doc What's inside
Configuration reference Every .jailbee/config.yaml and global.yaml key
Generic agent support Wiring a terminal coding agent (Claude Code or otherwise) into the container lifecycle; the shipped presets and their verification status
Security and limitations Isolation model, git-remote handling, known limits
Architecture How the pieces fit together
Who JailBee is for What JailBee is good at, what it costs, and how it differs from Dev Containers, BranchBox, nono and Docker Sandboxes

Meta — project internals:

Doc What's inside
Manual testing End-to-end smoke-test recipes (require a real Incus daemon)
Releasing Release process
Contributing Development setup and repo conventions

License

jailbee is free software, released under the GNU General Public License v3.0 or later (GPL-3.0-or-later). See LICENSE for the full text.

Copyright © 2026 GISGRO Oy.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jailbee-1.2.2.tar.gz (579.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jailbee-1.2.2-py3-none-any.whl (613.4 kB view details)

Uploaded Python 3

File details

Details for the file jailbee-1.2.2.tar.gz.

File metadata

  • Download URL: jailbee-1.2.2.tar.gz
  • Upload date:
  • Size: 579.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.12

File hashes

Hashes for jailbee-1.2.2.tar.gz
Algorithm Hash digest
SHA256 0942156ec117168429239287caed30bbc7eb54dfd2ccc46edc76389368c0c96b
MD5 2c677bd997df45d323ded7434013ae71
BLAKE2b-256 6cc3ff7ca35add2403def7be67c660b3498d985fb65a7d7ca7b6af33d150ea3f

See more details on using hashes here.

File details

Details for the file jailbee-1.2.2-py3-none-any.whl.

File metadata

  • Download URL: jailbee-1.2.2-py3-none-any.whl
  • Upload date:
  • Size: 613.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.12

File hashes

Hashes for jailbee-1.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0d712ed7ce109811d0a946a4a6a4febe2907a1863be1ec281fde25a5ccd0b4cd
MD5 2e740d36ab5ce9a0e9bd9c7e7a28e16c
BLAKE2b-256 c09b13b13ebd4803d2c33eb54738da915da3959510de2d425493258b66f9681e

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.2.2 This release

2 files

1.2.1

2 files

1.2.0

2 files

1.1.0

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page