- Rust 98.5%
- Shell 1.5%
|
All checks were successful
release / release (push) Successful in 1m6s
Reviewed-on: #12 |
||
|---|---|---|
| .forgejo/workflows | ||
| bin | ||
| cli | ||
| fuse-mount | ||
| scripts | ||
| .gitignore | ||
| AGENTS.md | ||
| bubblebox.toml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
bubblebox
A userspace, no-sudo package manager for CLI tools — a nix-lite for tools, built on OCI images + composefs.
Each package is a container image whose rootfs is stored content-addressed
as a composefs descriptor in ~/.local/share/bubblebox/store. Running a tool
mounts that rootfs through a rootless FUSE daemon and drops you into a
bwrap sandbox — no root, no daemon, nothing installed system-wide. A
declarative profile.toml (the flake.nix analog) pins your desired set of
tools, dotfiles, and systemd user units; apply realizes it into a locked,
rollback-able generation and syncs ~/.local/bin wrappers.
Status: work in progress, single maintainer, Linux x86_64. Developed on Fedora atomic hosts; expected to run anywhere with the requirements below.
How it works
- Packages = OCI images → composefs descriptors, deduplicated in a
content-addressed store. Recipes live in a source repo: one directory per
package with a
Containerfile+ an optionalentrypoint.toml(which binary to exec, what to bind/env — co-located because the author knows what the tool needs). - Running = mount the image's rootfs via FUSE + sandbox it with bwrap.
Multi-package entrypoints overlay their rootfs read-only at runtime
(
compose = ["nvim", "rg", "fd"]) so tools share files without vendoring. - State is declarative:
~/.config/bubblebox/profile.tomllists what you want;bubblebox applyresolves, pulls/builds, locks digests intoprofile.lock, archives a generation (rollback target), and reconciles~/.local/binwrappers,$HOMEdotfiles, and systemd user units.
Requirements
| Need | Why | Package |
|---|---|---|
| bubblewrap | every sandbox | bubblewrap |
| FUSE 3 | mounts each rootfs | fuse3 |
| composefs tools | descriptor verify / store accounting | composefs |
| util-linux | mountpoint (liveness), unshare (composition) |
usually preinstalled |
| git | git-based package sources | usually preinstalled |
| podman | building packages + first-run FUSE-server build; not needed to run pulled packages | podman |
Unprivileged user namespaces must be allowed (they are by default nearly
everywhere). On Ubuntu ≥ 24.04 AppArmor restricts them;
bubblebox doctor detects this and prints the exact fix.
Install
From a release tarball (self-contained: both binaries + helpers):
tar xzf bubblebox-v*-linux-x86_64.tar.gz
cd bubblebox-v*-linux-x86_64/
./install.sh # -> ~/.local/bin, then runs `bubblebox doctor`
From source (no host toolchain needed — builds happen in containers):
git clone <this repo> && cd bubblebox
./scripts/build-portable.sh # podman rust:bookworm build -> dist/*.tar.gz
# then install from dist/ as above
Quickstart
Declare what you want (~/.config/bubblebox/profile.toml):
packages = ["nvim", "rg", "fd"]
[[source]]
name = "personal"
kind = "local" # or kind = "git", url = "git+https://..."
path = "~/Code/bubblebox-pkgs"
Realize it:
bubblebox apply # resolve + pull/build + lock + wrappers + dotfiles
bubblebox run nvim # sandboxed, auto-mounted
bubblebox shell --base rust-dev # or a project devshell: cd proj && bubblebox shell
rg --version # wrappers make applied roots normal commands
Everyday commands:
| Command | Does |
|---|---|
bubblebox apply [--refresh] |
realize profile.toml (--refresh: re-resolve floating versions) |
bubblebox list / info <pkg> |
what's applied / one package's state |
bubblebox generations list|switch|delete... |
history, rollback (switch <id-prefix>), pruning |
bubblebox gc [--apply] |
reclaim orphaned store bytes (dry-run default) |
bubblebox config cat|edit <pkg> |
view / override a tool's sandbox spec |
bubblebox install <pkg|url> |
imperative one-off pull + wrapper |
bubblebox import <oci-ref> |
turn any container image into a package (import alpine:3.20 --binary /bin/sh) |
bubblebox push <pkg> [--stage-dir D] |
publish to S3-compatible cache / local dir |
Project devshells
Check a bubblebox.toml into a repo — the nix develop analog:
base = "rust-dev" # reusable base shell entrypoint
init = "devshell.sh" # sourced on entry (project file)
compose = ["sqlx-cli"] # appended onto the base's tools
[sandbox.env]
DATABASE_URL = "sqlite:///work/db.sqlite"
cd ~/Code/my-project && bubblebox shell
Documentation
All documentation lives in the repo wiki — architecture, store/mount model, override layering, gotchas, locked decisions, feature designs (GC/generations, devshells), and status.
AGENTS.md— brief agent guide; points at the wiki.