ZZ Linux Setup is a modular, idempotent Linux post-install desktop bootstrapper for a minimal Niri + Noctalia v4 Shell desktop with GTK-oriented applications and GTK/Qt integration. Ghostty is the default terminal. gum provides the primary interactive wizard.
- Fedora is the supported target for v1.
- The design keeps Fedora-specific package-manager logic isolated so additional distros can be added later without rewriting common modules.
- Niri is the compositor/session target.
- Noctalia v4 Shell is a shell layer, not a full desktop environment. Fedora installs it from Terra with the
noctalia-shellpackage. - GTK desktop defaults are the baseline:
- Nautilus for file management
- Neovim as the default handler for plain text and source files
- Evince for PDFs and other document viewing
- imv for lightweight image viewing
- Satty-backed screenshots using the
grim+slurpcapture flow - GTK/GNOME portals, Noctalia's
polkit-agentplugin, Adwaita GTK defaults, Yaru icons, and qtct integration - Noctalia's
gtk,qt, andkcolorschemetemplates drive GTK and Qt application color theming
- Ghostty is the default terminal. The installer enables Ghostty's user systemd service on first login, keeps the background process running, and uses
ghostty +new-windowfor Niri/Noctalia terminal launches.
- SDDM provides the graphical login and session chooser.
- Choose the
Nirisession at login. - Noctalia is launched from Niri autostart with
spawn-at-startup "qs" "-c" "noctalia-shell", and Niri's terminal keybinding opens Ghostty throughghostty +new-window. - Noctalia ships with the Niri template pre-enabled through managed user settings.
- Bundled wallpapers are seeded to
~/Wallpapers, Noctalia's wallpaper picker is pointed there, and~/.cache/noctalia/wallpapers.jsonselectsBlueTide.jpgby default. - Niri config and Noctalia user templates are stowed from this repo. Noctalia's live
settings.jsonandplugins.jsonare seeded into~/.config/noctalia/and then left as writable user state so GUI changes do not dirty the repo. - When Visual Studio Code is selected,
~/.config/Code/User/settings.jsonis also managed so the editor stays onNoctaliaTheme. ~/.config/noctalia/plugins.jsonenables Noctalia's built-inpolkit-agentplugin from the official plugin source, so no separate session polkit binary is launched from Niri.- Noctalia template activation is plan-aware: GTK, Qt, and KColorScheme are always enabled; built-in templates are enabled for installed supported apps such as Niri, Ghostty, Starship, btop, Yazi, VS Code, Pywalfox, and Zen Browser; user templates are kept for repo-specific Neovim, Zsh syntax highlighting, and icon-theme integration.
- Noctalia v4 uses the existing JSON settings flow in
~/.config/noctalia/settings.json; TOML settings/package handling for later Noctalia releases is intentionally out of scope. - Firefox Noctalia theming uses Pywalfox. Fedora installs it globally with
sudo python3 -m pip install --upgrade pywalfoxand then registers the native messaging host for the target user. - The installer never starts SDDM immediately. When no display manager is already enabled, reboot to begin using the graphical login.
- Selecting Visual Studio Code also enables Noctalia's built-in
codetemplate automatically. Fedora uses Microsoft's RPM repo.
BASE_BUNDLE_IDS_fedoradefines the non-optional base bundles.- Base bundles are always planned and installed first. They are the protected desktop baseline, including Niri, Noctalia, SDDM when no display manager is already enabled, Zsh, Firefox, core services, portals, GTK/Qt integration, project-managed fonts, shell tooling, file integration, and managed base dotfiles.
- A base bundle failure is fatal because the result would not be a functioning desktop baseline.
DEFAULT_BUNDLE_IDS_fedorais intentionally empty while the base desktop is being hardened. AI, development, .NET, office, gaming, media, and extra browser bundles are opt-in.- Wizard and
--selectchoices add optional categories. Optional package/source/action failures warn and continue where possible so one broken optional component does not prevent the base desktop setup from completing. - Each generated plan writes
base-rationale.tsvunder the plan directory so required base package, action, Flatpak runtime, and source ownership is explicit. The report includes a responsibility class, consumer, and reason for each base item. - Each generated plan writes
files/managed-config-policy.tsvso planned config paths are visible asstow,seed-if-missing,first-run, orgenerated, with the conflict behavior shown before install.
- The base install always includes Zsh and its managed config.
- The base install always includes Zsh, Oh My Zsh setup, Starship, zoxide, fastfetch,
gh, btop, fd, fzf, bat, Yazi, and their managed dotfiles. - The Starship prompt uses a managed static config and Noctalia's built-in
starshiptemplate injects the active theme palette. - Zsh setup bootstraps Oh My Zsh, installs the managed
~/.zshrc, and changes the target user's login shell to/bin/zsh. doctorchecks the selected shell tools and their managed config files when they are present in the saved plan.
Remote install:
curl -fsSL https://raw.githubusercontent.com/bgmulinari/zz-linux-setup/main/bootstrap.sh | bash -s -- --ref mainThis prints the bootstrap packages it will install, asks for confirmation, clones the repo to ~/zz-linux-setup by default, and then launches the installer.
Pinned install:
curl -fsSL https://raw.githubusercontent.com/bgmulinari/zz-linux-setup/main/bootstrap.sh | bash -s -- --ref v0.1.0Unattended dry-run bootstrap:
curl -fsSL https://raw.githubusercontent.com/bgmulinari/zz-linux-setup/main/bootstrap.sh | bash -s -- --yes --dry-run --ref mainClone to a custom directory:
curl -fsSL https://raw.githubusercontent.com/bgmulinari/zz-linux-setup/main/bootstrap.sh | bash -s -- --dir "$HOME/src/zz-linux-setup" --ref mainLocal install:
git clone https://github.com/bgmulinari/zz-linux-setup.git
cd zz-linux-setup
./install.sh wizardNon-interactive install:
./install.sh install --yes
./install.sh install --yes --select browser=brave --select dev=vscode,neovimSupported commands:
zz doctor
zz logs --tail
zz debug
zz first-run
zz defaults
zz update all
zz commands --json
./install.sh wizard
./install.sh install --yes
./install.sh install --dry-run
./install.sh install --preview-commands
./install.sh install --use-saved
./install.sh print-plan
./install.sh print-plan --format json
./install.sh check
./install.sh doctor
./install.sh first-run
./install.sh defaults
./install.sh list-profiles
./install.sh list-choices
./install.sh list-sourcescheck is read-only. It accepts the same selection flags as install and print-plan, builds the plan, and reports readiness, source trust policy, service status, managed-config conflicts, managed-config policy, and key command availability without enabling repos, installing packages, or changing dotfiles.
--preview-commands prints each command before running it and asks for confirmation in an interactive terminal. Use it with install when debugging a live run. --yes --preview-commands prints the commands without stopping for each confirmation.
The project is intended to be safe to re-run after repository updates.
Managed items:
- package sources and repositories
- package installation
- Flatpak remotes and apps
- base bundle installation before optional bundle installation
- system services
- SDDM enablement
- managed dotfiles through
stow --restow - managed dotfile conflict previews before Stow moves or backs up existing files
- modular Niri config under
~/.config/niri/cfg/ - MIME defaults and selected post-actions
Re-running should:
- install newly selected packages
- update managed files only when content changes
- re-enable required services if needed
- avoid duplicate repos, remotes, services, and stow entries
- disk partitioning
- user creation
- Secure Boot setup
- automatic reboot
- starting SDDM immediately
- full desktop environment installation
- immutable Fedora Atomic support
- Debian, openSUSE, or NixOS support in v1
- Fedora COPRs are optional or required depending on the base and selected component set. Review them before enabling.
- RPM Fusion is part of the protected Fedora base source set so appstream metadata and RPM Fusion packages are available before optional package planning.
- Flathub is part of the protected Fedora base source set because the base plan installs GTK Flatpak theme runtimes and optional Flatpak apps use the same remote.
- Terra is a required base source for Noctalia Shell and Ghostty. Its generated source-trust line is marked as an explicit bootstrap exception.
- Selecting
zshalso fetches Oh My Zsh plus thezsh-autosuggestionsandzsh-syntax-highlightingplugin repositories from GitHub.
Add a package:
- Put the package name in the appropriate Fedora/source manifest under
packages/fedora/. - Reference that manifest from a bundle descriptor.
- Add the bundle to
BASE_BUNDLE_IDS_fedoraonly if it is required for the non-optional functioning desktop baseline. Otherwise expose it throughDEFAULT_BUNDLE_IDS_fedoraor a choice file.
Add a source:
- Add a
.sourcedescriptor undersources/fedora/. - Teach the Fedora adapter how to enable it if it is a new source kind.
- Reference the source ID from a bundle descriptor.
- Mark sources required only when a base bundle depends on them.
Add a wizard choice:
- Add or update the relevant
choices/fedora/*.confTSV. - Ensure referenced sources and manifests exist.
- The planner will include it in
list-choices, validation, and plan generation.
Add another distro:
- Add
distros/newdistro.sh. - Add
sources/newdistro/. - Add
packages/newdistro/. - Add
choices/newdistro/. - Define
BASE_BUNDLE_IDS_newdistrofor the non-optional desktop baseline andDEFAULT_BUNDLE_IDS_newdistrofor broader default selections.
The common modules should not need changes for a straightforward new adapter.
Logs default to $XDG_STATE_HOME/zz-linux-setup/logs or ~/.local/state/zz-linux-setup/logs. Set LOG_DIR to override the location.
The test suite uses Bats. On Fedora, install the runner with:
sudo dnf install batsRun:
./tests/smoke.shThat is the required fast PR gate. It covers shell syntax, manifest parsing, catalog validation, distro detection, fast planner behavior, and CLI smoke checks. It does not run shellcheck unless ZZ_TEST_LINT=1 is set.
Run the full regression suite with:
./tests/full.sh
./tests/full.sh --timings
./tests/profile.shtests/full.sh runs all Bats suites and shellcheck when available. tests/profile.sh prints suite timings and fails when a Bats file exceeds ZZ_TEST_PROFILE_THRESHOLD, defaulting to 15 seconds.