Version: 2.1.1 | Changelog | GitHub
- Installation
- Configuration
- Plugins
- CLI Reference
- Writing a Plugin
- Security Model
- Troubleshooting
- Architecture
git clone https://github.com/zerolinux/terminal ~/.zerolinux-src
bash ~/.zerolinux-src/install.sh
exec zshOh My Zsh is not installed by default. Pass --with-ohmyzsh to include it:
bash ~/.zerolinux-src/install.sh --with-ohmyzshbash install.sh --yes # skip all prompts
bash install.sh --yes --with-ohmyzsh # skip prompts + install OMZ
bash install.sh --dry-run # preview without changing anythingZL_HOME=/opt/zerolinux bash install.shsha256sum -c zerolinux-v2.1.1.sha256
# Expected: zerolinux-v2.1.1.tar.gz: OK- Checks prerequisites (zsh ≥ 5.3, git, curl/wget, write permissions)
- Creates a timestamped backup at
~/.zerolinux_backup/<timestamp>/ - Writes the framework to
$ZL_HOME(default:~/.zerolinux) - Creates a symlink:
~/.local/bin/zl → $ZL_HOME/bin/zl - Injects a guarded block into
~/.zshrc - Generates a
restore.shfor rollback
The installer never overwrites ~/.zshrc. It injects a tagged block:
# >>> ZEROLINUX START >>>
export ZL_HOME="$HOME/.zerolinux"
source "$HOME/.zerolinux/core/loader.zsh"
# <<< ZEROLINUX END <<<bash ~/.zerolinux/uninstall.shRemoves the block from .zshrc, deletes $ZL_HOME, removes the zl symlink.
bash ~/.zerolinux_backup/<timestamp>/restore.shSettings are applied in this order (highest priority wins):
- Environment variables
~/.zerolinuxrc(user overrides)$ZL_HOME/config/default.zsh(shipped defaults)
# ~/.zerolinuxrc
# ── Logging ──────────────────────────────────────────────────────────────────
# 0=DEBUG 1=INFO (default) 2=WARN 3=ERROR
ZL_LOG_LEVEL=1
# Suppress all terminal output (log to file only)
ZL_LOG_SILENT=0
# ── Shell behaviour ───────────────────────────────────────────────────────────
# Spell-correction for commands and arguments (setopt CORRECT CORRECT_ALL).
# Disable if zsh's correction interferes with CLI subcommands such as
# "zl disable", "zl remove", or "git reset".
# 1=on (default), 0=off
ZL_CORRECT=1
# ── Safety ───────────────────────────────────────────────────────────────────
# Block plugin load on any security scanner finding (default: warn only)
ZL_STRICT_SAFETY=0
# ── Startup ──────────────────────────────────────────────────────────────────
# Start without any plugins (useful for debugging)
# Use from command line: ZL_SAFE_MODE=1 zsh
ZL_SAFE_MODE=0
# ── Telemetry ────────────────────────────────────────────────────────────────
# Log startup and plugin timing to file (no network calls)
ZL_TELEMETRY=0
# ── Update channels ──────────────────────────────────────────────────────────
# stable = tagged releases (default)
# beta = main branch
ZL_CHANNEL=stableStart a shell without any plugins loaded:
ZL_SAFE_MODE=1 zsh
# or use the alias:
zl-safeUse this when a plugin is crashing your shell on startup.
zl enable plugin docker
zl disable plugin docker
exec zsh # or: source ~/.zshrcChanges take effect on the next shell start.
~/.zerolinux/core/plugins.conf is the source of truth for which plugins load:
# One plugin name per line. Comments start with #.
git
system
# docker ← uncomment to enable
Requires git in PATH. Enriched with fzf if available.
| Command | Description |
|---|---|
gbr |
Interactive branch switcher (fzf + live log preview) |
glog |
Browse commit history in fzf, open selected in $PAGER |
gstash |
fzf stash manager: pop, drop, preview diff |
groh |
git reset --hard origin/<current-branch> (safe) |
gst |
git status -sb |
gaa |
git add --all |
gcm |
git commit -m |
gpf |
git push --force-with-lease (safer than --force) |
gwip |
Commit everything as WIP |
No external requirements. Optional: fzf, btop, eza, bat.
| Command | Description |
|---|---|
sysinfo |
Full system overview: CPU, RAM, disk, network, uptime |
memtop [n] |
Top N processes by memory usage (default: 10) |
fkill [signal] |
fzf process picker with multi-select kill |
portopen <host> <port> |
Check if a port is reachable |
dus [path] |
Disk usage sorted by size |
psg <pattern> |
Grep running processes |
Requires docker in PATH. Daemon availability is checked but not required.
| Command | Description |
|---|---|
dksh [container] |
fzf container picker → exec shell |
dkclean |
Prune stopped containers, images, volumes, networks |
dkip |
Print all running container IPs |
dps / dpsa |
docker ps / docker ps -a |
dcu / dcd |
docker compose up -d / docker compose down |
dklog |
docker logs -f |
dkstats |
docker stats --no-stream |
Requires pacman. Auto-detects yay, paru, or pikaur for AUR.
| Command | Description |
|---|---|
zl_arch_orphans [list|remove] |
List or remove orphaned packages |
zl_arch_biggest [n] |
Top N packages by installed size |
zl_arch_updates |
Check for available updates via checkupdates |
pacfzf |
fzf-powered package search and install |
Enables a plugin that exists in $ZL_HOME/plugins/<n>/. Adds it to plugins.conf.
Runs the security scanner before enabling. Prompts for confirmation unless --yes.
Removes the plugin from plugins.conf. Plugin files are kept on disk.
Same as install/remove but without the safety scan prompt. Use for plugins you've already reviewed.
Shows all plugins in $ZL_HOME/plugins/ with version, status (loaded/disabled/failed),
and description.
Shows only enabled plugins with their metadata.
Displays plugins from $ZL_HOME/config/registry.json. Requires jq.
Runs a full health check across 8 sections:
- System (zsh version, login shell, disk, memory)
- ZeroLinux installation (core files, symlinks, .zshrc block)
- Plugin validation (structure, metadata, dependencies, security)
- Required and optional tools
- Configuration files
- Fonts
- Shell environment
- Arch-specific (orphans, updates)
Exit codes: 0 = healthy, 1 = failures found, 2 = warnings only.
Shows version, ZL_HOME path, shell version, and plugin count.
Prints the commands to reload ZeroLinux in the current session.
The zl binary cannot reload its parent shell — use source ~/.zshrc or
the zl-reload alias instead.
cp -r ~/.zerolinux/plugins/example ~/.zerolinux/plugins/mypluginname = myplugin
version = 1.0.0
description = One sentence describing what this plugin does
dependencies = # comma-separated plugin names, or empty
requires_zl = 2.1.0
author = Your Name# Dependency guard — always return 0 on missing deps (never fail hard)
if ! zl::has mytool; then
zl::log::warn "plugin[myplugin]: 'mytool' not found — disabled"
return 0
fi
plugin_init() {
zl::log::debug "plugin[myplugin]: init"
# Pre-load setup: environment checks, variable initialization
# Do NOT source commands.zsh here — the plugin manager does this
}
plugin_register_commands() {
zl::log::debug "plugin[myplugin]: commands registered"
# Register keybindings or completions here if needed
}# All function names must be prefixed: zl_myplugin_*
# All variables must be local or typeset
alias mp='myplugin-shortcut'
zl_myplugin_main() {
local arg="${1:-}"
[[ -z "$arg" ]] && { echo "Usage: zl_myplugin_main <arg>"; return 1; }
zl::has mytool || { zl::log::error "mytool not found"; return 1; }
mytool "$arg"
}zl install plugin myplugin
exec zsh
zl list plugins # confirm it loaded
zl doctor # confirm no issuesThe plugin manager controls this order exactly. Do not deviate.
1. source init.zsh
2. plugin_init() ← called and immediately unfunction'd
3. source commands.zsh
4. plugin_register_commands() ← called and immediately unfunction'd
plugin_init and plugin_register_commands are removed from the shell
after each call. This prevents name collisions between plugins.
# plugin.zl
dependencies = git, systemZeroLinux resolves dependencies with a topological sort and detects circular
dependencies. If myplugin depends on git, the git plugin loads first.
Every plugin function that executes during load (plugin_init, plugin_register_commands)
is unfunction'd immediately after. This means:
- Plugin A cannot call Plugin B's init function
- Generic names like
initorsetupcannot leak globally - A broken plugin does not affect other plugins
Runs before every plugin load. Detects:
| Pattern | Risk |
|---|---|
alias rm=… |
Replaces system command |
function sudo() |
Shadows system command |
curl … | sh |
Remote code execution |
eval "$var" |
Arbitrary code execution |
In warn mode (default): logs the finding, loads the plugin anyway.
In strict mode (ZL_STRICT_SAFETY=1): blocks the plugin from loading.
The loader uses ZL_SAFE_MODE=1 to skip all plugins:
ZL_SAFE_MODE=1 zsh # safe shell for debuggingThe shell always starts, even if every plugin fails. Failures are logged, not propagated.
ZL_LOG_LEVEL=0 ZL_TELEMETRY=1 zsh -i -c exitDebug output will show which plugin or step is slow. Typical causes:
- A plugin that runs a slow command at init time
compinitrunning a full check (fixed by deleting~/.zcompdumponce)
ZL_LOG_LEVEL=0 zsh -c "source ~/.zerolinux/core/loader.zsh"Look for [ZL:ERROR] lines. Common causes:
- External dependency not installed (
zl::hascheck at top ofinit.zsh) - Syntax error in
commands.zsh - Plugin directory missing from
$ZL_PLUGINS_DIR
Disable the offending plugin and restart:
zl disable plugin <name>
exec zshZL_SAFE_MODE=1 zsh # starts without any pluginsThen identify the problem plugin:
ZL_LOG_LEVEL=0 ZL_SAFE_MODE=0 zsh 2>&1 | head -30bash ~/.zerolinux_backup/<timestamp>/restore.sh~/.zerolinux/
├── VERSION
├── bin/
│ └── zl # CLI tool
├── core/
│ ├── loader.zsh # Entry point — sourced from .zshrc
│ ├── logger.zsh # Structured logging (DEBUG/INFO/WARN/ERROR)
│ ├── utils.zsh # Shared utilities (zl::* namespace)
│ ├── plugin_manager.zsh # Lifecycle, dependency resolution, scanner
│ ├── config.zsh # Shell environment, aliases, completions
│ └── welcome.zsh # Startup screen (once per session)
├── config/
│ ├── default.zsh # Shipped defaults
│ ├── plugins.conf # Enabled plugin list
│ └── registry.json # Plugin registry
├── plugins/
│ └── <name>/
│ ├── plugin.zl # Metadata
│ ├── init.zsh # plugin_init()
│ └── commands.zsh # Aliases and functions
├── themes/
│ └── zerolinux.zsh-theme
└── logs/
└── zl.log
.zshrc
└── source loader.zsh
├── source logger.zsh
├── source utils.zsh
├── source plugin_manager.zsh
├── source config.zsh
│ ├── source config/default.zsh
│ └── source ~/.zerolinuxrc
├── welcome screen (once)
└── zl::plugin::load_all
├── read plugins.conf
├── resolve dependency order (topological sort)
└── for each plugin:
├── validate structure
├── check ZL version compatibility
├── run security scanner
├── source init.zsh
├── call plugin_init() → unfunction
├── source commands.zsh
└── call plugin_register_commands() → unfunction
| Scope | Convention |
|---|---|
| Core public API | zl::module::function |
| Core private helpers | _zl::module::function |
| Plugin functions | zl_pluginname_function |
| Global state variables | ZL_UPPERCASE |
| Temp/loop variables | _zl_lowercase |