Skip to main content
podbox/docs/getting-started.md
On this page

Getting Started

Installation

bash
curl -fsSL https://bethropolis.github.io/podbox/install.sh | sh
Other install options

mise

bash
# Install as a mise tool (Linux only)
mise use -g github:bethropolis/podbox

Homebrew

bash
# Homebrew (Linux only)
brew install bethropolis/homebrew-tap/podbox

Arch Linux, via AUR

bash
# Arch Linux, via AUR (binary, fast)
paru -S podbox-bin
 
# ...or build from source
paru -S podbox

From crates.io (supports prebuilt images only)

bash
# From crates.io (supports prebuilt images only)
cargo install podbox-cli

Source install (builds CLI and guest daemon)

bash
# Source install (builds CLI & guest daemon)
git clone https://github.com/bethropolis/podbox
cd podbox && scripts/install.sh # installs to ~/.local/bin

The 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:

MethodUse caseHow it works
PrebuiltTrying things out, gamingPull a ready-made image. Everything is baked in — just create and enter.
CustomYour own packages and setupStart 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

ProfileBaseUse case
cachyCachyOS (Arch-based)Gaming, general purpose
fedoraFedoraDevelopment, general purpose
devFedoraDevelopment tooling, focused toolset

Run podbox profile list to see the full list.

Non-interactive

bash
# Create a gaming-ready container
podbox create cachy
 
# Or a Fedora-based one with a custom name
podbox create fedora --name dev

Interactive

bash
# Launch the wizard and pick a profile
podbox init -i
 
# After the wizard finishes, create the container
podbox create dev

Verify it works

bash
1# List all podbox containers
2podbox list
3 
4# Check status
5podbox status cachy
6 
7# Run diagnostics
8podbox doctor

What happens

  • podbox init creates a config file at ~/.config/podbox/<name>.toml
  • podbox create pulls 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

bash
1# Create a config from a base image
2podbox init fedora:44 --name myenv
3 
4# Build the image, enable Quadlet, and start
5podbox create myenv
6 
7# Jump in
8podbox enter myenv

Or in one step with create:

bash
# podbox create works with any OCI image reference
podbox create myenv
podbox create ubuntu:26.04 --name dev

Interactive

bash
1# Launch the interactive wizard
2podbox init -i
3 
4# Select "Custom (from scratch)" at the top of the list
5# Choose: base image, packages to install, extra RUN commands
6# Complete the wizard (shell, XDG dirs, GPU, lifecycle)
7 
8# Build and start
9podbox create myenv

Container naming

When podbox init <image> is called without --name, the container name is derived from the image tag:

Image refContainer name
fedora:44fedora-44
fedora:latestfedora
ubuntu:26.04ubuntu-26-04
ghcr.io/user/img:v1img-v1

This avoids name conflicts when creating containers from different tags of the same base image. Use --name to override explicitly.

Custom config example

toml
1# ~/.config/podbox/myenv.toml
2[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 = true
16audio = true
17gpu = "auto"
18 
19[integration.xdg_dirs]
20documents = true
21downloads = true
22projects = true
TIP

Empty or default sections ([lifecycle], [dbus], [container.env], etc.) are omitted automatically — the generated TOML stays concise.

Inspect what was generated

bash
1# View the resolved TOML config
2podbox inspect myenv --toml
3 
4# View the generated Quadlet systemd units
5podbox inspect myenv --quadlet
6 
7# View the computed environment
8podbox inspect myenv --env

Check for drift

After installing packages manually inside the container, see what differs from your config:

bash
podbox diff myenv

Use --apply to update the config TOML's install list to match the running container:

bash
podbox diff myenv --apply

What happens

  • podbox init creates a config file at ~/.config/podbox/<name>.toml
  • podbox build auto-generates a Containerfile from the config, copies in the guest binary (podbox-guest), and runs podman build
  • podbox enable writes Quadlet files (<name>.container, <name>.socket, <name>-host.service) to ~/.config/containers/systemd/
  • podbox start starts the container — the guest daemon connects to the host socket
  • podbox enter <name> opens an interactive shell

Daily Usage

Active context

Set a default container so bare commands "just work":

bash
1# Set myenv as the active context
2podbox use myenv
3 
4# All commands now target myenv
5podbox status
6podbox logs
7podbox exec -- htop

To target a different container, pass the name explicitly:

bash
podbox status fedora
podbox enter fedora

Open a shell

bash
podbox enter myenv
podbox shell myenv

Both work. shell is an alias for enter.

Run commands

bash
1# Run interactively inside the container
2podbox exec -- htop
3podbox exec -- cargo build
4 
5# Run as root
6podbox exec --root -- apt update
7 
8# Launch a GUI app (detached)
9podbox run firefox
10podbox run gedit ~/notes.txt

Export to host

Make container apps and binaries available on the host:

bash
1# Add Firefox to your host launcher
2podbox export app firefox
3 
4# Make ripgrep available as a host command
5podbox export bin rg
6 
7# Remove all exports for the current container
8podbox export clean
TIP

Exported .desktop files go to ~/.local/share/applications/ and binary shims to ~/.local/bin/.

Resource usage

bash
1# Show real-time resource usage
2podbox stats
3 
4# Single snapshot, no streaming
5podbox stats --no-stream
6 
7# JSON output for scripting
8podbox stats --output json

Snapshots

Commit the current container state and roll back if needed:

bash
1# Tag the current state (defaults to timestamp tag)
2podbox snapshot create myenv
3 
4# Tag with a custom name
5podbox snapshot create myenv --tag before-upgrade
6 
7# List snapshots
8podbox snapshot list myenv
9 
10# Restore to a previous state (tag first, then name)
11podbox restore before-upgrade myenv

Path translation

Find the equivalent path between host and container:

bash
# Host → container
podbox translate-path --to-container ~/Projects/myapp
 
# Container → host
podbox translate-path --to-host /home/user/Projects/myapp

Troubleshoot

bash
# Run diagnostics
podbox doctor
 
# Auto-fix common issues (Wayland socket ownership, etc.)
podbox doctor --fix

Lifecycle Management

Understanding the chain

podbox uses four stages:

bash
podbox build # Build the container image from the TOML config
podbox enable # Write Quadlet systemd files (~/.config/containers/systemd/)
podbox start # Start the container
podbox enter # Open a shell

podbox create runs all of these in one command.

Preview without side effects

bash
# See what would happen without executing anything
podbox build --dry-run
podbox enable --dry-run

Quadlet 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

bash
1# Start
2podbox start myenv
3 
4# Stop (container stays, can be started again)
5podbox stop myenv
6 
7# Disable and remove Quadlet files
8podbox disable myenv
9 
10# Force-disable without loading the config
11podbox disable myenv --force

Remove

bash
1# Remove the container only (config stays)
2podbox remove myenv
3 
4# Remove container and home directory
5podbox remove myenv --all
6 
7# Force-remove without confirmation
8podbox remove myenv --all --force
9 
10# Also delete the TOML config file
11podbox remove myenv --remove-config
12 
13# Clean up orphaned/failed containers
14podbox remove --stale

Update and rebuild

bash
1# Rebuild the image (picks up config changes automatically)
2podbox build
3 
4# Force a full rebuild from scratch
5podbox build --rebuild
6 
7# Pull latest image and restart (prebuilt containers)
8podbox update myenv
9 
10# Pull without restarting
11podbox update myenv --no-restart

Edit config interactively

bash
# Open the config in your editor
podbox edit myenv
 
# After saving, rebuild if the image config changed
podbox edit myenv --rebuild

Commands at a Glance

Profiles

CommandDescription
podbox profile listList all available profiles (bundled + custom)
podbox profile show <name>Show the TOML configuration of a profile

Creating and building

CommandDescription
podbox initScaffold a config from the default base image (fedora:44)
podbox profile listList available profiles (bundled + custom)
podbox init <image>Scaffold a custom config from a base image
podbox init -iInteractive 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

CommandDescription
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

CommandDescription
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 --staleClean 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

CommandDescription
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 cleanRemove all exported shims and .desktop files

Diagnostics and utilities

CommandDescription
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 listList 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

podbox — declarative Linux container environments
Licensed under MIT. Open Source by bethropolis.