~/projects / terminaal
Terminaal
Rust Fluent TOMLTerminaal
A GPU-rendered terminal emulator for COSMIC with a built-in SSH manager.
Written in Rust. English and German UI.
Features · Installation · Getting around · Configuration · Documentation · Roadmap
Terminaal combines an everyday terminal with Termius-style host management, in the spirit of Tabby/Terminus. Open local shells and SSH sessions side by side in tabs and split panes, keep your hosts, logins and keys in a sidebar, work with a server's files over the same connection – and never have a secret written to disk.
Note
Status: under active development and used as a daily driver on Linux (CachyOS, Wayland and X11). Expect rough edges, and expect the config format to change.
Important
Disclaimer: this project is coded mostly by Claude Code. I make all the decisions, though – every feature was planned by me.
Contents
- Highlights
- Features
- Installation
- Getting around – shortcuts, mouse, command line
- Configuration
- Documentation
- Known limitations
- Roadmap
- Contributing
Highlights
- Fast and quiet: a custom wgpu renderer that redraws only when something changes
- SSH manager built in: hosts, several logins per host, keys, jump hosts, port forwards, automatic reconnect
- Files over the same connection: browse, copy, edit locally and keep folders in sync – no second login
- Split panes, broadcast, command palette for working on many terminals at once
- Shell integration without setup for fish, bash and zsh: prompt jumps, exit codes, run times, notifications
- Nothing secret on disk, and your own config files are never rewritten behind your back
- Fits COSMIC: follows the desktop theme live, frosted see-through window, drop-down mode
Features
Terminal
- Tabs and split panes – local shells and SSH sessions side by side; drag tabs to reorder them, split a tab right or down, resize panes by dragging the line between them, maximize one pane. → Split panes
- Search the scrollback – matches light up as you type. → Search and links
- Clickable links – hold Ctrl to underline URLs, hyperlinks (OSC 8) and existing files; Ctrl+click opens them
- Broadcast – what you type into one terminal of the group goes to all of them: one command on ten servers at once. → Tutorial
- Command palette (Ctrl+Shift+P) – switch tabs, connect to hosts, run snippets, trigger actions or pick a theme by typing a few letters. → Command palette
- Activity in background tabs – a dot for new output or the bell, and "watch for silence" with a desktop notification
- A look before risky pastes – several lines that would run at once,
sudo,curl … | sh,rm -rf, or anything going to several terminals is shown first - Restores the last session – tabs, splits, working directories, SSH connections, files and settings tabs. → Sessions
- Drop-down window (
terminaal --quake) – drops down from the top of the screen and hides again, a real layer surface on COSMIC, KDE, Sway and Hyprland. → Drop-down window - Images in the terminal – the kitty graphics protocol, for yazi's previews,
kitten icat, chafa or timg, over SSH too. → Images - Hints (Ctrl+Shift+H) – links, paths, IP addresses and hashes on screen get a letter or two; type them to copy, open or insert that text. → Search, links and the scrollback
- Keys as programs expect them – Alt, Ctrl and Shift with arrows, function and editing keys the xterm way, and the kitty keyboard protocol for programs that ask for it (fish 4, Neovim, Helix)
- Vi mode (Ctrl+Shift+Space) – move through
the scrollback with vi's keys, select with
v/V/Ctrl+V, copy withy. → Search, links and the scrollback - Clipboard from programs (OSC 52) – vim or tmux, on a server too, copy into your clipboard; reading it asks first. Synchronized output (mode 2026) for flicker-free full-screen programs
- Bracketed paste, mouse selection that scrolls along (double-click a word,
triple-click a line), a scrollbar that shows when needed, the mouse wheel in
full-screen programs (
less,htop,vim), a right-click menu, and a settings tab for every option
Shell integration
Set up by Terminaal itself for fish, bash and zsh; any shell that sends OSC 7 and OSC 133 works too, also over SSH. → Shell integration
- Tab titles show the working directory (or the running program), and a new tab opens in the same folder
- Ctrl+Shift+↑/↓ jump from prompt to prompt
- A failed command gets its exit code (
✘ 1) next to the prompt, a slow one its run time (4.2 s) - Copy the last command's output, or click a prompt to select a command with its output
- A desktop notification when a long command finishes in a tab you're not looking at
SSH
→ SSH hosts · Tutorial: your first SSH host
- Saved hosts plus your
~/.ssh/config(Include,Match,%tokens …), read-only or copied over to edit - Several logins per host (user + key), one of them the default
- ProxyJump chains and ProxyCommand
- Reconnects on its own when a connection drops, keeping the scrollback
- Port forwarding – local, remote and SOCKS (
DynamicForward), Unix sockets too; pause, start and retry each one live from the sidebar. → Tutorial - Per-host options with their
ssh_configkeyword: timeouts, keepalives, compression, agent forwarding,StrictHostKeyChecking,RemoteCommand,SetEnv, algorithms and more - A color per host – a warning color on its tabs and frames, or a theme of its own, so production never looks like a test box
- Host keys checked against
~/.ssh/known_hosts; a changed key shows both fingerprints, and old entries can be removed from the sidebar. → Host keys - Prompts for host keys, passphrases and passwords appear inside the tab, like OpenSSH – nothing secret is stored
Files on the server (SFTP)
Ctrl+Shift+O in an SSH terminal opens its files tab, over the terminal's own connection. → Files on a server
- Browse, upload, download and delete – several entries at once with Ctrl/Shift+click, or by dropping files onto the window. Copies never overwrite; local deletions go to the trash
- Keep folders in sync – per host, two-way or one-way, when the files tab opens or live in the background while a terminal is logged in. Conflicts keep both versions; deletions only travel where you allow it. → Syncing folders
- Edit a server file in your local editor – every save goes back, after checking (by SHA-256 on the server) that nobody changed it meanwhile
- Files only root may change go through sudo in the terminal, where it asks for the password as usual
- Transfers and saves wait out a dropped connection and carry on once it's back
Shells and commands
- Any shell from
/etc/shellsfor a new tab, and a default one - Aliases, functions and lines of your own for fish, bash and zsh, managed
in the sidebar. They live in a separate file only Terminaal loads – your
.bashrcand friends are never touched - Built-in commands as buttons: update the system (plus Flatpak and AUR separately), pending updates, disk space, memory, top processes, failed services, log errors, open ports – tailored to the system of the active tab (pacman, apt, dnf, zypper, apk, xbps, emerge, nixos-rebuild, brew, pkg), locally and over SSH
- Snippets – your own commands as buttons, optionally only for one system or host, or run by themselves with every new shell or after an SSH login
- Middle-click any command button to run it in a new tab like the active one
Keys
→ Tutorial: keys and the agent
- Generate Ed25519 keys (optionally with a passphrase), add existing key files, or take over keys from your SSH agent (e.g. 1Password)
- Copy the public key with one click; renaming a key updates the hosts that use it
- Only keys generated in Terminaal can have their files deleted, and only after asking
Look and feel
→ Appearance · Tutorial: your own theme
- Themes for console and interface alike: seven built in, and your own in Alacritty's format (its themes work as they are)
- A COSMIC theme that follows the desktop's colors, light/dark and accent live
- A see-through window, frosted on COSMIC (and other compositors with
ext-background-effect) and KDE - Your choice of console font and menu font
- Every keyboard shortcut configurable, several per action if you like
- English and German, following your locale or set in the settings
Installation
From a release (x86_64 Linux): download terminaal-x86_64-linux.tar.gz from
the latest release,
unpack it and run the installer:
tar xzf terminaal-x86_64-linux.tar.gz
cd terminaal-x86_64-linux
./install.shThis puts Terminaal in ~/.local/bin/terminaal, plus a desktop entry, icons and
the man page under ~/.local/share. It needs a GPU driver with Vulkan or OpenGL,
and OpenSSL 3, zlib and libxkbcommon, which practically every desktop has. From
then on Terminaal updates itself: it offers new releases at start
(Updates).
From source
Requirements
- Rust 1.88 or newer (rustup)
- A C compiler,
pkg-config, and the OpenSSL and zlib development headers (for libssh2). On Debian/Ubuntu:sudo apt install build-essential pkg-config libssl-dev zlib1g-dev - A GPU driver with Vulkan or OpenGL support
- ImageMagick (
magick), only forinstall.sh, which scales the icons
Install for the current user
git clone https://github.com/mergedeyes/terminaal terminaal
cd terminaal
./install.shThis builds and installs ~/.cargo/bin/terminaal, plus a desktop entry,
icons and the man page (man terminaal) under ~/.local/share, so Terminaal
appears in your app launcher.
| Command | What it does |
|---|---|
./install.sh |
Binary, desktop entry, icons and the terminaal(1) man page |
./install.sh --no-binary |
Desktop entry, icons and man page only |
./install.sh --uninstall |
Removes all of the above |
Run ./install.sh again after updating the source – the launcher always starts
the installed binary. Installed from source, Terminaal still offers new releases;
turn that off under Settings → General → Updates to stay on your own builds.
Making releases: RELEASING.md.
Just try it
cargo run --releaseNew here? Getting started walks through the window and the first steps.
Getting around
Keyboard shortcuts
The ones you'll use most:
| Shortcut | Action |
|---|---|
| Ctrl+Shift+T | New tab |
| Ctrl+Shift+W | Close the pane (the tab, when it's the only one) |
| Ctrl+Tab / Ctrl+Shift+Tab | Next / previous tab |
| Ctrl+Shift+D / Ctrl+Shift+Alt+D | Split right / down |
| Ctrl+Shift+C / V | Copy / paste |
| Ctrl+Shift+F | Search the scrollback |
| Ctrl+Shift+P | Command palette |
| Ctrl+Shift+O | Files of the SSH connection |
| Ctrl+Shift+B | Show or hide the sidebar |
| Ctrl+, | Settings |
All default shortcuts
| Shortcut | Action |
|---|---|
| Ctrl+Shift+T | New tab with the default shell |
| Ctrl+Shift+W | Close the pane (the tab, when it's the only one) |
| Ctrl+Shift+Alt+W | Close the tab with all its panes |
| Ctrl+Shift+Alt+T | Reopen the tab closed last |
| Ctrl+Tab / Ctrl+Shift+Tab | Next / previous tab |
| Alt+1 … 9 | Go to tab 1 … 9 |
| Ctrl+Shift+PageUp / PageDown | Move the tab left / right |
| Ctrl+Shift+D / Ctrl+Shift+Alt+D | Split right / split down |
| Ctrl+Alt+← → ↑ ↓ | Go to the pane in that direction |
| Ctrl+Shift+Alt+← → ↑ ↓ | Move the divider of the pane that way |
| Ctrl+Shift+Enter | Maximize the pane / show all panes again |
| Ctrl+Shift+I | Terminal joins / leaves the broadcast |
| Ctrl+Shift+O | Files of the SSH connection (SFTP) |
| Ctrl+Shift+B | Show or hide the sidebar |
| Ctrl+, | Open the settings tab |
| Ctrl+Shift+P | Command palette |
| Ctrl+Shift+C / V | Copy / paste |
| Ctrl+Shift+Alt+C | Copy the last command's output |
| Ctrl+Shift+H | Hints: copy, open or insert a link, path, IP or hash by its letters |
| Shift+PageUp / PageDown | Scroll the scrollback a page up / down |
| Shift+Home / End | Scroll to the top / bottom |
| Ctrl+Shift+F | Search the scrollback |
| Ctrl+Shift+Space | Vi mode: select and copy in the scrollback with vi keys |
| Ctrl+Shift+↑ / ↓ | Previous / next prompt |
| Ctrl++ / - / 0 | Font bigger / smaller / back (until Terminaal quits) |
"Paste and run", "Watch for silence" and swapping panes have no default. In full-screen programs
such as less or vim, the scrolling keys go to the program.
Every shortcut can be changed, removed or given more key combinations – in the
settings tab under Shortcuts (click + and press the keys) or in
config.toml. → Keyboard shortcuts
Mouse
- Ctrl+click a link or file name to open it
- Middle-click a tab to close it; the ☰ button in the tab bar toggles the sidebar
- Clicking into a pane gives it the keyboard; the wheel scrolls the pane under the mouse (Shift+wheel scrolls Terminaal's scrollback even in full-screen programs)
- Right-click in a terminal for copy, paste, broadcast, splitting and the files tab
Command line
terminaal # a local shell
terminaal --connect myserver # connect to a saved or ~/.ssh/config host
terminaal --connect admin@myserver # ...using that host's login for "admin"
terminaal -s # list the installed shells and exit
terminaal -s fish # first tab with that shell (name or path)
terminaal -c "journalctl -f" # run that line instead of a shell, like xterm -e
terminaal -s bash -c "make" --hold # ...in bash, and keep the tab once it ends
terminaal --connect web -c "htop" # run it on the server (RemoteCommand)
terminaal --quake # show or hide the drop-down window (bind it to a key)
terminaal --help # all of it, and `man terminaal` for moreWith --connect, -s or -c the saved session is neither restored nor
written. → The command line
Configuration
Everything is optional and can be set in the settings tab (⚙ in the sidebar,
or Ctrl+,). Behind it, everything lives in
~/.config/terminaal/ – plain TOML you may edit by hand. None of it holds
anything secret.
| File | Contents |
|---|---|
config.toml |
Your settings. Terminaal changes just the line you changed in the settings and keeps your comments |
hosts.toml |
Saved SSH hosts, logins, options and synced folders |
keys.toml |
Named keys: file paths, or the public half of agent keys |
snippets.toml |
Your own commands |
themes/*.toml |
Your own color themes, in Alacritty's format |
shell-integration/ |
Startup files Terminaal generates for bash, zsh and fish |
A missing or broken config.toml just means defaults, never a failed start.
Example config.toml with every option
font_size = 15.0 # logical pixels
line_height_factor = 1.25
padding = 8.0 # around the terminal grid
scrollback_lines = 10000
scroll_lines = 3.0 # lines per mouse-wheel notch
scrollbar = true # scrollbar at the right edge, shown when scrolling or on hover
scroll_select_factor = 3.0 # wheel multiplier while marking text (1 = off)
select_path_segments = false # double-click marks one folder of a path, not all of it
default_width = 1000.0 # window size at start
default_height = 650.0
cursor_blink = true
cursor_blink_interval_ms = 600
notifications = true # desktop notifications at all
notify_after_secs = 10 # notify when a command ran this long unseen (0: never)
paste_warning = true # ask before risky pastes (several lines, sudo, curl | sh, rm -rf)
kitty_keyboard = true # programs may switch on the kitty keyboard protocol
clipboard_write = true # programs may set the clipboard (OSC 52)
images = true # programs may show images (kitty graphics protocol)
clipboard_read = "ask" # programs reading the clipboard: "never", "ask" or "always"
silence_secs = 15 # a terminal watched for silence is quiet after this long
tab_bar = true
sidebar = true # show the sidebar at start
sidebar_width = 300.0
splash = true # start-up animation
restore_session = true # open last time's tabs again
update_check = true # offer new releases at start
quake_height = 50.0 # drop-down window height, percent of the screen
quake_hide_on_unfocus = true # hide it when another window gets the keyboard
# shell = "/usr/bin/fish" # default shell for new tabs (default: $SHELL)
# language = "en" # "en" or "de" (default: from your locale)
# theme = "Dracula" # color theme (default: "Terminaal")
# font_family = "Hack" # console font (default: Noto Sans Mono)
# ui_font_family = "Inter" # font of menus and panels (default: built in)
opacity = 1.0 # below 1 the window is see-through (0.2–1.0)
# ui_opacity = 0.85 # tab bar, sidebar, settings in a see-through window
# (default: the theme's, else 0.85)
blur = true # blur what's behind a see-through window
commands_run = true # command buttons run at once; off: typed into the prompt
commands_assume_yes = false # let them skip confirmations (-y, --noconfirm)
# system = "debian" # what the built-in commands build for
# (default: from /etc/os-release)
# editor = "code" # opens server files edited locally
# (default: the desktop's default app)
[shortcuts] # only what differs from the defaults
new_tab = "Ctrl+Alt+N"
copy = ["Ctrl+Shift+C", "Ctrl+Insert"]
paste_and_run = "Ctrl+Shift+Alt+V"
tab_9 = [] # no shortcut→ The configuration reference documents every
key of every file, including hosts.toml and snippets.toml.
Documentation
The docs/ folder goes into detail:
| Start here | Getting started · Tips and tricks · Troubleshooting |
| Tutorials | Your first SSH host · Keys and the agent · Port forwarding · One command on many servers · Your own theme |
| Guides | Configuration · Shortcuts · Command line · SSH hosts · Host keys · Files and SFTP · Shell integration · Commands and snippets · Command palette · Search and links · Split panes · Sessions · Drop-down window · Appearance |
| Background | Architecture · Security and your files · How prompt marks work |
Known limitations
Platform
- Linux only for now
- A see-through window needs Wayland; on X11 it stays opaque
- The drop-down window needs a Wayland desktop with the layer shell (not GNOME); on X11 it's an always-on-top window. It takes no dropped files and no input method (dead keys work)
- Desktop notifications need
notify-send, opening linksxdg-open, the local trashgio
SSH
- Based on libssh2: the server can't listen on a Unix socket, and there's no
ControlMaster - Only Ed25519 keys can be generated; existing RSA/ECDSA keys work
Match execin~/.ssh/configis never evaluated, on purpose- Reconnecting on its own needs a login without prompts (agent, key without passphrase); otherwise press Enter and answer them. A dropped connection is noticed through keepalives – with the defaults after about a minute and a half
- A paused remote port forward keeps listening on the server and turns connections away; libssh2 can't cancel it cleanly mid-session
- The built-in commands ask an SSH host what it is right after login, which can hold the tab for up to two seconds on a slow link; set the host's system under Advanced to skip that
Files
- Deleting on the server is final. Transfers resume after a dropped connection only while Terminaal stays open
- Folder sync compares by size and modification time; live pairs watch only the local folder, so server changes arrive with the next sync
- Editing through sudo pastes a command into the terminal, so that terminal should be at a shell prompt
Terminal
- A command's exit code shows once the next prompt appears. Over SSH, prompt marks and the working directory only work if the remote shell sends them
- With broadcast on, the built-in command buttons send the line for the focused terminal's system to every terminal in the group
- A restored session starts every terminal fresh: no scrollback, and SSH terminals log in again. Closing the last tab leaves nothing to restore – close the window to keep your tabs
Roadmap
Done
- Local terminal core, tabs and sessions
- Shell management with per-shell aliases, functions and lines of your own
- SSH sessions, host manager, keys, per-host options
- Configurable keyboard shortcuts for every action
- Appearance: themes for console and interface, console and menu font, COSMIC theme sync, see-through and frosted window
- Built-in commands per system, local and over SSH
- Terminal correctness and search: bracketed paste, search in the
scrollback,
known_hostsentries shown and removable from the sidebar - Shell integration: working directory (OSC 7) and prompt marks (OSC 133), plus clickable URLs and paths
- Own commands: snippets bound to a system or host, input broadcast, a live list of a session's port forwards
- Split panes
- SFTP: browse, transfer, edit server files locally with conflict check, through sudo where needed
- Restoring the last session
- Drop-down (Quake) window
- Startup commands: snippets that run with every new shell, or after an SSH login
- Separate update buttons for Flatpak and AUR helpers (yay/paru)
- A color per host
- Command palette
- Command output through the prompt marks: copy the last output, select a command, run times
- A warning before risky pastes
- Activity in background tabs
-
terminaal -c,-sand--hold, and aterminaal(1)man page - Folder sync over SFTP – two-way or one-way, on opening or live in the background
- Selecting several files at once in the files tab
- Updates from the GitHub releases, offered at start and installed on request
- A scrollbar for the scrollback
- OSC 52: programs (also over SSH) may set the clipboard; reading it asks first
- Synchronized output (mode 2026)
- Keyboard hints: copy, open or insert URLs, paths, IPs and hashes on screen by a letter
- Kitty keyboard protocol, and modifiers on every key the xterm way
- Vi mode for selecting and copying in the scrollback
- Images in the terminal (kitty graphics protocol)
- Reopen a closed tab
- Resize and swap panes with the keyboard
- Search: number of matches, optional regex
Everyday comfort
- An integrated title bar: window buttons in the tab bar instead of the desktop's title bar
SSH
- Folders and tags for hosts, search in the sidebar
- X11 forwarding
- Add a port forward on the fly from a connected tab
- Connection quality in the tab (latency, reconnecting)
- Import hosts from Termius, PuTTY and Remmina
- More session types: serial console, containers (
docker/podman exec, distrobox/toolbox,kubectl exec)
Files (SFTP)
- Drag and drop between the local and the server side
- Sort by name, type, size and date
- Filters: hidden files, folders or files only, name pattern, size, date range, file type
- Change permissions in a small dialog, with the octal mode alongside; recursively for folders
- Preview text and images
- A preview of what a folder sync would copy
Bigger pieces
- Workspaces: named layouts with splits, folders, hosts and startup commands
- Recording a tab's output as an asciinema cast or a log file
- tmux control mode (
tmux -CC): a server's tmux windows as real tabs and splits - Detach a tab into a window of its own
- Profiles: font, theme and environment per shell or host
Contributing
Development
cargo run # dev build
cargo run -- --connect myserver # pass arguments after --
cargo test
cargo clippy --all-targets # should stay warning-free
RUST_LOG=terminaal=debug cargo run # per-frame timing
RUST_LOG=terminaal=trace cargo run # plus the SSH worker's timelineCode comments are in English. User-facing text goes in locales/*.ftl, never
inline in the code. The architecture overview
explains how the pieces fit together.
Translations
The texts live in locales/, one Fluent
file per language, compiled into the binary. To improve a translation, edit the
.ftl file; cargo test checks that every language has the same messages with
the same arguments. To add a language, copy locales/en.ftl, translate it, and
register it in Language in src/i18n.rs – a few lines.
