π ctty - Connection Manager
September 15, 2026 Β· View on GitHub
π ctty - Connection Manager
A lightweight, all-in-one connection manager β SSH, serial, telnet, SFTP, and FTP in a single TUI π₯
ctty is a fast, native terminal tool for managing all your connections β SSH hosts, serial devices, telnet endpoints, SFTP file transfers, and FTP sites β without the overhead of Electron apps. Built with Go and featuring an intuitive TUI interface, it brings the convenience of GUI connection managers like Tabby to the terminal, with zero bloat.
Why ctty?
- Tabby too heavy? ctty is a single ~5MB binary, no Electron, no browser engine β just pure Go
- Need serial + SSH + SFTP + FTP in one tool? Most terminal emulators only do SSH; ctty covers them all
- Native telnet client built in β no system
telnetbinary required (macOS dropped it, Windows and Termux need extras); IAC-aware with conservative negotiation - Want to stay in the terminal? No context switching between apps β everything is keyboard-driven
π±οΈ Click on the image to view in full size
β¨ Features
π Core Capabilities
- π¨ Beautiful TUI Interface - Navigate your SSH hosts with an elegant, interactive terminal UI and zero vertical layout jitter
- β‘ Quick Connect & Health Peek - Connect instantly with
Enteror inspect real-time system metrics (uptime, CPU load, memory bar, root disk space) via Quick Peek (v/P) without opening a full shell - π¦ Multi-Select & Batch Exec - Press
Spaceto multi-select hosts with visual[ ]/[β]checkboxes,Ctrl+Ato select all,pto probe selected hosts,yto copy commands, andxto batch-execute remote snippets in parallel with an aggregated scrollable results modal - π Unified Cross-Protocol Navigation - Switch between SSH, Serial (
t), Telnet (T), FTP (F), and Local File Browser (b) directly via hotkeys or[/]tabs without leaving your current view - π·οΈ Tag Organization & Quick Drawer - Organize hosts with automatic color-coding (e.g.,
#prodin red,#devin green); presswto open an interactive Tag Drawer with host counts and 1-key filtering (1-9), or usehiddentag to hide sensitive hosts - π Direct Config Editing - Press
Eto open your active SSH configuration directly in$EDITOR/$VISUAL(vim, nano, notepad) with automatic live config reload upon exit - π Universal Clipboard - Copy commands (
y) seamlessly across local terminals, remote SSH sessions, and tmux via OSC 52 fallback - π Port Forwarding - Easy setup for Local, Remote, and Dynamic (SOCKS) forwarding with history persistence
- π Easy Management - Add, edit, move, and manage SSH configurations seamlessly; typing in search and pressing
aauto-fills the host name - π Smart Search - Find hosts quickly with real-time filtering across names, addresses, and
#tags - π Real-time Status - Live SSH connectivity indicators with latency gradient colors (π’ <100ms, π‘ 100-300ms, π΄ >300ms / offline)
- π Serial Connections - Manage and connect to serial devices (mcu, console, switch, router) with configurable baud rate, data bits, parity, and stop bits; auto-detected ports appear in the list instantly
- π‘ Telnet Connections - Native RFC 854 telnet client (no system telnet needed): save and manage lab equipment, console servers, and legacy devices; reachability probe with one keypress
- π SFTP File Transfer - Full-featured SFTP browser (
okey) with remote browsing, upload/download queue with progress and cancel, transfer bell (\a), search, mkdir/delete, plus headless CLI transfers (put/get/scp+sftp ls/mkdir/rm/rmdir/rename) - π FTP Site Manager - Plain-FTP support (
Fkey) for hosts without SSH: tagged site inventory, dual-pane local|remote browser, mkdir/delete/rename in both panes, single/dual layout toggle, passwords in the encrypted vault, plus headless CLI transfers (ftp ls/get/put/mkdir/rm/rmdir/rename) - ποΈ Local File Browser - Standalone local filesystem manager (
bkey orctty browse [path]): navigate, search, sort, mkdir/delete/rename with confirms, file details, open-with-default-app, reveal in file manager - π Password Storage & Zero-Touch Auto-Login - Save SSH passwords securely in a local AES-256-GCM encrypted vault (
~/.config/ctty/credentials.json,0600permissions) with native OpenSSHSSH_ASKPASSprotocol bridge (zero third-party dependencies, works on macOS, Linux, Windows, and Termux) - π₯οΈ Split-Pane & Small Terminal Friendly - All forms and dialogs (Add/Edit Host, Port Forwarding, Host Info, Help Menu, Quick Peek, Batch Exec) feature focus-following dynamic viewport scrolling with fixed headers/footers. Works flawlessly in tmux/Zellij splits, VS Code/JetBrains embedded terminals, and tiling WMs (i3/Sway) down to 8~12 lines with zero height blocking or truncation
- π Bilingual i18n & Settings UI - Full English and Simplified Chinese support with automatic OS detection (macOS, Windows, Linux, Termux) and interactive in-TUI Settings menu (
Skey) to configure language, updates, and keybindings
π οΈ Technical Features
- π Secure - Works directly with your existing
~/.ssh/configfile (credentials stored separately, never pollutes standard SSH configs) - π Custom Config Support - Use any SSH configuration file with the
-cflag - π€ Agent Skill & Headless CLI - Agent skill for Cursor, Claude Code, and Codex; every operation available from the CLI without the TUI, with JSON output for scripts and agents
- π¦ Host Import - Migrate SSH profiles from Tabby with
ctty import --from tabby - π SSH Include Support - Full support for SSH Include directives to organize configurations across multiple files
- βοΈ SSH Options Support - Add any SSH configuration option through intuitive forms
- π Automatic Conversion - Seamlessly converts between command-line and config formats
- π Automatic Backups - Backup configurations automatically before changes
- β Validation - Prevent configuration errors with built-in validation
- π ProxyJump/ProxyCommand Support - Secure connection tunneling through bastion hosts
- β¨οΈ Keyboard Shortcuts - Power user navigation with vim-like shortcuts and universal
Tab/Shift+Tabfocus cycling - π Cross-platform - Supports Linux, macOS (Intel & Apple Silicon), Windows, and Android (Termux)
- β‘ Lightweight - Single binary with no dependencies, zero configuration required
π Quick Start
Agent Skill
Teach Cursor, Claude Code, Codex, and other agents to use ctty (search hosts, run remote commands, list serial/telnet devices) without opening the TUI. This is separate from installing the ctty binary below.
# Preview skills in this repo
npx skills add zsuroy/ctty --list
# Install into the current project (committed under .agents/skills/)
npx skills add zsuroy/ctty -y
# Install globally so every project can use it (recommended)
npx skills add zsuroy/ctty -g -y
-y skips prompts. -g installs to your user global skills dir. Default without -g is project-local.
npx skills list # see what is installed
npx skills remove ctty # uninstall
npx skills update ctty # pull the latest SKILL.md
The skill lives at skills/ctty/ in this repository.
Installation
Homebrew (Recommended for macOS):
brew install zsuroy/ctty/ctty
Unix/Linux/macOS (One-line install):
curl -sSL https://raw.githubusercontent.com/zsuroy/ctty/master/install/unix.sh | bash
Termux (Android):
curl -sSL https://raw.githubusercontent.com/zsuroy/ctty/master/install/unix.sh | bash
The installer auto-detects Termux (via $PREFIX/$TERMUX_VERSION) and installs to $PREFIX/bin without sudo. On Termux it picks the cgo Android build, whose DNS goes through the system resolver (pure-Go builds fail on devices with Private DNS or stub resolvers); releases without Android assets fall back to the Linux build.
Windows (PowerShell):
irm https://raw.githubusercontent.com/zsuroy/ctty/master/install/windows.ps1 | iex
Alternative methods:
Linux/macOS:
# Download specific release
wget https://github.com/zsuroy/ctty/releases/latest/download/ctty_Linux_x86_64.tar.gz
# Extract and install
tar -xzf ctty_Linux_x86_64.tar.gz # contains the single "ctty" binary
sudo mv ctty /usr/local/bin/ctty
Windows:
# Download and extract
Invoke-WebRequest -Uri "https://github.com/zsuroy/ctty/releases/latest/download/ctty_Windows_x86_64.zip" -OutFile "ctty_Windows_x86_64.zip"
Expand-Archive ctty_Windows_x86_64.zip -DestinationPath C:\tools\
# Add C:\tools to your PATH environment variable
From source (requires Go 1.23+):
git clone https://github.com/zsuroy/ctty.git
cd ctty
go build -o ctty .
sudo mv ctty /usr/local/bin/
π Usage
Interactive Mode
Launch ctty without arguments to enter the beautiful TUI interface:
ctty
Navigation & Host Actions:
β/βorj/k- Navigate hostsEnter- Connect to selected hostvorP- Quick Peek host health stats (uptime, CPU load, memory %, disk % progress bars)Space- Multi-Select toggle (auto-advances cursor down by 1 row)Ctrl+A- Select all / deselect all visible hostsEsc- Clear multi-selection (when active) or cancel/exit modey- Copy SSH command to clipboard (copies newline-separated commands for all selected hosts when multi-selection is active)x- Remote command snippet execution (runs in parallel across all selected hosts when multi-selection is active)p- Ping hosts to test latency (pings only selected hosts when multi-selection is active)w- Open interactive Tag Filter Drawer (1-9orEnterto filter,cto clear)c- Clear active tag filterE- Open active SSH configuration file directly in$EDITOR(vim/nano/notepad)[/]- Switch to previous / next protocol tab (SSH β Serial β Telnet β FTP β Local Browser)g/Home- Jump to first rowG/End- Jump to last row1-9- Quick jump to rowa- Add new host (auto-fills search query if typing)e- Edit selected hostd- Delete selected hostm- Move host to another config file (requires SSH Include directives)i- Show host configuration infof- Setup port forwardingt- Open serial device managerT- Open telnet device managero- Open SFTP file browser for selected hostF- Open FTP site managerb- Open local file browserS- Open Settings & Preferences (Language, Updates, ESC behavior)U- Open self-update modal (when an update is available)H- Toggle hidden hosts visibilityh- Open help screenq- Quit/- Search/filter hosts
Real-time Status Indicators:
- π’ Online - Low latency (<100ms)
- π‘ Moderate / Connecting - Moderate latency (100-300ms) or checking connectivity
- π΄ Offline / High Latency - Host unreachable, timeout, or latency >300ms
- β« Unknown - Connectivity status not yet determined
Sorting & Filtering:
s- Cycle through all sort modes (Name β Hostname β Tags β Last Login)n- Sort by name (alphabetical)r- Sort by recent (last login time)Tab- Switch focus between search input and table- Type to search - Real-time filtering across name, hostname, and
#tags
The interactive forms will guide you through configuration:
- Hostname/IP - Server address
- Username - SSH user
- Port - SSH port (default: 22)
- Identity File - Private key path
- ProxyJump - Jump server for connection tunneling
- ProxyCommand - Jump command for connection tunneling
- SSH Options - Additional SSH options in
-oformat (e.g.,-o Compression=yes -o ServerAliveInterval=60) - Tags - Comma-separated tags for organization
Serial Connections
Press t from the main TUI to enter the serial device manager. Available serial ports are auto-detected and listed immediately β no manual setup required for quick access.
Serial device list:
- Detected ports appear automatically with default settings (115200 8N1)
- Saved devices (with custom names and settings) appear at the top
Enter- Connect to selected serial devicei- Show device info (name, port, baud, parity, etc.)a- Add a new serial device with custom settingsd- Delete a saved serial device/- Search/filter devices by name or port pathEsc/q- Return to SSH host list
Device info view:
eorEnter- Edit parameters (baud rate, data bits, parity, stop bits) before connectingEsc/i- Back to device list
Adding a serial device:
- Name - Friendly alias (e.g.,
Switch-Console) - Device - Port path (e.g.,
/dev/cu.usbserial-1420); useβ/βto pick from detected ports - Baud Rate - Default: 115200
- Data Bits - 5, 6, 7, or 8 (default: 8)
- Parity -
none,even, orodd(default:none) - Stop Bits - 1 or 2 (default: 1)
Editing parameters before connect:
- Baud rate can be typed directly or cycled via
β/βthrough presets (9600/19200/38400/57600/115200/230400/460800/921600) - Press
Enterto connect with the modified parameters
Connecting: The TUI suspends and bridges your terminal directly to the serial port. Press Ctrl+] or Ctrl+C to disconnect and return to the TUI.
You can also launch the serial manager directly:
ctty serial # Skip the SSH host list, go straight to serial devices
Telnet Connections
Press T (Shift+T) from the main TUI to open the telnet device manager β for lab equipment, console servers, and legacy network gear that expose a telnet service.
β οΈ Cleartext protocol β Telnet transmits everything, including passwords, unencrypted. Prefer SSH wherever the device supports it.
Telnet device list:
Enter- Connect to selected telnet devicei- Show device info (name, host, port, tags)a- Add a new telnet devicee- Edit the selected deviced- Delete a saved telnet devicep- Probe reachability of all saved hosts (TCP dial with 3s timeout; π’ up / π΄ down)/- Search/filter devices by name, host, or tagsEsc/q- Return to SSH host list
Connecting: The TUI suspends and bridges your terminal directly to the telnet session. Press Ctrl+] (classic telnet escape) to disconnect and return to the TUI. The client negotiates conservatively: it accepts ECHO / SGA / BINARY, refuses other options, and answers window-size queries with 80Γ24.
You can also connect without opening the manager:
ctty telnet # Telnet device manager TUI
ctty telnet core-sw # Connect to a saved device by name
ctty telnet 192.168.1.1 # Direct connection (port 23)
ctty telnet 10.0.0.5:2001 # Direct connection with explicit port
Saved devices live in ~/.config/ctty/telnet.json, separate from your SSH config.
SFTP File Transfer
While selected an SSH host, press o to open the SFTP file browser. The SFTP interface provides a full-featured file transfer experience directly in your terminal:
SFTP Browser Features:
- Remote and local file browsing
- Upload/download with progress and cancel
- Search functionality (/ key) for both remote and local files
- Two-line help for better readability
- Clear [LOCAL] and [REMOTE] labels (no confusing emoji)
- Error handling with friendly messages
SFTP Navigation:
β/βorj/k- Navigate filesβ/lorEnter- Enter directory / download file (remote) / upload file (local)β/horBackspace- Go to parent directoryu- Switch to local file browser for uploadd- Delete selected file (remote only)n- Create new directory (remote only)r- Refresh file list/- Search/filter filesEsc- Cancel current operation / return to SSH session
Uploading Files:
- Press
uto switch to local file browser - Navigate to the file you want to upload
- Press
Enterto upload to the current remote directory - Monitor progress in the status bar
- Press
Escto cancel upload (returns to remote file list)
Downloading Files:
- Navigate to the file you want to download
- Press
Enterto download to your local download directory (~/Downloads/ctty) - Monitor progress in the status bar
- Press
Escto cancel download (returns to remote file list)
Searching Files:
- Press
/to enter search mode - Type to filter files by name (real-time filtering)
- Press
EnterorTabto confirm selection - Press
Escto cancel search and restore full file list
Error Handling:
- If SFTP fails to start, you'll see a friendly error message:
β SFTP Error: failed to start SFTP session. - Press
Escto return to the SSH session - Your SSH connection remains active for other operations
You can also launch the SFTP file browser directly from the command line:
ctty sftp prod-server # Open SFTP browser directly for a host
Headless SFTP file ops:
ctty sftp ls prod-server # List remote directory
ctty sftp ls prod-server /var/log --format json
ctty sftp mkdir prod-server /tmp/newdir
ctty sftp rm prod-server /tmp/file.txt
ctty sftp rmdir prod-server /tmp/olddir
ctty sftp rename prod-server /tmp/old.txt /tmp/new.txt
# Transfers remain at root level:
ctty put prod-server ./app.tar.gz /srv/app.tar.gz
ctty get prod-server /var/log/app.log ./app.log
FTP File Transfer
Press F (Shift+F) from the main TUI to open the FTP site manager β for plain-FTP hosts that don't speak SSH/SFTP (lab NAS boxes, legacy file servers, appliance uploads).
β οΈ Cleartext protocol β FTP transmits everything, including passwords, unencrypted. Prefer SFTP wherever the server supports it.
FTP site manager:
Enter- Open the dual-pane browser for the selected sitea/e- Add / edit a site (name, host, port, user, password, tags)d- Delete the selected site (also removes its saved password)i- Show site details (e/Enterjumps to edit)/- Search/filter sitesr- Refresh the listEsc- Back
Saved sites live in ~/.config/ctty/ftp.json (0600). Passwords are encrypted in the shared credentials vault (~/.config/ctty/credentials.json, FTP entries under ftp: names) β the same AES-256-GCM vault SSH passwords use.
FTP browser (dual-pane local | remote):
Tab/u- Switch focus between local and remote panesβ/βorj/k- Navigate filesβ/lorEnter- Enter directory / download file (remote downloads confirm first)β/horBackspace- Go to parent directoryd- Delete selected file (with confirm)n- Create new directoryR- Rename selected file/directoryi- Show details of the selected file/directoryv- Toggle single/dual pane layout (persisted)r- Refresh current directory/- Search/filter filesEsc- Cancel transfer / go back
File management (n/d/R) works in both panes and mirrors SFTP keybindings. The pane layout can also be set persistently via S Settings β FTP browser layout. Narrow terminals (under 80 columns) always use the single pane.
You can also open the site manager or a site browser directly:
ctty ftp # FTP site manager TUI
ctty ftp lab-nas # Open browser directly for a saved site
Headless FTP transfers:
ctty ftp ls lab-nas # List remote directory
ctty ftp ls lab-nas /pub --format json # Machine-readable listing
ctty ftp get lab-nas /pub/file.txt ./file.txt
ctty ftp put lab-nas ./file.txt /pub/file.txt
ctty ftp mkdir lab-nas /pub/newdir
ctty ftp rm lab-nas /pub/file.txt
ctty ftp rmdir lab-nas /pub/olddir
ctty ftp rename lab-nas /pub/old.txt /pub/new.txt
Progress is on stderr; directories are recursive; passwords are reused from the encrypted vault (ftp: names) or anonymous.
Port Forwarding
ctty provides an intuitive interface for setting up SSH port forwarding. Press f while selecting a host to open the port forwarding setup:
Forward Types:
-
Local (-L) - Forward a local port to a remote host/port through the SSH connection
- Example: Access a remote database on
localhost:5432via local port15432 - Use case:
ssh -L 15432:localhost:5432 serverβ Database accessible onlocalhost:15432
- Example: Access a remote database on
-
Remote (-R) - Forward a remote port back to a local host/port
- Example: Expose local web server on remote host's port
8080 - Use case:
ssh -R 8080:localhost:3000 serverβ Local app accessible from remote host's port 8080 - β οΈ Requirements for external access:
- SSH Server Config: Add
GatewayPorts yesto/etc/ssh/sshd_configand restart SSH service - Firewall: Open the remote port in the server's firewall (
ufw allow 8080or equivalent) - Port Availability: Ensure the remote port is not already in use
- Bind Address: Use
0.0.0.0for external access,127.0.0.1for local-only
- SSH Server Config: Add
- Example: Expose local web server on remote host's port
-
Dynamic (-D) - Create a SOCKS proxy for secure browsing
- Example: Route web traffic through the SSH connection
- Use case:
ssh -D 1080 serverβ Configure browser to uselocalhost:1080as SOCKS proxy - β οΈ Configuration requirements:
- Browser Setup: Configure SOCKS v5 proxy in browser settings
- DNS: Enable "Proxy DNS when using SOCKS v5" for full privacy
- Applications: Only SOCKS-aware applications will use the proxy
- Bind Address: Use
127.0.0.1for security (local access only)
Port Forwarding Interface:
- Choose forward type with β/β arrow keys
- Configure ports and addresses with guided forms
- Optional bind address configuration (defaults to 127.0.0.1)
- Real-time validation of port numbers and addresses
- Port forwarding history - Save frequently used configurations for quick reuse
- Connect automatically with configured forwarding options
Troubleshooting Port Forwarding:
Remote Forwarding Issues:
# Error: "remote port forwarding failed for listen port X"
# Solutions:
1. Check if port is already in use: ssh server "netstat -tln | grep :X"
2. Use a different port that's available
3. Enable GatewayPorts in SSH config for external access
SSH Server Configuration for Remote Forwarding:
# Edit SSH daemon config on the server:
sudo nano /etc/ssh/sshd_config
# Add or uncomment:
GatewayPorts yes
# Restart SSH service:
sudo systemctl restart sshd # Ubuntu/Debian/CentOS 7+
# OR
sudo service ssh restart # Older systems
Firewall Configuration:
# Ubuntu/Debian (UFW):
sudo ufw allow [port_number]
# CentOS/RHEL/Rocky (firewalld):
sudo firewall-cmd --add-port=[port_number]/tcp --permanent
sudo firewall-cmd --reload
# Check if port is accessible:
telnet [server_ip] [port_number]
Dynamic Forwarding (SOCKS) Browser Setup:
Firefox: about:preferences β Network Settings
- Manual proxy configuration
- SOCKS Host: localhost, Port: [your_port]
- SOCKS v5: β
- Proxy DNS when using SOCKS v5: β
Chrome: Launch with proxy
chrome --proxy-server="socks5://localhost:[your_port]"
Remote Command Execution
Press x on a selected host to open the remote command execution interface. This allows you to run commands on remote hosts without opening an interactive SSH session.
Features:
- Built-in common command snippets:
docker ps,df -h,free -m,uptime,top,last,ps,du - Add custom snippets with
nkey (saved to~/.config/ctty/snippets.jsonwith0600permissions) - Delete custom snippets with
dkey - User snippets marked with β in the list
Tabto fill input with selected snippetβ/βto browse snippetsEnterto execute the command- SSH auto-login with saved passwords supported
- First-connection host key auto-accept (no interactive
yes/noprompt)
Command Execution Navigation:
β/βorj/k- Browse command snippetsTab- Fill input with selected snippetEnter- Execute the commandn- Add new custom snippetd- Delete selected custom snippetEsc- Return to host list
CLI Usage
ctty provides both command-line operations and an interactive TUI interface:
# Launch interactive TUI mode for browsing and connecting to hosts
ctty
# Connect directly to a specific host (with history tracking)
ctty my-server
# Execute a command on a remote host
ctty my-server uptime
# Execute command with arguments
ctty my-server ls -la /var/log
# Force TTY allocation for interactive commands
ctty -t my-server sudo systemctl restart nginx
# Launch TUI with custom SSH config file
ctty -c /path/to/custom/ssh_config
# Connect directly with custom SSH config file
ctty my-server -c /path/to/custom/ssh_config
# Add a new host using interactive form
ctty add
# Add a new host with pre-filled hostname
ctty add hostname
# Add a new host with custom SSH config file
ctty add hostname -c /path/to/custom/ssh_config
# Edit an existing host configuration
ctty edit my-server
# Edit host with custom SSH config file
ctty edit my-server -c /path/to/custom/ssh_config
# Move a host to another SSH config file (requires Include directives)
ctty move my-server
# Move host with custom SSH config file (requires Include directives)
ctty move my-server -c /path/to/custom/ssh_config
# Search for hosts (interactive filter or keyword/tag query)
ctty search
ctty search prod
ctty search "#web"
# Open SFTP file browser directly for a host
ctty sftp prod-server
# Open FTP site manager, or a site browser directly
ctty ftp
ctty ftp lab-nas
# FTP headless transfers (no TUI, dirs recursive, progress on stderr)
ctty ftp ls lab-nas /pub --format json
ctty ftp get lab-nas /pub/file.txt ./file.txt
ctty ftp put lab-nas ./file.txt /pub/file.txt
ctty ftp mkdir lab-nas /pub/newdir
ctty ftp rm lab-nas /pub/file.txt
ctty ftp rmdir lab-nas /pub/olddir
ctty ftp rename lab-nas /pub/old.txt /pub/new.txt
# Browse the local filesystem (search, mkdir/delete/rename, file details)
ctty browse
ctty browse ~/Downloads
# Open Serial device manager directly
ctty serial
# Add/edit a host without opening the form
ctty add --name web-server --hostname 10.0.1.10 --user root --tags prod
ctty edit --name web-server --port 2222
# Transfer files over SFTP (no TUI needed)
ctty put web-server ./app.tar.gz /srv/www/app.tar.gz
ctty get web-server /var/log/app.log ./app.log
ctty scp web-server:/etc/ctty.conf ./ctty.conf
# Run the same command on many hosts at once
ctty exec --tags prod -- uptime
ctty exec --hosts web-01,db-01 -- df -h
# Query saved devices as JSON (for scripts / agents)
ctty serial list --format json
ctty telnet search core --format json
# Override interface language (auto, zh, en)
ctty --lang zh
ctty search prod --lang en
# Print machine-readable info (JSON) for scripting
ctty info prod-server
ctty info prod-server --pretty
# With a custom SSH config file
ctty -c /path/to/custom/ssh_config info prod-server
# Pipe to jq
ctty info prod-server | jq -r '.result.target.hostname'
ctty info prod-server | jq -r '.result.target.user'
# Show version information
ctty --version
# Disable automatic update check (useful on air-gapped machines)
ctty --no-update-check
# Self-update: check for a newer release (add --yes to download & install)
ctty update
ctty update --yes
# Import SSH hosts from Tabby (writes ~/.ssh/config.d/tabby.conf)
ctty import --from tabby
ctty import tabby --dry-run
ctty import tabby -f /path/to/tabby/config.yaml
# Show help and available commands
ctty --help
Host Info (JSON)
ctty info <hostname> prints a single JSON object to stdout so you can script against it with jq.
# Extract fields
ctty info prod-server | jq -r '.result.target.hostname'
ctty info prod-server | jq -r '.result.target.port'
# Check not-found (exit code 2)
ctty info does-not-exist | jq -r '.error.code'
Shell Completion
ctty supports shell completion for host names, making it easy to connect to hosts without typing full names:
ctty <TAB> # Lists all available hosts
ctty pro<TAB> # Completes to hosts starting with "pro" (e.g., prod-server)
Setup Instructions:
Bash:
# Enable for current session
source <(ctty completion bash)
# Enable permanently (add to ~/.bashrc)
echo 'source <(ctty completion bash)' >> ~/.bashrc
Zsh:
# Enable for current session
source <(ctty completion zsh)
# Enable permanently (add to ~/.zshrc)
echo 'source <(ctty completion zsh)' >> ~/.zshrc
Fish:
# Enable for current session
ctty completion fish | source
# Enable permanently
ctty completion fish > ~/.config/fish/completions/ctty.fish
PowerShell:
# Enable for current session
ctty completion powershell | Out-String | Invoke-Expression
# Enable permanently (add to your PowerShell profile)
Add-Content $PROFILE 'ctty completion powershell | Out-String | Invoke-Expression'
Direct Host Connection
ctty supports direct connection to hosts via the command line, making it easy to integrate into your existing workflow:
# Connect directly to any configured host
ctty production-server
ctty db-staging
ctty web-01
# All direct connections are tracked in your history
# Use the TUI to see your most recently connected hosts
Features of Direct Connection:
- Instant connection - No TUI navigation required
- History tracking - All connections are recorded with timestamps
- Error handling - Clear messages if host doesn't exist or configuration issues
- Config file support - Works with custom config files using
-cflag
Remote Command Execution
Execute commands on remote hosts without opening an interactive shell:
# Execute a single command
ctty prod-server uptime
# Execute command with arguments
ctty prod-server ls -la /var/log
# Check disk usage
ctty prod-server df -h
# View logs (pipe to local commands)
ctty prod-server 'cat /var/log/nginx/access.log' | grep 404
# Force TTY allocation for interactive commands (sudo, vim, etc.)
ctty -t prod-server sudo systemctl restart nginx
Features:
- Exit code propagation - Remote command exit codes are passed through
- TTY support - Use
-tflag for commands requiring terminal interaction - Pipe-friendly - Output can be piped to local commands for processing
- History tracking - Command executions are recorded in connection history
Backup Configuration
ctty automatically creates backups of your SSH configuration files before making any changes to ensure your configurations are safe.
Backup Location:
- Unix/Linux/macOS:
~/.config/ctty/backups/(or$XDG_CONFIG_HOME/ctty/backups/if set) - Windows:
%APPDATA%\ctty\backups\(fallback:%USERPROFILE%\.config\ctty\backups\)
Key Features:
- Automatic backup before any modification
- One backup per file (overwrites previous backup)
- Stored separately to avoid SSH Include conflicts
- Easy manual recovery if needed
Additional Storage:
- Connection History: Stored in the same config directory for persistent tracking
- Port Forwarding History: Saved configurations for quick reuse of common forwarding setups
Quick Recovery:
# Unix/Linux/macOS
cp ~/.config/ctty/backups/config.backup ~/.ssh/config
# Windows
copy "%APPDATA%\ctty\backups\config.backup" "%USERPROFILE%\.ssh\config"
Configuration File Options
By default, ctty uses the standard SSH configuration file at ~/.ssh/config. You can specify a different configuration file using the -c flag:
# Use custom config file in TUI mode
ctty -c /path/to/custom/ssh_config
# Use custom config file with commands
ctty add hostname -c /path/to/custom/ssh_config
ctty edit hostname -c /path/to/custom/ssh_config
ctty move hostname -c /path/to/custom/ssh_config
Advanced Features
Host Movement Between Config Files
ctty provides a powerful move command to relocate SSH hosts between different configuration files. This feature requires SSH Include directives to be present in your SSH configuration.
# Move a host to another config file (requires Include directives)
ctty move my-server
# Move with custom config file (requires Include directives)
ctty move my-server -c /path/to/custom/ssh_config
β οΈ Important Requirements:
- SSH Include directives must be present in your SSH config file (either
~/.ssh/configor the file specified with-c) - The config file must contain
Includestatements referencing other SSH configuration files - Without Include directives, the move command will display an error message
Features:
- Interactive file selector - Choose destination config file from Include directives
- Include support - Works seamlessly with SSH Include directives structure
- Atomic operations - Safe host movement with automatic backups
- Validation - Prevents conflicts and ensures configuration integrity
- Error handling - Clear messages when Include files are needed but not found
Use Cases:
- Reorganize hosts from main config to specialized include files
- Move development hosts to separate environment-specific configs
- Consolidate configurations for better organization
Example Setup Required: Your main SSH config file must contain Include directives like:
# ~/.ssh/config
Include ~/.ssh/config.d/*
Include work-servers.conf
Include projects/*.conf
Host personal-server
HostName personal.example.com
User myuser
Real-time Connectivity Status
ctty features asynchronous SSH connectivity checking that provides visual indicators of host availability:
Status Indicators:
- π’ Online - SSH connection successful (shows response time)
- π‘ Connecting - Currently testing connectivity
- π΄ Offline - SSH connection failed or host unreachable
- β« Unknown - Status not yet determined
Features:
- Non-blocking checks - Status updates happen in the background
- Response time tracking - See connection latency for online hosts
- Automatic refresh - Status indicators update continuously
- Error details - Detailed error information for failed connections
Automatic Update Checking
ctty includes built-in version checking that notifies you of available updates:
Features:
- Background checking - Version check happens asynchronously, never blocking startup
- Release notifications - Clear indicators when updates are available
- Pre-release detection - Identifies beta and development versions
- GitHub integration - Direct links to release pages
- Non-intrusive - Updates don't interrupt your workflow
- Configurable - Can be disabled for air-gapped or offline environments
Update notifications appear:
- In the main TUI interface as a subtle notification
- Only when a newer stable version is available
Disabling update checks:
Via the CLI flag (one-time):
ctty --no-update-check
Via ~/.config/ctty/config.json (persistent):
{
"check_for_updates": false
}
Self-Update
When a new release is detected, update directly from inside ctty:
- From the TUI β press
Uwhen the update banner is shown, confirm withy. Progress (download β checksum verification β install) runs in a modal; restart ctty afterwards to run the new version. - From the CLI β
ctty updatechecks for a newer release;ctty update --yesdownloads and installs it.
Updates download the same release assets as the installers (ctty_<Os>_<Arch>.tar.gz, .zip on Windows), verify the sha256 against the published checksums.txt, and swap the binary in atomically β an interrupted update never leaves you with a broken binary. If the binary was installed to a directory requiring elevated permissions, re-run with sudo or fix ownership of the executable.
Import from Tabby
Migrate SSH profiles from Tabby into OpenSSH config that ctty already uses:
ctty import --from tabby
ctty import tabby --dry-run
ctty import tabby -f /path/to/tabby/config.yaml
Profiles (type: ssh) are appended to ~/.ssh/config.d/tabby.conf, and an Include line is added to ~/.ssh/config if needed. Existing Host names are skipped. Tabby vault passwords are not imported β set them again in ctty or keep using keys.
Port Forwarding History
ctty remembers your port forwarding configurations for easy reuse:
Features:
- Automatic saving - Successful forwarding setups are saved automatically
- Quick reuse - Previously used configurations appear as suggestions
- Per-host history - Forwarding history is tracked per SSH host
- All forward types - Supports Local (-L), Remote (-R), and Dynamic (-D) forwarding history
- Persistent storage - History survives application restarts
Platform-Specific Notes
Windows:
- ctty works with the built-in OpenSSH client (Windows 10/11)
- Configuration file location:
%USERPROFILE%\.ssh\config - Compatible with WSL SSH configurations
- Supports the same SSH options as Unix systems
Unix/Linux/macOS:
- Standard SSH configuration file:
~/.ssh/config - Full compatibility with OpenSSH features
- Preserves file permissions automatically
Termux (Android):
- Detected automatically by the
install/unix.shinstaller - Installs to
$PREFIX/bin(e.g.~/termux/files/usr/bin), not/usr/local/bin - No
sudoβ runs with the Termux user permissions - Architecture detection (
aarch64 β arm64,armv7* β armv7) picks the cgoctty_Android_*release asset, which uses Android system DNS (the pure-Go resolver breaks on some devices, e.g.[::1]:53 connection refused); the saved-password vault is shared with the Linux build
ποΈ Configuration
ctty works directly with your standard SSH configuration file (~/.ssh/config). It adds special comment tags for enhanced functionality while maintaining full compatibility with standard SSH tools.
SSH Include Support
ctty fully supports SSH Include directives, allowing you to organize your SSH configurations across multiple files. This is particularly useful for managing large numbers of hosts or organizing configurations by environment, project, or team.
Include Examples:
# Main ~/.ssh/config file
Host personal-server
HostName personal.example.com
User myuser
# Include work-related configurations
Include work-servers.conf
# Include all configurations from a directory
Include projects/*
# Include with relative paths
Include ~/.ssh/configs/production.conf
Organization Examples:
work-servers.conf:
# Tags: work, production
Host prod-web-01
HostName 10.0.1.10
User deploy
ProxyJump bastion.company.com
# Tags: work, staging
Host staging-api
HostName staging-api.company.com
User developer
projects/client-alpha.conf:
# Tags: client, development
Host client-alpha-dev
HostName dev.client-alpha.com
User admin
Port 2222
Example configuration: Include ~/.ssh/conf.d/*
# Tags: production, web, frontend
Host web-prod-01
HostName 192.168.1.10
User deploy
Port 22
IdentityFile ~/.ssh/production_key
Compression yes
ServerAliveInterval 60
# Tags: development, database
Host db-dev
HostName dev-db.company.com
User admin
Port 2222
IdentityFile ~/.ssh/dev_key
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
# Tags: production, backend
Host backend-prod
HostName 10.0.1.50
User app
Port 22
ProxyJump bastion.company.com
ProxyCommand ssh -W %h:%p Jumphost
IdentityFile ~/.ssh/production_key
Compression yes
ServerAliveInterval 300
BatchMode yes
Supported SSH Options
ctty supports all standard SSH configuration options:
Built-in Fields:
HostName- Server hostname or IP addressUser- Username for SSH connectionPort- SSH port numberIdentityFile- Path to private key fileProxyJump- Jump server for connection tunneling (e.g.,user@jumphost:port)ProxyCommand- Jump command for connection tunneling (e.g,ssh -W %h:%p Jumphost)Tags- Custom tags (ctty extension); the special taghiddenhides the host from the TUI andctty searchwhile keeping it connectable viactty <host>
Additional SSH Options:
You can add any valid SSH option using the "SSH Options" field in the interactive forms. Enter them in command-line format (e.g., -o Compression=yes -o ServerAliveInterval=60) and ctty will automatically convert them to the proper SSH config format.
Common SSH Options:
Compression- Enable/disable compression (yes/no)ServerAliveInterval- Interval in seconds for keepalive messagesServerAliveCountMax- Maximum number of keepalive messagesStrictHostKeyChecking- Host key verification (yes/no/ask)UserKnownHostsFile- Path to known hosts fileBatchMode- Disable interactive prompts (yes/no)ConnectTimeout- Connection timeout in secondsControlMaster- Connection multiplexing (yes/no/auto)ControlPath- Path for control socketControlPersist- Keep connection alive durationForwardAgent- Forward SSH agent (yes/no)LocalForward- Local port forwarding (e.g.,8080:localhost:80)RemoteForward- Remote port forwardingDynamicForward- SOCKS proxy port forwarding
Example usage in forms:
SSH Options: -o Compression=yes -o ServerAliveInterval=60 -o StrictHostKeyChecking=no
This will be automatically converted to:
Compression yes
ServerAliveInterval 60
StrictHostKeyChecking no
Application Configuration
ctty supports a configuration file to customize its behavior, including language, key bindings, update checking, and custom tag colors. You can also configure these interactively in the TUI by pressing S.
Configuration File Location:
- Linux/macOS:
~/.config/ctty/config.json(respects$XDG_CONFIG_HOME) - Windows:
%APPDATA%\ctty\config.json
Example Configuration:
{
"language": "zh_CN",
"check_for_updates": true,
"key_bindings": {
"quit_keys": ["q", "ctrl+c"],
"disable_esc_quit": false
},
"tag_colors": {
"prod": "#FF0055",
"staging": "#FFAA00",
"k8s": "#326CE5",
"mine": "#00DDFF"
}
}
Available Options:
- language: Interface language:
"auto"(follow OS locale),"zh_CN"(Simplified Chinese), or"en"(English). Default:"auto". - check_for_updates: Boolean to enable or disable the automatic update check at startup. Default:
true. Set tofalseon air-gapped or offline machines to avoid connection delays. - key_bindings.quit_keys: Array of keys that will quit the application. Default:
["q", "ctrl+c"] - key_bindings.disable_esc_quit: Boolean flag to disable ESC key from quitting the application. Default:
false. Useful for Vim users. - tag_colors: Map of custom hex color codes for specific tags (e.g.
{"prod": "#FF0055"}). Overrides built-in semantic colors and hash palette.
For Vim Users:
If you frequently press ESC accidentally causing the application to quit, set disable_esc_quit to true. This will disable ESC as a quit key while preserving all other functionality.
For Air-gapped Machines:
If ctty is slow to start due to DNS timeouts when reaching GitHub, set check_for_updates to false. You can also use the --no-update-check CLI flag for a one-time override without editing the config file.
Default Configuration: If no configuration file exists, ctty will automatically create one with default settings that maintain backward compatibility.
π οΈ Development
Prerequisites
- Go 1.23+
- Git
Build from Source
# Clone the repository
git clone https://github.com/zsuroy/ctty.git
cd ctty
# Build the binary
go build -o ctty .
# Run
./ctty
Project Structure
ctty/
βββ main.go # Application entry point
βββ cmd/ # CLI commands (Cobra)
β βββ root.go # Root command, CLI flags, and interactive mode
β βββ add.go # Add host command
β βββ edit.go # Edit host command
β βββ move.go # Move host command
β βββ search.go # Search command
β βββ serial.go # Serial device manager command
β βββ telnet.go # Telnet manager / direct-connect command
β βββ sftp.go # SFTP file browser command
β βββ ftp.go # FTP site manager / browser command
β βββ info.go # Machine-readable JSON host info
β βββ completion.go # Shell tab completion script generator
βββ internal/
β βββ config/ # SSH & App configuration management
β β βββ ssh.go # SSH config parsing, manipulation, and include support
β β βββ appconfig.go# App settings (~/.config/ctty/config.json)
β βββ connectivity/ # SSH connectivity checking
β β βββ ping.go # Asynchronous SSH ping functionality
β βββ history/ # Connection history tracking
β β βββ history.go # History management and last login tracking
β βββ i18n/ # Internationalization & locale auto-detection
β β βββ i18n.go # Core translation lookup & state
β β βββ locales.go # Translation dictionaries (English & Chinese)
β β βββ detect_darwin.go # macOS AppleLocale/AppleLanguages detector
β β βββ detect_windows.go # Windows Win32 API GetUserDefaultLocaleName
β β βββ detect_other.go # Linux POSIX locale & Android getprop
β βββ serialconfig/ # Serial device configuration and connection
β β βββ serial.go # Device config storage (~/.config/ctty/serial.json)
β β βββ ports.go # Port enumeration and helpers
β β βββ connect.go # Serial connection bridge (ExecCommand)
β β βββ raw_unix.go # POSIX raw terminal mode (x/term)
β β βββ raw_windows.go # Windows raw terminal mode (x/term)
β βββ rawterm/ # Shared raw-mode helpers for serial & telnet
β β βββ rawterm.go # MakeRaw / Restore wrappers over x/term
β βββ telnetconfig/ # Telnet device configuration
β β βββ telnet.go # Device config storage (~/.config/ctty/telnet.json, atomic writes)
β βββ telnetclient/ # Native RFC 854 telnet client
β β βββ telnet.go # IAC state machine, negotiation, interactive bridge
β βββ sftpconfig/ # SFTP client engine & file transfer
β β βββ client.go # SFTP session, upload, download, and listing
β βββ ftpconfig/ # FTP site inventory (~/.config/ctty/ftp.json)
β βββ ftpclient/ # Plain-FTP transport (list, download, upload, mkdir, delete, rename)
β βββ ftpcred/ # FTP passwords in the encrypted vault (ftp: names)
β βββ version/ # Version checking and updates
β β βββ version.go # GitHub release checking and version comparison
β β βββ version_test.go # Version parsing and comparison tests
β βββ ui/ # Terminal UI components (Bubble Tea)
β β βββ tui.go # Main TUI interface and program setup
β β βββ model.go # Core TUI model and state
β β βββ update.go # Message handling and state updates
β β βββ view.go # UI rendering and layout
β β βββ table.go # Host list table component with status indicators & tag colors
β β βββ tag_color.go# Semantic & hash-based tag color mapping
β β βββ add_form.go # Add host form interface
β β βββ edit_form.go# Edit host form interface
β β βββ move_form.go# Move host form interface
β β βββ info_form.go# Host details modal
β β βββ help_form.go# Keyboard shortcut help modal
β β βββ port_forward_form.go # Port forwarding setup with history
β β βββ styles.go # Lip Gloss styling definitions
β β βββ sort.go # Sorting and filtering logic
β β βββ serial_form.go # Serial device list UI
β β βββ serial_add_form.go # Add serial device form
β β βββ serial_connect_form.go # Edit serial parameters form
β β βββ telnet_form.go # Telnet device list UI with reachability probe
β β βββ ftp_sites.go # FTP site manager UI
β β βββ ftp_view.go # FTP dual-pane local|remote browser UI
β β βββ sftp_view.go # SFTP remote & local browser UI
β βββ validation/ # Input validation
β βββ ssh.go # SSH config validation
βββ images/ # Documentation assets
β βββ logo.png # Project logo
β βββ ctty.gif # Demo animation
βββ install/ # Installation scripts
β βββ unix.sh # Unix/Linux/macOS installer
β βββ README.md # Installation guide
βββ .github/ # GitHub configuration
β βββ copilot-instructions.md # Development guidelines
β βββ workflows/ # CI/CD pipelines
β βββ build.yml # Multi-platform builds
βββ go.mod # Go module definition
βββ go.sum # Go module checksums
βββ LICENSE # MIT license
βββ README.md # Project documentation
Dependencies
- Cobra - CLI framework
- Bubble Tea - TUI framework
- Bubbles - TUI components
- Lipgloss - Styling
- Serial - Cross-platform serial port communication
π¦ Releases
Automated releases are built for multiple platforms:
| Platform | Architecture | Download |
|---|---|---|
| Linux | AMD64 | ctty_Linux_x86_64.tar.gz |
| Linux | ARM64 | ctty_Linux_arm64.tar.gz |
| macOS | Intel | ctty_Darwin_x86_64.tar.gz |
| macOS | Apple Silicon | ctty_Darwin_arm64.tar.gz |
| Windows | AMD64 | ctty_Windows_x86_64.zip |
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Workflow
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
π License
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments
This project is a fork of sshm by @Gu1llaum-3. We are grateful for the original work that made ctty possible.
- Charm for the amazing TUI libraries
- Cobra for the excellent CLI framework
- @Gu1llaum-3 for creating sshm, the ssh foundation of ctty
- @yimeng for contributing SSH Include directive support
- @ldreux for contributing multi-word search functionality
- @qingfengzxr for contributing custom key bindings support
- Linux.do for opensource support
- The Go community for building such fantastic tools
Made with β€οΈ by zsuroy
β Star this repo if you found it useful! β