One command. Every package manager.
Remembering the exact syntax to install a package across different operating systems
(apt, pacman, brew, apk, winget) is a frustrating and error-prone chore.
pkgwrap gives you one universal command that detects your OS and translates
standard operations into native syntax.
$ pkgwrap install nmap curl
→ Running: sudo apt install nmap curl- Zero configuration. Detects your OS and native package manager out of the box.
- Muscle-memory saver. Stop pausing to recall whether it is
pacman -S,apt installordnf install. - Safe by default. pkgwrap never silences your package manager's own confirmation prompt
unless you explicitly pass
-y. Commands run withshell=False, so package names are never interpreted by a shell. - Ultra lightweight. No dependencies, no network calls, no background services.
Why not just memorise apt/pkg/pacman? If you only use one OS, do exactly that.
But if you move between a Debian VPS, a macOS workstation, an Alpine container, a
Windows laptop and a Termux shell, pkgwrap removes the friction.
pkgwrap is distributed from source only - it is not published on PyPI or any other package index. Install it directly from this repository.
curl -fsSL https://raw.githubusercontent.com/trmxvibs/pkgwrap/main/install.sh -o install.sh
less install.sh # always read a script before running it
bash install.shThe script clones the repository to ~/.local/share/pkgwrap/src and picks the
right install strategy for your system automatically: an active virtualenv,
then pipx, then pip --user, and finally a dedicated venv with
pkgwrap/pkw symlinked into ~/.local/bin.
git clone https://github.com/trmxvibs/pkgwrap.git
cd pkgwrap
bash install.sh --localIf you would rather run pip yourself:
git clone https://github.com/trmxvibs/pkgwrap.git
cd pkgwrap
pipx install . # isolated, always on PATH
# or
pip install --user .On modern Debian, Ubuntu and Fedora the system Python is externally managed
(PEP 668), so a plain pip install . is refused. Use pipx, pip --user, or
a virtual environment.
install.sh is a bash script and does not run in cmd.exe or PowerShell
directly (use it from Git Bash or WSL if you prefer a bash workflow). On a
plain Windows Command Prompt, install with pip instead:
git clone https://github.com/trmxvibs/pkgwrap.git
cd pkgwrap
pip install -e ".[dev]"-e (editable) means git pull alone picks up new changes without
reinstalling - this is also the workflow for anyone developing pkgwrap
itself. .[dev] additionally pulls in pytest and ruff for testing and
linting; drop it for a plain end-user install (pip install .).
Verify the install:
pkgwrap --version
pkw --version
pkgwrap --backendIf pkgwrap/pkw are "not recognized" right after installing, pip put
them in a Scripts folder that is not on your PATH yet - most commonly
%APPDATA%\Python\Python3x\Scripts for a per-user install, or
<venv>\Scripts inside a virtual environment. pip install prints the
exact folder in a "WARNING: The script ... is installed in '...' which is
not on PATH" line when this happens; add that folder to PATH (Windows
Settings → "Edit environment variables for your account") and open a new
terminal.
To uninstall on Windows:
pip uninstall pkgwrapbash install.sh --updateOn Windows, update by pulling and letting the editable install pick it up:
git pull origin mainbash install.sh --uninstallNote on PyPI. Earlier builds were published as
pkgwrap-lokeshon PyPI. That package is no longer maintained and will not receive further updates. If you installed it that way, remove it withpip uninstall pkgwrap-lokesh(orpipx uninstall pkgwrap-lokesh) and reinstall from source.
pkgwrap install <package> [<package> ...] # install one or more packages
pkgwrap remove <package> [<package> ...] # remove packages
pkgwrap refresh # refresh repository metadata only
pkgwrap upgrade # upgrade all installed packages
pkgwrap search <query> # search the repositories
pkgwrap list # list installed packages
pkgwrap info <package> # show package details
pkgwrap clean # clean the local package cache
pkw install <package> # short alias, identical behaviour| Flag | Meaning |
|---|---|
-y, --yes |
Non-interactive: skip pkgwrap's prompts and pass the package manager's own non-interactive flag |
-n, --dry-run |
Print the exact command that would run, without executing it |
--backend |
Print the detected backend and exit |
--backend NAME |
Force a specific backend for this run |
--no-cache |
Ignore the cached detection result and probe again |
--clear-cache |
Delete the cached detection result and exit |
--version |
Print the version |
| Command | Aliases |
|---|---|
install |
in, add |
remove |
uninstall, del, rm |
refresh |
sync |
upgrade |
up, update |
search |
find |
list |
ls |
info |
show |
refreshvsupgrade.refreshonly updates repository metadata (apt update,pacman -Sy,zypper refresh).upgradeactually upgrades installed packages. They are separate commands on purpose, so nothing is upgraded by surprise.
| Variable | Effect |
|---|---|
PKGWRAP_BACKEND |
Force a backend for every invocation |
NO_COLOR / PKGWRAP_NO_COLOR |
Disable coloured output |
FORCE_COLOR |
Force colour even when output is piped |
XDG_CONFIG_HOME |
Where the detection cache is stored (Unix) |
pkgwrap tries never to leave you without a safety net:
- If the operation needs root and you are not root, pkgwrap prefixes
sudoand asks you to confirm. Ifsudois missing, it says so instead of failing cryptically. - Without
-y, pkgwrap does not pass-y/--noconfirmto the package manager, so the package manager's own confirmation still appears. - For package managers that never prompt (apk, brew, nix, MacPorts, winget, pkg_add), pkgwrap adds its own confirmation before removals.
- With
-y, both layers are skipped. Use it in scripts, knowingly. --dry-runshows the exact command and executes nothing.
| OS / distro | Backend | Command | Root handling |
|---|---|---|---|
| Debian, Ubuntu, Mint | apt |
apt |
sudo |
| Termux (Android) | pkg |
pkg |
none needed |
| Arch, Manjaro, EndeavourOS | pacman |
pacman |
sudo |
| Fedora, RHEL 8+, CentOS Stream | dnf |
dnf |
sudo |
| RHEL 7, older CentOS, slim images | yum |
yum |
sudo |
| Alpine | apk |
apk |
sudo |
| openSUSE, SLE | zypper |
zypper |
sudo |
| Void Linux | xbps |
xbps-install |
sudo |
| Solus | eopkg |
eopkg |
sudo |
| Gentoo | emerge |
emerge |
sudo |
| NixOS / Nix profiles | nix |
nix-env |
none needed |
| macOS (Homebrew) | brew |
brew |
never root |
| macOS (MacPorts) | port |
port |
sudo |
| FreeBSD | freebsd |
pkg |
sudo |
| OpenBSD, NetBSD | openbsd |
pkg_add |
sudo |
| Windows | winget |
winget |
UAC |
| Windows (fallback) | choco |
choco |
elevated shell |
Verification status. Commands for every backend have been checked against
upstream documentation, and the shapes that matter are pinned by tests in
tests/backends/test_verified_commands.py. Five backends — yum, emerge,
port, openbsd and choco — have not yet been run on the systems they
target. If you use one of these, pkgwrap <command> --dry-run prints the
exact command without executing it; please report what you see.
Notes:
- Termux and FreeBSD both expose a
pkgcommand; they are distinguished by strict environment and OS checks, never by the command name alone. - Homebrew refuses to run as root, so pkgwrap never escalates for it and warns if you are already root.
- On NixOS, system packages are managed declaratively in
configuration.nix. This backend only touches the current user'snix-envprofile. - On Arch, installing without a recent sync can fail; run
pkgwrap upgrade(pacman -Syu) rather than mixing a bare refresh with an install. - Not every backend supports every command.
pkgwrap liston Gentoo, for example, reports that the operation is unsupported instead of guessing.
User runs `pkgwrap install nmap curl`
|
v
[cli.py] -- argparse, aliases, flags (-y, -n, --backend, --no-cache)
|
v
[validation.py] -- rejects flag-like or malformed package names
|
v
[detector.py] -- PKGWRAP_BACKEND -> validated cache -> Termux/BSD/Windows/macOS
checks -> prioritised shutil.which() probe
| ^
| |
| [config.py] -- versioned JSON cache in the user config dir
v
[package_map.py] -- canonical name -> backend-specific name
|
v
[backends/__init__.py registry] -- name -> Backend subclass, executable lookup
|
v
[Backend subclass] -- builds the native argument list
|
v
[base.py _run_command()] -- sudo detection, confirmation, dry run,
subprocess.run(shell=False)
|
v
Native package manager executes
git clone https://github.com/trmxvibs/pkgwrap.git
cd pkgwrap
python -m venv venv && source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e ".[dev]"
pytest # run the test suite
ruff check . # lintA virtual environment is optional here - the Windows commands in
Installation install directly with pip install -e ".[dev]"
and work fine without one.
Adding a package manager is a single file in src/pkgwrap/backends/ plus one
line in the registry. The contract tests in tests/backends/test_all_backends.py
apply to it automatically. See CONTRIBUTING.md.
- Core universal wrapper (17 backends)
- Automatic sudo/root detection with confirmation
- Termux-aware detection
- Windows support (winget, Chocolatey fallback)
- Package name mapping across backends
- Multiple packages per command
-
--dry-run - Separate
refreshandupgrade - Shell completion (bash/zsh/fish)
- Language-level package managers (pip/npm/cargo)
-
snap/flatpak/rpm-ostreesupport
MIT — see LICENSE.
Made with ❤️ for the terminal by trmxvibs