battery is a MicroVM Warm Pool Manager for flintlock. It manages pools of pre-provisioned, pre-booted microVMs so consumers can claim an already-running VM instantly, instead of waiting for flintlock to provision one on demand. It's part of the liquidmetal-dev family of projects, alongside flintlock and guest-agent.
Status: early-stage / pre-alpha. The gRPC API surface is defined, but the pool reconciliation, replenishment, and lease logic is not yet implemented.
battery is made up of two binaries:
-
poolmgrd(cmd/poolmgrd) — the central pool manager daemon. It serves the gRPC API defined underapi/proto/poolmgr/v1alpha1:PoolAdmin— create, update, delete, and list pool definitions.Lease— claim a VM from a pool, heartbeat it, and release it back.Events— a server-streaming subscription for pool/VM/lease lifecycle events.
It's designed to reconcile a fleet of flintlock hosts against each pool's desired state, replenishing VMs using a per-pool strategy, and, once implemented, persist state (e.g., in an embedded SQLite database).
-
poolmgr-hostagent(cmd/poolmgr-hostagent) — a sidecar that runs alongside each flintlock host. Flintlock's guest-agent is only reachable over a host-local vsock socket, so this sidecar proxiesexec/pingcalls to the in-VM guest-agent onpoolmgrd's behalf, exposed via theHostagentgRPC service.
See docs/design/2026-09-05-microvm-warm-pool-manager-design.md
for the full design rationale and decisions, and
docs/runbooks/e2e-manual-verification.md for the
manual end-to-end verification runbook against a real flintlockd + Firecracker VM.
- Go 1.25+
- mise (recommended) to install pinned tool versions from
mise.toml— buf, golangci-lint,protoc-gen-go, andprotoc-gen-go-grpc.
go build ./...
go vet ./...
go test ./...
golangci-lint runThe gRPC API is defined in api/proto using buf. After editing a
.proto file, regenerate the Go code with:
./hack/generate-proto.shReleases are cut by pushing a semver tag matching v*.*.* (e.g. v0.1.0)
to main. This triggers .github/workflows/release.yml, which:
- builds
poolmgrdforlinux/amd64andlinux/arm64via GoReleaser - publishes a multi-arch container image to
ghcr.io/liquidmetal-dev/poolmgrd:<version>(and:latest) — note the image tag drops the leadingvfrom the git tag (e.g. taggingv0.1.0producesghcr.io/liquidmetal-dev/poolmgrd:0.1.0), unlike the GitHub release itself, which keeps it - creates a GitHub release with a changelog grouped by commit type
- pushes
api/proto(PoolAdmin/Lease/Events/types) to the Buf Schema Registry atbuf.build/liquidmetal-dev/battery, creating the BSR module on first push if it doesn't exist yet, and labels the push with both the release tag and the movingmainlabel —mainis whatbuf breaking(below) compares PRs against, so every release advances it
One-time setup: a BUF_TOKEN repository secret (a Buf Schema Registry
API token with write access to liquidmetal-dev/battery) must exist
before the first tag is pushed. Until the first successful buf push,
the buf breaking check in CI (.github/workflows/ci.yml) has nothing
to compare against — that specific "no baseline yet" failure is treated
as a pass with a warning, but any other buf breaking failure (a real
incompatible schema change) still fails the job normally, before and
after the first release.
If buf push fails after GoReleaser has already published successfully,
the proto schema push can be re-run manually without re-cutting the
release: buf push --create --create-visibility public --label <tag> --label main from a checkout of that tag.
git tag v0.1.0
git push origin v0.1.0Apache License 2.0 — see LICENSE for details.
Thanks to @phoban01 for the original idea of using warm pools with flintlock, based on his work building a GitLab executor that used flintlock warm pools.