Replace the shell-only user workflow with `banger` and `bangerd`: Cobra commands, XDG/SQLite-backed state, managed VM and image lifecycle, and a Bubble Tea TUI for browsing and operating VMs.\n\nKeep Firecracker orchestration behind the daemon so VM specs become persistent objects, and add repo entrypoints for building, installing, and documenting the new flow while still delegating rootfs customization to the existing shell tooling.\n\nHarden the control plane around real usage by reclaiming Firecracker API sockets for the user, restarting stale daemons after rebuilds, and returning the correct `vm.create` payload so the CLI and TUI creation flow work reliably.\n\nValidation: `go test ./...`, `make build`, and a host-side smoke test with `./banger vm create --name codex-smoke`. |
||
|---|---|---|
| cmd | ||
| internal | ||
| wtf/root | ||
| .gitignore | ||
| AGENTS.md | ||
| customize.sh | ||
| dns.sh | ||
| firecracker | ||
| firecracker-api.yaml | ||
| go.mod | ||
| go.sum | ||
| id_ed25519 | ||
| interactive.sh | ||
| kill.sh | ||
| list.sh | ||
| logs.sh | ||
| make-rootfs.sh | ||
| Makefile | ||
| namegen | ||
| nat.sh | ||
| packages.apt | ||
| packages.sh | ||
| ps.sh | ||
| README.md | ||
| restore.sh | ||
| rm.sh | ||
| run.sh | ||
| ssh.sh | ||
| stop.sh | ||
| verify.sh | ||
banger
Minimal Firecracker launcher.
Requirements
- Linux host with KVM (
/dev/kvmaccess) sudo,ip,curl,ssh,jqdmsetup,losetup,blockdev(device-mapper snapshot for rootfs)e2cp,e2rm(writes hostname and resolv.conf into rootfs snapshot)
Files
firecracker: Firecracker binarywtf/root/boot/vmlinux-6.8.0-94-generic: guest kernelwtf/root/boot/initrd.img-6.8.0-94-generic: guest initrdwtf/root/lib/modules/6.8.0-94-generic/: guest kernel modulesrootfs.ext4: guest root filesystem (base image if present)rootfs-docker.ext4: docker-ready guest rootfs (built viamake-rootfs.sh)packages.apt: apt packages baked into rebuilt guest imagesid_ed25519: SSH key forrootmapdns: local DNS mapping CLI used to publish<vm-name>.vm→ guest IP records
Run
./run.sh
Experimental Go Control Plane
There is now an XDG-based Go daemon + CLI prototype alongside the shell scripts. It keeps persistent VM/image state in SQLite under your XDG state directory and talks over a Unix socket under your XDG runtime directory.
Build it with:
make build
Or directly with Go:
go build -o ./banger ./cmd/banger
go build -o ./bangerd ./cmd/bangerd
Basic usage:
./banger daemon status
./banger tui
./banger vm list
./banger vm create --name calm-otter --disk-size 16G
./banger vm set calm-otter --memory 2048 --vcpu 4
./banger image list
Notes:
bangerauto-starts the per-user daemon when needed.banger tuilaunches a terminal UI for browsing, creating, editing, and operating VMs.- VM configs are persistent by default.
- RAM, vCPU, and work-disk size edits are stopped-only.
- The Go image build path currently delegates guest customization to
customize.sh.
Run Options
./run.sh --name calm-otter --vcpu 4 --ram 2048 --overlay-size 12G
--name: must be unique and match[a-z0-9][a-z0-9-]{0,63}.--vcpu: defaults to 2, max 16.--ram: MiB, defaults to 1024, max 32768.--overlay-size: writable dm-snapshot size for VM changes under/, including/rootand/var(default: 8G).--rootfs: path to the rootfs image (default:./rootfs-docker.ext4).--kernel: path to the kernel image (default:./wtf/root/boot/vmlinux-6.8.0-94-generic).--initrd: path to the initrd image (default:./wtf/root/boot/initrd.img-6.8.0-94-generic).
Storage Layout
rootfs.ext4is used as the read-only origin for a per-VM device-mapper snapshot mounted as/.- Each VM gets one sparse writable overlay file (
cow.ext4) that stores its changes on top of the shared base image. /rootand/varlive inside that per-VM overlay, so VMs can install packages without copying separate disks per VM.run.shmasks stalehome.mountandvar.mountunits at boot so older images with/dev/vdband/dev/vdcentries in/etc/fstabstill boot./runand/tmpshould be tmpfs via/etc/fstab.
SSH
ssh -i "./id_ed25519" root@<guest_ip>
Shortcut:
./ssh.sh <vm-name-or-ip>
VM DNS
- Spawned VMs register
<vm-name>.vm→ guest IP throughmapdns set. - VM teardown removes the mapping through
mapdns rm. mapdnswrites to/home/thales/.local/share/mapdns/records.json.
Internet Access
VMs do not get internet access by default. You must enable forwarding and NAT:
./nat.sh up <id-or-name-prefix>
This enables net.ipv4.ip_forward=1 and installs per-VM NAT rules for the VM's
guest IP and TAP device. To remove rules:
./nat.sh down <id-or-name-prefix>
Check status with:
./nat.sh status <id-or-name-prefix>
Shutdown
reboot
Customize Rootfs (Docker + Kernel Modules)
Use customize.sh to build a writable rootfs with Docker and kernel modules
preloaded so Docker works out of the box. Pass the base rootfs as a positional
argument; the output defaults to docker-<base filename> in the same directory
unless you pass --out.
Base guest packages come from ./packages.apt. Edit that file to bake tools
like vim and tmux into rebuilt images.
./customize.sh ./rootfs.ext4 --size 6G --docker
Options:
--size: optional size for the output image.--kernel: kernel path (default:./wtf/root/boot/vmlinux-6.8.0-94-generic).--initrd: initrd path (default:./wtf/root/boot/initrd.img-6.8.0-94-generic).--modules: kernel modules directory (default:./wtf/root/lib/modules/6.8.0-94-generic).--docker: install Docker packages into the image.--out: output rootfs path (default:docker-<base filename>).
After boot, enable NAT and validate Docker:
./nat.sh up <id-or-name-prefix>
ssh -i "./id_ed25519" root@<guest_ip> "systemctl enable --now docker"
ssh -i "./id_ed25519" root@<guest_ip> "docker run --rm hello-world"
Build Rootfs On Demand
run.sh defaults to ./rootfs-docker.ext4. If it is missing, run.sh will
invoke make-rootfs.sh to build it.
./make-rootfs.sh
make-rootfs.sh chooses the first available base image:
./rootfs.ext4
If ./packages.apt changes after rootfs-docker.ext4 is built, run.sh will
warn and keep using the existing image. make-rootfs.sh will also warn and
exit without rebuilding while the image already exists.
To rebuild after package changes:
rm -f ./rootfs-docker.ext4 ./rootfs-docker.ext4.packages.sha256
./make-rootfs.sh
Interactive Customization
To create a writable copy and customize it manually over SSH (no automatic package/config changes), use:
./interactive.sh ./rootfs-docker.ext4
You can override the output path:
./interactive.sh ./rootfs-docker.ext4 --out ./my-rootfs.ext4
VM Info File
Each VM writes:
state/vms/<id>/vm.json: local metadata under.metaplus the raw Firecracker config under.config.
Log Notes
PCI: Fatal: No config space access function foundandMissingAddressRangelines are expected withpci=offinrun.sh.SELinux: Could not open policy file ...is expected in the minimal rootfs.