ZoiOS Management
Declarative system management features exclusive to ZoiOS distributions.
ZoiOS (and its reference implementation, Parlex Linux) features a declarative system management engine powered by Zoi. These features allow you to manage the entire operating system state using a single Lua configuration file.
The commands on this page are only available on ZoiOS-based systems. Generic Linux, macOS, and Windows installations of Zoi do not include these features.
The zoi system Command
The zoi system suite is used to manage system-level generations and configuration.
zoi.system.apply [file]
Reads a system.lua file and applies its state to the machine. This involves:
- Resolving all required packages.
- Creating a new System Generation record.
- Directly installing/updating packages in the system root within an atomic transaction.
- Declarative State Enforcement: Automatically identifies and removes any packages currently installed in the system scope that are not explicitly listed in the configuration file.
# Apply the default system configuration
sudo zoi system apply
# Apply a specific configuration file
sudo zoi system apply ./my-server.luazoi system distro build --target <path> --config <file>
The primary command for bootstrapping new ZoiOS systems onto manually partitioned and formatted disks.
Safety Features:
- Pre-flight Validation: Automatically verifies that all base packages exist in your registry before touching the disk.
- Build Plan Summary: Shows a detailed table of configured filesystems and packages before proceeding.
- Dry-Run Mode: Use
--dry-runto see exactly what commands will be executed without modifying your hardware.
# Preview the build plan
sudo zoi system distro build --target /mnt --config ./system.lua --dry-run
# Orchestrate the full build
sudo zoi system distro build --target /mnt --config ./system.luazoi system distro chroot <target>
Enter a ZoiOS sysroot (chroot) with automatic device mounting and sandbox protection. This is the recommended way to run commands like dracut or grub-install during the final stages of bootstrapping a ZoiOS installation, as it ensures all operations are safely contained within the target environment.
Options:
--run <command>: Run a specific command inside the chroot and exit, rather than dropping into an interactive shell.
# Enter an interactive shell inside the ZoiOS root
sudo zoi system distro chroot /mnt/zoios
# Run a specific command inside the ZoiOS root
sudo zoi system distro chroot /mnt/zoios --run "grub-mkconfig -o /boot/grub/grub.cfg"zoi system list
Lists all available system generations on the machine, including their creation date, the packages they contain, and their linked Zoi transaction IDs.
zoi system listzoi system status
Shows the current system status, including the active generation ID and transaction state.
zoi system statuszoi system rollback <id>
Reverts the operating system to a previous generation by sequentially rolling back the Zoi package transactions that occurred after the target generation.
sudo zoi system rollback 41zoi system pin <id>
Pins a specific system generation to prevent it from being automatically pruned. Pinned generations are ignored by the system_generations_limit cleanup logic.
sudo zoi system pin 42zoi system unpin <id>
Unpins a generation, allowing it to be pruned if it exceeds the system generations limit.
sudo zoi system unpin 42zoi system secret
Manage sensitive information like passwords, API keys, and ZoiSEC master keys.
zoi system secret hash <password>: Generates a one-way Argon2 hash of a password. Use this in yoursystem.luafor user passwords.zoi system secret encrypt <value>: Encrypts a string so only Zoi on this specific machine can decrypt it. It returns aZOISEC:v1:...string.zoi system secret decrypt <ZOISEC>: Decrypts aZOISECstring back to plaintext.zoi system secret export-key: Exports the machine-specific ZoiSEC master key as a base64 string. Use this to make your secrets portable to other machines.zoi system secret import-key <key>: Imports a base64-encoded ZoiSEC master key.
Security Warning
The ZoiSEC master key is the root of trust for all your encrypted secrets.
Keep it safe! If someone obtains your master key, they can decrypt all your
ZOISEC strings.
zoi system secret
Manage sensitive information like passwords, API keys, and ZoiSEC master keys.
zoi system secret hash <password>: Generates a one-way Argon2 hash of a password. Use this in yoursystem.luafor user passwords.zoi system secret encrypt <value>: Encrypts a string so only Zoi on this specific machine can decrypt it. It returns aZOISEC:v1:...string.zoi system secret decrypt <ZOISEC>: Decrypts aZOISECstring back to plaintext.zoi system secret export-key: Exports the machine-specific ZoiSEC master key as a base64 string. Use this to make your secrets portable to other machines.zoi system secret import-key <key>: Imports a base64-encoded ZoiSEC master key.
Security Warning
The ZoiSEC master key is the root of trust for all your encrypted secrets.
Keep it safe! If someone obtains your master key, they can decrypt all your
ZOISEC strings.
Declarative Configuration
ZoiOS uses two primary Lua files to manage its state:
- system.lua Reference: Manage system-wide packages, users, bootloaders, and filesystems.
- home.lua Reference: Manage your personal user environment, dotfiles, and user-scoped packages.
A functional ZoiOS system is defined by a collection package, typically @core/base. This package provides a foundational set of utilities (POSIX tools, C library, Shell) and allows you to choose your primary system components via interactive or declarative options.
The @core/base Profile
When installing or building a ZoiOS system, you can pre-select your core components in system.lua to avoid interactive prompts:
-- /etc/zoi/system.lua
packages({
["@core/base"] = {
options = {
"zoi:@core/systemd", -- Choose your Init system
"zoi:@core/linux-hardened", -- Choose your Kernel
"zoi:@core/doas" -- Choose your privilege escalator
}
}
})Multi-Init and Escalation Support
ZoiOS is designed to be flexible. It supports multiple init systems and privilege escalation tools out of the box:
- Init Detection: Use
SYSTEM.INITin your.pkg.luascripts to detect if the target system is runningsystemdoropenrc. - Privilege Escalation: Zoi automatically detects and uses either
sudoordoasfor Just-in-Time escalation. In yourbasepackage, these are interchangeable virtual providers.
Architectural Foundation
ZoiOS uses a Transaction-based architecture:
- The Store: All packages reside in
/var/lib/zoi/pkgs/store/, isolated by version and input hashes. - Shared Pool: Zoi packages use a "Shared Pool + Mapping" architecture. Files are stored in a central
pool/directory within the archive and mapped to their final destinations (/usr,/etc, etc.) at install time based on the scope. - Generations: A generation is a lightweight record (e.g.
/var/lib/zoi/generations/42/) of the system state, linked to a specific Zoi package transaction. - Traditional Management: Unlike NixOS, ZoiOS installs files directly into the system root (
usrroot). Rollbacks are performed by sequentially reverting package transactions, providing a traditional FHS experience with declarative safety.
Bootloaders and Kernels
A machine only boots if something tells the bootloader about the new kernel. ZoiOS runs that pipeline automatically, after any transaction that touched kernel paths:
- Rebuild the kernel module dependency index with
depmod. - Regenerate the initramfs with whichever generator is installed:
dracut,mkinitcpioorbooster. - Sign the kernel, initramfs and modules with
sbsignwhen the firmware is enforcing UEFI Secure Boot and a key is present under/etc/zoi/secure-boot. - Write one boot entry per kernel, so several are selectable at the next boot.
The bootloader is taken from bootloader.type in system.lua, or detected from
the filesystem when unset:
| Type | Notes |
|---|---|
systemd-boot | One .conf per kernel in /boot/loader/entries. The ESP location is probed (/boot, /boot/efi, /efi). |
grub2 | Writes a snippet into /etc/grub.d and runs grub-mkconfig. Reads the same per-kernel files. |
limine | Writes /boot/limine.conf, preserving any hand-written preamble. Runs limine-install when present. |
Several kernels stay bootable
Zoi keeps previous kernels so a bad update is recoverable. Before an upgrade
removes the old kernel, its image, initramfs and module tree are preserved
under /var/lib/zoi/kernels, and each one gets its own boot entry. Selecting
an earlier kernel at the next boot is all that is needed to recover.
How many are kept is controlled by the kernel_retention setting, and defaults to three.
Secure Boot signing needs a key pair placed at /etc/zoi/secure-boot/DB.key and
/etc/zoi/secure-boot/secure-boot.crt. Signing only runs when the firmware is
actually enforcing Secure Boot, so a machine without it is unaffected.
Users and Groups
system.lua declares accounts, and zoi system apply reconciles them against
the real account databases:
groups({
wheel = {},
docker = { gid = 998 },
})
users({
alice = {
groups = { "docker" },
shell = "/bin/zsh",
home = "/home/alice",
password_hash = "ZOISEC:v1:...",
},
})Accounts are written directly to /etc/passwd, /etc/shadow, /etc/group and
/etc/gshadow, rather than by shelling out to useradd. That is what lets the
same code path serve zoi system apply on a running machine and
zoi system distro build --target /mnt against a disk that does not have an
account database yet.
The behaviour worth knowing:
- Idempotent. Re-applying an unchanged
system.luaperforms no writes at all, sozoi system applyis safe to run on a schedule. - Deterministic. Users are processed in sorted order, so two machines applying the same configuration end up with identical UIDs.
- Existing UIDs are preserved. Changing a UID underneath a populated home directory would orphan every file in it.
- Home directories come from
/etc/skeland are created mode0700. - An account with no
password_hashis locked, not passwordless. It cannot be logged into with a password, but rootsuand SSH key login still work, which is what you want when the key material arrives later. ZOISEC:values are decrypted automatically, so an encrypted secret can be used directly aspassword_hash.- Missing group references warn rather than fail, so one typo does not abort an apply.
Accounts the base packages ship (root, nobody, and so on) are left alone.
system.lua is the source of truth for whether a group exists, not for every
attribute of it, because the packages that own those groups have deliberate GIDs
and memberships.
Packaging Conventions
For developers building ZoiOS-native packages:
- Scope Awareness: Use
ZOI.scopein your.pkg.luato adjust behavior. WhenZOI.scope == "system", files should generally be staged to${usrroot}/usr/...or other absolute paths. - Pooled ZPA: Zoi automatically builds "Pooled" archives that capture the package state for
user,system, andprojectscopes simultaneously, ensuring zero duplication while supporting perfect scope-specific behavior. - Transactional Safety: All changes to
/usr,/etc, and/varare recorded in Zoi's transaction log, enabling atomic rollbacks of the entire system state.
2026 © All Rights Reserved.
- All the content is available under CC BY-SA 4.0, expect where otherwise stated.
- Source code is available on GitLab, licensed under Apache 2.0.
Last updated on
