Commands
NAILS is one binary that lives on the hidden volume. Run every command with
sudo and the binary’s full path, for example sudo /mnt/data/nails status.
sudo does not search the hidden volume, so a bare sudo nails is not found.
nails <command> --help prints the help for each command, with examples, and
nails --version prints the version.
activate and deactivate soft-reboot the machine, so every program closes and
you are logged out. emergency kills the hidden session at once and returns to
the decoy or powers off.
On the decoy
Section titled “On the decoy”init <PATH>lays out a mounted hidden volume, once. It refuses a target that is not a volume of its own before it writes or probes anything.checkreports readiness to activate and changes nothing. It runs the same pre-flight checks asactivate.doctoris an alias.activatesoft-reboots into the hidden session.recoverremoves what an interrupted activation left in/runand resets the state. It never reboots, and it refuses to run in the hidden session.reset-upper <PATH>deletes a path’s hidden copy from the upper layer, so the decoy’s own files show through again. It is refused in the hidden session.
In the hidden session
Section titled “In the hidden session”deactivatesoft-reboots back to the plain decoy. Every program gets an orderly stop first, so applications can save.verifyscans for known artifacts, live or with--offlineagainst a mounted decoy image. A clean result is evidence, not proof.
In either place
Section titled “In either place”emergencykills every hidden program at once and soft-reboots back to the decoy, or powers off. It never asks for confirmation. On the decoy, it removes what an interrupted activation left.statusshows the session, the security posture and the hidden volume’s free space.rehearse plantputs a canary in a hidden session, andrehearse scanthen searches the raw decoy disk for it, from the decoy or a later session.rehearsealone shows where the rehearsal stands, andrehearse resetremoves it from the hidden volume.config path,config showandconfig validatelocate, inspect or check the configuration file.completions <SHELL>prints a completion script forbash,elvish,fish,powershellorzsh. It installs nothing, sosource <(/mnt/data/nails completions bash)in the hidden session leaves no completion file on the decoy.
Ending a session compares deactivate, emergency
and recover. Check your setup walks through
check, verify and rehearse.
Options by command
Section titled “Options by command”activate and check
Section titled “activate and check”activate --dry-runpreviews the activation steps without changing anything.activate --overlay-onlyenters with the decoy’s own NixOS system, without building the hidden configuration. The hidden/etcand home still apply.activate --nixos-flake <REF>builds the hidden NixOS system from a flake, such as/mnt/data/nixos#my-host.checktakes--overlay-onlyand--nixos-flaketoo, to check what that activation would do.--accept-persistent-decoyonactivateandcheckaccepts a decoy that keeps a persistent journal or runs a syslog or audit daemon, instead of refusing it. What the decoy logs while it shuts down for the soft-reboot, and while it starts again afterwards, then survives on its disk. It never overrides the swap check.--allow-decoy-storageoninit,activateandcheckturns the refusal of a hidden root that this computer’s own storage seems to hold into a warning. Use it only for storage you know the decoy does not use, such as a disk its fstab lists but never mounts. It never accepts a folder, a root with a second filesystem mounted over it or storage that cannot be judged.activate --no-preflightskips the pre-flight checks. The help marks it as dangerous and for expert use only. It never skips the check that the hidden root is a volume of its own, thebackend-entriescheck or the refusal to build the decoy’s own NixOS flake.
deactivate and emergency
Section titled “deactivate and emergency”deactivate --poweroffpowers off instead of returning to the decoy. Powering off lets RAM decay, so leave the machine off for a few minutes before you hand it over.emergency --poweroffpowers off instead of returning to the decoy, whatever the outcome.emergency --rebootreboots fully, through the firmware and boot loader. A warm reboot does not clear RAM, so prefer--poweroffwhen RAM residue matters.emergency --countdown <SECS>waits first, with a hint that Ctrl+C aborts. Without it,emergencyacts at once.
verify, status and init
Section titled “verify, status and init”verify --deepadds homes, shell histories, temporary and log directories and the journal to the scan.verify --offline --root <MOUNT>scans a decoy image or partition mounted read-only, instead of the live host.verify --offline --examineradds the setup traces an examiner looks for, such as encryption headers, containers and crypttab lines, and reports them without changing anything.--disk <DEVICE>adds the partition-level checks.status --detailsadds resolved paths and overlay details.init --no-hardware-configskips the hidden NixOS layout, andinit --hardware-config <PATH>seeds it from another file than/etc/nixos/hardware-configuration.nix.
Confirmation and Ctrl+C
Section titled “Confirmation and Ctrl+C”activate, deactivate and reset-upper ask for confirmation on a terminal.
Without a terminal they refuse with exit code 2 and the error code
needs_confirmation, so add -y to every script, key binding or unit that runs
them. emergency never asks. Answering n cancels with exit code 1 and changes
nothing.
During an activation, Ctrl+C or a SIGTERM cancels it at its next step, up to
the soft-reboot, and removes everything it built, with exit code 130. A step
that runs a program to its end, such as the hidden NixOS system’s activation,
finishes first. At the confirmation prompt of activate, Ctrl+C ends the prompt
at once. Troubleshooting says what to do when a
command refuses or an activation is interrupted.
Global options
Section titled “Global options”nails init does not take --config, and nails emergency reads no
configuration. Otherwise these options work with every command, in any position.
| Option | Effect |
|---|---|
-c, --config <PATH> | Read this configuration file instead of the one next to the binary |
-v, --verbose | More diagnostics on standard error. -vv adds trace output |
-q, --quiet | Print only errors and the final result |
--color <WHEN> | auto (the default), always or never |
--ascii | Use ASCII markers instead of Unicode symbols and box drawing |
--json | Print machine-readable JSON on standard output |
--no-log-file | Do not write the log file on the hidden volume for this run |
With auto, NAILS colors a stream only when it is a terminal, TERM is not
dumb and NO_COLOR is unset or empty.
Exit codes
Section titled “Exit codes”Every command returns one of these codes, and scripts can rely on them.
| Code | Meaning |
|---|---|
0 | Success |
1 | The operation failed |
2 | Command-line usage error |
3 | The configuration file or environment was unusable |
4 | A pre-flight check refused the operation |
5 | The operation needs privileges it did not have |
6 | The on-disk state could not be trusted |
7 | A degraded or interrupted session, or an incomplete cleanup. nails status names the fix, usually nails recover |
8 | The host is not one NAILS can operate on |
9 | Completed, but with a warning the caller should act on |
10 | verify found warnings |
11 | verify found critical artifacts, or rehearse scan found its canary |
130 | Canceled by SIGINT (Ctrl+C) or SIGTERM. An activation in progress is rolled back |
Some commands use these codes in a specific way:
checkexits with4while a check fails.statusexits with7on a degraded posture or after an interrupted activation, and with6on a state file it cannot trust.verifyexits with0,10or11for no known artifacts, warnings or critical findings, with1when the scan could not run and with3when the configuration could not be loaded.rehearse scanexits with0when the canary is not found,11when it is, and9when a device could not be scanned completely.emergencyexits with7when it leaves a mount behind or can only ask the kernel to power off.- A command that changes something exits with
5when run without root.activate,deactivate,emergencyandrecoverrefuse before they write anything and print the fullsudoline to use.
JSON output
Section titled “JSON output”With --json, every command writes one line with a stable envelope. It holds
schema_version, currently 1, the command name, an ok boolean and either
a typed data object or an error object with a snake_case code, a message
and an optional hint. activate is the exception. It prints a progress line
first and then its result, one JSON object per line. Log lines go to standard
error. A new schema version signals an incompatible change. The schemas are in
the repository’s
docs/schemas
directory.
Full details
Section titled “Full details”The CLI reference
is generated from the code and lists every flag. It also ships as the nails.1
man page. The README’s
Commands section
has the same command overview.