Horizon

A small terminal UI for managing SSH connections on macOS and Linux. Pick a
server, pick an environment file, and Horizon connects you with your variables
exported and your setup commands already run. Connections are kept alive in the
background and reused instantly.
Horizon is deliberately tiny: the UI is tview,
and all SSH work is done by your system's own OpenSSH client using
ControlMaster/ControlPersist multiplexing. That means your keys, ssh-agent,
~/.ssh/config, passwords and 2FA all work exactly as they do with plain ssh,
and live connections survive between sessions with no daemon.
Install
Pre-built binary (macOS and Linux)
Download the binary for your platform from the
latest release and put it
on your PATH:
curl -sL "https://github.com/davvi/horizon/releases/latest/download/horizon_$(uname -s)_$(uname -m).tar.gz" | tar xz horizon
sudo install -m 0755 horizon /usr/local/bin/horizon
On macOS uname -m prints arm64 on Apple Silicon and x86_64 on Intel;
both are published, so the one-liner above picks the right one automatically.
With go install
Requires Go 1.25 or newer:
go install github.com/davvi/horizon@latest
The binary lands in $(go env GOPATH)/bin (usually ~/go/bin) — make sure
that directory is on your PATH.
Build from source
git clone https://github.com/davvi/horizon.git
cd horizon
make build # builds ./horizon
sudo make install # installs to /usr/local/bin (PREFIX=... to change)
Or with plain Go:
go build -o horizon .
Run
./horizon # uses ~/.horizon
./horizon -f /some/dir # use a different config folder
The config folder (and template files) are created automatically on first run
with 0700/0600 permissions.
Files (all plain text)
~/.horizon/list_of_servers.txt
One server per line — name user@host[:port], # for comments:
web1 deploy@203.0.113.10
db admin@db.internal:2222
~/.horizon/*.txt — environment files
Every other .txt file in the folder is an environment file. Lines like
KEY=value are exported on the server after connecting; every other
non-comment line runs as a command, in order. You then land in an interactive
login shell.
APP_ENV=staging
DB_URL=postgres://app@db/main
cd /srv/app
~/.horizon/sockets/
ControlMaster sockets for live connections. Managed automatically.
Using the UI
Everything is clickable with the mouse, and fully usable from the keyboard:
| Key |
Action |
| ↑/↓, Enter |
choose a server and connect |
n |
new server form |
e |
new environment file form |
r |
refresh the list and connection statuses |
q |
quit (live connections keep running) |
| Tab / Esc |
move focus / close a dialog |
Connecting to a server that already has a live connection pops up a choice:
Reuse opens a new session over the existing connection instantly (no
re-authentication); New connection closes the old one, lets you pick an
environment file, and reconnects fresh.
When you pick a server, Horizon's UI closes and hands your terminal directly to
ssh — typing exit on the remote host drops you straight back into the local
shell you started from. The underlying connection stays alive in the background
(ControlPersist=yes), so the next ./horizon run offers instant re-use. It
lives until you choose "New connection" or kill it yourself with
ssh -O exit -o ControlPath=~/.horizon/sockets/<name>-<port> <target>.
Development
make test # go test -race ./...
make vet # go vet ./...
make fmt # gofmt -w .
Releases are cut by pushing a tag: git tag v0.1.0 && git push origin v0.1.0.
GitHub Actions then builds macOS and Linux binaries (amd64/arm64) with
GoReleaser and attaches them to the GitHub release.
Contributing
Issues and pull requests are welcome. Please run make fmt test vet before
submitting.
License
MIT