The SSH picker

Not just package managers.

Why a page of its own

The completion contract is not reserved for package managers.

ssh is not a package manager, and that is exactly what it demonstrates. It is the same popup, the same keys and the same frame as for brew or winget — only the catalogue changes. Nothing in the popup knows it is looking at servers rather than packages, because nothing in the contract a provider honours ever mentions packages.

That was written down before the picker existed: a provider announces candidates, and the popup draws them. The SSH picker is what proves the rule holds outside Homebrew, winget, scoop, pacman and yay — and what the next provider, whatever it completes, would look like.

Read ADR-0005 →

In action

Type ssh and a space.

The recordings below read the same ~/.ssh/config — a fixture of invented servers, identical from one system to the next. Nothing about SSH is platform-specific, which is why the three show exactly the same list.

macOS

Type ssh and a space: the servers of your ~/.ssh/config, each with its address alongside. Captured on macOS.

Windows

The same list and the same ~/.ssh/config, under PowerShell — atelier included, which comes from an Include. Captured on Windows.

Omarchy

The same list again, on Arch: the picker reads ~/.ssh/config and nothing else, so nothing about it is platform-specific. Captured on Omarchy.
What it completes

Three commands, and three things worth knowing.

  • Three providers, not one

    ssh, scp and sftp are three separate providers rather than one answering to three names. They read the same file, but each answers for its own command — which is how scp can behave differently from the other two.

  • No verb, so the catalogue comes on the space

    brew install fire needs its subcommand before the catalogue means anything. ssh does not: the operand comes straight after the command name, so the servers appear on the space, with nothing else typed.

  • scp inserts a colon

    Picking nas behind scp inserts nas:, colon attached. It is not cosmetic — without it the command still runs, and does something else entirely.

The two lines below differ by one character, and only one of them reaches a server. The first copies rapport.pdf to a local file named nas, in the current directory — valid, silent, and wrong.

scp rapport.pdf nas /tmp
scp rapport.pdf nas:/tmp

The second is the one you meant. So scp gets the colon, and the other two don't: ssh nas and sftp nas want the bare name.

What it reads

One file, and nothing else.

~/.ssh/config. No known_hosts, no /etc/ssh/ssh_config, no network — jigger never opens a connection, and never asks a server anything.

Three columns: on the left ~/.ssh/config and the Include that pulls in a second file; in the middle the six hosts the popup offers, atelier among them because the Include is followed; on the right the two patterns, Host *.exemple.net and Host *, struck out — a pattern is not a server, and is never offered. WHAT IT READS WHAT THE POPUP OFFERS WHAT IT DROPS ~/.ssh/config Include conf.d/*.conf Host passerelle Host nas Host proxmox Host omarchy Host windows Host *.exemple.net Host * includes are followed conf.d/atelier.conf Host atelier a second file, one more host the six hosts the popup offers passerelle passerelle.exemple.net nas 192.168.1.20 proxmox 192.168.1.10 omarchy 192.168.1.31 windows 192.168.1.32 atelier atelier.exemple.net atelier comes from the second file the Include is what puts it here the two patterns, never offered Host *.exemple.net Host * a name with * ? or ! is not a server offering it would insert an unreachable name what it never reads known_hosts /etc/ssh/ssh_config and no network at all re-read on every keystroke, nothing cached

The file behind both recordings holds an Include, six hosts and two patterns. The Include pulls in atelier from a second file, which is how the recordings show that includes are followed. The six — passerelle, nas, proxmox, omarchy, windows and atelier — are the ones the popup offers, each with its HostName to the right when it differs from the name. The two patterns, Host *.exemple.net and Host *, never appear: a name containing *, ? or ! is not a server, and offering it would insert something you cannot connect to.

Everything is re-read on every keystroke. There is no cache and no warm-up: reading a few fragments of configuration costs a millisecond. SSH is not alone in having nothing to keep — scoop doesn't either, for a different reason: its catalogue is already laid out on disk, one manifest per package, so reading it costs less than caching it.

On a machine with no ~/.ssh/config, nothing appears at all — no popup, no empty box, no “no candidates”. Same when nothing matches what you typed. A provider with an empty catalogue draws no frame.

Nothing to add

It ships with jigger.

There is no separate install and no setting to switch on: the picker lives in the same binary and the same shell plugin as everything else. JIGGER_COMMANDS lists the commands that open the popup — drop ssh, scp and sftp from it and the picker is gone.

Download, wire, use →