A small Fish-shell wrapper around Debian and Ubuntu package tools. Originally a port of rummik/patpat, now maintained at codefriendly/patfish.
Modern apt already handles most package-management tasks. patfish adds short
commands, automatic privilege elevation, and one interface for apt, apt-file,
repository management, and package reconfiguration. It is a convenience layer,
not a new package manager. It is not intended for Arch Linux or Omarchy.
- Fish 3.6 or newer.
- Debian or Ubuntu with
aptanddpkg. sudowhen running privileged commands as a non-root user.apt-fileforupdate,up,find, andfile.software-properties-commonfor repository/PPA commands.aptitudeonly forpat ui.
Install the extra tools you need, for example:
sudo apt install fish apt-file software-properties-common aptitudePPAs are an Ubuntu feature; do not assume an Ubuntu PPA is compatible with Debian.
Clone the repository, then run these commands in Fish:
git clone https://github.com/codefriendly/patfish.git
mkdir -p ~/.config/fish/functions
cp patfish/pat.fish ~/.config/fish/functions/pat.fishFish will load pat automatically on first use. If you customize XDG_CONFIG_HOME,
use $__fish_config_dir/functions instead of ~/.config/fish/functions.
To try it without installing, run source patfish/pat.fish in your current Fish
session. To update an installed copy, pull the repository and copy the file again.
| Command | What it runs |
|---|---|
pat, pat help |
Show help (-h and --help also work) |
pat update / pat u |
sudo apt update, then sudo apt-file update |
pat upgrade |
sudo apt upgrade |
pat up |
Update both indexes, then sudo apt upgrade |
pat install curl / pat i curl |
sudo apt install curl |
pat install ./app.deb |
sudo apt install ./app.deb (including dependencies) |
pat search curl |
apt search curl |
pat show curl |
apt show curl |
pat find bin/curl |
apt-file search bin/curl |
pat file list curl |
sudo apt-file list curl |
pat ui |
sudo aptitude |
pat ppa owner/name |
sudo add-apt-repository ppa:owner/name, then update both indexes |
pat add-repository <repository> / pat add <repository> |
sudo add-apt-repository <repository>, then update both indexes |
pat reconfigure tzdata |
sudo dpkg-reconfigure tzdata |
pat autoremove |
sudo apt autoremove |
pat remove curl |
Other commands pass through to sudo apt |
sudo is omitted when already running as root. Read-only search, show, and
find commands do not request elevated privileges.
Arguments are passed through without eval, preserving spaces and shell
metacharacters. Quote patterns as you normally would in Fish:
pat search 'terminal music player'
pat install './package with spaces.deb'
pat install curl wget ./local-package.deb
pat upgrade -yLocal package paths must start with ./, ../, or /, as required by apt.
pat up accepts no arguments: run pat update and pat upgrade -y separately
if you need upgrade options. pat update passes its arguments only to apt update,
not to apt-file update.
Failures are returned to the caller. An index-update failure stops pat up
before upgrading, and a failed repository addition stops before updating.
Commands retain the underlying tools' confirmation prompts; patfish does not
supply -y automatically. Index updates refresh system state; they are not
transactions and cannot undo an earlier successful step if a later step fails.
- Everyday commands and unknown-command passthrough use
apt, notaptitude. These tools can make different dependency-resolution decisions; useaptitudedirectly if you need its behavior. Its interactive UI remains available throughpat ui. - Local
.debinstallation usesaptto resolve dependencies in one operation, replacing the broken file check and the olddpkg/apt-get -fsequence. - Dispatch no longer uses
eval. - Update and repository failures stop subsequent steps.
- Missing required arguments return status 2 with a diagnostic.
From the repository root:
fish --no-config --no-execute pat.fish
fish --no-config tests/pat.fish
fish_indent --check pat.fish tests/pat.fish tests/debian.fishtests/pat.fish mocks privilege elevation and package-management commands. It
does not install packages, modify repositories, or require Debian/Ubuntu.
CI also runs a separate job in a Debian 13 (debian:trixie-slim) container on an
Ubuntu host. It runs the mocked tests and tests/debian.fish, which exercises
real apt and apt-file index updates, searches, package information, local
.deb installation with dependencies, and package installation/removal through
sudo as a non-root user. Upgrade and autoremove use simulation mode. PPA
commands and the interactive Aptitude UI are not integration-tested.
The integration script changes system packages and creates a test user with
passwordless permission to run apt. Run it only in a disposable container,
never on a persistent machine. It refuses to run outside a recognized Docker or
Podman container. The container is removed after the following local test, and
the repository is mounted read-only:
docker run --rm \
--mount "type=bind,source=$PWD,target=/work,readonly" \
--workdir /work --env DEBIAN_FRONTEND=noninteractive \
debian:trixie-slim sh -ec '
apt-get update
apt-get install -y --no-install-recommends ca-certificates git fish sudo apt-file
fish --no-config tests/pat.fish
fish --no-config tests/debian.fish
'The real package tests require network access to Debian mirrors. apt prints a
warning about its unstable CLI when used noninteractively; this is expected.
The smoke tests check a few package-output markers and installed package state,
not the complete human-readable output.
MIT.