A zero-config, interactive terminal UI to connect, manage, and transfer files to VMs over SSH
heyvm is a lazygit-style TUI (Terminal User Interface) for managing VMs via SSH. It eliminates the need to remember SSH/SCP syntax, manually track IPs and credentials, or juggle multiple tools for terminal access and file transfer.
- Split-Pane Interface: View your VM list and details side-by-side
- Interactive TUI: Fully keyboard-driven navigation with intuitive controls
- Full Terminal Emulator: Complete SSH terminal with xterm.js - vim, nano, htop all work
- Terminal Scrollback: 1000 lines of history with smooth scrolling
- File Browser: Dual-pane file manager for easy local ↔ remote file transfers
- Secure Credentials: Password and SSH key storage via OS keychain
- Multiple Auth Methods: Support for SSH keys and password authentication
- Zero Config: No configuration files to write - just add a VM and go
heyvm uses a modern two-tier architecture with clean separation of concerns:
- UI Layer (TypeScript + Ink) - Interactive terminal interface
- Core Backend (Go) - SSH/SFTP operations, VM management, and credential storage
These components communicate via JSON-RPC over stdio, providing process isolation, clear API boundaries, and easy debugging.
┌──────────────────────────────┐
│ Ink TUI (TypeScript) │
│ - Split-pane interface │
│ - VM list & detail screens │
│ - File browser │
│ - Terminal view │
│ - Forms & dialogs │
└──────────────┬───────────────┘
│ JSON-RPC (stdio)
┌──────────────▼───────────────┐
│ heyvm-core (Go Backend) │
│ - SSH session manager │
│ - SFTP file operations │
│ - VM registry & config │
│ - Secure auth handling │
│ - OS keychain integration │
└──────────────┬───────────────┘
│ SSH/SFTP
┌─────▼──────┐
│ Remote VMs │
└────────────┘
- Node.js >= 18.0.0
- Go >= 1.21
- SSH access to at least one VM (for testing)
# Clone the repository
git clone https://github.com/adishm/heyvm.git
cd heyvm
# Install dependencies for both UI and Core backend
make install
# Build the complete application
make build-all# Development mode (with hot reload)
make dev
# Or run the production build
make runThe UI will start in your terminal, and the Go backend will run as a background process communicating via stdio.
heyvm uses a split-pane interface:
- Left Pane: VM list (always visible)
- Right Pane: Selected VM details with multiple tabs (Overview, Terminal, Files)
Navigate between panes using keyboard shortcuts to efficiently manage your VMs.
j/kor↑/↓- Navigate through VMsEnter- Select VM (switches focus to right pane)a- Add new VMd- Delete selected VMr- Refresh VM listq- Quit application
1- Switch to Overview tab2- Switch to Terminal tab3- Switch to Files tabc- Connect to VM (establish SSH session)x- Disconnect from VMEsc- Return focus to VM list (left pane)
- All keys - Sent directly to remote shell (complete terminal liberty)
PgUp/PgDnorShift+↑/↓- Scroll through terminal history (1000 lines)Ctrl+O- Switch to Overview tab (keeps session alive)Esc- Return to VM list- Interactive programs: vim, nano, htop, sudo all work perfectly
Tab- Switch between local (left) and remote (right) file panesj/kor↑/↓- Navigate through files/directoriesEnter- Enter selected directoryBackspaceorh- Go to parent directoryp- Push file (copy from local → remote)g- Get file (copy from remote → local)d- Delete selected filer- Refresh current directoryEsc- Return to VM detail view
- Press
ain the VM list screen - Select authentication method:
- SSH Key - Use existing SSH key file
- Password - Store password securely in OS keychain
- Enter connection details:
- Name - Friendly identifier for the VM
- Host - IP address or hostname
- Port - SSH port (default: 22)
- Username - SSH user account
- SSH Key Path (if using key auth) - Path to private key file (e.g.,
~/.ssh/id_rsa)
- Press
Enterto save
heyvm will automatically validate the connection and persist the VM configuration to ~/.heyvm/config.yaml.
- Select a VM from the list with
Enter - Press
cto establish SSH connection - Switch to Terminal tab (
2) for full interactive shell:- Complete terminal emulator with ANSI support
- Works with vim, nano, htop, sudo, and all interactive programs
- Scroll through history with
PgUp/PgDnorShift+↑/↓ - Press
Ctrl+Oto switch to Overview without closing terminal
- Or switch to Files tab (
3) to browse and transfer files
heyvm/
├── ui/ # Frontend - TypeScript/Ink TUI
│ ├── src/
│ │ ├── components/ # Reusable UI components
│ │ │ ├── Header.tsx
│ │ │ ├── StatusBar.tsx
│ │ │ ├── LoadingSpinner.tsx
│ │ │ ├── ErrorMessage.tsx
│ │ │ └── ConfirmDialog.tsx
│ │ ├── screens/ # Main screen components
│ │ │ ├── VMListScreen.tsx
│ │ │ ├── AddVMScreen.tsx
│ │ │ ├── VMDetailScreen.tsx
│ │ │ └── tabs/
│ │ │ ├── OverviewTab.tsx
│ │ │ ├── TerminalTab.tsx
│ │ │ └── FilesTab.tsx
│ │ ├── hooks/ # Custom React hooks
│ │ │ ├── useVM.ts
│ │ │ ├── useVMList.ts
│ │ │ └── useFiles.ts
│ │ ├── utils/ # Utility functions
│ │ │ └── terminalEmulator.ts # xterm.js wrapper
│ │ ├── core/ # IPC client and type definitions
│ │ │ ├── ipc.ts
│ │ │ └── types.ts
│ │ ├── keybindings.ts # Keyboard shortcut definitions
│ │ ├── App.tsx # Main application component
│ │ └── index.tsx # Entry point
│ ├── scripts/
│ │ └── start-with-core.js # Development launcher
│ ├── package.json
│ └── tsconfig.json
├── core/ # Backend - Go
│ ├── cmd/
│ │ ├── heyvm-core/ # Main backend entry point
│ │ ├── heyvm/ # CLI wrapper
│ │ └── file-browser/ # Standalone file browser
│ ├── internal/
│ │ ├── auth/ # Authentication providers
│ │ │ ├── provider.go
│ │ │ ├── ssh_key.go
│ │ │ └── password.go
│ │ ├── config/ # Configuration management
│ │ ├── ipc/ # JSON-RPC protocol handler
│ │ │ ├── handler.go
│ │ │ ├── protocol.go
│ │ │ └── actions.go
│ │ ├── sftp/ # File transfer operations
│ │ │ ├── manager.go
│ │ │ ├── types.go
│ │ │ └── errors.go
│ │ ├── ssh/ # SSH session management
│ │ │ ├── manager.go
│ │ │ ├── session.go
│ │ │ └── errors.go
│ │ ├── vm/ # VM models and registry
│ │ │ ├── registry.go
│ │ │ ├── models.go
│ │ │ └── errors.go
│ │ └── tui/ # Terminal UI utilities
│ └── go.mod
├── docs/ # Documentation
│ ├── PRD.md # Product requirements
│ ├── architecture.md # System architecture
│ ├── development.md # Development guide
│ └── exploration/ # Development notes
├── bin/ # Compiled binaries (generated)
│ ├── heyvm-core
│ ├── heyvm
│ └── file-browser
├── build/ # Build artifacts (generated)
├── Makefile # Build automation
├── README.md # This file
└── LICENSE
- Framework: Ink - React for interactive CLIs
- Language: TypeScript
- Build Tool: esbuild
- Terminal Emulator: @xterm/headless - Full ANSI/VT100 support
- Key Libraries:
ink-select-input- Interactive selection listsink-text-input- Text input components
- Language: Go 1.24+
- SSH/SFTP:
golang.org/x/crypto/ssh+pkg/sftp - Credential Storage:
99designs/keyring(OS keychain integration) - Configuration: YAML (
gopkg.in/yaml.v3) - IPC Protocol: JSON-RPC over stdin/stdout
# Install all dependencies (UI + Core)
make install
# Build individual components
make build-ui # Build TypeScript UI only
make build-core # Build Go backend only
make build-all # Build everything
# Development
make dev # Run with hot reload
make run # Run production build
# Testing
make test # Run all tests
# Cleanup
make clean # Remove build artifacts
# Help
make help # Show all available commands-
Start development mode:
make dev
This builds the Go backend and runs the UI with TypeScript compilation.
-
Make changes to either UI (TypeScript) or Core (Go) code
-
Test changes:
- For UI changes: The dev mode supports hot reload
- For Core changes: Rebuild with
make build-coreand restart
-
Run tests:
make test
Add new components in ui/src/components/ and import them in your screens.
- Add new methods in
core/internal/ipc/actions.go - Register them in the IPC handler
- Add corresponding TypeScript types in
ui/src/core/types.ts - Call from UI using
ipcClientinui/src/core/ipc.ts
heyvm takes security seriously and implements multiple layers of protection:
- Passwords: Securely stored in OS-native keychain:
- macOS: Keychain
- Linux: Secret Service (GNOME Keyring, KWallet)
- Windows: Credential Manager
- SSH Keys: Never copied or stored - referenced by file path only
- Access: Credentials are only accessed when establishing connections
- Passwords: Never logged or written to disk in plaintext
- Config Files: Stored with
0600permissions (owner read/write only) in~/.heyvm/ - Logs: Sanitized to prevent credential leakage
- Memory: Sensitive data cleared from memory after use
- Host Key Verification: Verified on first connection
- Known Hosts: Tracked to prevent man-in-the-middle attacks
- Connection Isolation: Each VM connection is independent
- UI and Core backend run as separate processes
- Communication only via controlled JSON-RPC interface
- No shared memory or state
heyvm stores all configuration and state in ~/.heyvm/:
~/.heyvm/
├── config.yaml # VM definitions and settings
├── state.json # Runtime state (connections, sessions)
├── known_hosts # SSH host key verification
└── logs/
└── heyvm-core.log # Backend logs
Example config.yaml:
vms:
- id: "vm-001"
name: "Production API Server"
host: "api.example.com"
port: 22
user: "deploy"
auth:
type: "key"
key_path: "~/.ssh/production.pem"
- id: "vm-002"
name: "Development Database"
host: "10.0.1.50"
port: 22
user: "ubuntu"
auth:
type: "password"
# Password stored securely in OS keychainWhile heyvm is designed to work without manual configuration, you can directly edit ~/.heyvm/config.yaml if needed. The file is automatically created when you add your first VM.
Note: When using password authentication, passwords are stored in the OS keychain, not in the YAML file.
Problem: Cannot connect to VM
Solutions:
- Verify SSH access works manually:
ssh user@host - Check firewall rules allow SSH (port 22 or custom port)
- Ensure SSH key has correct permissions:
chmod 600 ~/.ssh/your_key - Check if the host key has changed (remove from
~/.heyvm/known_hosts)
Problem: "Permission denied" error
Solutions:
- Verify username is correct
- For SSH keys: Ensure the key is authorized on the remote VM (
~/.ssh/authorized_keys) - For passwords: Re-enter the password (it may have changed)
Problem: File transfer fails
Solutions:
- Ensure you have write permissions on the target directory
- Check available disk space on remote VM
- Verify SFTP is enabled on the SSH server
Problem: UI not responding
Solutions:
- Check logs:
~/.heyvm/logs/heyvm-core.log - Restart the application:
qto quit, then restart - Clear build artifacts and rebuild:
make clean && make build-all
Problem: Backend process crashes
Solutions:
- Review logs in
~/.heyvm/logs/heyvm-core.log - Ensure Go backend was built correctly:
make build-core - Check for port conflicts or permission issues
If you encounter issues:
- Check the logs:
cat ~/.heyvm/logs/heyvm-core.log - Review existing GitHub Issues
- Open a new issue with:
- heyvm version
- Operating system
- Error messages
- Steps to reproduce
- ✅ VM management and storage
- ✅ SSH key and password authentication
- ✅ Split-pane TUI interface
- ✅ Full terminal emulator (xterm.js with ANSI/VT100 support)
- ✅ Terminal scrollback (1000 lines)
- ✅ Interactive programs support (vim, nano, htop, sudo)
- ✅ File browser with dual-pane view
- ✅ Secure credential storage
- 🔄 Cloud provider integration (AWS, Azure, GCP)
- 🔄 Bastion/jump host support
- 🔄 VM lifecycle management (start/stop/restart)
- 🔄 Port forwarding
- 🔄 Tunnel management
- 🔄 Session recording and playback
- 🔄 Multi-VM command execution
- 🔄 SSH config import
Contributions are welcome! Here's how you can help:
- Check if the issue already exists
- Create a detailed bug report with:
- Steps to reproduce
- Expected vs actual behavior
- Environment details (OS, versions)
- Relevant logs
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Write/update tests if applicable
- Ensure code builds:
make build-all - Run tests:
make test - Commit with clear messages:
git commit -m 'Add amazing feature' - Push to your fork:
git push origin feature/amazing-feature - Open a Pull Request
- Follow existing code style
- Add comments for complex logic
- Update documentation for user-facing changes
- Keep commits focused and atomic
- Write meaningful commit messages
MIT License - see LICENSE file for details.
heyvm draws inspiration from excellent tools in the terminal UI ecosystem:
- lazygit - TUI UX patterns and keyboard navigation
- k9s - Architecture design and command abstraction
- Ink - React-based terminal UI framework
Built with:
- Ink - Terminal UI framework
- Go SSH - SSH client implementation
- 99designs/keyring - Secure credential storage
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: docs/
Made with ❤️ for developers who manage VMs