Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Farrow documentation

Install Farrow, boot a Pigsty inventory, operate the one deployment, and look up the exact configuration and CLI contracts.

Farrow turns one Pigsty-compatible Inventory into fixed-IP QEMU virtual machines. It manages one deployment per Unix user; state lives under ~/.farrow, so lifecycle and SSH commands work from any directory.

Choose the shortest path for your task:

  • Start — install, first lab, daily changes, and troubleshooting.
  • Reference — exact Inventory fields, commands, flags, output, and exit codes.
  • About — simplified design, native validation, limits, and release gates.

New users should follow the tutorial. The complete normal path is farrow setup, farrow up, then farrow status.

Important

Farrow is pre-1.0. Current source behavior, native validation, packaging, release, and publication are separate gates. Read Status before depending on a development build.

1 - Start

Install Farrow, boot one or four nodes, operate the deployment, and resolve common failures.

Use these pages in order:

  1. Installation — build the current source and check the host.
  2. Tutorial — boot one node, expand to four, and use Pigsty.
  3. Operations — start, stop, change, inspect, and destroy nodes.
  4. Troubleshooting — short symptom-to-fix runbooks.

1.1 - Installation

Build Farrow, verify native acceleration, and understand the one-time host setup.

Supported path today

Build from the current checkout:

cd /path/to/farrow
make build
export PATH="$PWD/bin:$PATH"
farrow version
farrow doctor

There is no published v1 package yet. Do not substitute an unofficial binary for the matching farrow and farrow-hosts-helper build.

The source build requires Go 1.27.x. macOS also needs an existing Homebrew installation; Farrow can install QEMU through Homebrew but never bootstraps Homebrew itself. The current compiled image repository is the development host https://m0/farrow; use FARROW_REPO or --repo when another reachable mirror is required.

Host requirements and dated evidence

Native HVF/KVM is the normal path. Farrow never retries an arbitrary native failure under emulation. TCG is selected only for an explicit foreign vm_arch, or for the catalogued stock EL8 arm64/Apple-Silicon incompatibility. TCG is compatibility evidence, never performance evidence.

Host Last recorded evidence (2026-08-27)
macOS arm64 verified with HVF, QEMU 11.1, and socket_vmnet
Ubuntu 26.04 amd64 verified with KVM, QEMU 10.2.1, and NetworkManager
Rocky Linux 8.10 arm64 guest on macOS arm64 verified with automatic TCG and full readiness
other Debian/Fedora/EL9 amd64 implemented; repeat native validation before relying on it
macOS amd64, Linux arm64 cross-built and unit-tested, not currently native-verified

macOS needs Homebrew. Linux needs systemd plus either NetworkManager or systemd-networkd. farrow setup installs missing supported packages through Homebrew, APT, or DNF.

What setup changes

Run a dry plan first if desired:

farrow setup --dry-run
farrow setup --yes

Setup may install QEMU dependencies, prepare the host fixed-IP network, and install the narrow root-owned hosts publisher. It prints each mutation and the reason for sudo before applying anything.

In automation use --yes. Non-interactive sudo works with either a cached credential or a suitable NOPASSWD policy; every privileged command still uses an exact absolute argv.

Setup is idempotent. A healthy repeat reuses the network and installed helper. Source tests and this dated native matrix are separate: rebuilding a newer working tree does not silently refresh the rows above.

1.2 - Tutorial

Boot a one-node lab, verify it, expand it to four nodes without restarting the first, and hand the same inventory to Pigsty.

1. Create the lab

mkdir -p ~/lab
cd ~/lab
export FARROW_REPO=https://m0/farrow   # replace outside the development network
farrow setup --dry-run
farrow setup --yes
farrow up

With no existing file, setup writes farrow.yml for one node:

all:
  vars:
    admin_ip: 10.10.10.10
  children:
    nodes:
      hosts:
        10.10.10.10: { nodename: meta }

up downloads and verifies the image, creates the disks and cloud-init seed, starts QEMU, and waits for the guest readiness record.

2. Verify the node

farrow status
farrow ssh meta
farrow exec meta -- hostname
ping 10.10.10.10

The default node has 2 vCPU, 4 GiB memory, a 64 GiB root disk, and a 128 GiB XFS disk at /data.

farrow status also reports the effective Guest architecture and accelerator. The default EL9/EL10 path is native HVF/KVM. On Apple Silicon, vm_image: el8 automatically selects same-architecture TCG for the stock 64K-granule kernel. To run an amd64 Guest explicitly, set deployment-wide vm_arch: amd64; this uses single-threaded TCG and is intentionally much slower. EL7 is available only as a deprecated, native Linux/amd64 BIOS/KVM Guest.

3. Expand to four nodes

Add three host entries below the same hosts: mapping:

        10.10.10.11: { nodename: node-1 }
        10.10.10.12: { nodename: node-2 }
        10.10.10.13: { nodename: node-3 }

Then converge:

farrow plan       # create: node-1, node-2, node-3
farrow up
farrow status

Only the new nodes are created. meta keeps its process and uptime. The control node received the deployment key on its first boot, so it can SSH to the new nodes immediately:

farrow exec meta -- ssh [email protected] hostname

4. Use the same file with Pigsty

If Pigsty already generated pigsty.yml, skip the example file and run Farrow in that checkout:

./configure -c meta
farrow setup
farrow up
./install.yml

Farrow reads the documented VM fields plus native fields for naming, control-node selection, and the login identity. Unconsumed settings such as pg_role, pg_version, repo_*, and node_packages do not produce VM drift; pg_cluster/pg_seq and the node-admin fields are consumed.

5. Stop or remove it

farrow stop
farrow start
farrow destroy --force

Normal destroy preserves the verified image cache, deployment keys, and persistent disks. Use --delete-persistent or --purge only when intended.

1.3 - Operations

The normal lifecycle for the one deployment: inspect, access, scale, change, stop, and destroy.

Inspect and access

farrow status
farrow ssh meta
farrow exec node-1 -- hostname
farrow logs meta --source serial
farrow ss                         # install SSH aliases; then: ssh meta

Applied state is under ~/.farrow; these commands work from any directory. Status includes the persisted Guest architecture and accelerator, so TCG is never an invisible fallback. plan, up, reload, and recreate prefer -f, then a discovered Inventory, then the applied spec when no file exists. validate always needs a file.

Stop and start

farrow stop                       # alias: halt
farrow start
farrow restart node-1
farrow reload -f farrow.yml       # stop, re-read config, converge

restart uses applied state. reload reads the Inventory again.

Change the deployment

farrow plan
farrow up                         # create additions and start stopped selected nodes
farrow recreate node-1 --force    # applies a changed VM definition

Inventory changes fall into three visible fields:

Field Meaning Action
create desired node has no state farrow up
recreate VM definition changed farrow recreate <node> --force
missing stateful node left the file restore it, or destroy it explicitly

Deleting YAML never deletes a VM. Unconsumed Pigsty changes produce action:none; native naming and node-admin fields are consumed even though they do not begin with vm_.

Destroy

farrow destroy node-3 --force
farrow destroy --force
farrow destroy --force --delete-persistent
farrow destroy --force --purge

--delete-persistent and --purge are valid only for whole-deployment destroy, not with node selectors. --purge removes persistent disks, keys, and deployment state; images remain cached. Host network removal is separate and refuses while a VM is attached:

farrow network uninstall --yes

Images

farrow image list
farrow image info u24
farrow image pull u24
farrow image prune --dry-run

Images are signed-catalog entries and SHA-256 checked before use. Current images are testing, except EOL EL7 which is deprecated, so starts print the corresponding warning.

1.4 - Troubleshooting

Short, safe runbooks for setup, networking, images, drift, interrupted state, and SSH.

Start read-only:

farrow doctor --json
farrow network status --json
farrow status --json

No configuration found

For the first deployment, run plan, up, or validate beside farrow.yml/pigsty.yml, or pass -f /path/to/file. Once state exists, plan, up, reload, and recreate can fall back to its applied spec. Status, start, stop, SSH, and destroy always use applied state. If status prints the same message, the selected FARROW_HOME has no applied state.

Setup needs sudo

The line before the prompt names the exact host mutation. Farrow attaches an interactive terminal directly to sudo when the privileged step begins. Automation needs an existing credential or a suitable NOPASSWD policy, then passes --yes.

Native acceleration or compatibility runtime is unavailable

Native paths require HVF on macOS or KVM on Linux. TCG is selected only for an explicit foreign vm_arch or a built-in image/host compatibility rule; an arbitrary native failure never falls back. Homebrew QEMU contains both system emulators. Linux setup installs only the native family, so a foreign Guest also requires its matching qemu-system-* binary and firmware.

plan, up, and recreate validate the selected emulator and firmware before any destructive mutation. Performance results from TCG are not meaningful.

Network is partial or invalid

Do not delete host files by hand. Review the owned cleanup plan:

farrow network status --json --verbose
farrow network uninstall

Apply it with --yes only when it names Farrow-owned paths. Linux bridge smoke failures now trigger automatic manifest-bounded rollback; an explicit automatic rollback failed message means manual inspection is required.

Linux bridge helper fails

id
stat -c '%U:%G %a %n' /usr/lib/qemu/qemu-bridge-helper
dpkg-statoverride --list /usr/lib/qemu/qemu-bridge-helper

Debian/Ubuntu uses root:<caller-accessible-group> 4750; the caller does not have to belong to kvm when /dev/kvm access comes from a desktop ACL.

Plan reports recreate or missing

recreate needs farrow recreate <node> --force. missing is only a report: restore the host entry or run farrow destroy <node> --force.

SSH fails

Check farrow status, farrow ssh-config, and the serial log. Farrow’s own SSH uses a loopback management port; direct Ansible traffic uses the fixed IP.

Catalog or image verification fails

The current binary embeds active and standby Catalog public keys. Unknown signers, version rollback/equivocation, artifact size/SHA mismatch, and unsafe qcow2 structure are distinct integrity failures. Use a correctly signed repository or farrow image import --sha256 ...; do not copy bytes directly into ~/.farrow/images.

A command was killed

Run farrow status. A provably live or dead runtime is converged from its recorded identity; an ambiguous process remains blocked. Do not kill an unknown PID based only on a state file.

If a recorded QEMU process still exists but its QMP socket is absent, preserve the evidence and inspect serial/QEMU logs before using stop to converge it. Do not delete runtime sockets or state files by hand.

For a bug report include the exact command and exit code, farrow version, the three JSON reports above, host OS/architecture, and QEMU version.

2 - Reference

Exact contracts for the Pigsty-compatible Inventory and Farrow command line.
  • Configuration — discovery, accepted variables, defaults, disks, shares, naming, and drift.
  • CLI — commands, important flags, output modes, and exit codes.
  • Images — signed catalogs, aliases, cache layout, pulls, imports, and pruning.
  • Image Pipeline — candidate validation and offline normalization.

Farrow exposes no supported Go library API. Packages under internal/ are implementation details.

2.1 - Configuration

The Pigsty-compatible Inventory fields Farrow reads, their defaults, and node-level drift behavior.

Discovery

Configuration lookup order is explicit -f, then farrow.yml, farrow.yaml, pigsty.yml, and pigsty.yaml in the current directory. Every name uses the same Pigsty-compatible YAML Inventory format.

The retired top-level version:/nodes: format is rejected with migration guidance.

For plan, up, reload, and recreate, absence of a file falls back to the applied spec when a deployment exists. validate has no fallback. A configuration must be a regular non-symlink file no larger than 4 MiB.

What Farrow reads

Farrow reads host IPs, nodename, admin_ip, pg_cluster, pg_seq, node_admin_username, node_admin_uid, and the documented vm_* variables. admin_ip is read from all.vars; it selects the control node, or the first managed host is used. All nodes must resolve the same login username. For the default dba user, an explicit node_admin_uid must be 88.

Everything else is opaque and cannot create drift. This means unconsumed fields such as pg_role, pg_version, repo_*, and node_packages, not all possible pg_* or node_* names.

Inside this namespace validation is strict: unknown vm_* names, wrong types, Jinja expressions, invalid addresses, and conflicting sibling-group values are errors.

VM variables

Variable Default Meaning
vm_skip false do not virtualize this real/external host
vm_image u24 image alias
vm_arch native deployment-wide Guest architecture: native, amd64, or arm64
vm_cpu 2 vCPU count
vm_mem 4096 MiB integer, or a size such as 8GiB
vm_disk 64 root disk GiB
vm_disks [{path: /data}] extra disks
vm_alias [] guest /etc/hosts, SSH-config, and optional host aliases
vm_shares [] QEMU 9p host-directory shares

An empty host entry is a complete VM. A deployment contains 1–20 managed hosts; vm_cpu accepts 1–256 and memory must be at least 512 MiB.

vm_arch is stricter than ordinary per-host VM fields: when present it must resolve to one value on every managed host, so define it once in all.vars. Changing it is a deployment-envelope change and requires whole-deployment recreation. Linux setup installs only the native emulator; a foreign architecture also needs its matching qemu-system-* binary and firmware.

Data disks

vm_disks:
  - path: /data
    size: 128
    fs: xfs
    persistent: false

path is the disk identity and mount point. fs is xfs or ext4. persistent: true survives normal destroy. Use vm_disks: [] for no extra disk.

Shares

vm_shares:
  - host: /absolute/owned/source
    guest: /src
    readonly: true

Shares must be real, caller-owned, non-overlapping directories. They are for trusted development files, not PostgreSQL data.

Names and addresses

Node name order: nodename, then <pg_cluster>-<pg_seq>, then node-<last-octet>. Names must be unique.

All managed hosts must be in one RFC1918 /24: .1 is the host, .2.8 are reserved, and nodes use .9.254.

Drift

Farrow hashes each resolved node. Added hosts are created by up; selected existing stopped nodes are started; running peers stay untouched. Changed VM definitions require per-node recreate; removed hosts are reported but never destroyed. Deployment architecture, user, or subnet changes require whole-deployment recreation. Changing a field used to derive a node name appears as a missing old node plus a new node, so prefer stable explicit nodename values.

2.2 - CLI

Farrow commands, important flags, structured output, and exit codes.
farrow [--json|--yaml] [--verbose] <command> [flags] [node...]

The installed binary is the authoritative reference for its own version. Every visible command includes its operational boundary and copyable examples:

farrow --help
farrow setup --help
farrow image pull --help

In text mode, bare farrow and namespaces such as farrow image display contextual help and exit successfully. In JSON/YAML mode a bare namespace is a structured usage error; explicit --help always renders human help.

Commands

Area Commands
Prepare setup, init, validate, doctor
Lifecycle plan, up, start, stop/halt, restart, reload, recreate, status, destroy
Access ssh, exec, logs, provision, ssh-config, ss, hosts
Images image list/info/pull/import/sync/prune/reset-manifest
Host network network status/install/uninstall
Misc version, completion

Commands using applied state work from any directory. Configuration selection is command-scoped; -f is deliberately not a global flag:

Commands Desired-state source
setup [template] explicit -f, otherwise discovery, otherwise generate meta; template and -f are exclusive
init [template] generate a new inventory; read no desired state
validate explicit -f, then discovery; never applied state
plan, up, reload, recreate explicit -f, then discovery, then the applied resolved specification
other lifecycle/access commands no desired-state inventory; use applied or marker-owned state as applicable

Important flags

Flag Meaning
--json, --yaml machine-readable stdout; progress remains on stderr
--verbose bounded diagnostics on stderr
--yes apply a displayed host/setup plan
--force skip the interactive destroy/recreate confirmation; required without a terminal
--no-wait return after QMP/process identity without guest readiness
--delete-persistent during whole destroy, also delete retained data disks; invalid with node selectors
--purge whole-deployment disposal: delete disks, keys, and deployment state; keep images

If a failing command has not already emitted a richer typed result, structured mode writes one object containing error and message before returning the documented non-zero exit code. Existing typed failure results are never followed by a second JSON/YAML document.

plan is read-only and returns success even when its action is recreate or blocked-removal; automation must inspect the action and create, recreate, and missing fields. up creates additions and starts selected stopped nodes, but returns a conflict instead of applying destructive drift.

status reports the persisted guest_arch and accelerator for each node. TCG selection is therefore explicit in both text and structured output.

SSH passthrough and completion

farrow ssh [node] [--] [command ...] opens a session or runs an optional command. farrow exec [node] [--] <command ...> requires a command and passes through its exit status. Presentation flags before -- belong to Farrow; arguments after -- belong to OpenSSH or the remote program.

Load farrow completion bash|zsh|fish|powershell for command and scoped-flag completion. It also provides templates, image aliases, closed flag choices, and best-effort node names from the desired or applied specification.

Exit codes

Code Meaning
0 success
1 runtime failure
2 usage or invalid configuration
3 missing host capability
4 state conflict or explicit convergence required
5 partial multi-node completion
6 resource conflict
7 integrity or ownership failure

ssh and exec pass through the remote program’s exit code, except SSH’s reserved transport-failure code 255, which Farrow maps to runtime failure 1.

2.3 - Images

Signed catalogs, built-in aliases, repository selection, local cache verification, imports, and pruning.

Farrow uses a signed static-file Catalog plus immutable qcow2 artifacts. A Catalog update does not require a new Farrow binary, but the binary decides which signing keys and image safety rules are trusted.

Warning

EL7 is deprecated; every other built-in image is currently testing, not supported. The warning printed by up is intentional: a successful pull is an integrity result, not a production-support promise.

Aliases and pull order

The embedded Catalog contains 9 families and 17 artifacts: el7 is amd64-only; el8, el9, el10, d12, d13, u22, u24, and u26 have amd64 and arm64 artifacts. u24 is the VM default.

Alias Distribution Architectures Boot Status
el7 CentOS Linux 7.9 / 2211 amd64 BIOS deprecated
el8 Rocky Linux 8.10 amd64, arm64 UEFI testing
el9, el10 Rocky Linux amd64, arm64 UEFI testing
d12, d13 Debian amd64, arm64 UEFI testing
u22, u24, u26 Ubuntu amd64, arm64 UEFI testing
farrow image list
farrow image info u24
farrow image pull u24

For a pull, Farrow:

  1. refreshes catalog.json and its adjacent .minisig from --repo, then FARROW_REPO, then the compiled default repository;
  2. verifies the signature with an embedded active or standby public key;
  3. selects the Catalog’s default release; standalone image pull uses the native architecture, while lifecycle resolution honors vm_arch;
  4. reuses a local file only after size, SHA-256, and qcow2 checks pass;
  5. otherwise downloads the repository artifact, with the Catalog’s immutable HTTPS upstream URL as fallback.

The current compiled default is the development repository https://m0/farrow; no public image service is claimed yet. An explicit repository failure is fatal, while an unreachable compiled default falls back to the embedded Catalog.

Runtime policy

Matching architectures use native HVF/KVM except one catalogued incompatibility: the stock EL8 arm64 64K-granule kernel cannot run through Apple HVF, so Apple Silicon uses visible same-architecture TCG automatically. Explicit foreign vm_arch also uses TCG. amd64-on-arm64 uses a single translation thread to preserve x86 memory ordering. TCG results are not performance evidence.

EL7 is deliberately limited to native Linux/amd64. Linux setup installs only the native QEMU family; foreign architectures require the matching system emulator and UEFI firmware before plan, up, or recreate can proceed.

farrow image pull --repo https://mirror.example/farrow u24
FARROW_REPO=/absolute/local/repository farrow up

Repository URLs may be HTTP or HTTPS because the Catalog signature and image digest remain authoritative; immutable upstream artifact URLs must be HTTPS.

Trust and verification

Current ordinary builds embed both production public verification keys. The private signing keys are external to the source repository. Catalog activation rejects unknown keys, malformed content, equivocation, and versions below the recorded high-water mark unless the operator explicitly allows a downgrade.

Every accepted image must be a size- and SHA-256-matched plain qcow2 with no backing file, external data file, encryption, or unknown incompatible feature. Verified base images become read-only; node root disks are overlays and never modify the base.

farrow image sync https://repo.example/farrow/catalog.json
farrow image sync --allow-downgrade /absolute/repo/catalog.json
farrow image reset-manifest

reset-manifest restores the embedded bootstrap Catalog but keeps the anti-rollback high-water mark.

Local layout and imports

Images live under FARROW_HOME/images (default ~/.farrow/images): family directories contain downloaded artifacts, manifests/ stores Catalog state, and local/ plus local-images.json hold imports. There is no old ~/.farrow/cache or content-addressed sha256/ hierarchy.

farrow image import --sha256 <digest> /path/to/base.qcow2
farrow image import --name local-mybase --boot uefi \
  --source-user ubuntu --sha256 <digest> /path/to/base.qcow2

Named local aliases must begin with local-, so a future signed Catalog cannot shadow them. --boot and --source-user are required with --name; Farrow does not guess the guest bootstrap contract.

Pruning

farrow image prune --dry-run
farrow image prune --yes

Prune lists exact unreferenced images and stale staging files before deletion. An image referenced by applied deployment state is never a candidate. Images remain cached after destroy, including destroy --purge.

The compiled Catalog can be exported byte-for-byte with go run ./tools/catalogexport /absolute/new/catalog.json. A public Catalog at the embedded version must use those exact bytes; same-version different bytes are rejected as equivocation. Release signing and image Catalog signing remain separate trust domains.

2.4 - Image Pipeline

Validate or offline-normalize an explicit qcow2 candidate without downloading, uploading, or signing it.

packaging/image-pipeline/ accepts one already-downloaded immutable qcow2 and an independently obtained SHA-256. It never downloads, uploads, touches Farrow runtime/network state, reads signing keys, or marks an image supported.

Modes

  • validate: copy/re-hash, force qcow2 inspection, validate the single backing chain, run qemu-img check, and emit an explicitly unpublishable evidence bundle. Guest credentials are not changed.
  • offline: additionally use libguestfs virt-customize --no-network and virt-cat on the staged copy. It rejects unrelated UID/GID 88 occupants, normalizes the locked dba/admin identity, disables password/root SSH, removes keys/history/host identity/cloud-init cache, restores targeted SELinux labels, and reads back a deterministic marker.
SOURCE_DATE_EPOCH=1787486400

./packaging/image-pipeline/build.sh \
  --mode validate \
  --source /absolute/source.qcow2 \
  --expected-sha256 <digest> \
  --output /absolute/new/evidence-directory \
  --name u24 --release 20260801.0.0 --arch amd64 \
  --source-user ubuntu --boot uefi \
  --source-uri https://immutable.example/source.qcow2 \
  --artifact-url 'https://images.example/u24/{sha256}.qcow2' \
  --license NOASSERTION \
  --source-date-epoch "$SOURCE_DATE_EPOCH" \
  --manifest-version 2026082801

Source/output paths must be absolute; source is canonical, regular, non-symlinked, stable while copied, and at most 16 GiB. Output must not exist. The builder uses an exclusive adjacent lock, mode-0700 staging, and one final rename. Failure removes only its guarded staging directory.

Every successful bundle contains the read-only qcow2, recipe, SLSA provenance, SPDX boundary SBOM, manifest-candidate.json (testing), validation evidence, and checksums. Signing is deliberately outside this pipeline. Validate mode is byte-reproducible for fixed inputs/tools; offline mutation must be built twice and compared before release evidence is accepted.

3 - About Farrow

The simplified product model, implementation boundaries, native evidence, current limits, and release gates.
  • Design explains why Farrow has one Inventory, one deployment, and one fixed-IP network.
  • Status separates implemented behavior, native validation, and remaining release gates.
  • Engineering defines source, generated-output, package, image-pipeline, and evidence boundaries.

3.1 - Design

Farrow’s simplified one-deployment architecture, networking, state, safety boundaries, and review conclusion.

One useful abstraction

Farrow boots one Pigsty Inventory as one local QEMU deployment. It deliberately has no project marker, project registry, lease model, provider layer, or second configuration format.

State lives under ~/.farrow for one Unix user. The product assumes one active Pigsty deployment per computer; this is not a root-enforced cross-user singleton.

Node-level convergence

Farrow extracts only the documented VM and Pigsty-native fields, computes per-node hashes, and keeps applied state plus process identity. Additions are incremental. Changes require an explicit per-node recreate. up also starts selected existing stopped nodes; already-running peers remain untouched. Absence never authorizes deletion.

Runtime selection

Guest architecture is deployment-wide desired state. Omitted/native follows the host; explicit amd64 or arm64 selects that Catalog artifact exactly. Native HVF/KVM remains the default. A foreign architecture or one catalogued image/host incompatibility selects a fixed TCG profile; there is no user accelerator argument and no arbitrary failure fallback.

The effective architecture and accelerator are persisted in each QEMU invocation and exposed by status. Before destructive recreate, Farrow proves the selected QEMU binary and version, network backend, image bytes, boot mode, and firmware. A later binary changing runtime policy cannot mix new nodes with old invocations: runtime drift requires whole-deployment recreation.

Two NICs, one fixed subnet

The management NIC supplies DHCP, DNS, egress, and loopback SSH. The fixed-IP NIC supplies host/peer/Ansible traffic. macOS uses socket_vmnet. Linux follows active NetworkManager; otherwise it uses systemd-networkd and connects through the distribution bridge helper. Inactive networkd is started only after an activation-safety scan proves existing units cannot claim a real host link.

On Debian, the helper is temporarily and reversibly scoped to a group the caller actually belongs to. A real unprivileged QEMU bridge smoke must pass before setup accepts the network; failure triggers manifest-bounded rollback.

Safety boundary

QEMU and all guest artifacts run as the caller. Root is limited to host network setup and the optional hosts publisher. Destruction requires matching ownership, containment, node identity, QMP/process identity, and an allowlist of artifacts. Ambiguity stops the operation.

Review conclusion

The pivot away from projects and leases is correct for a one-lab product and greatly reduces cognitive and state complexity. Native review was still essential: the first implementation had cross-layer gaps in control-node keys, sudo policy, Debian helper access, NetworkManager verification, runtime preflight, result messages, and failed-install cleanup. Those paths were fixed and replayed on macOS and Linux before this documentation was simplified. A later adversarial review also caught destructive preflight ordering and signed Catalog-baseline upgrade bugs before EL7/EL8 compatibility was committed.

3.2 - Status

What the current simplified tree has passed natively, what remains unverified, and what blocks 1.0.

Farrow is pre-1.0. Source tests, dated native replays, packages, release, CI, and the public site are separate gates.

Last recorded native replay — 2026-08-27

This matrix belongs to the exact checkpoint exercised that day. Later source or documentation edits do not inherit native proof without another replay.

Host Path Result
macOS 26.6.2 arm64 HVF, QEMU 11.1, socket_vmnet one node and additive four nodes passed
Ubuntu 26.04 amd64 (mx) KVM, QEMU 10.2.1, NetworkManager setup, one node, additive four nodes, and uninstall passed

Both hosts passed fixed IP, SSH readiness, default CPU/memory/root/data disk, cloud-init, stop/start, cross-directory commands, unchanged control-node boot ID during scale-out, control-to-peer SSH, ignored unconsumed Pigsty changes, absence-never-destroys, and explicit destroy.

Linux additionally proved valid NOPASSWD automation, caller-accessible Debian helper policy, unprivileged bridge smoke, refusal to uninstall with four tap members, and exact restoration after destroy.

Interactive host-network and hosts commands now invoke sudo themselves; an external sudo -v is optional. Darwin cleanup can reconstruct an uninstall- only ownership plan from byte-identical interface evidence, the exact launchd plist, and installed binary digests when network.json is missing.

On 2026-08-28 the post-calibration tree passed unit, race, vet, staticcheck, govulncheck, all four cross-builds, the simulated image-pipeline boundary, license verification, and GoReleaser configuration validation. An isolated local GoReleaser snapshot also built and verified all four archives, both DEB/RPM architectures, SPDX documents, checksums, dependencies, modes, and archive/package parity. Nothing was published, and those results do not extend this native matrix.

EL7/EL8 compatibility — 2026-08-28

Commit 7c666c7 restored EL7/EL8 after two independent Claude Code Opus 5 max adversarial reviews. The first review blocked on destructive runtime preflight ordering and signed-Catalog baseline migration; both were fixed, regression tested, and the second review returned PASS with no required fixes.

Catalog 2026082801 is signed and active on the development repository: 9 families, 17 image artifacts, and 19 SHA-verified repository payloads including the two socket_vmnet archives. A clean client accepted the public signature and exact embedded digest.

An isolated macOS arm64 lifecycle replay booted Rocky Linux 8.10 arm64 with the built-in TCG compatibility rule, passed stop/start and readiness in 44.2 seconds, and verified NetworkManager, fixed IP/no-route/no-DNS, dba UID/GID 88, and the generation/spec marker. EL7 bytes, qcow2 structure, BIOS layout, and 4K XFS root are verified; the current native Linux/amd64 Farrow lifecycle replay remains open.

Still open

  • EL9 + NetworkManager + firewalld native replay;
  • current systemd-networkd replay;
  • host reboot persistence;
  • macOS amd64 and Linux arm64 native runs;
  • EL7 through the current native Linux/amd64 lifecycle;
  • current 9p share replay;
  • a complete current Pigsty configure → farrow up → install.yml run;
  • published Homebrew/DEB/RPM consumption and release CI.

Current images remain testing, except EOL EL7 which is deprecated. Active and standby Catalog public keys are embedded, but the repository must move off the development host and private-key custody/rotation plus release custody must be formalized before 1.0.

3.3 - Engineering

Source layout, build and test gates, image normalization, release outputs, and evidence policy.

Repository boundary

The Farrow source repository contains code, tests, build/package definitions, legal notices, and a short landing README. This site is the authoritative home for user, design, operator, and release documentation. Raw review transcripts, historical scratch inventories, demo directories, generated binaries, and release output trees are not source inputs and must not be committed.

Generated output is disposable:

  • bin/ — development builds;
  • dist/ and .goreleaser-* — release/snapshot staging;
  • root farrow, farrow-hosts-helper, and catalogsign binaries;
  • Hugo public/ and resources/.

Build and source gates

make build
make test
make race
make vet
make staticcheck
make vuln
make cross-check
make image-pipeline-test
make license-check

make check combines these gates. A source gate is not native VM evidence; macOS HVF, Linux KVM/networking, package consumption, release publication, and the public render remain separate gates.

Release and package contract

Release tooling under packaging/, .goreleaser.yaml, and .github/workflows is source, even though its generated directories are not. Archives and Linux packages contain the matching binaries plus LICENSE, the minimal source README, build metadata, and exact upstream license bytes reconstructed from the module versions pinned by go.mod. Those generated license texts live under licenses/ in archives and are not tracked as source. Detailed documentation stays on this versioned site rather than being copied into every binary payload.

Never infer publication from a successful build. Commit, tag, archive/package, signature/attestation, upload, CI, and public consumption are distinct gates.

Image normalization

packaging/image-pipeline/ accepts an explicit local qcow2 source; it never downloads or uploads. It copies and hashes the source, forces qcow2 parsing, rejects backing/external/encrypted/unknown features, runs qemu-img check, and can perform a no-network offline Guest mutation in an explicit QEMU sandbox. UID/GID 88 collisions are rejected rather than rewritten ambiguously.

Catalog bytes are exported with:

go run ./tools/catalogexport /absolute/new/catalog.json

The exporter is atomic and no-clobber. Catalog signing and application release signing use separate keys and trust domains.

Evidence policy

Historical M0–M4 notes were useful during implementation but are not product documentation. Their durable conclusions are condensed into Design and Status. A later source edit inherits no native proof; every status claim names its date, host, path, and remaining gates.