A small Bash wrapper around Lima for disposable development VMs. It creates and starts Lima instances, keeps host files out of the guest, creates a dev user, and runs your own setup scripts. Tool installation lives in those scripts.
Defaults:
- no host mounts
- VM
<name>maps to Lima instancedvm-<name> - code lives at
/home/<user>/code/<vm> - config in
~/.config/dvm - setup scripts are ownership/permission checked before they run
Requirements: Bash and Lima 2.0+.
git clone https://github.com/eshlox/dvm.git dvm
cd dvm
./install.sh # symlinks bin/dvm into ~/.local/bin (override with PREFIX)dvm new app # writes ~/.config/dvm/vms/app/{config.sh,setup.sh}
# and scaffolds ~/.config/dvm/config.sh on first runResource and user settings live in the global ~/.config/dvm/config.sh and apply
to every VM. The per-VM config only holds what this VM needs to differ on:
# ~/.config/dvm/vms/app/config.sh
DVM_MEMORY=4 # more RAM than the global default for this VM
DVM_PORTS=(3000:3000 5173:5173) # extra forwards on top of Lima's automatic onesDVM_CPUS auto-detects from host cores and is a time-shared ceiling, not a
reservation: idle VMs cost no host CPU and a busy one can burst to most of the
machine, so a high value is safe. DVM_MEMORY is the opposite, reserved up
front, so set it to what each VM actually needs. See the
config reference
for details.
Edit the setup script:
# ~/.config/dvm/vms/app/setup.sh
#!/usr/bin/env bash
set -Eeuo pipefail
sudo dnf5 install -y git ripgrep fd-find tmuxBuild and enter:
DVM_DRY_RUN=1 dvm sync app # preview, no Lima contact
dvm sync app
dvm sh appdvm sync <vm> | <vm>/<proj> | --all
dvm sh <vm> | <vm>/<proj>
dvm ssh <vm> -- cmd... | <vm>/<proj> -- cmd...
dvm cp <src> <dst>
dvm ls [--only-config] [<vm>]
dvm stop <vm> | <vm>/<proj> | --all [--only-config]
dvm logs <vm>/<proj> [-f]
dvm rm <vm> --yes [--config] | <vm>/<proj> --yes [--keep-data]
dvm reset <vm> --yes | <vm>/<proj> --yes [--keep-data]
dvm new <vm>
dvm add <vm>/<proj>
dvm base <subcommand>
dvm version
See the command reference for details.
Instead of one VM per project, group projects by trust tier in a pool VM and run each as a disposable rootless-podman container inside it. The VM is the durable boundary that protects the host; containers isolate projects from each other and reset in seconds.
dvm new trusted # a pool VM for one trust tier
dvm add trusted/api # define a project (container) in it
dvm sync trusted # build the dev-base, bring up every container
dvm sh trusted/api # shell into the api container
dvm reset trusted/api --yes # recreate just that container, cleanSee Trust tiers & project containers.
When every VM installs the same tooling, baking it once into a base image makes
dvm sync boot a ready VM in seconds instead of re-provisioning from scratch:
dvm base init # writes ~/.config/dvm/base/Containerfile (FROM dvm-base)
dvm base build # builds the image in a throwaway Lima builder VM
dvm sync app # boots from the base imagePer-VM setup.sh still handles unique, stateful steps (SSH keys, dotfiles).
See the base image reference.
Full documentation lives at dvm.eshlox.net:
- Commands — command reference
- Config & setup scripts — config variables and setup scripts
- Trust tiers & project containers — many projects in one pool VM
- Security model — threats and trade-offs
- Lima behavior — Lima behavior and limits
- Troubleshooting — errors and recovery
- Examples — copy/paste setup snippets
The docs source lives in site/src/content/docs/. The website is an
Astro + Starlight project under site/ — see site/README.md.
Development check (runs the smoke test and ShellCheck):
bash scripts/check