A Go-based SSH terminal emulator with session management, built on Fyne 2 GUI framework and the gopyte terminal emulation library.
The first fully-functional Fyne-based SSH terminal with session management, scrollback history, bracketed paste, and text selection.
Hierarchical folder/session tree with search filter, connection status indicators, and multi-tab interface
htop running with full 256-color support, proper resize handling, and alternate screen buffer
CRUD interface for managing sessions and folders with full authentication configuration
- SSH connectivity with password and public key authentication
- Multi-tab terminal interface with tree-based session navigator
- Full terminal emulation via gopyte (VT100/ANSI parsing)
- Keyboard input routing to SSH sessions
- Dynamic terminal resize with proper SSH window-change signaling
- Full-screen applications (htop, vim, nano, etc.)
- 256-color support with proper color mapping
- Independent app and terminal theming - three built-in themes (Cyber, Light, Corporate) selectable separately for the chrome and the terminal pane, with per-theme color customization
- Flicker-free standard-mode rendering via incremental per-cell updates
- HiDPI-safe cell backgrounds and selection - device-pixel-snapped background rendering, no tiling seams on scaled displays
- Scrollback history (1000+ lines) with mouse wheel scrolling
- Text selection with clipboard support (double-click word, triple-click line)
- Right-click Copy/Paste context menu in the terminal
- Bracketed paste - multi-line content (configs, scripts) pastes verbatim into vim, editors, and shells, with no auto-indent cascade or premature line-by-line execution
- Optional paced paste with a configurable per-line delay for slow CLI parsers (network gear, serial-style links)
- Tree-based session navigator with collapsible folders
- Right-click context menu on sessions (Connect, Edit)
- Session persistence via YAML configuration
- Session search/filter for quick access to devices
- Session editor with full CRUD operations
- Quick Connect dialog for ad-hoc connections
- SSH key authentication with encrypted key support
- Settings dialog with persistent configuration
- Session logging - cleaned, timestamped transcript per session, toggled live from the terminal right-click menu (Start/Stop Logging), with optional auto-start per session or globally
- SSH agent support not fully implemented
- Host key verification not yet implemented
- Alternate-screen (full-screen app) rendering uses a full-grid repaint rather than the incremental path used in standard mode
TetherSSH uses gopyte, a custom terminal emulation library written specifically for this project. Unlike the Fyne project's proof-of-concept terminal, gopyte provides:
- Full history buffer with configurable scrollback (default 1000 lines)
- Wide character support for CJK characters and emojis
- Alternate screen buffer for full-screen applications (vim, htop, less)
- Proper resize handling that syncs local screen, gopyte buffers, and SSH session
Standard-mode output is rendered incrementally: each redraw diffs against the on-screen grid and repaints only the cells that actually changed, so typing stays flicker-free even over colored prompts. All redraws are driven by a single coalesced update pass on a short timer rather than one repaint per byte received. Full-screen (alternate-screen) applications use a full-grid repaint, since they tend to redraw most of the screen on each update anyway.
- Bracketed paste (DEC mode 2004): when the remote application requests it (vim, shells, editors), pasted text is wrapped in paste markers so it inserts verbatim - no auto-indent stair-stepping, and no multi-line commands running line by line. Mode 2004 is tracked on both the local PTY and SSH output paths.
- Optional line pacing: a configurable per-line delay (Settings -> Paste Line Delay) for slow CLI parsers on network gear or serial-style links that do not support bracketed paste.
- Unified paste path: the Ctrl+V / Cmd+V shortcut and the right-click Paste menu both route through the same handler, and Ctrl+C aborts an in-flight paced paste.
- Tree-based navigator with collapsible folders and session counts
- Right-click context menu for quick Connect or Edit
- Real-time search/filter - instantly find sessions by name, host, group, or device type
- Multiple concurrent SSH connections in tabs
- Visual connection status indicators
- One-click connect with automatic credential handling
- Password authentication - prompted on connect or stored in session
- SSH key authentication - supports RSA, ECDSA, Ed25519 keys
- Encrypted key support - passphrase prompts for protected keys
- Keyboard-interactive - for MFA/RADIUS environments (including YubiKey)
- Configurable per-session authentication type
Press the fast-forward button for ad-hoc connections without saving a session:
- Enter host, port, username
- Choose Password or SSH Key authentication
- Default key path: ~/.ssh/id_rsa
- Optional key passphrase for encrypted keys
Press the gear button to open the full session manager:
- Folders panel - organize sessions into groups
- Sessions panel - view/edit sessions in selected folder
- Add/Edit/Delete - full CRUD operations
- Import - load sessions from other YAML files
- Export - save current configuration
- Device metadata fields (type, vendor, model) for network equipment
All configuration is stored in ~/.tetherssh/:
- Sessions:
~/.tetherssh/sessions/sessions.yaml - Settings:
~/.tetherssh/settings.json - Logs:
~/.tetherssh/logs/(when logging is enabled)
# TetherSSH Sessions File
# Auth types: password, publickey, keyboard-interactive
- folder_name: Production
sessions:
- display_name: web-server-01
host: 10.0.1.10
port: "22"
username: admin
auth_type: publickey
key_path: ~/.ssh/id_rsa
DeviceType: linux
- folder_name: Lab
sessions:
- display_name: cisco-router
host: 172.16.1.1
port: "22"
username: admin
auth_type: password
DeviceType: cisco_ios
Vendor: CiscoPress the gear icon in the toolbar to open the Settings dialog. Settings are persisted to ~/.tetherssh/settings.json.
| Setting | Description | Default |
|---|---|---|
| Row Offset | Adjust terminal row calculation (increase for Retina/HiDPI displays) | 2 |
| Column Offset | Adjust terminal column calculation | 0 |
| Font Size | Terminal font size in points (not yet implemented) | 12 |
| Scrollback Lines | History buffer size (not yet implemented) | 1000 |
| Paste Line Delay | Per-line delay for multi-line paste; paces output for slow CLI parsers (None / 25 / 50 / 100 / 250 ms) | None |
| Copy on Select | Auto-copy selected text to clipboard (not yet implemented) | Off |
| Setting | Description | Default |
|---|---|---|
| App Theme | Theme for the application chrome (sidebar, tabs, toolbar, dialogs) | Cyber |
| Terminal Theme | Theme for the terminal pane (background, default text, ANSI palette) | Cyber |
| Remember Window Size | Restore window dimensions on startup | On |
The two selectors are independent - see Themes below. Changing the App Theme applies immediately; the Terminal Theme applies to newly connected tabs (reconnect an open tab to repaint it).
TetherSSH separates theming into two independent axes, both set on the Appearance tab:
- App Theme drives the application chrome - sidebar, tabs, toolbar, dialogs, buttons - via the Fyne theme.
- Terminal Theme drives the terminal pane on its own - its background, the default (unset-color) text color, and which ANSI palette colored output maps to.
Because the axes are separate, the chrome and the terminal can run different themes. Three built-in themes are available on each axis:
| Theme | Chrome | Terminal pane |
|---|---|---|
| Cyber | Deep blue-black with cyan / matrix-green accents | Black background, bright on-dark ANSI palette |
| Light | White surfaces with a Microsoft-blue accent (Fluent/Office) | White background, dark-on-light ANSI palette |
| Corporate | Navy with cyan accents | Navy background, bright on-dark ANSI palette |
This yields any combination of the two - for example Corporate chrome over a Light terminal gives a navy application frame around a white terminal pane.
The terminal's default text color (output with no explicit color, e.g. most shell and htop text) is taken from the active terminal palette's default entry, so it stays legible against that palette's own background rather than inheriting the chrome's foreground.
Each built-in theme can be customized. The Colors tab has a sub-tab per theme (Cyber, Light, Corporate); leave a field blank to use the theme's built-in value. Overridable colors include primary/accent, secondary, background, surface, surface variant, foreground, input background/border, selection, hover, and error/success/warning. A live preview updates as you edit, and changes apply without restarting. Overrides are stored per theme in settings.json.
| Setting | Description | Default |
|---|---|---|
| Default SSH Key | Default key path for new sessions | ~/.ssh/id_rsa |
| Default Port | Default SSH port | 22 |
| Default Username | Pre-fill username for new sessions | (empty) |
| Connection Timeout | SSH connection timeout in seconds | 30 |
| Keepalive Interval | SSH keepalive interval in seconds | 60 |
Session logs are cleaned transcripts: ANSI/control sequences are stripped and carriage-return/backspace edits applied, so each logged line matches what was on screen. Logging is toggled live per session from the terminal right-click menu (Start/Stop Logging); the settings below are the global defaults.
| Setting | Description | Default |
|---|---|---|
| Auto-start logging on new connections | Begin logging automatically when a session connects | Off |
| Log Directory | Directory for session logs | ~/.tetherssh/logs |
| Add timestamps to log entries | Prefix each line with a timestamp | On |
Log filename format: {session_name}_{YYYYMMDD_HHMMSS}.log
Any session may also set logging: true in its YAML to auto-start logging on connect. Full-screen apps (vim, htop) drive the screen by cursor addressing and will log as noise - logging is intended for line-oriented CLI sessions.
tetherssh/
├── cli/
│ ├── main.go # Application entry, window setup
│ ├── paths.go # Centralized path management (~/.tetherssh)
│ ├── session_manager.go # Tree navigator, search, tab management
│ ├── session_persistence.go # YAML load/save, SessionStore
│ ├── session_editor.go # CRUD modal dialog
│ ├── settings.go # Application settings dialog
│ ├── ssh_backend.go # SSH client, auth chain, SSHTerminalWidget
│ ├── terminal_logger.go # Session logging - cleaned, timestamped transcript
│ ├── terminal_widget.go # NativeTerminalWidget - core terminal UI
│ ├── terminal_pty.go # Local PTY support, WriteToPTY, history
│ ├── terminal_events.go # Keyboard/mouse event handling
│ ├── terminal_events_bus.go # Event bus for terminal events
│ ├── terminal_display.go # TextGrid rendering, incremental cell diff, viewport
│ ├── terminal_bglayer.go # Cell/selection background overlay (HiDPI-safe snapped runs)
│ ├── terminal_paste.go # Paste handling - bracketed paste, line pacing, context menu
│ ├── terminal_selection.go # Text selection and clipboard
│ ├── terminal_containers.go # Custom container widgets
│ ├── tappable_tree_node.go # Right-click support for tree nodes
│ ├── theme.go # Named themes (chrome + terminal), color mappings
│ ├── pty_unix.go # Unix PTY implementation
│ └── pty_windows.go # Windows PTY implementation
├── internal/
│ └── gopyte/ # Terminal emulation library
│ ├── screen.go # Base screen buffer (NativeScreen)
│ ├── screen_interface.go # Screen interface definitions
│ ├── history_screen.go # Scrollback history management
│ ├── wide_char_screen.go # Wide character support
│ ├── alternative_screen.go # Alternate screen buffer (vim, htop)
│ ├── streams.go # ANSI escape sequence parser
│ ├── escape.go # Escape sequence definitions
│ ├── control.go # Control character handling
│ ├── graphics.go # SGR/graphics attributes
│ ├── modes.go # Terminal mode handling
│ ├── charset.go # Character set support
│ └── gopyte_test/ # Test suite
├── screenshots/
│ ├── htop.png
│ ├── session_detail.png
│ └── session_manager.png
├── go.mod
├── go.sum
├── LICENSE
└── README.md
- Go 1.21 or later
- GCC compiler (required for CGO/OpenGL):
- Windows: Install TDM-GCC from https://jmeubank.github.io/tdm-gcc/ (MinGW-w64 based)
- Linux:
sudo apt install build-essential(Debian/Ubuntu) or equivalent - macOS:
xcode-select --install
# Linux/macOS - run directly
go run -tags='!windows' ./cli
# Linux/macOS - build with debug symbols
go build -tags='!windows' -o tetherssh ./cli
# Windows - run directly
go run ./cli
# Windows - build with debug symbols
go build -o tetherssh.exe ./cliStripped binaries are approximately 50% smaller with no debug symbols.
# Linux/macOS
go build -tags='!windows' -ldflags="-s -w" -o tetherssh ./cli
# Windows
go build -ldflags="-s -w" -o tetherssh.exe ./cliCross-compiling Fyne apps requires CGO, which complicates cross-builds. Build natively on each target platform, or use fyne-cross with Docker:
# Install fyne-cross
go install github.com/fyne-io/fyne-cross@latest
# Build for Windows from Linux/macOS
fyne-cross windows -arch=amd64 ./cli
# Build for Linux from macOS/Windows
fyne-cross linux -arch=amd64 ./cli| Build Type | Size |
|---|---|
| Debug (full symbols) | ~53 MB |
| Release (stripped) | ~26 MB |
| Zipped release | ~12 MB |
fyne.io/fyne/v2 # GUI framework
golang.org/x/crypto/ssh # SSH client
github.com/creack/pty # Local PTY (Unix)
github.com/mattn/go-runewidth # Wide character width calculation
github.com/google/uuid # Tab/session unique IDs
gopkg.in/yaml.v3 # Session persistence
TetherSSH stores all configuration in ~/.tetherssh/:
| File | Purpose |
|---|---|
~/.tetherssh/sessions/sessions.yaml |
Session definitions |
~/.tetherssh/settings.json |
Application settings |
~/.tetherssh/logs/ |
Session logs (when enabled) |
On first run, a stub sessions file is created with example entries.
| YAML Value | Description |
|---|---|
password |
Prompt for password on connect |
publickey |
Use SSH key from key_path |
keyboard-interactive |
MFA/RADIUS environments |
The ~ character is expanded to the user's home directory:
~/.ssh/id_rsabecomes/home/username/.ssh/id_rsa(Linux)~/.ssh/id_rsabecomes/Users/username/.ssh/id_rsa(macOS)~/.ssh/id_rsabecomesC:\Users\username\.ssh\id_rsa(Windows)
- Fix vim/htop resize issues
- Implement resize callback pattern
- Post-connect resize sync
- Buffer bounds safety in gopyte
- Session persistence (YAML config)
- Public key authentication
- Encrypted key passphrase support
- Session search/filter
- Session editor with CRUD
- Quick Connect dialog
- Tree-based session navigator
- Settings dialog with persistence
- Right-click context menu
- Bracketed paste support (DEC mode 2004)
- Right-click Copy/Paste in terminal
- Optional paced multi-line paste
- Incremental, flicker-free standard-mode rendering
- HiDPI-safe background and selection rendering (no tiling seams)
- Session logging (cleaned, timestamped transcripts; live right-click toggle)
- Implement SSH agent support
- Add host key verification with known_hosts
- Clean up debug logging (gate render/paste diagnostics behind a debug flag)
- Bring incremental rendering to the alternate screen (full-screen apps)
- More cross-platform testing (Windows, Linux, macOS)
- Log viewer/browser
- Encrypted credentials manager (AES-256-GCM)
- Master password unlock flow
- Credential references in sessions (decouple passwords from YAML)
- Split panes (horizontal/vertical)
- Find in terminal output
- Clickable URLs
- Command snippets/macros
- SFTP file browser integration
- Port forwarding UI
- Jump host/proxy support
- Session import from PuTTY/SecureCRT
gopyte is a terminal emulation library built specifically for TetherSSH. It provides:
- NativeScreen: Base screen buffer
- HistoryScreen: Adds scrollback history
- WideCharScreen: Adds wide character support and alternate screen buffer
- VT100/ANSI parsing via Stream.Feed()
- Scrollback history with linked list storage
- Alternate screen buffer for vim, htop, less, etc.
- Wide character support for CJK and emojis
- Resize handling that preserves content and history
- Cursor movement (CUP, CUU, CUD, CUF, CUB)
- Erase operations (ED, EL)
- SGR attributes (colors, bold, underline, etc.)
- Scroll regions (DECSTBM)
- Alternate screen (DECSET/DECRST 1049)
- Bracketed paste mode (DECSET/DECRST 2004)
- Window title (OSC 0, 1, 2)
- Secure Cartography: https://github.com/scottpeterman/secure_cartography - Network discovery and topology mapping
- TerminalTelemetry: https://pypi.org/project/terminaltelemetry/ - PyQt6-based SSH terminal with real-time monitoring
- VelociTerm: https://github.com/scottpeterman/velociterm - Web-based SSH terminal with NetBox integration
MIT License - See LICENSE file
Last updated: May 28, 2026
Author: Scott Peterman


