A smart terminal dashboard for SSH hosts and Docker containers. One command to find, connect, and manage everything you SSH into.
You have 10 servers. Some run Docker containers. To reach a container, you SSH into the server, remember the container name, then docker exec into it. Every time.
sls flattens that into one step: pick the thing, you're in it.
sls > █
11/11
⭐︎jgopi
⭐︎vaultwarden 🐳
proxmox
oci_atlas_0
webdav 🐳
coolify-proxy 🐳
nas
plex 🐳
jellyfin 🐳
RockyLinux
- Built-in fuzzy finder with inline search
- Docker container discovery across remote servers via SSH
- One-step container access: select a container, get a shell instantly
- Favorites: pin frequently used hosts and containers to the top (⭐)
- Usage-based sorting: most connected hosts float up automatically
- Interactive dashboard: rename, delete, scan, and star without leaving the UI
- SSH config generation: generate an include file for container aliases such as
my-server::nginx - Safe writes: atomic file operations protect your SSH config from corruption
- Zero dependencies: single binary, no runtime requirements
brew tap jinmugo/tap brew install sls
curl -fsSL https://package.jinmu.me/install.sh | sudo sh -s slsgo install github.com/jinmugo/sls@latest
Download platform-specific binaries from the Releases page.
sls checks for a newer release in the background (at most once a day) and shows a
small ⬆ sls vX.Y.Z available line in the dashboard when one exists. To upgrade:
sls update
sls update detects how sls was installed and runs the matching command —
brew upgrade sls for Homebrew, the Linux package one-liner for deb/rpm,
go install ...@latest for source installs — asking for confirmation first.
Manually-downloaded binaries are pointed at the releases page instead.
sls update --check # report whether an update is available, without installing sls update --yes # upgrade without the confirmation prompt
The background check is anonymous (a single request to the GitHub releases API),
silent on failure, and skipped on dev builds and in non-interactive sessions.
Disable it entirely with export SLS_NO_UPDATE_CHECK=1.
# Launch the interactive dashboard sls # Discover Docker containers on a remote server sls discover my-server # Connect directly to a container sls connect my-server::nginx # Generate SSH config so vanilla ssh works too sls gen ssh-config # Then: ssh my-server::nginx (works without sls!)
The interactive dashboard stays open after every action (except connect). Changes are reflected immediately.
| Key | Action |
|---|---|
enter |
Connect via SSH |
ctrl+s |
Scan for Docker containers |
ctrl+r |
Rename host alias |
ctrl+f |
Toggle ⭐ favorite |
ctrl+d |
Delete host (containers must be removed first) |
ctrl+k / ctrl+p |
Navigate up |
ctrl+j / ctrl+n |
Navigate down |
esc |
Quit |
| Key | Action |
|---|---|
enter |
Open shell in container |
ctrl+r |
Rename (custom display name) |
ctrl+f |
Toggle ⭐ favorite (pinned to top) |
ctrl+d |
Remove from dashboard |
ctrl+k / ctrl+p |
Navigate up |
ctrl+j / ctrl+n |
Navigate down |
esc |
Quit |
Discover running Docker containers on any SSH host:
sls discover my-server
This will:
- SSH into the server and list running containers
- Let you select which containers to add (multi-select with
space) - Let you set custom names for each (e.g.,
vaultwarden-hddaw38nxjcaf4ufzo79yh6i→vaultwarden) - Cache the results locally
Discover all hosts at once:
sls discover --hosts # scan all SSH config hosts (concurrent, max 10) sls discover my-server --verbose # show debug output sls discover my-server -T 30s # custom timeout
Generate an SSH config include file so you can reach containers with plain ssh:
sls gen ssh-config
This creates ~/.config/sls/ssh_config with entries like:
Host my-server::nginx
HostName localhost
ProxyJump my-server
RemoteCommand docker exec -it nginx /bin/sh
RequestTTY yes
The Include directive will be added to your ~/.ssh/config if possible; otherwise, sls gen ssh-config prints manual instructions. After this is set up, ssh my-server::nginx works from any terminal, even without sls installed. ProxyJump routes through the parent host (inheriting all its SSH settings), and HostName localhost ensures the connection lands on the server itself before running docker exec.
# Host management sls config list sls config add <alias> sls config edit <alias> sls config remove <alias> sls config format # normalize indentation and spacing in ~/.ssh/config (creates .bak backup) # Favorites (also available via ctrl+f in dashboard) sls fav add <alias> sls fav remove <alias> sls fav list # Tags sls tag add <host> <tag> sls tag remove <host> <tag> sls tag list <host> sls tag show sls --tag <name> # filter dashboard by tag # Connectivity sls test <host> # test SSH connection sls connect <host::container> # direct container access # Shell completion sls completion [bash|zsh|fish|powershell]
| File | Purpose |
|---|---|
~/.ssh/config |
SSH host definitions (read/write) |
~/.config/sls/meta.json |
Favorites, usage counts, tags |
~/.config/sls/containers.json |
Cached container data |
~/.config/sls/ssh_config |
Generated container SSH entries |
~/.config/sls/telemetry |
Telemetry consent (enabled/disabled) |
~/.config/sls/anon_id |
Random per-install anonymous id (see Telemetry) |
~/.config/sls/update.json |
Cached latest-version check (see Updating) |
- Container names are validated against a strict allowlist (
[a-zA-Z0-9._-]) to prevent SSH config injection - All file writes use atomic temp-file-then-rename to prevent corruption
- The generated SSH config is a separate include file, never modifying your hand-crafted SSH config
- SSH connections use
BatchMode=yesto prevent hanging on auth prompts during discovery
sls collects anonymous, opt-in usage data to guide what to improve. On first
interactive run it asks for consent (stored in ~/.config/sls/telemetry); it never
prompts in non-interactive/CI/piped contexts and stays off until you opt in.
- Collected: command name (e.g.
connect,scan), OS, architecture, sls version, and a random per-installanon_id(a v4 UUID in~/.config/sls/anon_id, generated from randomness alone — not derived from any hostname, user, or machine). - Never collected: hostnames, IP addresses, SSH config, container names, paths, or any personal data.
- Opt out anytime:
export PULSE_DISABLED=1(orSLS_TELEMETRY=off), or setdisabledin~/.config/sls/telemetry.
Events are sent fire-and-forget (short timeout, failures ignored) as OTLP/HTTP logs to a self-hosted collector and never block or slow down the CLI.