I have four machines with active projects. The workstation has Claude Code sessions running. The home server is running tests. A VPS is building something. The workflow before sshler: open a terminal emulator, SSH into the box, cd to the project, tmux attach, do the thing, detach, open another terminal, SSH into a different machine, repeat. Six terminal windows, Alt-Tab, which one is the server again.
That was annoying enough that I built something about it.
The Problem
JuiceSSH on Android is fine but has no file browsing. VS Code Remote is powerful but heavy; I don’t want a full IDE just to check a log file. Nothing let me jump between machines from a single interface without drowning in windows.
sshler is a local-only web UI that reads ~/.ssh/config, shows all your boxes, lets you browse files over SFTP and open tmux sessions in the browser. One pip install, one command.
That was the original scope. What actually happened is more interesting.
How I Actually Use It
Multi-Agent Coordination
Here’s what a typical afternoon looks like. sshler open in a browser tab on the workstation. Three or four boxes active. Each has one or two tmux sessions running Claude Code, tests, or builds.
The workflow: glance at the sshler tab, see all my boxes, click the one I need, check the terminal, give Claude Code a new instruction or check its output, switch to another box, check the test results, switch back. The terminals are persistent tmux sessions on the remote hosts — if I close the browser or reload the page, the sessions are still there. Reconnect and pick up exactly where I left off.
A concrete example: working on sqler benchmarks on the workstation and sshler frontend improvements on the server simultaneously. Two Claude Code instances, two repos, two machines. I have sshler open and can see both terminals. Give sqler-Claude an instruction, switch tabs, give sshler-Claude an instruction, switch back. Agents working in parallel across machines, coordinated from one browser tab.
That’s not something I planned. I built sshler because I wanted a nicer SSH experience. The multi-agent coordination emerged from daily use — once you have persistent terminals across all your machines in one interface, parallel agent sessions are the obvious next step.
The Mobile Story
Desktop is the daily driver. But the mobile UX has gotten real attention because I do occasionally need to check something from my phone — look at test output, restart a hung process, give Claude a quick instruction between things.
The problem with SSH on mobile isn’t the SSH part; it’s the keyboard. Arrow keys, Escape, Ctrl+C — all clunky or missing entirely on a phone keyboard. So sshler has a custom input bar with quick-access buttons for exactly those keys. Arrow keys for navigating Claude Code menus. Escape for interrupting agent turns. Ctrl+C for killing runaway processes. Tab for autocomplete. Minimal header (14px with CPU and memory stats) to maximize terminal space.
Every button on that bar came from me trying to do something on my phone and failing. The input bar exists because I got frustrated trying to type Ctrl+C on an iPhone keyboard. It’s a real UX and it works — but it’s the secondary use case, not the reason to build the tool.
What Makes It Stick
I’ve built tools I used for a week and dropped. sshler stuck because it’s faster than the alternative for the things I actually do with remote machines.
File browsing: Click a box, click through directories, preview a file. Versus: open terminal, SSH, cd, cd, cd, less. sshler is two clicks.
Terminal access: Click “Open Terminal Here” on any directory. Versus: SSH, navigate to the directory, tmux new or attach. One click, already in a tmux session in that exact directory.
Context switching: All boxes in one interface with names and theme colors. Red is production. Green is staging. I typed rm -rf into what I thought was the dev server once. It was production. Added color-coded terminals the same day.
These are small individually. Across a full day of jumping between machines and agent sessions, they add up.
The Dogfooding Loop
I use sshler; I hit a friction point; I fix it; I use the improved version. The cycle is tight because the user and the developer are the same person.
Things that came from this loop:
- Frecency search: I kept navigating to the same directories. Built frecency-based search that learns which directories I visit most. Local boxes query zoxide; remote boxes track visits in SQLite.
- Per-box terminal themes: Typed
rm -rfinto production. Added color-coded terminals the same day. Never again. - Command snippets: Kept typing the same long commands (
uv run pytest tests/ -v --tb=short -x). Built a snippets panel to save and one-click insert them per box. - Port forwarding UI: Was manually running
ssh -Lcommands. Built a visual tunnel manager into sshler. Click to create, click to destroy. - Mobile input bar: Every button came from me trying to do something on my phone and failing. Real frustration, real fix.
This is the LLM-first philosophy applied to my own workflow: using the tool I built, running agents inside that tool to improve the tool itself. sshler running Claude Code to improve sshler. Recursive dogfooding.
Getting Started
pip install sshler
sshler serve
It reads ~/.ssh/config, shows your boxes, opens in your browser. Python 3.12+, tmux on your remote hosts, no remote installation.
Source at github.com/gabu-quest/sshler. 232 tests, MIT license.