Skip to content

CLI

Barn commands, important flags, structured output, and exit codes.

This reference describes the Barn 0.9.0 release candidate. Check barn version before scripting against these contracts. See the release status.

barn [--json|--yaml] [-v|--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:

barn --help
barn setup --help
barn image pull --help

Bare barn prints a short welcome with next commands, exits 0, and exposes actions[] in JSON/YAML. A bare namespace such as barn image still exits 2 (human help in text mode, a structured usage error in JSON/YAML). Explicit --help always renders human help and exits 0. Use barn --version or barn version to inspect the build identity.

Commands

Area Commands
Prepare setup, init, validate, doctor
Lifecycle plan, up, start, stop, restart, reload, recreate, status, destroy, purge
Access ssh, exec, logs, provision, ssh-config, hosts install/uninstall
Images update, image list/info/pull/import/sync/prune/reset, repo scan/build/verify
Host network network status/install/uninstall
macOS guests (unreleased) mac …; see Mac Commands
Misc version, completion

No command refreshes the Catalog implicitly. update fetches the configured repository’s Catalog, verifies it, and activates it; image sync is the explicit recovery path for an exact URL or file. Ordinary commands use the active local Catalog. Neither operation updates the Barn executable.

Frequently used commands have scoped aliases:

Command Aliases Command Aliases
setup s validate v
plan pl recreate rc
status st destroy de
ssh-config sc image images, im
doctor dt network n, net
exec / logs ex / l version ver

up, ssh, init, start, stop, restart, reload, provision, hosts, and completion have no aliases. Use the explicit barn purge spelling; rm is not a command alias. Inside a namespace, hosts and network use i/u for install/uninstall; network status uses st; and image maps list=ls, info=in, pull=p, prune=pr, sync=sy, and import=i.

Barn manages one deployment in the selected BARN_HOME (default ~/.barn), independently of the inventory directory. 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; --force explicitly replaces the output
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; they use applied state

When neither an inventory nor an applied deployment exists, interactive up can generate the default inventory. It can also prepare missing host dependencies and restore an intact inactive Barn network. This implicit preparation accepts the setup plan; sudo may still request credentials. Use setup --dry-run to review the host plan first. Scripts should run setup --yes explicitly; init is optional when no inventory exists.

Important flags

Flag Meaning
--json, --yaml machine-readable stdout; progress remains on stderr; intentionally no shorthand
-v, --verbose bounded diagnostics on stderr
-c, --cidr select the RFC1918 /24 for generated init/setup templates or host-network inspection/install
-f, --file select an Inventory for commands that read desired state
-r, --repo select a repository where exposed; overrides --mirror and BARN_REPO; validate gains this flag in the 0.9 candidate
--mirror use the China official repository for setup, Catalog, and image-resolving lifecycle commands
-m, --mode select host or shared where the command exposes the macOS network mode
-d, --dry-run show a setup/image plan without changing state
-y, --yes apply a displayed host/setup/image plan
--force (init, destroy, recreate) overwrite generated output or skip the typed confirmation; long-only because -f selects the Inventory
-n, --no-wait return once QEMU is running, without readiness or guest recovery checks
--rollback (up, reload) remove the prepare artifacts of nodes that failed to prepare in this run
--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

Flags belong to commands; the following table lists the less obvious scopes:

Command Local controls
init --output/-o (default ./barn.yml; - prints), --cidr/-c, --force
plan --file/-f, --repo/-r; no --mirror or --dry-run
start, restart --no-wait/-n; no --file or repository selection
provision required --script/-s; --sudo uses guest sudo -n; --parallel/-p is 1–4 (default 1); --timeout/-t is positive, at most 24h (default 1h)
ssh-config --install/-i or --remove (exclusive); --name defaults to barn; removal accepts no nodes and requires no deployment
logs --source/-s serial|qemu|events (default serial); --follow/-f; events accept no node
image info, image pull optional image selector, --arch/-a amd64|arm64, --repo/-r; only pull accepts --mirror
image import --sha256/-s; --name local-* also requires --boot/-b bios|uefi and --source-user/-u
image prune --dry-run/-d or --yes/-y (exclusive); --repo/-r
image sync URL or path, --repo/-r, and explicit --allow-downgrade
network install --cidr/-c (default 10.10.10.0/24), --mode/-m (default host), --yes/-y; macOS-only --archive/-a, --interface-id/-i
network status optional --cidr/-c; no --file
network uninstall, hosts install/uninstall --yes/-y

setup --dry-run and setup --yes are mutually exclusive. --cidr rebases a generated template; it does not rewrite an explicitly selected inventory. validate --repo is available in the 0.9 candidate and has no --mirror; use --repo https://repo.pigsty.cc/barn when checking that catalog.

In the 0.9 candidate, network and hosts install/uninstall show a plan and ask on a terminal (install defaults to yes, uninstall to no); without a terminal they only show the plan unless --yes is supplied. For a fresh macOS network, use setup; the candidate’s network install directs you there before asking for sudo. --yes accepts Barn’s plan but cannot supply a sudo password.

Rare, selection, or safety-widening controls such as --mirror, --force, --rollback, --remove, --allow-downgrade, --sudo, --delete-persistent, and --purge are long-only. On commands that read an Inventory, -f always selects a file; logs -f retains the conventional --follow. -n always means --no-wait, and -d always means a dry run.

With a deployment, barn purge performs the same disposal as barn destroy --force --purge, without confirmation. It accepts no nodes or Inventory, removes the complete deployment plus persistent disks, keys, state, and the default SSH fragment, and keeps images and the host network. With no deployment it succeeds without changing the image cache, and can remove provably owned retained disks. Missing state never authorizes deletion of residual node artifacts whose identity cannot be proven. In the 0.9 candidate, plain whole-deployment destroy without a deployment also succeeds; destroy --force --delete-persistent and destroy --force --purge without state instead fail with a hint to use purge.

Structured failures (0.9 candidate)

The following unified failure contract describes the Barn 0.9.0 release candidate.

Ordinary failures print error: <message> on stderr, the failing program’s last stderr lines when an external tool failed, and a next: line when there is one clear action. SSH child exit failures are silent because the child has its own output. If a failing command supplies no richer typed result, structured mode writes a generic failure object before returning the exit code: error (the class below), message, and where they apply a stable reason, next, operation_id, and command (name, argv, exit_status, signal, timed_out, stderr) for a failed external program. Existing typed failure results are never followed by a second JSON/YAML document. The closed generic error classes are listed below. recreate_required and nodes_removed are now reason values under error: "conflict", and the old resource_conflict class is now resource.

A nonzero exit does not guarantee that stdout has this generic envelope. doctor, network, provision, lifecycle operations, and remote commands can return their own report schemas. SSH child exits are internally classified as remote_exit, but their public result has fields such as success, exit_code, stdout, and stderr; its optional error is not the generic class contract. Always preserve the process exit code and interpret the payload for that command.

Lifecycle results

plan is read-only and returns success even when its action is recreate or blocked-removal; automation must inspect the action and create, recreate, start, missing, and blocked fields. For catalog images, plans read local configuration and catalog data without requiring QEMU or host networking. A registered local-* image also undergoes cache validation and requires qemu-img. Plans download no images. They show exact images, total resources, change reasons, and disk effects. The 0.9 candidate also lists each data disk, including the implicit 128 GiB /data. up checks host capabilities and address availability before applying changes. up creates missing nodes, starts stopped ones, re-checks readiness of running ones, and rewrites the SSH client configuration Barn installed from the complete applied deployment. recreate performs the same full refresh; node destroy removes stale entries, and whole destroy removes that configuration. start powers on stopped nodes and re-checks readiness of running ones; start and restart also refresh SSH aliases. Destructive drift returns a conflict that names the next commands: barn plan, then barn recreate <node> or barn destroy <node>. On a terminal those commands ask you to type the confirmation word; --force is for scripts. If VM lifecycle succeeds but the SSH client configuration cannot be written, the command reports a warning and remains successful; barn ssh still works. Structured output carries integration warnings in warnings[]. The 0.9 candidate leaves symlinked or hard-linked ~/.ssh/config untouched, publishes its fragment, and reports the Include line to add manually.

Guest management SSH is the readiness boundary. Optional setup failures are reported in nodes[].warnings; completed recovery actions, including data resets, are in nodes[].repairs. A usable guest with these limitations exits 0. Repeat up to retry unfinished stages without restarting running VMs. Inspect the warning fields when automation requires every configured feature.

A lifecycle batch with isolated node failures can exit 5 even when every selected node failed; it reports N of M node(s) failed: <node> (<stage>: <error>); .... Common stages include prepare, start, readiness, bootstrap, guest-setup, stop, and status; readiness or bootstrap failures add run \barn logs ` for the guest console. Structured output carries failures[]withnode, stage, and error(and optionalreasonin the **0.9 candidate**), plusrolled_backwhen–rollback` removed the prepare artifacts of nodes that never committed. See A node did not become ready.

status shows node, state, IP, exact image, and CPU/memory. Use --verbose for SSH ports, architecture, accelerator, and PID. TCG is marked in ordinary text as well. One degraded node does not hide its peers; status exits 5 and retains per-node errors and failures[]. Running means the VM process is running; status does not claim to have checked guest readiness.

Starting commands also refresh Barn hosts and control-node SSH entries in running guests. Stopped guests catch up when started. --no-wait skips guest readiness, guest recovery, and that refresh; a later up completes them. Selected recreate refuses remaining peer drift before stopping or deleting disks; select the required nodes together as directed.

The control guest’s Barn-managed SSH entries accept replacement host keys without recording them in known_hosts, so recreated lab nodes remain reachable. User-added SSH entries are preserved.

Recovery

up and start isolate missing host-share failures by node; up also continues existing stopped peers when a new node fails to prepare. Partial results keep exit code 5 and preserve successful nodes. Retry hints retain the inventory, repository and applicable flags; a start retry remains start.

Setup and its lifecycle retry share one operation_id. Even before deployment state exists, barn logs --source events --json can read the bounded phase trace after failed setup. Setup traces omit command arguments and authentication data; retain the command output for its detailed cause. setup --dry-run writes no trace. Successful destroy --delete-persistent and purge summaries describe the final deletion/retention result; purge leaves the image cache and host network. Owned persistent disks left by a previously removed node no longer block destroying the remaining nodes. Ordinary destroy retains those disks; explicit persistent deletion or purge is still required to remove them.

On macOS, fresh network setup finishes Homebrew discovery/installation or the pinned-archive download before requesting administrator authentication. Homebrew can invalidate an earlier sudo credential; the new order avoids that failure without widening the privileged operation. Failed downloads do not prompt.

Interrupted operations (0.9 candidate)

The candidate recognizes a recorded QEMU PID reused by an unrelated process as a stopped node. An interrupted stop whose VM still runs is reconciled to running; other unfinished transitions name the command that can finish them. destroy settles interrupted transitions itself. A failed first up can be retried after editing the inventory because its uncommitted artifacts are rolled back from the journal.

Logs and environment

logs defaults to the guest serial console; --source qemu reads QEMU diagnostics, and --source events reads the deployment-wide bounded event log. With --follow, text output streams bytes and JSON emits NDJSON records (YAML emits a document stream). The 0.9 candidate renders ordinary event/QEMU log reads as readable records, showing a QEMU argv only with --verbose.

Environment variable Purpose
BARN_HOME absolute private state directory; default ~/.barn; not a symlink or broad directory such as your home
BARN_REPO repository default; overridden by --mirror, then --repo where exposed
BARN_OUTPUT text, json, or yaml; presentation flags override it
BARN_VERBOSE boolean diagnostic default; presentation flags override it
BARN_VMNET_ARCHIVE absolute path to the pinned socket_vmnet archive for macOS setup; digest checks still apply
NO_COLOR non-empty disables color

SSH passthrough and completion

barn ssh [node] [--] [command ...] opens a session or runs an optional command. barn exec [node] [--] <command ...> requires a command and passes through its exit status. Presentation flags before -- belong to Barn; ssh arguments after -- are joined with spaces and interpreted by the remote shell, like plain SSH. exec preserves argument boundaries; explicitly use sh -c when you need shell expansion or pipelines. A single command string retains the shell shorthand. Before --, only zero or one known node is accepted. For convenience, omitting -- uses a known first argument as the node, or runs all arguments as a command on the default node with a warning. In the 0.9 candidate, a first argument containing a digit or - is checked for a near-miss node name: at most one edit for words of four characters or fewer, or two edits for longer words. Such a typo is refused; ordinary commands such as ls, df, and wc still run. Use an explicit -- in scripts.

Load barn completion bash|zsh|fish|powershell for command and scoped-flag completion. It also provides command aliases, templates, image aliases, closed flag choices, and best-effort node names from the desired or applied specification. In the 0.9 candidate, -f completion filters for YAML files.

Exit codes

This table gives the Barn 0.9.0 release candidate exit-code contract. Missing inventory and unknown images are usage errors (2); setup and network failures use runtime (1) or capability (3), according to their cause.

Code error Meaning
0 success, including usable guests with optional limitations
1 runtime the operation ran and failed (a tool, download, or guest failed)
2 usage the command line or inventory is wrong
3 capability the host lacks a tool, the Barn network, or a privilege
4 conflict the deployment’s state forbids it, or another barn command holds it
5 partial node-level batch failures; inspect failures[]; any successful peers are retained
6 resource a host address, port, subnet, or disk is taken
7 integrity a verified digest, signature, identity, or ownership did not match
130 cancelled interrupted (SIGINT/SIGTERM) or confirmation declined

In the 0.9 candidate, a modifying command that finds another Barn command holding the deployment waits up to 10 minutes and names it; timeout is exit 4 with reason: "deployment_busy". status, ssh, exec, ssh-config, and hosts do not wait. status reports the concurrent operation in note while showing recorded state; this is not a guarantee of a completed deployment.

ssh and exec pass through the SSH child exit code unchanged, including 255. That value may indicate an SSH connection failure or a remote command returning 255; text, JSON, and process exit status agree.