systui is a comprehensive Linux system administration tool with:
- Modular architecture — Clean separation of concerns
- Dialog-based TUI — Terminal UI for easy navigation
- Multi-distro support — Alpine, Arch, Debian, Devuan
- Easy installation — Single
install.shscript - Extensible design — Add features by creating modules
# Clone or download the project
git clone https://github.com/R0GUEEE/systui.git systui
cd systui
# Run installation (requires root)
sudo ./install.sh
# Use systui
sudo systuisudo systui
→ Main Menu
→ Ultimate Provision
→ Configure quick-setup settings
→ Quick setup (install/update, review, and run)
→ Re-login to activate the new shell environmentsystui/
│
├── install.sh # Installation script (dependencies + setup)
├── update.sh # Update from Git and reinstall
├── README.md # This file
│
├── src/ # Source code (modules)
│ ├── core/ # Core utilities and framework
│ │ ├── config.sh # System detection, logging, config, run_strict
│ │ ├── tui-widgets.sh # TUI widget functions
│ │ └── common.sh # Common utilities & package mapping
│ │
│ ├── provision/ # Multi-distro quick-setup provisioning
│ │ ├── runtime.sh # Shared distro adapters, sshd + config helpers
│ │ └── provision-ultimate.sh # Portable multi-distribution quick setup
│ │
│ └── features/ # Feature modules
│ ├── health.sh # System health scanner
│ ├── rootfs.sh # Rootfs builder and manager
│ ├── sysconfig.sh # System configuration (shells, repos, packages,
│ │ # services, users, storage, Awesome Linux)
│ └── ultimate-provision.sh # Quick-setup lifecycle menu
│
├── share/ # Non-code resources
│ └── homebrew/ # Root-compatible Homebrew compatibility layer
│ └── install-homebrew-root.sh
│
└── tests/ # Test suite
└── test-*.sh # Test files
The `systui` executable is generated by install.sh into $INSTALL_PREFIX/bin;
it is not checked into the repository.
- System detection (PM, init, distro)
- Logging and error handling
- Configuration management
Key Functions:
detect_pm() # Detect package manager -> $PM
detect_init() # Detect init system -> $INIT
detect_distro() # Detect distribution -> $DISTRO, $DISTRO_ID_LIKE,
# $DISTRO_VERSION,
# $DISTRO_PRETTY_NAME
require_root() # Ensure root access (calls die, which exits)
log <message> # Append to $LOGFILE (/var/log/systui.log when writable,
# else ~/.local/state/systui.log; override with
# $SYSTUI_LOGFILE)
warn <message> # Record a warning and log it
die <message> # Fatal error and exit
get_config <key> [default] # Read a value from $(systui_config_file)
set_config <key> <value> # Write a value to $(systui_config_file)
run_strict <desc> <fn> [args...] # Run one routine fail-fast in a subshell- Dialog wrapper functions
- TUI components (menu, input, checkbox, etc.)
- Command execution with output
Key Functions:
tui_msg <title> <message> # Message dialog
tui_yesno <title> <question> # Yes/no dialog
tui_input <title> <prompt> [default] # Input dialog
tui_menu <title> <text> <tag> <desc> # Menu selection
tui_check <title> <text> <tag> <desc> # Checkbox list
tui_radio <title> <text> <tag> <desc> # Radio list
tui_text <title> <file> # Text viewer
tui_menu_no_tags <title> <text> ... # Menu showing descriptions only
run_cmd <description> <cmd...> # Run command with output- Package mapping (Debian → Alpine/Arch/Fedora/Void)
- Package manager operations
- Common utilities
Key Functions:
map_packages <family> <pkgs...> # Map package names
pm_install <pkgs...> # Install packages
pm_remove <pkgs...> # Remove packages
pm_update # Update package lists
cmd_exists <command> # Check if command existsPortable, single quick-setup path for Alpine, Arch, Debian, Devuan, and other package-manager families (apt/apk/pacman/dnf/yum/zypper/xbps/portage), driven by the package-manager family detected at runtime rather than a dedicated script per distro. Installs the shared package set, sets timezone and locale, creates the user account, configures sudo access, enables services, and writes the MOTD/shell environment — with a skip-and-continue installer so one unavailable package doesn't abort the whole run.
Shared, distro-agnostic helpers used by the provisioning path above: sshd
configuration with sshd -t validation, and a config-file loader
(provision_load_config) that snapshots and restores internal variables
(LOGFILE, PM, DISTRO, PATH, ...) so a sourced config file can never
override them.
-
Detects package manager (APT, APK, pacman, DNF, Zypper, XBPS, or Portage)
-
Pre-installs the core dependencies declared in
share/systui-deps.tsv, without recommended/weak packages:Tier Contents corebash, dialog, coreutils, grep, sed, gawk, findutils, diffutils, tar, gzip, bzip2, xz, unzip, ca-certificates, curl, procps, util-linux, less, ncurses The extra and build tiers were removed: optional tooling, compilers and language managers are installed on demand from the menus (Packages → Managers) instead of up front. Packages a distribution cannot provide are located first and then skipped with a report — a missing package never aborts the install, and neither does a failed package-index refresh. Each run ends with a summary of what was skipped; set
SYSTUI_DEPS_STRICT=1to make unavailable packages a hard error instead. -
Replaces managed project files in
/usr/local/lib/systui/with the latest copy -
Creates or replaces the executable at
/usr/local/bin/systui -
Creates man page for documentation
-
Verifies installation
sudo ./install.sh # core dependencies + install
sudo ./install.sh --deps-only # install dependencies, then exit
sudo ./install.sh --dry-run # print the dependency plan, change nothing
sudo ./install.sh --no-deps # skip dependency installationEnvironment overrides: SYSTUI_DEPS_TIERS=core, SYSTUI_DEPS_DRY_RUN=1,
SYSTUI_PM_OVERRIDE=<pm> to force a package-manager backend, and
SYSTUI_DEPS_STRICT=1 to fail instead of skipping unavailable packages.
Everything installed automatically from share/systui-deps.tsv:
Core (required to start):
- bash 4.0+, dialog
- coreutils, grep, sed, gawk, findutils, diffutils
- tar, gzip, bzip2, xz, unzip
- procps, util-linux, less, ncurses
- curl, ca-certificates
Installed on demand (menus install these when an action needs them):
- git, wget, rsync, jq, openssh-client, iproute2, iputils, dnsutils, netcat, socat
- lsof, pv, tree, ncdu, tmux, nano, vim, neovim, micro, htop, ripgrep, fd, fzf, bat, eza
- w3m, lynx, most, zip, p7zip, zstd, strace, mtr, nmap, tcpdump, fastfetch, figlet
- python3, gnupg, file, which
- make, gcc, cmake, ninja, pip, python3-venv
# Run systui
sudo systui
# Navigate with arrow keys, Enter to select
Main Menu
→ Ultimate Provision
→ Quick setup (install/update, review, and run)
→ Install or update Ultimate Provision
→ Configure quick-setup settings
→ Show status and current settings
→ Run Ultimate Provision now
→ Remove installed Ultimate Provision# On a supported Linux distribution
sudo systui
→ Ultimate Provision → Configure quick-setup settings
→ Quick setup (install/update, review, and run)Ultimate Provision configures the timezone, primary user, hostname, sudo policy, terminal package set, services, Bash environment, Neovim, and tmux. It selects distribution-specific packages and service names for APT, Alpine APK, Arch pacman, Fedora/RHEL DNF or YUM, openSUSE zypper, Void XBPS, and Gentoo Portage. Unavailable packages are reported and skipped without stopping the run.
Configuration stored in ~/.systui/config:
# Set timezone preference
systui-config-set "timezone" "America/New_York"
# Set preferred shell
systui-config-set "shell" "bash"Location: /etc/systui/config
# Default distro preferences
default_timezone=America/Los_Angeles
enable_services=true
install_docs=true- Create file:
src/features/myfeature.sh - Define functions:
#!/bin/bash
# systui — My Feature
menu_myfeature() {
local choice
choice=$(tui_menu "My Feature" "Description:" \
option1 "First option" \
option2 "Second option" \
back "Back") || return
case "$choice" in
option1) do_something_1 ;;
option2) do_something_2 ;;
back) return ;;
esac
}
export -f menu_myfeature- Add to main menu in
bin/systui:
. "$LIBDIR/src/features/myfeature.sh"
# In main_menu():
myfeature) menu_myfeature ;;provision-ultimate.sh provisions by detected package-manager family, not by
a per-distro script, so a new distro usually needs no new provisioning code —
only:
- Update
detect_distro()/detect_pm()insrc/core/config.shif the distro isn't already recognized. - Extend the package-name map in
src/core/common.shif it needs distro-specific package names. - Add any distro-specific package-manager branch to
src/provision/provision-ultimate.shif its family isn't already handled (apt/apk/pacman/dnf/yum/zypper/xbps/portage).
# Install dialog
sudo apt install dialog # Debian
sudo apk add dialog # Alpine
sudo pacman -S dialog # Arch
sudo dnf install dialog # Fedora# Run with sudo
sudo systui- Check
/tmp/systui.logfor details - Package mapping in
src/core/common.shmay need updates - Some packages have distro-specific names
- Check log file:
cat /tmp/systui.log - Check internet connectivity
- Verify distro is supported
- Try again (scripts are idempotent)
- Modular design → Easy to test, extend, maintain
- Function-based → No class complexity, pure bash
- Logging everywhere → Debug issues easily
- Consistent patterns → Similar code style throughout
- Use
#!/bin/bash(bash-specific features OK) - Export functions:
export -f function_name - Log important operations:
log "message" - Validate input in functions
- Use
set -eto catch errors - Comment complex logic
# Syntax check
bash -n src/core/config.sh
bash -n src/core/tui-widgets.sh
bash -n src/core/common.sh
bash -n src/features/rootfs.sh
# Rootfs backend tests
bash tests/test-rootfs-backends.sh
# Full test
sudo ./install.sh
sudo systui
# Test menu navigation and features- Startup: < 1 second
- Menu navigation: Instant
- Provisioning: 5-15 minutes (depends on distro and internet)
- Memory: < 10 MB
- Disk: < 5 MB (project files)
| Distro | Version | Init | PM | Status |
|---|---|---|---|---|
| Alpine | 3.23+ | OpenRC | apk | ✓ Supported |
| Arch | Current | systemd | pacman | ✓ Supported |
| Debian | 12+ | systemd | apt | ✓ Supported |
| Devuan | 6+ | sysvinit | apt | ✓ Supported |
| Ubuntu | 22.04+ | systemd | apt | ✓ Compatible |
| Fedora | 38+ | systemd | dnf | ✓ Partial |
- Feature modules not yet implemented — Shells, repos, rootfs planned
- Offline provisioning — Requires internet for package downloads
- Non-interactive provisioning — TUI always shown (but scriptable via env vars)
- Limited customization — Edit scripts for fine-grained control
- Feature modules (shells, repos, rootfs)
- Fedora/RHEL/CentOS support
- Configuration file support
- Package version pinning
- Automated testing suite
- Plugin system
- Cloud-init integration
- Backup/restore functionality
Free and open for use, modification, and distribution.
- Documentation: See
/usr/local/lib/systui/docs/ - Log file:
/tmp/systui.log - Man page:
man systui
- 1.0.0 (2026-07-29) — Initial release
- Modular architecture
- Multi-distro provisioning
- TUI framework
- Alpine, Arch, Debian, Devuan support
Happy provisioning! 🚀
For detailed architecture, see docs/ARCHITECTURE.md
For developers, see docs/DEVELOPER_GUIDE.md
The package catalogue now includes:
- 17 software categories covering terminal tools, development, networking, security, monitoring, servers, containers, backups, multimedia and more.
- Curated one-click collections for iSH-AOK essentials, development stacks, servers, networking, security and backup environments.
- Bulk package-list export/import and bulk removal.
- Package health checks, orphan detection, cache cleanup and integrity checks.
- Rich package pages with install, remove, reinstall, metadata, installed-file, version-hold and package-integrity actions.
- Package-name translation for APT, APK, Pacman and DNF environments.
- Guided backend selection with Automatic or explicit choices: mmdebstrap, debootstrap, cdebootstrap, qemu-debootstrap, and multistrap for Debian-family roots; pacstrap or the official bootstrap tarball for Arch; and the native APK, DNF, Zypper, stage3, or Void tarball backend for other distributions.
- The backend menu is driven by
rootfs_backend_catalog, the single source of truth for which tool can bootstrap which distribution. Target architecture is chosen first (step 2), so the menu lists only backends that are compatible with the selected distro and architecture and installed on this host. Anything compatible but missing is reported as a "what to install" hint rather than offered as a choice that fails after selection.qemu-debootstraptherefore appears only for foreign-architecture targets on hosts that still ship it; Arch x86_64 gets pacstrap, ARM goes through Arch Linux ARM, and RISC-V (riscv64) through the archriscv port's rootfs tarball. - Backend-specific configuration menus cover variants/flavours, components,
bootstrap include/exclude lists, keyrings, merged
/usr, execution modes, documentation/locale pruning, cdebootstrap configuration directories and authentication, and generated or custom multistrap configurations. - Backend settings are persisted in
.systui-backend.confinside the build so interrupted rootfs generation resumes with the same tool configuration. They can be edited later through Rootfs → Manage → Configure bootstrap backend. - Repository-backed, SPACE-selectable release discovery with offline fallbacks.
- Expanded minimal, workstation, development, server, web, and security presets.
- Profile-based custom package installation and additional individual packages.
- In-rootfs locale, timezone, shell, editor, SSH, services, package update/upgrade, cleanup, machine-id, and mount-helper configuration.
- Rootfs management exposes the same post-build configuration controls.
- System Configuration → Common tasks is a flat front door to the settings that otherwise sit two or three levels down — install/remove packages, update the system, hostname, timezone, add a user, default shell, editors, SSH, services and a full system scan. Every entry calls the same function the section menu does, so there is one implementation of each action.
- Midnight Commander is available under System Configuration → File managers,
with a sectioned configuration editor, skin management and an
mcdshell wrapper that returns the shell to the directory you were browsing. mc has no plugin API in the lf/yazi sense, so the add-on manager handles what the ecosystem actually ships — skins from upstream and community repositories — and links cloned.inifiles into~/.local/share/mc/skinswhere mc looks for them. - System Configuration → iOS LinuxKit manages
rcarmo/ios-linuxkit — the iSH fork
that runs an AArch64 Linux userland as a command-line process on an AArch64
Linux host and inside the iOS app. One screen covers the documented toolchain:
check out the source with submodules, check and install the build
dependencies against the detected package manager, build the release or debug
runtime, download and verify the pinned Alpine root filesystem (SHA-256 plus a
bin/busyboxarchitecture check, mirroring the app's own downloader), import it withfakefsify, export it back to a portable tarball withunfakefsify(with the quiescence andmeta.db/WAL/SHM caveats stated up front), and run guest shells or commands.- Host integration —
ISH_BIND_MOUNTSwith per-entry validation (both paths absolute, host path must exist,:ro/:rwshown), and explainer pages for the native-offload contracts and the opt-in route-netlink switch (ISH_NETLINK_STUB=1), including what netlink deliberately does not do. - Validation — the focused gate list taken from the checkout's own
Makefile, runnable in one pass with the release/debug runtime coverage gates, plus the failure rules and cold-cache timeout trap. - Diagnostics — every documented
ISH_*tracing/statistics variable and the guest compatibility defaults (GODEBUG,GOMAXPROCS, the JSC/Node settings), the known-limits summary, and a full host report. - Application bundle and releases — version and Apple build-number fields
read from
app/AppARM64.xcconfigand the project file, the bundle identifier, the effective packaging rootfs pin, tag provenance, the Xcode build path with its requirements, and the gadget-guard gate. - Native / AOT pipeline — the recorder → seed → generated set → build
stages, the
jit_aotkit commands, the freeze checklist and the honest limits (images are not executable on iOS today; no scheme enables the backend). Settings — repository, branch, directories, default image, root filesystem pin, bind mounts, the netlink switch and the preferred runtime — live in/etc/systui/ios-linuxkit.conf, and the checkout's ownapp/GuestARM64.xcconfigis used as the pin when present. The manager states its limits instead of offering dead actions: the Linux-host build targets AArch64, Xcode and signing cannot run here, and the runtime cannot be executed from the iOS sandbox because a sideloaded app cannot spawn processes.
- Host integration —
- Rootfs → Chroot workbench works on any rootfs directory, not just builds
under
$ROOTFS_BASE, including trees unpacked from a third-party tarball:- Selectable execution engine —
chroot,proot(no root required),systemd-nspawn, orunshare— with foreign-architecture targets routed throughqemu-user-staticautomatically. The engine determines the mount strategy: onlychrootgets real kernel mounts, because proot binds in userspace and nspawn/unshare own their namespaces. - Persistent bind mounts stored in the rootfs's own
/etc/systui-chroot.conf, so they travel with the tree. Sources must be absolute and existing, and targets may not contain... - Mount management driven by
/proc/mountsrather than session bookkeeping, so mounts left behind by a crash or made by hand are still found. Detach runs deepest-first and falls back to a lazy unmount for busy paths. - Packing verifies the tree is fully unmounted first. Archiving a rootfs with
/procor/devstill bound captures the host's virtual filesystems — in testing, 113 host/deventries versus 2 for a clean tree. Optional excludes cover package caches, logs,/tmp, systui state and shell history, with an optional SHA-256 checksum alongside the archive. - Unpack a tarball into a new directory to start the modify/repack cycle.
- Menus use
tui_menu_no_tags, so internal selection tags are never shown.
- Selectable execution engine —
- Rootfs → Distro managers integrates
proot-distro,chroot-distro,distrobox, Toolbx,schroot,udocker,machinectlandarch-chroot. These are not bootstrap backends: they own their own rootfs store and ship one pinned version per distribution, so the builder's target, release, mirror and architecture steps do not apply to them.- Each manager can be installed from systui — via its native package
where one exists, or from upstream (
termux/proot-distro, the distrobox installer,pipfor udocker).chroot-distrois a Magisk/KernelSU module for rooted Android and cannot be installed non-interactively, so systui shows what to flash instead of pretending otherwise. - Available distributions are parsed from each tool's own output rather
than hardcoded:
proot-distro'sAlias:blocks andchroot-distro's bare identifier list are handled separately, with a generic fallback and a manual-entry escape hatch. - Configurable per manager: rootfs store location (auto-detected, with a manual override for relocated stores), the unprivileged user to run as, and the prefix used for upstream installs.
- "Open in workbench" hands the resulting tree to the chroot workbench for
modification and packing.
proot-distro, distrobox, Toolbx and udocker refuse to run as uid 0, so systui drops to a normal user when invoking them.
- Each manager can be installed from systui — via its native package
where one exists, or from upstream (
- Additional bootstrap backends:
bdebstrap(YAML-driven mmdebstrap wrapper, Debian family),rinse(bootstraps RPM distributions from a Debian host, covering the casednf --installrootcannot),alpine-chroot-install(upstream's own installer; native architecture only, so cross-architecture Alpine roots stay on theapk.staticbackend), andarchriscv-tarball(the Arch Linux RISC-V port, for riscv64 Arch targets). - riscv64 (RISC-V 64-bit) targets are supported wherever an upstream
repository actually exists: Debian (trixie+), Ubuntu (ports), Alpine
(v3.21+), Gentoo, Devuan (ceres only), openSUSE Tumbleweed (ports), and
Arch via the archriscv port. Fedora, Kali, Void and Bedrock do not publish
riscv64 packages/installers, so riscv64 is not offered for them. Foreign
riscv64 builds route chroot steps through
qemu-riscv64-staticautomatically, like the other foreign architectures. tar.gzis the default build and management compression format.- System Configuration → Packages begins with Package Managers, followed by Repositories and Catalogue.
- System Configuration → Scanner provides full system reports and package/file queries.
- Package-manager configuration covers APT, apt-fast, Nala, pip, pipx, Flatpak, Snap, Cargo, npm, pnpm, and Yarn.
- Additional iSH-AOK, memory, writeback, tmpfs, and DNS-cache performance controls.
Each persisted
sysctlkey is written by exactly one file under/etc/sysctl.d/, so no two Performance entries can override each other. - Rootfs backend prerequisites remain optional; the minimal
install.shdoes not install them. They are checked before the backend menu is drawn, so an unavailable tool is never offered. - Menu cancellation paths return to their parent menu instead of propagating a fatal status.
Kali Linux, openSUSE Leap, openSUSE Tumbleweed, and Gentoo stage3 are available from the Rootfs Builder.
The main-menu System Health section replaces the former log viewer and provides:
- Quick health dashboard
- Full exportable health reports
- Package integrity and dependency checks
- Storage, filesystem, inode, and mount checks
- Failed/crashed service detection
- Network, route, resolver, and listening-port checks
- Security configuration audit
- CPU, memory, process, zombie, and kernel-warning checks
- Conservative package repair, cleanup, SSH validation, and fstab validation
The internal operation log remains available at /tmp/systui.log for command diagnostics.
The Awesome Linux menu synchronizes the upstream software list and rebuilds it as a 26-group catalogue. All 1,235 current software entries are retained under stable categories such as Audio & Music, Development, Gaming & Emulation, Security, System Utilities, and Terminal & CLI. Documentation-only sections, including “Unsure how to contribute?”, contribution guidelines, news, Reddit, contributors, and licensing, are excluded and cannot appear as installable categories. Existing caches are automatically reparsed when the taxonomy version changes. Nested category menus use independent state, so returning from a subcategory cannot corrupt its parent menu. Project installer scripts are generated only after a project is selected, keeping first launch and catalogue refresh responsive.
System Configuration > Packages now contains Package Managers, Repos, Catalogue, Packages, and Advanced. Native install, remove, search, information, installed-package listing, hold, update, and cleanup actions are grouped under the Packages submenu.
APT repository management includes both /etc/apt/sources.list and /etc/apt/sources.list.d/. The signing-key menu can install available Debian, Ubuntu, Devuan, and Kali archive keyrings using a SPACE-to-select checklist.
System Configuration > Shells separates Managers from Plugins. The manager list contains every shell systui knows — Bash, Zsh, Fish, Nushell, POSIX sh (dash/ash/yash), Korn shell (ksh/mksh), tcsh/csh, Elvish, Xonsh, PowerShell and Niu (niubash) — and each entry opens the same manager surface: install/reinstall (with per-distro package names, pip for xonsh, a GitHub-release installer for PowerShell, and the niubash release/bundle installer for niu), uninstall, set as the default login shell, that shell's configuration files, its plugin integration, its alias dialect, plus its own plugin framework when it has one (oh-my-bash, Bash-it, ble.sh, oh-my-zsh, zinit, awesome-zsh-plugins, Fisher, nushell plugins, oh-my-niu). There is no separate "More shells" install-only list any more. Cross-shell plugins include Starship, fzf, completion packages, zoxide, Atuin, direnv, Carapace, syntax highlighting, and autosuggestions.
niubash is a Bash-compatible shell that is
native on Windows (rubash engine + winuxcmd, no WSL and no MSYS emulation). systui
manages it exactly like the other Bash-family shells: ~/.niubashrc (and the
legacy ~/.winshrc) in the config-file menu, validated with niu -n when niu is
installed and bash -n otherwise, the POSIX alias dialect, and the Bash-form
integration lines for Starship, zoxide, direnv and fzf.
Install (Shells ▸ Niu (niubash) ▸ Install) offers the GitHub release payload for
Windows x64 or ARM64 (unpacked into ~/.niubash/niubash), a Cargo build from
source, and the framework bundle. The payload is Windows-only — on a non-Windows
host systui says so instead of pretending otherwise, and still configures the rc
file and the plugins.
oh-my-niu / oh-my-winuxsh (unixwin/oh-my-winuxsh)
is the plugin framework, and Shells ▸ Niu ▸ Plugins ▸ framework (or ▸ Plugins ▸
GitHub catalogue) is where it is installed from: the released bundle is
downloaded, its published sha256 is verified, it is unpacked into
~/.niubash/oh-my-niu, and the loader line is written into ~/.niubashrc inside
a removable systui block. The plugin choices are parsed from GitHub: the
bundle repository's git tree lists every plugins/<name>/plugin.toml (plugins,
prompt packs and themes) and its index.toml supplies the kind, category and
summary. The selection is written back as one managed block
# >>> systui niu plugins >>>
NIU_PLUGINS=(prompt-core git docker zoxide)
NIU_THEME=minimal
NIU_THEME_PLUGIN=theme-minimal
# <<< systui niu plugins <<<so the framework keeps loading the same plugins the menu shows. With no network
and no bundle the built-in pack list from index.toml is used, so the menu never
depends on GitHub being reachable.
System Configuration > Shells > Plugins now opens a per-user manager for each plugin. Starship, fzf, completions, zoxide, Atuin, direnv, Carapace, Zsh syntax highlighting, and Zsh autosuggestions include install/remove actions, shell integration, editable configuration, status inspection, and cleanup controls.
The awesome-zsh-plugins catalogue (Plugins ▸ awesome-zsh-plugins catalogue) exposes a curated subset of unixorn/awesome-zsh-plugins — about 75 plugins grouped by category (navigation, history, git, completion, vi-mode, aliases, prompt widgets, language tooling, misc). Plugins can be installed into oh-my-zsh (custom/plugins + plugins=()), zinit (zinit light lines), or plain Zsh (~/.local/share/zsh-plugins + auto-detected source lines). The oh-my-zsh external and zinit popular catalogues were also enriched with top picks from the list.
System Configuration > File Managers manages terminal file managers and their user configuration:
- lf
- tere
- Yazi
- Ranger
- nnn
- Vifm
- Broot
- xplr
Each entry supports installation/removal, a recommended starter configuration, direct configuration editing, launching, and a GitHub-backed add-on manager. Add-ons are installed per user under the applicable ~/.config directory; custom Git repositories are also supported.
From a Git checkout:
sudo ./update.shAfter installation, the same updater is available globally:
sudo systui-updateThe updater replaces the local tree with a fresh main clone (fixed root-owned checkout at /var/lib/systui/source) and then reruns install.sh, which pre-installs the full dependency manifest before the new tree is used.
Options: --minimal (core dependency tier only), --dry-run (print the clone/install/dependency plan and exit without touching anything), --no-deps (skip dependency installation), --force (accepted for compatibility; updates are always full replacements).
The RootFS Builder now opens a categorized package catalogue after preset selection. It supports space-to-select package lists, reusable rescue/developer/server/network/container/diagnostic presets, catalogue search, manual native package names, selection review, and de-duplication. Canonical package names are translated through the existing Alpine, Arch, Fedora, and Void package maps where available.
System Configuration → Shells includes:
- Shell config files — every file of every shell systui knows, chosen from a
shell-then-file menu: Bash (
.bashrc,.bash_profile,.bash_login,.bash_logout), Zsh (.zshrc,.zprofile,.zshenv,.zlogin,.zlogout), Fish (config.fish,conf.d/systui.fish), Nushell (config.nu,env.nu,login.nu), POSIX sh (.profile), Korn shell (.kshrc,.mkshrc), tcsh/csh (.tcshrc,.cshrc,.login,.logout), Elvish (rc.elv), Xonsh (rc.xsh), PowerShell (profile.ps1,Microsoft.PowerShell_profile.ps1), niubash (.niubashrc,.winshrc) and Readline (.inputrc). Common settings are selected with SPACE and written into a removable systui-managed block in that shell's own syntax (tcshsetenv, Elvishset E:…, Xonsh$VAR, PowerShell$env:VAR, kshHISTSIZE, POSIX exports), and syntax validation uses the shell's own parser —bash -n,sh -n,ksh -n,zsh -n,fish -n,tcsh -n,nu -n,niu -n(niubash rc files, falling back tobash -n), or the PowerShell AST parser. Custom entries, backups, direct editing and viewing are available for every file. - Alias dialects — the alias manager keeps one POSIX master file and
regenerates a dialect for every shell family: POSIX/Bash/Zsh/ksh, Fish, tcsh
(
alias x "cmd"), Nushell (alias x = cmd), Xonsh (aliases['x']), Elvish (fn x {|@a| e:cmd $@a }) and PowerShell (function x { cmd @args }), each sourced from the rc file of the shells that are actually installed. - Plugin integration for every shell — the plugin managers resolve the right
rc file and use the right "load this file" syntax per shell instead of writing
POSIX
. filelines everywhere, the status view reports across all of them, and an All-shell integration action writes one tool's init line (Starship, zoxide, Atuin, direnv, Carapace, fzf) into every selected shell — including tcsh, Nushell, Elvish, Xonsh and PowerShell. A Custom plugin source action integrates any file or GitHub project into any shell, resolving the project's entry file (or explaining that it has none) rather than adding a broken line. - Alias manager — installs aliases from a catalog, adds or replaces custom aliases, removes aliases, imports existing alias definitions, validates syntax, and generates Fish-compatible aliases. Managed aliases are stored under
~/.config/systui/and sourced from supported shell files.
- Shell plugin catalogue for Bash, Zsh, and Fish GitHub projects with installation, updates, and shell integration, plus per-shell integration lines for the cross-shell tools on every shell the tool manages (the catalogue also accepts any other shell id, cloning into a per-shell directory and using that shell's own source syntax; for niu it also installs the oh-my-niu bundle and enables its plugins from the bundle repository's
index.tomlandplugins/tree). - Expanded GitHub add-on catalogues and update/status management for terminal file managers.
- Full OpenSSH server configuration for authentication, access controls, keys, forwarding, keepalives, SFTP, banners, host keys, logs, and validation.
- Additional iSH-AOK compatibility, storage, cache, logging, shell, APT, and capability-report tuning.
Beyond install/configure/run, the Ultimate Provision menu exposes the parts of the run that were previously fixed in the script:
- Package set — extra packages are added to the distribution's list and
excluded packages are dropped from it, using the host's own package names
(
EXTRA_PKGS,SKIP_PKGSare passed to the script). - Service configuration — the enable/start pass (rsyslog, ssh, cron, chrony)
can be skipped, which is what containers and emulated hosts usually want
(
SKIP_SERVICES=1). Configuration files are still written. - Preview — runs the tool with
PROVISION_DRY_RUN=1, printing the package list and the settings it would use, and changing nothing.
Every step that can block goes through one bounded runner, so a single wedged child can no longer freeze the whole run:
- stdin is detached (
/dev/null) for every package and service command, so a maintainer script, a licence/GPG prompt or a compatibility launcher asking a question gets EOF instead of waiting for input that will never arrive. - every step has a wall-clock limit, enforced by a watchdog subshell rather
than by coreutils
timeout, so it also works on hosts wheretimeoutis missing or cannot kill a wedged child. A step that reaches its limit is terminated, reported, and the run continues (exit status 124, the same convention astimeout). - long steps print a heartbeat (
... still running (120s): apk add ...), so slow-but-alive is visibly different from hung. - the init system is detected by inspection only. The old SysVinit probe ran
/sbin/init --version; on iSH-AOK/sbin/initis a live PID-1 supervisor (systui's systemd compatibility launcher), so the probe started a real init and then blocked forever — provisioning froze before printing its first status line. - the per-package fallback reports its position (
[12/89] curl) and stops afterPROVISION_MAX_CONSECUTIVE_TIMEOUTS(default 3) timed-out operations in a row, instead of grinding through the whole list against a wedged package manager. - service activation is bounded too (60–90 s per service), so a hanging service manager cannot freeze the final step.
Knobs, passed through the environment like the settings above:
PROVISION_HEARTBEAT=<secs> (0 disables the heartbeat),
PROVISION_TIMEOUT_MAX=<secs> (caps every limit, useful for tests),
PROVISION_MAX_CONSECUTIVE_TIMEOUTS=<n>, PROVISION_SKIP_FILTER=1 (do not
pre-verify package names), PROVISION_PACMAN_SYSUPGRADE=0 (Arch: skip the refresh
instead of upgrading the whole system), PROVISION_TOTAL_TIMEOUT=<secs> (whole-run cap applied
by the menu, default 21600; 0 disables), and PROVISION_NO_TIMEOUT=1 (run steps
in the foreground and block — debugging only).
Two more things the audit fixed:
- package names are verified before the bulk install. The bulk transaction is all-or-nothing, so one name the index does not know (renamed, release-specific, or living in an overlay) used to throw the whole list into the per-package pass. Unknown names are now dropped up front and listed.
- sshd hardening can no longer lock you out. The in-place path keeps a
timestamped backup and restores it when
sshd -trejects the result; the drop-in path removes its fragment on the same failure. The advertised daily maintenance job also exists now (package-cache trim,/tmptidy, one-line disk record), registered with/etc/periodic/dailyon Alpine and/etc/cron.dailyelsewhere.
Settings persist with the other provision options in
/etc/systui/provision-ultimate.conf. Install status is compared against the
patched payload, so a freshly installed tool reports installed (current)
instead of looking perpetually out of date (the installer applies compatibility
patches, so a plain byte comparison with the bundled script could never match).
systui loads ~126 feature modules at start. Three things dominated that cost on constrained hosts, and all three are now addressed:
- Export scrubbing is batched. The loader used to re-enumerate the whole
function table after every feature (tens of milliseconds each once ~1500
functions exist). It now scrubs every
SYSTUI_SCRUB_INTERVALfeatures (default 4) plus a final pass. Measured on an iSH-AOK host with ARG_MAX 128 KiB: interval 1 → 8.7 s startup and a 1% peak environment; interval 4 → 4.5 s and 32%; interval 8 → 4.2 s and ~50%. Set the variable to 1 for the historical behaviour. - Function aliasing is fork-free. The 60
eval "$(declare -f fn | sed ...)"sites that rename a function body now usesystui_alias_function(src/core/alias.sh), which redirectsdeclare -finto a reusable file and reads it back withmapfile— no subshell and nosedper alias. - Bedrock menu wrapping is deferred. Wrapping ~25
menu_*_installentry points for host/stratum targeting only happens when/bedrockexists (or whenSYSTUI_BEDROCK_WRAP_INSTALL_MENUS=1forces it); the wrappers are created on first confirmed Bedrock detection otherwise.
Remaining startup (~4.5 s here) is parse-bound: ~1.7 s is bash reading and parsing the 42k lines of feature code, and most of the rest is bash re-parsing function bodies while load-time wrappers copy them. Two things were measured and deliberately not adopted because they do not pay off:
- stripping comments/blank lines from the features (13% fewer lines, only ~90 ms faster parse and ~115 ms end to end);
- lazy-loading modules on first use — 64 features have no load-time references from later features, but only 2 of them are safe to defer once wrappers, global data and cleanup passes are excluded, for ~26 ms.
Going further means removing the load-time wrapping architecture itself (menus intercepting each other by copying bodies), not tuning it.
Measure a change with the bundled profiler:
tools/feature-profile.sh --top 20 # per-feature load times
SYSTUI_SCRUB_INTERVAL=1 tools/feature-profile.sh # compare configurationstests/test-startup-performance.sh guards these optimizations.
Package installs — single, batch and catalogue — use the distribution's own
package manager (apt, apk, pacman, dnf/yum, zypper, xbps,
emerge) and do not interrupt with a source chooser. The native manager is
re-detected whenever $PM is empty or was temporarily overridden, so it is
always present in any list of managers.
Other ecosystems are one action away rather than in the way:
- Packages → Package operations → Install packages opens the manager picker,
with the native manager listed first and named (
Native system package manager (apk)). SYSTUI_PM_OPTION_PROMPT=1forces the chooser for a run.- Bootstrap and repository-recovery paths try the native route first and only offer the alternates when it cannot provide the package.
SYSTUI_PM_AUTO_<TAG>/SYSTUI_INSTALL_MANAGER=<manager>still script a specific manager.
System Configuration > Packages > Managers now provides configuration and maintenance hubs for APT, apt-fast, Nala, aptitude, pacman, yay, paru, DNF, YUM, zypper, apk, XBPS, Portage, Flatpak, Snap, Nix, Homebrew, pip, pipx, npm, pnpm, Yarn, Cargo, RubyGems, Composer, and Go tools.
Install package managers (the SPACE-to-select checklist) installs everything you select without a single follow-up prompt. Each manager has an automatic strategy with fallbacks — native package, official unattended installer, npm global, corepack, cargo, official tarball, GitHub release binary or AUR build — and every helper runs with stdin closed so upstream installers cannot block on a question. The run ends with a log summary of which managers are now available; the per-manager method menus remain available under Configure individual package managers.
Automation hooks: SYSTUI_PM_INSTALL_MODE=menu restores the old method prompts,
SYSTUI_PM_AUTO_<TAG>="command" overrides one manager's install command (for
example SYSTUI_PM_AUTO_BREW="brew update"), and SYSTUI_PM_AUTO_STRICT=1
makes the tool exit non-zero when a selected manager could not be installed.
Automatic strategy per manager
| Manager | Automatic strategy |
|---|---|
| apt-fast | native package, then aria2 + upstream quick-install script |
| nala | native package, then the official PPA |
| aptitude, Flatpak, Snap | native package (Flatpak adds Flathub, Snap enables snapd.socket) |
| pip | native package, python3 -m ensurepip, then get-pip.py |
| pipx | native package, then pip install --user pipx + ensurepath |
| npm | native package, then the NodeSource LTS repository |
| pnpm, Yarn | npm global install, then corepack |
| Cargo | native package, then rustup -y --no-modify-path |
| RubyGems | native ruby + ruby-dev/devel |
| Composer | native package, then the signature-verified official installer |
| Go | native package, then the official go.dev tarball |
| yay, paru | GitHub release binary, then cargo, then an unattended AUR makepkg build |
| Nix | official multi-user installer, then single-user, then native package |
| Homebrew | the bundled root-compatible installer, then upstream NONINTERACTIVE=1 |
Homebrew is managed through a permanent root-compatibility layer for iSH-AOK /
Debian arm64: a shared installer under share/homebrew/, a system wrapper at
/usr/local/bin/brew, a UID shim at /usr/local/lib/homebrew-root/, and a
managed environment file at /etc/systui/homebrew.env.
config.sh does not enable a shell-wide set -e. dialog returns 1 on Cancel
and 255 on ESC as ordinary control flow, so a global set -e plus an ERR
trap turned every stray Escape keypress into a fatal error. Routines that want
fail-fast semantics opt in:
run_strict "rootfs_builder" rootfs_builder_impl "$@"run_strict runs the routine in a subshell with set -eE and an ERR trap, so
a failure aborts that routine and is recorded as a warning, without tearing
down the surrounding menu.
The catalogue is generated from a community-maintained upstream README. The
github install method clones the listed repository and runs its build system
— and its own install.sh, where one exists — with root privileges.
Because of that, it is never reached implicitly: auto tries the native
package, Flatpak and Snap, then stops and tells you what to run. Choosing the
GitHub method shows the resolved repository URL and requires typing yes
before anything is fetched. Set SYSTUI_ASSUME_YES=1 to skip the prompt in an
unattended run.
Review the repository, and the generated installer (GitHub: review generated installer), before using this method.
get_config / set_config read and write /etc/systui/config when running as
root and ${XDG_CONFIG_HOME:-~/.config}/systui/config otherwise. Set
$SYSTUI_CONFIG_DIR to override. A bare ~ is not used, because whether sudo
resets HOME varies by distribution and the same install would otherwise read
two different files.
provision_load_config in src/provision/runtime.sh sources a config file as
a shell script with root privileges. Values that systui depends on internally
(LOGFILE, PM, DISTRO, PATH, ...) are snapshotted and restored around the
source, and any attempt to change them is logged and reverted.