nor-cli
v0.84.4
Published
Organise packages and reproducible workstation state
Readme
NOR - Organize Repos
A unified Linux CLI for managing packages, systemd units, editor extensions, dotfiles, custom GitHub release packages, and reproducible workstation state across multiple package managers.
What This Solves
Modern Linux workstations often end up spread across multiple package and configuration systems: DNF packages, Homebrew tools, Flatpak apps, global pnpm packages, editor extensions, dotfiles, and sometimes Arch/AUR packages through a container. Keeping that setup updated, searchable, and reproducible usually means remembering many different commands and manually tracking what is installed where.
nor turns that scattered environment into a single managed package stack. It provides one CLI for syncing updates, searching across supported repositories, saving package inventories, and restoring a workstation later. This makes it easier to rebuild a machine, migrate to a new laptop, recover after a reinstall, or simply keep a daily Linux setup consistent.
This project came from trying different Linux distributions, including NixOS, and wanting the reproducibility benefits without adopting the full Nix workflow. nor keeps the familiar package managers and habits of standard Linux distributions while adding a practical restore path for the tools, apps, extensions, and dotfiles that make up a real workstation.
Installation
Homebrew
Homebrew needs a working system C compiler and the standard development tools when it builds formulae without bottles.
Fedora:
sudo dnf group install development-tools
sudo dnf install procps-ng curl fileDebian or Ubuntu:
sudo apt-get install build-essential procps curl file gitbrew tap yunieralvarez/tap https://gitlab.com/yunieralvarez/nor.git
brew install norThe formula installs the nor command into Homebrew's bin directory and builds the CLI from the tagged release source.
Arch Linux
Build and install the tracked PKGBUILD:
git clone https://gitlab.com/yunieralvarez/nor.git
cd nor
makepkg -siThe package installs nor under /usr/lib/nor and links the command into
/usr/bin.
npm
Install the public npm package globally:
npm install --global nor-cliThe package name is nor-cli, but the installed command is nor.
Updating
Homebrew:
brew update
brew upgrade norFor Arch packages built directly from the PKGBUILD, pull the latest release and
run makepkg -si again.
For npm:
npm update --global nor-cliUninstall
brew uninstall norArch Linux:
sudo pacman -Rns nornpm:
npm uninstall --global nor-cliFeatures
- Unified interface for Pacman/AUR, DNF, Homebrew, Nix, Flatpak, AppImages through Gear Lever, npm, pnpm, .NET global tools, VS Code extensions, VSCodium extensions, Archbox (Arch via Distrobox), systemd, ZVM, and YADM
- Custom sync hook for running additional user-defined commands
- Custom release packages downloaded from GitHub Releases and integrated through Gear Lever
nor sync- update everything with one commandnor search <name>- search all supported package repositories simultaneously- Per-manager restore commands - restore saved package and extension lists
- State tracking - package inventories persisted to
~/.local/state/nor/state.json
Requirements
- Node.js
- Homebrew,
makepkg, or npm for the supported installation methods
The Homebrew formula and Arch package install Node.js automatically. Linux
systems still need the build tools listed above when Homebrew builds nor from
source. Individual nor subcommands require their underlying tools when enabled,
such as pacman, dnf, brew, nix, flatpak, npm, pnpm, dotnet,
systemctl, code, codium, yadm, zvm, distrobox, archbox, or
gearlever.
Usage
Confirm the installed command and inspect the commands available for your configuration:
nor --version
nor --help
nor <command> --helpnor creates ~/.config/nor/config.json, sync.ts, and types.ts on its first
run. Package-manager commands are shown only when that manager's enabled
setting is true; the global, custom, wrapper, and state commands are always
available. Edit config.json, then run nor --help again to see the enabled
command groups.
Common examples:
nor sync
nor search ripgrep
nor dotnet install dotnet-ef
nor code install esbenp.prettier-vscode
nor codium install jnoortheen.nix-ideFor local development, install dependencies and run commands through pnpm start:
pnpm install
pnpm start [command] [options]pnpm start sync
pnpm start search ripgrep
pnpm start dotnet install dotnet-ef
pnpm start code install esbenp.prettier-vscode
pnpm start codium install jnoortheen.nix-ideGlobal commands
| Command | Description |
| ------------------- | -------------------------------------- |
| nor sync (sy) | Sync all enabled package managers |
| nor search <name> (se) | Search enabled searchable managers |
| nor restore | Run the aggregate restore workflow |
| nor state --all | Print all saved state in the flat format |
| nor state --all --json | Print all saved state as JSON |
| nor state <manager> [query] | Inspect or filter one manager's state |
Most manager command groups use the same short aliases: sync → sy,
install → in, update → up, remove → rm, and search → se.
Run nor <manager> --help for the exact commands and arguments supported by a
manager.
Pacman
Native Arch Linux repository and AUR package management. The configured command backend can use Pacman, aurutils, or an AUR helper.
| Command | Description |
| -------------------------------- | ------------------------------------------- |
| nor pacman sync | Update packages, autoremove, and save state |
| nor pacman install <names...> | Install packages |
| nor pacman update [names...] | Update all or selected packages |
| nor pacman downgrade <names> | Install a cached older package version |
| nor pacman remove <names...> | Remove packages |
| nor pacman auto-remove | Remove unused dependencies |
| nor pacman search <name> | Search packages |
| nor pacman info <name> | Show package details |
| nor pacman ignore <names...> | Exclude packages from managed updates |
| nor pacman unignore <names...> | Stop excluding packages |
| nor pacman watch <names...> | Track uninstalled packages in saved state |
| nor pacman unwatch <names...> | Stop tracking uninstalled packages |
| nor pacman restore | Restore saved explicitly installed packages |
DNF
Fedora system packages and package groups.
| Command | Description |
| ---------------------------------- | ---------------------------------------- |
| nor dnf sync | Upgrade packages, autoremove, save state |
| nor dnf install <names...> | Install packages |
| nor dnf update | Upgrade packages |
| nor dnf remove <names...> | Remove packages |
| nor dnf group-install <names...> | Install package groups |
| nor dnf group-remove <names...> | Remove package groups |
| nor dnf auto-remove | Remove unused dependencies |
| nor dnf search <name> | Search packages |
| nor dnf info <name> | Show package details |
| nor dnf restore | Restore saved packages and groups |
Homebrew
Formulae, casks, and taps.
| Command | Description |
| ------------------------------------ | --------------------------------------- |
| nor brew sync | Update, upgrade, and save state |
| nor brew install <names...> | Install formulae |
| nor brew install --cask <names...> | Install casks |
| nor brew tap <name> [url] | Add a tap, optionally from a custom URL |
| nor brew untap <name> | Remove a tap |
| nor brew update | Update and upgrade packages |
| nor brew remove <names...> | Uninstall packages |
| nor brew search <name> | Search packages |
| nor brew search --appimage <name> | Search AppImage casks |
| nor brew info <name> | Show package details |
| nor brew restore | Restore saved taps, formulae, and casks |
Archbox
Arch Linux packages through the archbox Distrobox container and the configured AUR helper.
| Command | Description |
| --------------------------------------------- | --------------------------------------------- |
| nor archbox sync | Ensure Archbox exists, update, and save state |
| nor archbox install <names...> | Install packages |
| nor archbox update | Update packages |
| nor archbox remove <names...> | Remove packages |
| nor archbox search <names...> | Search packages |
| nor archbox info <names...> | Show package details |
| nor archbox export-apps <names...> | Export desktop apps from Archbox |
| nor archbox export-apps --delete <names...> | Delete exported desktop apps |
| nor archbox export-bins <names...> | Export binaries from Archbox |
| nor archbox export-bins --delete <names...> | Delete exported binaries |
| nor archbox restore | Restore packages and exports |
Flatpak
Flatpak applications and runtimes.
| Command | Description |
| ----------------------------------------- | ---------------------------------------------- |
| nor flatpak sync | Update, remove unused runtimes, and save state |
| nor flatpak install <remote> <names...> | Install apps from a remote |
| nor flatpak update | Update apps and remove unused runtimes |
| nor flatpak remove <names...> | Remove apps |
| nor flatpak search <name> | Search apps |
| nor flatpak restore | Restore saved apps by remote |
AppImage
AppImages integrated with Gear Lever. This group is shown when
appimage.enabled is enabled and requires the gearlever CLI. Installing from
Homebrew also requires brew.enabled and a Homebrew cask that contains an
AppImage artifact.
| Command | Description |
| --------------------------------------- | --------------------------------------------------- |
| nor appimage sync | Update Homebrew-sourced AppImages and save state |
| nor appimage install-from-brew <name> | Install a cask's AppImage and integrate it |
| nor appimage update | Update AppImages installed through Homebrew |
| nor appimage remove <name> | Remove an integrated AppImage and update saved state |
install-from-brew also has the alias in-from-brew.
AppImages installed through this command retain their Homebrew token and source
version in saved state so sync and update can check the corresponding cask.
AppImages from unknown sources are inventoried but are not automatically
updated.
pnpm
Global pnpm packages.
| Command | Description |
| ----------------------------- | ------------------------------------- |
| nor pnpm sync | Update global packages and save state |
| nor pnpm install <names...> | Install global packages |
| nor pnpm update | Update global packages |
| nor pnpm remove <names...> | Remove global packages |
| nor pnpm restore | Restore saved global packages |
npm
Global npm packages.
| Command | Description |
| ---------------------------- | ------------------------------------- |
| nor npm sync | Update global packages and save state |
| nor npm install <names...> | Install global packages |
| nor npm update | Update global packages |
| nor npm remove <names...> | Remove global packages |
| nor npm restore | Restore saved global packages |
Nix
Packages installed in the current Nix profile.
| Command | Description |
| ---------------------------- | ------------------------------------------------ |
| nor nix sync | Clean profile history and save state |
| nor nix install <names...> | Add packages from nixpkgs |
| nor nix update | Upgrade all profile packages |
| nor nix remove <names...> | Remove packages from the profile |
| nor nix search <name> | Search nixpkgs |
| nor nix gc | Clean profile history and run garbage collection |
| nor nix restore | Restore saved profile packages |
Dotnet
.NET global tools. This command only runs when dotnet.enabled is enabled in config.json and requires the dotnet CLI.
| Command | Description |
| ------------------------------- | ---------------------------------- |
| nor dotnet sync | Update global tools and save state |
| nor dotnet install <names...> | Install global tools |
| nor dotnet update | Update global tools |
| nor dotnet remove <names...> | Uninstall global tools |
| nor dotnet restore | Restore saved global tools |
VS Code and VSCodium
Extension management is available for both editor commands:
nor code ...uses thecodeCLI.nor codium ...uses thecodiumCLI.
| Command | Description |
| ------------------------------- | ----------------------------------------- |
| nor code sync | Update VS Code extensions and save state |
| nor code install <names...> | Install VS Code extensions |
| nor code update | Update VS Code extensions |
| nor code remove <names...> | Remove VS Code extensions |
| nor code restore | Restore saved VS Code extensions |
| nor codium sync | Update VSCodium extensions and save state |
| nor codium install <names...> | Install VSCodium extensions |
| nor codium update | Update VSCodium extensions |
| nor codium remove <names...> | Remove VSCodium extensions |
| nor codium restore | Restore saved VSCodium extensions |
Custom
The custom command combines a TypeScript sync hook with config-driven packages from GitHub Releases.
| Command | Description |
| -------------------------------------------- | --------------------------------------------- |
| nor custom sync (sy) | Run the hook, update packages, and save state |
| nor custom install <configured-name> (in) | Install one configured package |
| nor custom update (up) | Update all installed custom packages |
| nor custom remove <configured-name> (rm) | Remove one configured package |
Use ~/.config/nor/sync.ts for commands that are not covered by an enabled
manager. nor creates this file and its companion types.ts definition on first
run.
The module must default-export a synchronous or asynchronous function. Its
context exposes sh.exec, sh.capture, and sh.env. Commands and arguments
are passed separately:
import type { UserSync } from './types.ts';
export default (async ({ sh }) => {
sh.exec('example-command', ['--flag']);
const version = sh.capture('example-command', ['--version']);
console.log(version);
}) satisfies UserSync;The hook runs with nor custom sync and as part of the aggregate nor sync
workflow.
Custom packages are declared in config.json. Each package currently uses the
latest GitHub Release, selects an asset by its exact expanded name, verifies the
SHA-256 digest published by GitHub, and integrates the downloaded AppImage with
Gear Lever. {tag} and {name} in the asset pattern expand to the release tag
and release name respectively. The configured package names become subcommands
under nor custom install and nor custom remove:
{
"custom": {
"packages": [
{
"name": "example",
"source": {
"type": "github",
"repo": "owner/repository",
"asset": "example-{tag}-x86_64.AppImage"
},
"integration": "gearlever"
}
]
}
}This workflow requires curl, the gearlever CLI, and a GitHub Release asset
with a SHA-256 digest.
ZVM
Zig Version Manager.
| Command | Description |
| ---------------- | ----------- |
| nor zvm sync | Upgrade ZVM |
| nor zvm update | Upgrade ZVM |
YADM
Dotfile sync. This command only runs when yadm.enabled is enabled in
config.json. Paths in yadm.paths are added before committing and pushing.
Files mirrored under ~/.config/etc are copied over matching files in /etc;
nor creates a timestamped backup first and uses sudo for these copies.
| Command | Description |
| --------------- | ----------------------------------------- |
| nor yadm sync | Sync configured dotfiles and push changes |
systemd
Enabled system and user services, sockets, and timers.
| Command | Description |
| ------------------------------------- | ----------------------------- |
| nor systemd sync | Save enabled units |
| nor systemd enable <names...> | Enable and start system units |
| nor systemd enable-user <names...> | Enable and start user units |
| nor systemd disable <names...> | Disable and stop system units |
| nor systemd disable-user <names...> | Disable and stop user units |
| nor systemd restore | Restore saved enabled units |
Wrapper
Create or remove executable wrappers. Brew wrappers run commands with the
configured Homebrew environment; the optional wrapper.suffix setting is
appended to generated wrapper names.
| Command | Description |
| -------------------------------------- | ------------------------------------------ |
| nor wrapper add-brew <cmd> | Create a wrapper for a Homebrew command |
| nor wrapper add-flatpak <app-id> | Create a wrapper that runs a Flatpak app |
| nor wrapper rm <cmd> | Remove a generated wrapper |
State
Use nor state --all to print all saved state, or nor state <manager>
[query] to inspect one manager and optionally filter its entries. Add --json
to print the selected raw state object instead of the default flat,
human-readable output:
nor state --all --json
nor state --json appimageConfiguration
File: ~/.config/nor/config.json
{
"appimage": { "enabled": false },
"archbox": {
"aur": { "helper": null },
"enabled": false,
"name": "archbox",
"state": { "ignore": { "packages": [] } }
},
"brew": {
"enabled": false,
"path": "/home/linuxbrew/.linuxbrew/bin/brew"
},
"code": { "enabled": false },
"codium": { "enabled": false },
"custom": { "packages": [] },
"dnf": {
"enabled": false,
"refresh": false,
"state": { "ignore": { "groups": [], "packages": [] } }
},
"dotnet": { "enabled": false },
"flatpak": { "enabled": false },
"nix": {
"allowUnfree": false,
"enabled": false,
"store": { "historyRetention": "" }
},
"npm": { "enabled": false },
"pacman": {
"commands": {
"info": "pacman",
"install": { "backend": "package", "fallback": null, "retry": false },
"search": "pacman",
"update": "pacman"
},
"enabled": false,
"aurUtils": {
"cleanAfterUpdate": false,
"keepVersions": 1,
"repoDir": null,
"repoName": null
},
"restore": { "exclude": [] }
},
"pnpm": { "enabled": false },
"systemd": { "enabled": false },
"wrapper": { "suffix": "" },
"yadm": { "enabled": false, "paths": [] },
"zvm": { "enabled": false }
}Development Commands
pnpm fmt # Format source code with Prettier
pnpm start # Run the CLI from TypeScript
pnpm build # Build dist/main.js
scripts/release.sh # Publish a release to Git, Homebrew, Arch, and npmLicense
MIT
