FormalOS

Commands

Every fspec command and flag, grouped by what you use it for.

fspec <command> --help prints the same information from the binary you have installed.

Global options

These work with every command.

OptionDefaultMeaning
-s, --spec <path>spec.starThe spec entry point. The lock and secrets.star sit next to it
--root <dir>/Treat this directory as /. Commands are logged to <root>/var/log/fspec-commands.log instead of run, so you can try an apply safely
--home <dir>$HOMEThe user's home (with --root, <root>/home/<user>)

--host <name> appears on most commands. Without it, the command acts on the host whose name matches this machine.

Everyday

fspec update

fspec update [<pkg>...] [--cache] [--images] [--registry <r>]

Resolves versions, URLs and hashes from upstream and rewrites fspec.lock. Prints one line per change. With package names, re-resolves only those and keeps every other entry and every gh: load at its locked commit. Entries no host declares are dropped.

FlagMeaning
--cacheAlso record the OCI digest of each CI-built git(...) package (Building from source)
--imagesPin each image host's pushed image digest instead of resolving packages (The system layer)
--registry <r>Registry for --images (default ghcr.io/<owner>) or --cache (default ghcr.io/<owner>/fspec-cache)

In a directory with a dev.star and no spec.star, it locks the project environment instead.

fspec plan

fspec plan [--host <h> | --all] [--json] [--dirty]

Shows what apply would change. Never changes anything.

FlagMeaning
--host <h>Plan this host
--allPlan every host, asking each remote host over ssh. An unreachable one prints unreachable, skipped
--jsonPrint the plan as JSON
--dirtyShip a spec with uncommitted changes to remote hosts anyway

How FormalSpec works explains the output.

fspec apply

fspec apply [--host <h> | --all] [--dirty] [--scope system|user]

Converges a host. A remote host is reached over ssh.

FlagMeaning
--host <h>Apply this host
--allApply every remote host in spec order, then this machine. Stops at the first failure
--dirtyAllow uncommitted changes when applying remote hosts
--scope <s>Apply only the system or the user scope. Without it, the system scope runs through sudo, then the user scope

fspec rollback

fspec rollback [<generation>] [--host <h>] [--scope system|user]

Re-applies an earlier generation as a new one, the previous one by default. Packages, files, services and app data come back. fspec.lock is not changed.

fspec gc

fspec gc --older-than <age> [--host <h>] [--scope system|user]

Deletes generations, their trash and the store paths no kept generation uses, when last touched longer ago than <age> (90s, 30m, 12h, 14d, 2w). The current generation is always kept. --older-than 0s keeps only what the current generation needs.

Files and app data

CommandDoes
fspec adopt <path> [--host <h>]Copies an app's edit of a managed file back into the spec repository. <path> is the path as the spec writes it (~/.config/x) or on disk
fspec watchReports drift on managed files as it happens
fspec orphans [--host <h>]Lists app data under ~/.config, ~/.local/share, ~/.local/state and ~/.cache that no package claims
fspec orphans --claim <path> <pkg>Records <path> as <pkg>'s data, so removing the package trashes it
fspec orphans --delete <path>Moves <path> to the trash

Secrets

CommandDoes
fspec secret edit <file> [-i <identity>]...Decrypts a secret into $EDITOR and encrypts the result to the recipients in secrets.star. A file that does not exist yet starts empty
fspec secret rekey [-i <identity>]...Re-encrypts every secret to its current recipients
fspec secret install [--scope system|user]Decrypts the last apply's secrets again from their kept ciphertext, for a boot that starts with an empty /run

<file> is the secrets.star key, its file name, or the name without .age. -i is repeatable; the default identities are ~/.ssh/id_ed25519, ~/.ssh/id_rsa and ~/.config/fspec/age.key. See Secrets.

Project environments

CommandDoes
fspec devOpens $SHELL in the environment of the nearest dev.star
fspec dev -- <cmd>Runs one command in it
fspec dev planShows what the environment holds and what the lock could not resolve
fspec dev up / fspec dev downStarts the project's services and leaves them running, or stops them
fspec dev exportPrints the bash that turns the current environment into the project's
fspec dev direnvPrints the direnv library that defines use fspec

All take --dir <dir> to use another project directory. See Project environments.

Sync

fspec sync [<item>...] [--peer <h>] [--from <h>] [--rollback] [--dry-run] [--watch [<seconds>]]

Syncs app data with the other hosts that list the same sync(...) item, every item this host lists by default.

FlagMeaning
--peer <h>Only with this peer
--from <h>Copy each item from this host over the other's copy. The handoff of a seed item
--rollbackPut the items' previous version back on this host
--dry-runPrint what would move, change nothing
--watch [<seconds>]Sync again every 60 seconds, or the given interval, until stopped

See Sync between hosts.

Builds and CI

CommandDoes
fspec build --pkg <p> --platform <t> --out <dir> [--host <h>]Builds a git(...) package at its locked commit into <dir>/<p>-<t>.tar.zst. <t> must be this machine's platform. With --host, tries that host's builders first
fspec ci packagesWrites .github/workflows/fspec-packages.yml, which builds every git(...) package per platform and pushes it to the OCI cache
fspec ci init [--registry <r>]Writes .github/workflows/fspec-images.yml, which builds and pushes every image host's bootc image
fspec image containerfile [--host <h>]Prints the Containerfile CI builds for an image host

Distros and disks

These change how the machine boots. Read Switching distros before you run any of them. All need root.

CommandDoes
fspec switch --distro <d> --host <h> [--release <r>]Bootstraps the distro the host declares into a new btrfs root beside this one. <d> is fedora, arch, debian, ubuntu, void or aerynos. --release is the Fedora release or Debian/Ubuntu suite
fspec switch --beside <name> [--inherit @<root>] [--device <part>]Installs the host's tumbleweed() into @<name>, beside the other roots
fspec switch --to-image --yesConverts this classic system to the host's bootc image. Reinitialises /boot
fspec switch --to-image --beside <name> [--inherit @<root>] [--pull-from <repo>]Installs the host's bootc image into @<name> beside this root
fspec switch --adopt-bootMakes the running root own boot, so the old one can be forgotten
fspec switch --reset-varStages a reset of /etc and /var to the image's defaults for the next boot of a bootc host
fspec forget <distro>Deletes a root made by switch, or the NixOS a migration kept, and its boot entries
fspec disk plan [<device>] [--nixos-system <path>]Prints the steps that bring a disk onto a supported layout
fspec disk migrate [<device>] [--backup <path> | --no-backup] [--swap <GiB>] [--nixos-system <path>]Runs the in-place steps of disk plan
fspec disk init <device> [--layout default|zfs|bios] [--luks] [--distro <d> --host <h>] [--release <r>] [--backup <path>] [--swap <GiB>]Partitions and formats a disk from scratch
fspec disk unmask [--esp <dir>]After the first good boot of a migrated NixOS, drops the trial boot options

Diagnostics

CommandDoes
fspec facts [--json]Prints this machine's host name, platform and distro, as apply compares them with the declaration
fspec --versionPrints the version