A small terminal UI for organising SSH connections — add, edit, delete and tag hosts without hand-editing config files.
Hosts live in ~/.ssh/config, so everything this tool manages stays usable with
plain ssh <alias>, scp, rsync and anything else that reads the SSH config.
Uninstalling ssh-list leaves your connections working.
SSH LIST 3/3 hosts ~/.ssh/config
press / to search, ? for help
▸ ● web-01 deploy@192.0.2.10:2222 prod web 2h ago
● build-box ci@build.example.com ci 3d ago
db-01 db.example.com db prod never
↑↓ move · enter connect · / search · a add · e edit · d delete · ? help
The dot shows reachability after pressing p; hosts that have not been probed
carry no marker.
go build -o ssh-list . # build here
go install # or install to $(go env GOPATH)/binRequires Go 1.25+ and the ssh client on PATH.
| Key | Action |
|---|---|
↑/k, ↓/j |
Move selection |
enter |
Connect with ssh |
/ |
Search alias, hostname, user or tag |
a / e / d |
Add / edit / delete host |
t / T |
Cycle tag filter / clear it |
s |
Toggle sort: config order ↔ most recently used |
p |
Probe visible hosts for reachability |
y |
Copy ssh <alias> to the clipboard |
r |
Reload the config from disk |
? |
Full keyboard reference |
q |
Quit |
In the add/edit form: tab/shift+tab move between fields, ctrl+f cycles
through private keys found in ~/.ssh for the IdentityFile field, ctrl+s
saves and esc cancels.
Tags are written as a comment directly above the Host line. OpenSSH ignores
comments, so this is invisible to ssh itself:
#: tags: prod, web
Host web-01
HostName 192.0.2.10
User deploy
Port 2222
Tags are lowercased, de-duplicated and sorted on save.
The parser keeps every source line verbatim and only rewrites the specific
directives you change. Unknown keywords, Match blocks, Host * defaults,
comments, = separators, tabs and ordering all survive editing untouched.
Writes are atomic — a temp file is written and fsynced, then renamed over the
target — so an interrupted write cannot truncate a working config. The previous
contents are kept at ~/.ssh/config.bak.
Host * and Match stanzas configure defaults rather than destinations, so
they are not listed as connectable hosts, but they are preserved on write.
Include directives are preserved but not followed: hosts defined in included
files are not listed or editable.
-list prints alias<TAB>target<TAB>tags, which pipes cleanly into other tools:
ssh-list -list # all hosts
ssh-list -list -tag prod # only hosts tagged prod
ssh $(ssh-list -list | fzf | cut -f1) # pick with fzf and connectOther flags: -config <path> to work against a different file (useful for
trying things out on a scratch copy), and -version.
"Last used" times and connection counts are kept separately in
~/.local/state/ssh-list/usage.json (or $XDG_STATE_HOME). This file is purely
cosmetic — deleting it loses the ordering hints and nothing else.
This project was written using Claude Opus 5, Anthropic's coding model. As the developer, I reviewed and tested the code before releasing it.
The parts most worth your scrutiny are in internal/sshconfig, since that
package rewrites ~/.ssh/config. Its round-trip and atomic-write guarantees are
covered by tests in parse_test.go — start there if you want to verify the
behaviour yourself rather than take it on trust.
Bug reports are welcome. If you find something the review missed, please open an issue.