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 slscurl -fsSL https://package.jinmu.me/install.sh | sudo sh -s slsgo install github.com/jinmugo/sls@latestDownload 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 updatesls 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 promptThe 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-serverThis 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 timeoutGenerate an SSH config include file so you can reach containers with plain ssh:
sls gen ssh-configThis 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.