Getting Started
Installation
curl -fsSL https://bethropolis.github.io/podbox/install.sh | shOther install options
mise
# Install as a mise tool (Linux only)mise use -g github:bethropolis/podboxHomebrew
# Homebrew (Linux only)brew install bethropolis/homebrew-tap/podboxArch Linux, via AUR
# Arch Linux, via AUR (binary, fast)paru -S podbox-bin # ...or build from sourceparu -S podboxFrom crates.io (supports prebuilt images only)
# From crates.io (supports prebuilt images only)cargo install podbox-cliSource install (builds CLI and guest daemon)
# Source install (builds CLI & guest daemon)git clone https://github.com/bethropolis/podboxcd podbox && scripts/install.sh # installs to ~/.local/binThe crates.io build supports prebuilt images only. Custom image builds need a full source build.
Before you start
podbox needs three things:
- Podman 5.5 or newer. Use 5.6+ if you want SSH agent passthrough.
- A systemd user session. podbox hands the container lifecycle to systemd.
- Linux with a Wayland compositor. X11 apps still work through Xwayland.
Optionally, install xdg-dbus-proxy to get filtered D-Bus access instead of an open session bus.
If any of that is missing, podbox doctor will tell you.
Two Ways to Create a Container
podbox supports two workflows depending on how much control you need:
| Method | Use case | How it works |
|---|---|---|
| Prebuilt | Trying things out, gaming | Pull a ready-made image. Everything is baked in — just create and enter. |
| Custom | Your own packages and setup | Start from a distro image and declare the rest in TOML. podbox generates the build. |
Prebuilt (Quick Start)
Prebuilt profiles come with Wayland, audio, GPU, and common packages ready to go. They're the fastest way to get a working container.
Available profiles
| Profile | Base | Use case |
|---|---|---|
cachy | CachyOS (Arch-based) | Gaming, general purpose |
fedora | Fedora | Development, general purpose |
dev | Fedora | Development tooling, focused toolset |
Run podbox profile list to see the full list.
Non-interactive
# Create a gaming-ready containerpodbox create cachy # Or a Fedora-based one with a custom namepodbox create fedora --name devInteractive
# Launch the wizard and pick a profilepodbox init -i # After the wizard finishes, create the containerpodbox create devVerify it works
1# List all podbox containers2podbox list3 4# Check status5podbox status cachy6 7# Run diagnostics8podbox doctorWhat happens
podbox initcreates a config file at~/.config/podbox/<name>.tomlpodbox createpulls the prebuilt image, writes Quadlet systemd files, and starts the container- The guest daemon (
podbox-guest) starts inside and connects to the host for notifications, clipboard, and URI forwarding - The container is running and ready —
podbox enter <name>drops you into a shell
Custom (Build from Base)
Build a container from a plain distro image with your own packages, shell, and configuration.
Non-interactive
1# Create a config from a base image2podbox init fedora:44 --name myenv3 4# Build the image, enable Quadlet, and start5podbox create myenv6 7# Jump in8podbox enter myenvOr in one step with create:
# podbox create works with any OCI image referencepodbox create myenvpodbox create ubuntu:26.04 --name devInteractive
1# Launch the interactive wizard2podbox init -i3 4# Select "Custom (from scratch)" at the top of the list5# Choose: base image, packages to install, extra RUN commands6# Complete the wizard (shell, XDG dirs, GPU, lifecycle)7 8# Build and start9podbox create myenvContainer naming
When podbox init <image> is called without --name, the container name is derived from the image tag:
| Image ref | Container name |
|---|---|
fedora:44 | fedora-44 |
fedora:latest | fedora |
ubuntu:26.04 | ubuntu-26-04 |
ghcr.io/user/img:v1 | img-v1 |
This avoids name conflicts when creating containers from different tags of the same base image. Use --name to override explicitly.
Custom config example
1# ~/.config/podbox/myenv.toml2[image]3base = "fedora:44"4name = "myenv"5 6[image.packages]7install = ["git", "neovim", "gcc", "ripgrep"]8 9[container]10name = "myenv"11home = "~/containers/myenv"12shell = "/bin/bash"13 14[integration]15wayland = true16audio = true17gpu = "auto"18 19[integration.xdg_dirs]20documents = true21downloads = true22projects = trueEmpty or default sections ([lifecycle], [dbus], [container.env], etc.) are omitted automatically — the generated TOML stays concise.
Inspect what was generated
1# View the resolved TOML config2podbox inspect myenv --toml3 4# View the generated Quadlet systemd units5podbox inspect myenv --quadlet6 7# View the computed environment8podbox inspect myenv --envCheck for drift
After installing packages manually inside the container, see what differs from your config:
podbox diff myenvUse --apply to update the config TOML's install list to match the running container:
podbox diff myenv --applyWhat happens
podbox initcreates a config file at~/.config/podbox/<name>.tomlpodbox buildauto-generates a Containerfile from the config, copies in the guest binary (podbox-guest), and runspodman buildpodbox enablewrites Quadlet files (<name>.container,<name>.socket,<name>-host.service) to~/.config/containers/systemd/podbox startstarts the container — the guest daemon connects to the host socketpodbox enter <name>opens an interactive shell
Daily Usage
Active context
Set a default container so bare commands "just work":
1# Set myenv as the active context2podbox use myenv3 4# All commands now target myenv5podbox status6podbox logs7podbox exec -- htopTo target a different container, pass the name explicitly:
podbox status fedorapodbox enter fedoraOpen a shell
podbox enter myenvpodbox shell myenvBoth work. shell is an alias for enter.
Run commands
1# Run interactively inside the container2podbox exec -- htop3podbox exec -- cargo build4 5# Run as root6podbox exec --root -- apt update7 8# Launch a GUI app (detached)9podbox run firefox10podbox run gedit ~/notes.txtExport to host
Make container apps and binaries available on the host:
1# Add Firefox to your host launcher2podbox export app firefox3 4# Make ripgrep available as a host command5podbox export bin rg6 7# Remove all exports for the current container8podbox export cleanExported .desktop files go to ~/.local/share/applications/ and binary shims to ~/.local/bin/.
Resource usage
1# Show real-time resource usage2podbox stats3 4# Single snapshot, no streaming5podbox stats --no-stream6 7# JSON output for scripting8podbox stats --output jsonSnapshots
Commit the current container state and roll back if needed:
1# Tag the current state (defaults to timestamp tag)2podbox snapshot create myenv3 4# Tag with a custom name5podbox snapshot create myenv --tag before-upgrade6 7# List snapshots8podbox snapshot list myenv9 10# Restore to a previous state (tag first, then name)11podbox restore before-upgrade myenvPath translation
Find the equivalent path between host and container:
# Host → containerpodbox translate-path --to-container ~/Projects/myapp # Container → hostpodbox translate-path --to-host /home/user/Projects/myappTroubleshoot
# Run diagnosticspodbox doctor # Auto-fix common issues (Wayland socket ownership, etc.)podbox doctor --fixLifecycle Management
Understanding the chain
podbox uses four stages:
podbox build # Build the container image from the TOML configpodbox enable # Write Quadlet systemd files (~/.config/containers/systemd/)podbox start # Start the containerpodbox enter # Open a shellpodbox create runs all of these in one command.
Preview without side effects
# See what would happen without executing anythingpodbox build --dry-runpodbox enable --dry-runQuadlet persistence
When Quadlet is enabled ([lifecycle] quadlet = true), systemd manages the
container:
- It starts automatically on login (
WantedBy=default.target) - It restarts on crash (
Restart=on-failure) - The socket is created before the container and persists across restarts
Start and stop
1# Start2podbox start myenv3 4# Stop (container stays, can be started again)5podbox stop myenv6 7# Disable and remove Quadlet files8podbox disable myenv9 10# Force-disable without loading the config11podbox disable myenv --forceRemove
1# Remove the container only (config stays)2podbox remove myenv3 4# Remove container and home directory5podbox remove myenv --all6 7# Force-remove without confirmation8podbox remove myenv --all --force9 10# Also delete the TOML config file11podbox remove myenv --remove-config12 13# Clean up orphaned/failed containers14podbox remove --staleUpdate and rebuild
1# Rebuild the image (picks up config changes automatically)2podbox build3 4# Force a full rebuild from scratch5podbox build --rebuild6 7# Pull latest image and restart (prebuilt containers)8podbox update myenv9 10# Pull without restarting11podbox update myenv --no-restartEdit config interactively
# Open the config in your editorpodbox edit myenv # After saving, rebuild if the image config changedpodbox edit myenv --rebuildCommands at a Glance
Profiles
| Command | Description |
|---|---|
podbox profile list | List all available profiles (bundled + custom) |
podbox profile show <name> | Show the TOML configuration of a profile |
Creating and building
| Command | Description |
|---|---|
podbox init | Scaffold a config from the default base image (fedora:44) |
podbox profile list | List available profiles (bundled + custom) |
podbox init <image> | Scaffold a custom config from a base image |
podbox init -i | Interactive wizard (custom or profile) |
podbox init --profile <name> | Scaffold from a prebuilt profile |
podbox create <name> | Init → build → enable → start in one step |
podbox create <image> --name <n> | Pull + create config + enable + start |
podbox build [<name>] | Build or rebuild the container image |
podbox pull <name> | Pull a prebuilt image without building |
Running and entering
| Command | Description |
|---|---|
podbox enter [<name>] | Enter a running container (auto-starts) |
podbox shell [<name>] | Open an interactive shell |
podbox exec -- <cmd> | Execute a command |
podbox run <app> | Launch a GUI app (detached) |
Managing state
| Command | Description |
|---|---|
podbox enable [<name>] | Install Quadlet systemd files |
podbox disable [<name>] [--force] | Remove Quadlet files |
podbox start [<name>] | Start the container |
podbox stop [<name>] | Stop the container |
podbox remove [<name>] [--all] | Remove the container (and home with --all) |
podbox remove --stale | Clean up orphaned/failed containers |
podbox snapshot create [<name>] [--tag <t>] | Commit container state as an OCI image |
podbox snapshot list [<name>] | List snapshots for a container |
podbox restore <tag> [<name>] | Roll back to a previous snapshot |
podbox rollback [<name>] | Restore the image captured before the last update or rebuild |
podbox clone <src> <dst> | Copy a config for a variant |
podbox update [<name>] | Pull latest image and restart |
Exporting
| Command | Description |
|---|---|
podbox export app <name> | Export a .desktop file to the host launcher |
podbox export bin <name> | Create a binary shim in ~/.local/bin |
podbox export clean | Remove all exported shims and .desktop files |
Diagnostics and utilities
| Command | Description |
|---|---|
podbox status [<name>] | Show container state |
podbox logs [<name>] [-f] [--since <time>] | Show container logs |
podbox stats [<name>] | Show resource usage |
podbox diff [<name>] | Compare installed packages against config |
podbox doctor [--fix] | Diagnose and fix common issues |
podbox use [<name>] [--clear] | Set or show the active context |
podbox find-definition [<name>] | Print path to the matching config TOML |
podbox list | List all podbox-managed containers |
podbox inspect [<name>] | Show resolved config, Quadlet, or environment |
podbox edit [<name>] | Open the config in your editor |
podbox translate-path --to-container <path> | Translate a host path to container path |
podbox translate-path --to-host <path> | Translate a container path to host path |
podbox completions <shell> | Generate shell completions |
podbox dotfiles sync [<name>] | Update dotfiles and rerun their install command |
podbox dotfiles status [<name>] | Show dotfiles provisioning state |
podbox provision sync [<name>] | Run pending or stale provisioning steps |
podbox provision status [<name>] | Show the state of each provisioning step |
All commands support --dry-run to preview without side effects.
Next Steps
- Configuration Reference — all TOML keys, defaults, and examples
- Home Setup — dotfiles and one-shot provisioning steps
- Architecture Overview — how podbox works end-to-end
- Desktop Integration — exporting apps and binaries
- Troubleshooting Guide — common issues and fixes