nor-cli
v0.71.0
Published
Organise packages and reproducible workstation state
Downloads
1,007
Readme
NOR - Organize Repos
A unified Linux CLI for managing packages, systemd units, editor extensions, dotfiles, 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, dotfiles, and custom installs 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.
To update:
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-cliCustom packages installed from recipes are left under ~/.nor/out.
Features
- Unified interface for Pacman/AUR, DNF, Homebrew, Nix, Flatpak, npm, pnpm, .NET global tools, VS Code extensions, VSCodium extensions, Archbox (Arch via Distrobox), systemd, ZVM, YADM, and custom recipes
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, or archbox.
Usage
After installing, run commands with nor:
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 | Sync all package managers |
| nor search <name> | Search across enabled package managers |
| nor restore | Run the aggregate restore workflow |
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> | Add a tap |
| 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 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 |
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
Custom package flows provided as TypeScript recipes in ~/.config/nor/custom. Each file name is the custom package name, such as ~/.config/nor/custom/blender.ts, and is also the Arch/AUR package name used for version lookup.
Recipes export only normalizeVersion and install. Each function receives ctx, which includes ctx.version, ctx.sh, ctx.dirs, and small helpers for downloading and extracting archives. normalizeVersion receives the raw package version in ctx.version; install receives the normalized version.
Recipe installs use ctx.dirs.install, which resolves to ~/.nor/out/<name>. Custom packages also create command symlinks in ~/.nor/bin; add that directory to your PATH if you want to run custom package binaries from a shell. The symlink name defaults to the basename of the returned bin path, or recipes may return optional binName to choose a custom command name. Recipes may return optional desktop metadata to create a desktop launcher. Removal is handled by nor and cleans the download directory, install directory, bin links, and desktop launcher.
| Command | Description |
| ------------------------------- | -------------------------------------- |
| nor custom sync | Update tracked custom packages |
| nor custom install <names...> | Install custom packages by recipe name |
| nor custom update | Update tracked custom packages |
| nor custom remove <names...> | Remove installed custom packages |
| nor custom restore | Install all custom recipes |
Example ~/.config/nor/custom/blender.ts recipe:
import type { Custom } from '../types';
export default {
normalizeVersion(ctx) {
// Arch reports Blender versions with an epoch prefix, such as 17:4.4.3-1.
return ctx.version.split(':')[1]!.split('-')[0]!;
},
async install(ctx) {
// Blender hosts downloads under a major.minor release directory.
const release = ctx.version.split('.').slice(0, -1).join('.');
const archive = await ctx.download(
`https://download.blender.org/release/Blender${release}/blender-${ctx.version}-linux-x64.tar.xz`,
);
const dir = await ctx.extract(archive);
const icon = `${ctx.dirs.icons}/blender.svg`;
// Reuse the icon bundled in the extracted Blender archive.
ctx.sh.exec('cp', [`${dir}/blender.svg`, icon]);
return {
bin: `${dir}/blender-launcher`,
icon,
desktop: {
categories: ['Graphics', '3DGraphics'],
comment: 'Blender 3D Creation Suite',
name: 'Blender',
},
};
},
} satisfies Custom;Example ~/.config/nor/custom/godot.ts recipe:
import type { Custom } from '../types';
export default {
normalizeVersion(ctx) {
// Strip the package release suffix from versions such as 4.4.1-1.
return ctx.version.split('-')[0]!;
},
async install(ctx) {
const archive = await ctx.download(
`https://downloads.godotengine.org/?version=${ctx.version}&flavor=stable&slug=mono_linux_x86_64.zip&platform=linux.64`,
// Godot serves this URL through a redirect with the real filename in headers.
{ contentDisposition: true },
);
const dir = await ctx.extract(archive);
// Godot's release archive does not include a desktop icon in the needed path.
const icon = await ctx.downloadIcon(
'https://godotengine.org/assets/press/icon_color.svg',
);
return {
bin: `${dir}/Godot_v${ctx.version}-stable_mono_linux.x86_64`,
binName: 'godot',
icon,
desktop: {
categories: ['Development', 'IDE'],
comment: 'Godot Game Engine',
name: 'Godot',
},
};
},
} satisfies Custom;The installer writes the helper type file to ~/.config/nor/types.ts. The import is optional at runtime, but useful for editor checking.
nor custom sync also runs an optional user sync hook at ~/.config/nor/sync.ts before updating tracked custom packages:
export default async ({ sh }) => {
sh.exec('example-command', ['--flag']);
};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.
| 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 |
State
Use nor state --all to print all saved state, or nor state <manager>
[query] to inspect one manager and optionally filter its entries.
Configuration
File: ~/.config/nor/config.json
{
"archbox": {
"aur": { "helper": null },
"enabled": false,
"name": "archbox",
"state": { "ignore": { "packages": [] } }
},
"brew": { "enabled": false },
"code": { "enabled": false },
"codium": { "enabled": false },
"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
}
},
"pnpm": { "enabled": false },
"systemd": { "enabled": false },
"yadm": { "enabled": false },
"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
