A standalone SSH session manager with a terminal user interface (TUI), built in Rust. Store, browse, and connect to SSH sessions with vim-inspired keybindings and customizable themes.
- Session Management — Add, edit, delete, and search SSH sessions
- Secure Password Storage — Passwords are stored in the OS keychain (macOS Keychain / Linux Secret Service), never in plaintext; supplied to
ssh(andherdr) at connect time viaSSH_ASKPASS, never on disk or the command line - Optional Biometric Unlock — Off by default; when enabled, a fingerprint/Touch ID check gates password reveal at connect time
- SSH Config Import — Pull hosts straight from your existing
~/.ssh/config - Tags & Group Views — Label sessions and filter the list down to a tag
- Jump Hosts — Per-session
ProxyJumpsupport (ssh -J) - Live Reachability — Background TCP probes show per-host latency, color-coded status, and a latency sparkline
- Rich TUI — Vim-style navigation (
j/k,gg/G,Ctrl-d/Ctrl-u), search, and a which-key menu system - 7 Built-in Themes — auto, noir-cat, knew-pines (Rose Pine), catppuccin, gruvbox, nord, tokyo-night
- Two Connection Modes — Plain SSH or via
herdrhelper - CLI Interface — Direct connection, session listing, and config import without the TUI
cargo build --releaseThe binary will be at target/release/ssm.
- A Secret Service daemon (e.g.,
gnome-keyringorkwallet) for password storage - OpenSSH 8.4+ (for the stored-password hand-off; no
sshpassneeded) - Optional:
herdrfor the herdr connection mode - Optional:
fprintd(fprintd-verify) for biometric unlock - Optional:
xcliporxselfor clipboard yank support
- Xcode Command Line Tools (
xcode-select --install) for the Apple linker andSecurity.framework - No Homebrew packages needed — the native
apple-native(Keychain) backend is used instead of the Linux Secret Service one - macOS's bundled OpenSSH (9.x on recent releases) is already new enough
ssm can't be cross-compiled from Linux for macOS (the keychain backend links
Security.framework, which needs the macOS SDK); see
BUILD_MACOS.md for the full native build, universal-binary
(arm64 + x86_64), and code-signing steps.
# Launch the TUI
ssm
# List saved sessions
ssm --list
# Connect directly
ssm -c user@host
ssm -c user@host:2222
# Import hosts from your SSH config
ssm --import # ~/.ssh/config
ssm --import /path/to/ssh_config| Flag | Description |
|---|---|
| (none) | Launch the full-screen TUI |
-c USER@HOST[:PORT] |
Connect directly to a host |
-l, --list |
Print saved sessions as a table |
--import [PATH] |
Import hosts from an ssh_config file (default ~/.ssh/config); skips names that already exist |
--version |
Print version |
--help |
Print help |
| Key | Action |
|---|---|
j/k |
Move down/up (supports numeric prefixes, e.g. 5j) |
gg/G |
Go to first/last session |
Ctrl-d/Ctrl-u |
Half-page scroll |
Ctrl-f/Ctrl-b |
Full-page scroll |
Enter |
Connect to selected session |
a |
Add new session |
e |
Edit selected session |
D |
Delete selected session (prompts for confirmation) |
y |
Yank (copy) host to clipboard |
/ |
Search/filter sessions (matches tags too) |
T |
Filter by tag (group view); Esc clears the filter |
s |
Open settings menu (herdr, probe, biometric, theme) |
u |
Reload sessions from disk |
U |
Check for / apply ssm updates |
Space |
Open which-key menu (delete, yank, tag filter, import, settings) |
? |
Toggle help screen |
q |
Quit |
Configuration files are created automatically at:
| File | Purpose |
|---|---|
~/.config/ssm/config.toml |
Preferences (theme, herdr, probe, biometric toggles) |
~/.config/ssm/sessions.json |
Saved sessions |
Override the config directory with the DOTS_SSM_DIR environment variable.
use_herdr = true
theme = "auto"
probe = true # background reachability probing + latency in the list
biometric_unlock = false # require a biometric check before revealing a password
update_check = true # periodically check GitHub Releases for a newer ssm
update_frequency = 1440 # minutes between update checks (1440 = daily)ssm is a standalone binary, so it updates itself: on launch it checks the GitHub
Releases API (throttled by update_frequency) and shows ▲ update available in
the list when a newer version exists. Press U to open the update view, then a
to download and swap the binary in place. Restart ssm to run the new version.
Installs managed by a package manager (e.g. Homebrew) skip self-update and tell you to update through that manager instead. For a first install:
curl -fsSL https://raw.githubusercontent.com/CtrlUserKnown/ssm/main/install.sh | shTags — Sessions carry free-form tags (set them in the add/edit form as a
comma- or space-separated list). Tags show as dim chips in the list, are matched
by / search, and power a group view: press T to pick a tag and filter the
list down to it. Esc clears the filter.
Jump hosts — Each session has an optional ProxyJump field. When set, ssm
passes it to ssh as -J <jump> (e.g. bastion or user@bastion:2222). Imported
~/.ssh/config hosts carry their ProxyJump directive across automatically.
Reachability — When probe is on, ssm runs a background TCP connect to each
host's port every few seconds and shows a status dot, the round-trip latency, and
a small latency-history sparkline:
●green — reachable, low latency (< 50 ms)●yellow — reachable, higher latency (< 200 ms)●red — unreachable○gray — not probed yet
Toggle probing at runtime via Space → Settings → p, or with probe = false
in config.toml.
When a session has a stored password, ssm hands it to OpenSSH through the
SSH_ASKPASS mechanism (SSH_ASKPASS_REQUIRE=force, OpenSSH 8.4+): ssm points
SSH_ASKPASS at itself and serves the secret over a 0600 Unix socket guarded
by a one-time nonce. Nothing is written to disk and the password never appears
on a command line or in a persistent environment variable. Because herdr --remote shells out to system ssh, the same mechanism supplies the password
to herdr connections too — so stored passwords now work in both modes (no
sshpass required).
Notes:
- For plain
ssh, ssm adds-o StrictHostKeyChecking=accept-new, so first-time connections to new hosts still work; a changed host key still aborts. herdr --remotetakes only a target (no ssh flags), so per-session port /ProxyJumpmust live in~/.ssh/config, and the host should already be inknown_hosts.
Off by default. Enable via Space → Settings → b, or biometric_unlock = true.
When on, ssm requires a biometric check before revealing a stored password at
connect time. Passwords are loaded lazily (only at connect), so the prompt
actually gates access.
- Linux: uses
fprintd-verify— a fingerprint presence gate in front of the Secret Service release. (Not cryptographically bound to the secret.) - macOS: Touch ID is not wired up yet. A real implementation needs
LocalAuthenticationand a stably code-signed binary so the Secure-Enclave keychain item survives rebuilds. Usescripts/sign-macos.shwith a free self-signed "Code Signing" certificate for personal use, or a Developer ID certificate + notarization to distribute. Until it lands, enabling biometric on macOS falls back to a plain keychain read with a warning.
If biometric is enabled but no verifier is available, ssm warns and proceeds rather than locking you out of your own hosts.
Cycle through themes live from the TUI via Space → Settings → Theme. Available themes:
auto— matches terminal colorsnoir-catknew-pines— Rose Pine inspiredcatppuccingruvboxnordtokyo-night
Releases are split: GitHub Actions builds the Linux binaries; macOS is built and signed locally. There's no Apple Developer account, so CI can't notarize, and the stable self-signed identity that keeps biometric unlock working lives only in the maintainer's keychain — so the macOS arches are built on a Mac and uploaded to the same Release.
# 1. bump Cargo.toml version + CHANGELOG, commit, tag, push.
git commit -am "chore(release): vX.Y.Z"
git tag -a vX.Y.Z -m "ssm vX.Y.Z"
git push origin main --follow-tags # → CI builds & attaches the Linux tarballs
# 2. on your Mac, build/sign/upload both darwin arches to the same Release.
scripts/release-macos.sh vX.Y.Z # x86_64 + aarch64, signed with ssm-codesignThe two steps are order-independent — whichever runs second just adds its assets
to the Release. One Apple Silicon Mac produces both macOS arches
(rustup target add x86_64-apple-darwin; Xcode ships both SDKs). Requires the
gh CLI (authenticated) and the ssm-codesign identity from scripts/sign-macos.sh.
On notarization: self-signed (not notarized) binaries launch fine on the two
install paths that matter — install.sh (curl | sh) and the in-app self-updater
— because neither sets the macOS quarantine bit (and the updater strips it
anyway). Only a .tar.gz downloaded through a browser would be Gatekeeper-gated.
No license file is currently included in this repository.