The bhyve yard

A FreeBSD control plane
you can actually explain.

Apiary runs a small Colony of FreeBSD hosts as one thing: bhyve VMs and jails, placed and reconciled over Raft consensus, with ZFS storage, PF networking, and a web control plane that shows its work - not a black box wrapped around libvirt.

Colony → Comb → Cell

Apiary's own vocabulary for the physical containment hierarchy it manages.

Colony
The whole cluster: every Comb, and everything running on them, held together by a single Raft consensus group.
Comb
One physical FreeBSD host. A Colony can be a single standalone Comb or several Combs joined together - both are first-class, not a degraded state.
Cell
One VM or jail. Placed on a Comb, reconciled continuously against its desired state, and visible cluster-wide regardless of which Comb owns it.

Built to show its work

A running list of what makes Apiary a control plane instead of a wrapper.

Raft, not a leader-election script
Cluster membership, placement, and configuration are Raft-committed state (hashicorp/raft), with guarded join/approve flows instead of hand-edited peer lists.
Evidence, not vibes
Automated assumption checks, a Why-Not engine, and a resilience coverage map explain what's actually true about the Colony right now, and what would break it.
FreeBSD-native
bhyve, jails, ZFS, PF, and rc.d, used the way FreeBSD already does this well - a bolt-on control plane, not a reimplementation of the OS underneath it.

Recent changes

Selected changes merged to main. Each item links to its implementation or design record.

  1. 14 Oct

    Colony joins now enforce the full authorization flow

    Approval requires a live join window, a matching unused entry in the root-owned authorization store, and two approvals from distinct API keys presented to distinct Combs - even when the Colony currently has one member. The join path also records which Comb handled each approval, checks the joining Comb's reported certificate fingerprint, and refuses repeated first authorizations.

    ADR-0147 Join-flow fixes
  2. 14 Oct

    Join and authorization secrets are provisioned during setup

    Installation and join setup now create the required secrets automatically, so operators do not need to prepare them by hand before using the guarded Colony join flow.

    Implementation
  3. 14 Oct

    ISO upload forms reset after a successful upload

    The upload form clears its file and fields after the server accepts an ISO, confirming completion and leaving the form ready for another image.

    Implementation
  4. 13 Oct

    Join approvals explain the required operator actions

    The approval screen now labels the two authorization steps clearly, and shows the information operators need to complete each step on the appropriate Comb.

    Implementation
  5. 28 Sep

    An installer that needs no checkout

    apiaryctl install takes a bare FreeBSD host to an installed Comb - configuration, certificates, and identity - from a root shell and nothing else. It changes nothing without --apply, and the part of its report worth reading is the list of what it decided not to overwrite, and why.

    ADR-0147, Part 1
  6. 28 Sep

    A join window, closed by default

    A new Comb can only join while the Colony's join window is open, and closed is the normal state - a request that arrives at a closed Colony is refused by name. The window is replicated Raft state rather than a flag in one Comb's config file, and it carries an epoch, so a request approved against the old window does not survive its reopening. Alongside it, every Comb now derives its peer trust anchor from a replicated trust store instead of naming its own path. TLS by default is deliberately still not done: encryption with an unverified certificate is a worse failure than no encryption, so the trust anchor has to land first.

    ADR-0147, Part 4
  7. 28 Sep

    25 mutations, 25 killed, 0 survived

    The installer's test suite is now run against deliberately broken code. The one mutant that survived the first pass turned out to have found a real gap rather than a weak test - nothing asserted what the summary reports after it refuses something - so it became two new tests instead of a suppressed failure.

    Commit 534512e
  8. 27 Sep

    Updating the Colony without punching a hole in quorum

    A colony-wide update runs under a single-flight replicated through Raft, and managerd hands the update over cooperatively - which is what lets a controlled update restart the very daemon driving it. A restart is confirmed by its listener port, not by what service(8) claims about it, and there is a test for exactly the case where service(8) lies.

    ADR-0146
  9. 26 Sep

    A code audit, and what it cost

    15 findings across auth, join, Raft, login, and bhyve, from static analysis plus manual triage of every hit that looked real. Each one is either fixed with tests alongside it or explicitly accepted with the reason written down - including the two where the honest answer was that the exposure stays until an operator sets an allowlist.

    docs/audits/2026-09-26-code-audit.md
  10. 26 Sep

    Seven states, none of which is "probably fine"

    Every status badge in the UI now comes from one documented vocabulary. unknown means the check did not complete, stale means the observation is aging out of its freshness window, and contradictory means two evidence sources disagree with each other. Silence is a verdict rather than an all-clear, so it never renders green.

    ADR-0144

Screenshots

Current views from a live Apiary Colony: its Command Center, automated assumption checks, operational invariants, resilience coverage map, workload wizard, and image inventory.

Automated Assumption Checks
Resilience Coverage Map
Command Center
Create workload
ISO and Disk Images
Operational Invariants