I have been using SSH for a very long time.
SSH itself is not the problem.
OpenSSH is mature, ubiquitous, scriptable, compatible with just about everything, and already knows how to deal with keys, agents, jump hosts, port forwards, certificates, host verification and all the other things accumulated over decades of people administering Unix machines.
I had no particular desire to replace any of that.
My problem was everything around SSH.
After enough years and enough computers, your SSH setup stops being a configuration file and starts becoming archaeology.
Some hosts are in ~/.ssh/config. Some are in /etc/hosts. Some are in notes. Some are remembered by hostname, some by IP address, some by whatever nickname made sense six years ago. There are jump hosts, special ports, different identities, local forwards, commands you always run after connecting, and machines you vaguely remember require a particular ritual before they will cooperate.
And, of course, some of this exists on one laptop but not another.
I wanted somewhere for my SSH life to live.
That became StaSSH.
StaSSH is a portable, offline-first workspace for SSH. It organizes hosts, folders, notes, tags, identities, jump chains, forwards and reusable workflows, and then lets the system OpenSSH client do the actual connecting.
Or, put another way:
StaSSH doesn't replace SSH. It remembers how I use SSH.
I wanted my SSH collection to travel
Portability was one of the original motivations.
I use several computers, and not all of them are particularly impressive computers.
Some are old machines that had been sitting unused for years. I kept them mostly because throwing away working computers felt like turning them into e-waste for no good reason. I eventually installed lightweight Linux systems on some of them, encrypted the disks, and turned them into what I think of as “losable” computers: machines I can take somewhere without being particularly upset if one gets damaged or disappears.
A fifteen-year-old laptop is still spectacularly overqualified for being an SSH terminal.
The problem is that modern desktop software increasingly disagrees.
StaSSH therefore has three frontends:
stassh CLI
stassh-tui terminal UI
stassh-gui desktop GUI
The TUI in particular is deliberately light on resources. Rust helps considerably here, and I have also tried to keep open a path for building StaSSH for 32-bit x86 Linux. There are still perfectly functional old machines out there that have been abandoned by much of the modern application stack.
I don't need an old laptop to run a browser-sized desktop application just so I can remember the name of a server.
The TUI has another feature I particularly wanted. When StaSSH is itself running inside tmux or byobu, I can highlight a host and press t to open that connection in a new tmux window or byobu tab.
That turns an old laptop into a remarkably useful little administration station.
I can keep StaSSH in one tab, open machines into other tabs, jump between them, and never need a desktop environment at all.
Three interfaces, one program
The CLI, TUI and GUI are not three separate implementations that happen to read similar files.
StaSSH is a Rust Cargo workspace built around a shared crate called stassh-core.
Conceptually, it looks something like this:
stassh-core
|
+-------------+-------------+
| | |
CLI TUI GUI
stassh stassh-tui stassh-gui
| | |
+-------------+-------------+
|
system OpenSSH
The core owns the important concepts: hosts, folders, storage, identities, search, diagnostics, OpenSSH command generation, jump chains, forwards, Actions and so on.
The frontends are different ways of operating the same workspace.
That means I can use the GUI at my main workstation, the TUI on an ancient laptop, and the CLI from a script without maintaining three collections of hosts.
And underneath all of them is still the SSH implementation I already trust:
/usr/bin/ssh
StaSSH constructs the appropriate command, or a temporary OpenSSH configuration when something more complicated is needed, and runs the system client.
Existing SSH agents still work. Existing keys still work. Known hosts still work. OpenSSH remains OpenSSH.
This was an explicit design decision. I was trying to organize SSH, not reimplement it.
The portable part and the local part are different things
One of the problems with carrying an SSH setup between computers is that not everything should be portable.
StaSSH's default configuration lives under:
~/.ssh/stassh/
with three files:
vault.json
local.json
secrets.json
vault.json describes the portable workspace: folders, hosts, usernames, ports, notes, tags, jump chains, forwarding definitions, Actions and references to identities.
It is deliberately plain JSON.
local.json, on the other hand, answers questions specific to the computer currently running StaSSH.
An identity in the portable vault can be represented by the fingerprint of its public key. The corresponding private key itself is not stored in the StaSSH vault. local.json can say where that identity actually lives on this particular machine.
So one laptop might map an identity to:
/home/arturo/.ssh/work_ed25519
while another computer can map the same fingerprint to a different local path.
The portable workspace knows which identity I mean.
The local configuration knows where this computer keeps it.
The same idea applies to local programs used by StaSSH Actions. An Action can refer to a capability such as a VNC viewer without embedding the executable path used on one particular computer.
This separation turned out to be one of the more useful architectural decisions in the project.
Copy the portable workspace to another computer, configure its local mappings, and the meaning of the SSH estate travels without pretending every computer is identical.
About passwords
There is also an optional secrets.json.
I want to be careful about what this is, because StaSSH is not intended to be a password manager.
Most of the time I connect to my machines with SSH keys, and most routine work does not require a password at all. But occasionally I need to do some administrative work with sudo.
The strange thing about passwords for machines you have personally configured is that there is a category of password you don't exactly remember, but you recognize instantly when you see it.
While configuring a particular machine I may have typed its password fifty times. Six months later, among dozens of hosts, I cannot necessarily recall it cold.
Show it to me once and I think:
“Oh, right. That one.”
And then I remember it for the rest of the session.
That is the niche secrets.json is intended to cover: host-associated fallback operational secrets, not your entire digital life.
Secret values stored there are encrypted; the surrounding metadata should still be considered private. I would not put my banking passwords in it, and I don't recommend anyone else does either.
Then there are Actions
Hosts are only half of an SSH workflow.
Quite often I don't merely want to connect to a computer. I want to do the thing I normally do with that computer.
That distinction led to StaSSH Actions.
An Action can do several things around an SSH session:
run something locally
|
v
prepare values or ports
|
v
start SSH, possibly with temporary forwards
|
v
run something on the remote machine
|
v
launch something locally
|
v
cleanup
Described like that, it sounds suspiciously like I have invented a complicated way to avoid typing commands.
So let me give the example that made the feature worthwhile for me.
VNC
Sometimes I want a remote graphical desktop.
Manually, that can mean starting a VNC server remotely, creating an SSH tunnel, choosing a free local port and then launching the correct viewer against it.
With a StaSSH Action, I select the host and choose:
VNC forwarded
and the VNC window appears.
The Action can start x11vnc remotely, create a temporary SSH forward from an automatically selected local port to port 5900 on the remote machine, and launch my local VNC viewer against that port.
StaSSH has not become a VNC client.
It has simply learned how I use my VNC client.
A feature I didn't add
While discussing StaSSH, I realized that it couldn't upload a file to a remote machine.
The obvious response would have been:
Add file transfer to StaSSH.
That would mean starting down the road toward file browsers, transfer queues, progress interfaces and eventually some sort of built-in SFTP subsystem.
Instead, I asked the coding agent to write an Action.
The repository now contains a Send file to home example. The Action invokes a small local helper, lets me choose a file and sends it to the selected host using scp.
StaSSH itself did not acquire an SCP implementation.
It didn't acquire a file manager either.
The new workflow was mostly composed out of software that was already there.
That is increasingly how I think about Actions.
They are an escape hatch from feature creep.
I don't particularly want StaSSH to grow its own VNC client, browser, file manager, database frontend and every other application I might conceivably use through an SSH connection.
Those programs already exist.
StaSSH can remember how I use them together.
The first file-transfer Action is intentionally simple. One direction I am considering for a future release—possibly the 1.2 timeframe—is tighter SCP support, particularly so transfers can automatically inherit more of StaSSH's identity and jump-host knowledge.
But even this simple example demonstrated the point nicely.
A missing feature did not necessarily require a new subsystem.
It required a new recipe.
Actions are deliberately written as JSON
There is currently no graphical Action designer.
That is intentional.
Actions can combine local commands, environment values, port allocation, SSH forwards, remote commands, local applications and cleanup. A GUI capable of expressing every possible combination would either become surprisingly elaborate or gradually restrict the underlying model to whatever the GUI happened to support.
So Actions are JSON-first.
There is a HOWTO-Actions.md file in the repository explaining the schema, template variables, capabilities, forwarding and dry-run workflow.
You can write one yourself.
Or, this being 2026, you can give that document to an AI coding agent and describe what you want:
Read HOWTO-Actions.md and create an Action that...
That is also an interesting little experiment in interface design.
Not every interface necessarily needs to be optimized for a human to author manually.
A structured format can be easy for a human to inspect, easy for the application to validate, and easy for an AI agent to generate.
The important part is that the result remains visible.
It's still JSON. I can read it, change it, put it under version control if appropriate, and run the Action in dry-run mode to see exactly what StaSSH intends to execute before letting it do anything.
That feels like a much healthier use of AI than hiding another layer of magic behind a button.
A desktop workspace when I do want a desktop
None of this means I dislike graphical interfaces.
On my normal workstation I generally want one.
stassh-gui is built with Tauri and gives the same workspace a persistent host tree, inspector/editor panes and embedded terminal sessions.
Multiple SSH terminals can remain open at once. They can also be arranged into terminal layouts, including equal grids and layouts with one main terminal and smaller surrounding panes.
There is broadcast input for a layout when I genuinely want to type the same thing into several sessions, terminal find, full-screen panes, and indicators in the host tree showing which machines currently have sessions open.
The idea is not to turn SSH into a shiny dashboard.
It is to give an SSH-heavy working session somewhere to live.
The GUI's terminal sessions are real PTYs when not running in simulation mode, and real connections are still made using OpenSSH.
The desktop interface is another view over the same machinery, not a separate SSH universe.
Simulation mode
You may have noticed that all of the screenshot instructions in this article use --simulation.
That feature exists partly because screenshots of SSH tools are a privacy accident waiting to happen.
A realistic SSH interface naturally contains exactly the things you don't want to accidentally publish: hostnames, usernames, network addresses, notes, infrastructure topology and potentially terminal output from real machines.
Both the TUI and GUI therefore have a deterministic simulation mode.
It uses an in-memory demo workspace with fake folders, hosts, identities, forwards, jump chains, diagnostics and secrets. Simulated terminal sessions behave like tiny scripted SSH shells instead of making real network connections.
That makes it useful not only for documentation and demonstrations but also for visual regression testing.
The GUI test suite uses deterministic simulation data with Playwright screenshot baselines, so a feature originally useful for safely showing the program also became useful for checking that its interface hasn't quietly broken.
The files are the product
Another deliberate omission is built-in synchronization.
StaSSH doesn't require an account and doesn't have a cloud backend.
I already have ways to copy files between computers. Other people use Syncthing, Git, Nextcloud, Dropbox, rsync, a USB stick or whatever system they trust.
I don't want an SSH organizer to require me to adopt another synchronization service.
The portable files are meant to be portable as files.
That is decidedly unfashionable software architecture, and I rather like it.
There is also an important safety detail here: StaSSH frontends keep track of the vault.json state they loaded. If another program changes the vault on disk, StaSSH will refuse to blindly overwrite it and require a reload first.
Plain files should not mean careless files.
This project was written by an AI
There is one other unusual thing about StaSSH.
I did not write its code.
The project is part of an experiment I have been conducting with a different way of developing software. I decide what the program should do, define constraints, make architectural decisions, test it, reject things I don't like, discover missing features and keep steering the project.
The coding itself is done by an AI coding agent.
All of it.
Even if the change would take me one line, I ask the agent to make the change. Mixing my own quick fixes into the code would defeat part of the experiment.
I have spent decades programming by hand, so this is a strange way to work. But that is precisely why I am interested in exploring it seriously rather than treating AI as autocomplete with better publicity.
StaSSH itself has provided some nice examples of this relationship.
I wanted VNC to be one Action.
The Action machinery evolved around that requirement.
Then I noticed I wanted to transfer files.
Instead of telling the agent to build file transfer into StaSSH, I asked whether the existing Action system could express it.
It could.
For me, that design decision is still the human part of software development.
The interesting question was not:
Can you write an SCP feature?
It was:
Should StaSSH have an SCP feature at all?
What StaSSH is not
StaSSH is not a server-monitoring suite.
It is not Ansible.
It is not a password manager.
It is not a proprietary SSH service.
It doesn't want custody of my private keys.
It doesn't replace OpenSSH.
It doesn't require a cloud account.
And, unless an Action tells it to invoke one, it isn't trying to become my VNC client, browser or file manager either.
It is much closer to a memory and workbench for the SSH tools I already use.
That scope is deliberate.
There is always another remote-administration feature that could be added. At some point an SSH organizer can quietly turn into an operating environment.
I would rather StaSSH stay small enough to run happily on an old laptop.
Try it
StaSSH is open source, and the project is on GitHub:
Linux packages provide the CLI, TUI and GUI together, or you can build the Rust workspace from source.
If your SSH world still fits comfortably in ~/.ssh/config, you may not need any of this.
But if your collection of machines has begun leaking into configuration files, notes, shell history, old scripts and your increasingly unreliable biological memory, StaSSH may look familiar.
SSH itself was never the problem.
I just needed somewhere to remember how I use it.



Top comments (0)