Linux-first local VM orchestration for QEMU/KVM
Fast project-based virtual machines with cloud-init, trusted base images, post-boot provisioning, SSH access, stable JSON, and event streams.
Website · Quick Start · Current Scope · Commands · Examples · Architecture · Limits
Yeast is the local VM engine for TwargaOps.
At the user level, Yeast gives you a simple model:
- define machines in
yeast.yaml - pull a trusted base image
- run
yeast up - connect with
yeast ssh - stop with
yeast down - clean up with
yeast destroy
At the product level, Yeast is meant to become the foundation for:
- LabsBackery
- Yeast MCP
- future hosted Twarga Cloud workers
The important constraint is still simple: keep the core small and reliable before adding the larger ecosystem layers.
Yeast v1.0 is the first stable local engine release. It covers one complete loop: boot a VM, provision it into something useful, snapshot a clean baseline, restore it later, attach one private lab network, operate inside the guest through an SSH-backed control surface, start new projects from built-in or local templates, expose a versioned JSON/events contract for tools, and define the first LabsBakery integration boundary.
| Area | v1.0 status |
|---|---|
| Host support | Linux only |
| Runtime | QEMU + KVM |
| VM model | Project-local instances from yeast.yaml |
| Base images | Trusted shared cache in ~/.yeast/cache/images |
| Bootstrap | cloud-init seed ISO |
| Access | SSH over host port forwarding |
| State | Project-scoped state with locking and reconciliation |
| Automation | Versioned --json envelopes, stable command data fields, documented error codes, and JSON Lines --events for lifecycle workflows |
| Provisioning | Packages, files, shell, and yeast provision |
| Reset | Stopped-VM snapshot, list, restore, and delete |
| Private networking | One project-level lab network with static per-instance IPv4 |
| Guest control | exec, copy, logs, and inspect |
| Templates | Built-in ubuntu-basic, caddy-single-vm, and two-vm-lab; local template directories |
| LabsBakery integration | Stable local-engine contract, lab package convention, and first attacker/target example package |
| Examples | Single-VM Ubuntu, Caddy provisioning/reset, first two-VM lab example, and LabsBakery package example |
yeast doctoryeast inityeast init --list-templatesyeast init --template <name-or-path>yeast pull --listyeast pull <image>yeast up- post-boot provisioning during
yeast up yeast provision [instance]yeast snapshot <instance> <name>yeast restore <instance> <name>yeast snapshots <instance>yeast delete-snapshot <instance> <name>yeast statusyeast exec [instance] -- <command...>yeast copy <instance> --to-guest <source> <destination>yeast copy <instance> --from-guest <source> <destination>yeast logs <instance>yeast inspect <instance>yeast ssh [instance]yeast downyeast destroyyeast version- first private lab network with per-instance
LAB IP - versioned
--jsonoutput withschema_version: "yeast.v1" - browser-terminal-friendly
usermetadata instatus --jsonandinspect --json --json --eventsstreams forup,provision,restore,down, anddestroy- LabsBakery integration contract docs
- LabsBakery lab package convention docs
- first Yeast-backed LabsBakery attacker/target example package
- remote template downloads or registry search/update
- complex template variables
- daemon or web API
- Twarga Cloud features
- LabsBakery web UI
- packaged
.lbzimport/export - project-wide atomic snapshot/reset helper
- multiple private networks
- bridge mode
- DHCP lab guests
- event history or progress percentages
- Why It Exists
- Quick Start
- Install
- Commands
- Config
- Examples
- How Yeast Stores Data
- Architecture
- Testing
- Current Limits
- Project Docs
- License
Running local VMs is still more painful than it should be for Linux builders.
The raw workflow usually means stitching together too many manual steps:
- downloading cloud images
- creating qcow2 disks
- generating cloud-init files
- building a seed ISO
- composing QEMU arguments
- tracking SSH ports
- remembering which runtime files belong to which project
Yeast reduces that to a project workflow instead of a pile of ad hoc commands.
It is not trying to be a cloud platform, a container system, or a Proxmox replacement. The current goal is still simple: make local real VMs feel project-native and repeatable.
yeast doctorYeast needs:
- Linux
/dev/kvmqemu-system-x86_64qemu-imggenisoimageormkisofsssh~/.ssh/id_ed25519.pubor~/.ssh/id_rsa.pub
mkdir my-lab
cd my-lab
yeast initOr start from a built-in template:
yeast init --list-templates
yeast init --template caddy-single-vmDefault starter config without a template:
version: 1
instances:
- name: web
hostname: web-lab
image: ubuntu-24.04
memory: 1024
cpus: 1yeast pull --listCurrent trusted images:
ubuntu-22.04ubuntu-24.04
yeast pull ubuntu-24.04yeast upExpected human output shape:
OK Instances ready
RUN web 127.0.0.1:2222
yeast statusExpected human output shape:
Project status
NAME STATUS SSH
web running 127.0.0.1:2222
yeast ssh webyeast provision webyeast down
yeast snapshot web clean --description "Provisioned baseline"
yeast snapshots webyeast up
yeast ssh web
# change something inside the guest
exit
yeast down
yeast restore web clean
yeast upyeast exec web -- whoami
yeast copy web --to-guest ./artifact.txt /home/yeast/artifact.txt
yeast copy web --from-guest /home/yeast/artifact.txt ./artifact-out.txt
yeast inspect web
yeast logs web --tail 20Reference example:
examples/two-vm-lab
That example shows:
attackerandtargetVMs- separate management SSH ports
- one private lab network
- static lab IPs visible in
yeast status
yeast down
yeast delete-snapshot web clean
yeast destroyIf the repository is reachable over HTTPS:
curl -fsSL https://raw.githubusercontent.com/Twarga/yeast/main/install.sh | bashIf you already cloned the repo:
bash install.shThe installer attempts to:
- detect the package manager
- install Yeast runtime dependencies
- install Go for source build flow
- clone and build Yeast
- install
yeastinto/usr/local/bin - verify the installed binary version
- create the Yeast cache directory
- generate an SSH key if needed
- add the user to the
kvmgroup when possible
git clone https://github.com/Twarga/yeast.git
cd yeast
go build -o yeast ./cmd/yeast
sudo mv yeast /usr/local/bin/# Ubuntu / Debian
sudo apt install qemu-system-x86 qemu-utils genisoimage
# Fedora / RHEL
sudo dnf install qemu-system-x86 qemu-img genisoimage
# Arch Linux
sudo pacman -S qemu-base cdrtoolsIf needed:
sudo usermod -aG kvm $USERThen log out and back in before your first yeast up.
| Command | Purpose |
|---|---|
yeast doctor |
Check host readiness |
yeast init |
Create yeast.yaml and project metadata |
yeast init --list-templates |
List built-in project templates |
yeast init --template <name-or-path> |
Create a project from a built-in or local template |
yeast pull --list |
List supported trusted images |
yeast pull <image> |
Download a trusted base image |
yeast up |
Start all instances in the project |
yeast provision [instance] |
Rerun post-boot provisioning for a running instance |
yeast status |
Show tracked instance state |
yeast exec [instance] -- <command...> |
Run one command inside a running instance |
yeast copy <instance> ... |
Copy a file to or from a running instance |
yeast logs <instance> |
Read the VM runtime log for one instance |
yeast inspect <instance> |
Show detailed state for one instance |
yeast ssh [instance] |
Open SSH into a running instance |
yeast down |
Stop tracked running instances |
yeast destroy |
Stop and remove tracked runtime data |
yeast version |
Print the current version |
These commands support machine-readable output:
doctorinitpullupstatusexeccopylogsinspectdowndestroyversion
Example:
yeast status --jsonyeast ssh is interactive and should be treated as a terminal workflow, not a JSON workflow.
Current v1.0 example:
version: 1
instances:
- name: web
hostname: web-lab
image: ubuntu-24.04
memory: 1024
cpus: 1
disk_size: 20G
ssh_port: 2205
user: yeast
sudo: none
env:
APP_ENV: developmentnameimagememorycpusdisk_sizehostnamessh_portusersudoenvuser_data
user_datareplaces Yeast-generated cloud-init instead of merging into itdisk_sizeapplies to the overlay disk Yeast creates for the instance; existing disks are kept as-isdisk_sizeaccepts whole-number sizes with optionalK,M,G,T, orPsuffixes, such as20G,25600M, or raw byteshostnamecontrols the guest hostname written through cloud-init; if omitted, Yeast uses the instancenamessh_portoverrides the host-side SSH forwarding port; if omitted, Yeast auto-allocates starting at2222envis rendered into the guest bootstrap profile scriptprovisionnow supports packages, files, and shell steps duringyeast upandyeast provision- file provision
sourcepaths are resolved relative to the project root unless they are absolute - one project-level private lab
networksblock is active in v1.0 - guest-control commands are SSH-backed only and operate on one selected instance at a time
- templates are project starters only; after
yeast init --template, the generated files are normal editable project files
Built-in templates:
yeast init --list-templates
yeast init --template ubuntu-basic
yeast init --template caddy-single-vm
yeast init --template two-vm-labCurrent repo examples:
- examples/ubuntu-basic
- examples/caddy-single-vm
- examples/two-vm-lab
- examples/labsbackery-attacker-target-basic
The templates and examples are intentionally small:
ubuntu-basickeeps the lifecycle-only path minimalcaddy-single-vmshows provisioning with packages, files, and shelltwo-vm-labshows the first private lab networklabsbackery-attacker-target-basicshows the first Yeast-backed LabsBakery lab package convention
They exist to prove the current shipped paths cleanly.
yeast.yaml— desired VM configuration.yeast/project.json— project identity metadata
cache/images/— shared trusted base imagesprojects/<project-id>/state.json— project runtime stateprojects/<project-id>/state.lock— project state lockprojects/<project-id>/instances/<name>/— per-instance runtime files
Typical instance files:
disk.qcow2seed.isouser-datameta-datavm.log
This separation is important. Two different projects can both have an instance named web without colliding.
Yeast is structured so the CLI is only one entrypoint, not the whole product.
CLI
-> app workflows
-> config
-> project paths
-> state + locking
-> image cache
-> cloud-init
-> runtime interface
-> QEMU/KVM backend
That split matters because the long-term direction is larger than the local CLI:
- LabsBackery should call Yeast workflows, not reimplement VM logic
- Yeast MCP should depend on stable state and JSON output
- Twarga Cloud should eventually reuse the same engine model remotely
For the current detailed architecture document, see YEAST_TECHNICAL_ARCHITECTURE.md.
Fast package suite:
bash scripts/test-fast.shFull suite:
go test ./... -count=1
go build ./...The repo also includes fake-runtime workflow tests so core app flows can be validated without a real QEMU host.
This README is intentionally honest about the current product shape.
Current known limits:
- Linux host only
- QEMU/KVM only
- no Windows or macOS host support
- no VirtualBox backend
- snapshots are stopped-VM and per-instance only
- private networking supports one project-level lab network only
- guest control is SSH-backed and one instance at a time
- templates are project starters only
- no remote template downloads or registry workflow
- no daemon or remote worker mode yet
- first LabsBakery local-engine contract is documented, but LabsBakery itself is not part of Yeast
That is not a weakness in the README. It is the correct scope boundary for the current release line.
Terminal docs are available directly from the CLI:
yeast docs
yeast docs --list
yeast docs quickstart
yeast docs installation
yeast docs tutorial-test- YEAST_VISION.md
- YEAST_TECHNICAL_DISCOVERY.md
- YEAST_TECHNICAL_ARCHITECTURE.md
- YEAST_V2_IMPLEMENTATION_PLAN.md
- YEAST_TEST_PLAN.md
- YEAST_RELEASE_PLAN.md
- YEAST_PRODUCT_ROADMAP.md
- docs/quickstart.md
- docs/installation.md
- docs/tutorial-test.md
- docs/command-reference.md
- docs/config-reference.md
- docs/troubleshooting.md
- docs/known-limitations.md
- docs/architecture-overview.md
- docs/charm-cli-plan.md
- docs/json-contract.md
- docs/labsbackery-integration-contract.md
- docs/labsbackery-lab-package.md
- docs/release-checklist-v1.0.0.md
- docs/release-notes-v1.0.1.md
- docs/release-notes-v1.0.0.md
- docs/release-notes-v0.1.0.md
- docs/release-notes-v0.2.0.md
- docs/release-notes-v0.3.0.md
- docs/release-notes-v0.4.0.md
- docs/release-notes-v0.5.0.md
- docs/release-notes-v0.6.0.md
- docs/release-notes-v0.7.0.md
- docs/release-notes-v0.8.0.md
- docs/release-notes-v0.9.0.md
- TASKS.md
MIT. See LICENSE.