No description
  • Rust 96.4%
  • Shell 2.8%
  • Meson 0.8%
Find a file
2026-09-02 11:03:13 +00:00
.forgejo/workflows feat(build): add an rpm spec, install every schema 2026-08-19 17:29:05 +02:00
build-aux feat(sidebar): organize sessions into folders 2026-08-20 16:26:56 +02:00
crates feat(dialog): autofocus and select folder name input 2026-09-02 12:48:02 +02:00
data refactor!: remove background transparency feature 2026-08-20 07:24:01 +02:00
docs/spec feat(sidebar): organize sessions into folders 2026-08-20 16:26:56 +02:00
ui refactor!: remove background transparency feature 2026-08-20 07:24:01 +02:00
.gitignore chore: Initialize Terminalko project 2026-08-19 03:13:20 +02:00
Cargo.lock feat(session-types): add support for ssh, container, and root sessions 2026-08-19 15:45:17 +02:00
Cargo.toml chore: Initialize Terminalko project 2026-08-19 03:13:20 +02:00
CONTRIBUTING.md feat: implement search, link detection, paste guard, and drag-and-drop 2026-08-19 03:43:46 +02:00
LICENSE chore: Initialize Terminalko project 2026-08-19 03:13:20 +02:00
meson.build feat(ctl): add terminalkoctl CLI for session management 2026-08-19 15:29:32 +02:00
meson.format chore: Initialize Terminalko project 2026-08-19 03:13:20 +02:00
meson.options chore: Initialize Terminalko project 2026-08-19 03:13:20 +02:00
mprocs.yaml chore: Initialize Terminalko project 2026-08-19 03:13:20 +02:00
NOTICE feat(palette): integrate GNOME HIG palette as default 2026-08-20 03:26:26 +02:00
README.md refactor!: remove background transparency feature 2026-08-20 07:24:01 +02:00

Terminalko

A terminal emulator organised around sessions instead of tabs: a vertical session sidebar with folders, sessions you configure once and start automatically, per-session colour highlighting, and sessions that keep running when their window closes.

Built on VTE with GTK 4 and libadwaita.

Status

M2 landed. Sessions in a vertical sidebar with folders, accent colours, saved layout, plus a working terminal underneath: four colour palettes with day/night schemes following the desktop preference, zoom, link recognition with a context menu, per-session output search, a paste guard, and drag-and-drop of files and text.

M3 in progress. terminalko-agent works: it owns the pseudo-terminals, speaks a framed CBOR protocol over a unix socket, passes pty descriptors with SCM_RIGHTS, replays output buffered while nothing was attached, restarts sessions with backoff, autostarts those configured for it, allows only one agent per user, and exits by itself once it has no windows and no sessions. Ten end-to-end tests drive the real binary, including a session that survives its window disconnecting entirely.

The window uses it. Opening a session asks the agent to start it and hands the terminal the pty that comes back; closing a page detaches a persistent session and stops one that is not. Sessions marked persistent keep running when their window closes, and reattaching replays the output produced in between.

terminalkoctl looks at and steers sessions from a shell, so M3 is complete.

M4 in progress. Sessions can be local, ssh, container (podman, docker, toolbox or distrobox) or root (sudo, run0 or pkexec). The New menu is filled from the user's ssh configuration and the containers the installed runtimes know about. Misconfigured sessions fail with a reason instead of a dead terminal.

Each session has a settings dialog (Ctrl+Shift+,) showing only what its type needs, and application preferences live behind Ctrl+,.

M5 in progress. Sessions show what they are running and whether that is root, the window says where the shell is, sessions that ring while you are elsewhere are marked, sessions can carry their own font and palette, closing something still running asks first, a session that ends unwatched raises a notification, and Ctrl+Shift+P / Ctrl+Shift+O find a session and show them all.

An rpm can be built (see below). Remaining work is tracked as issues: drag-reorder in the sidebar, export/import of the session tree, i18n, and a Flatpak manifest.

Specified and implemented, see docs/spec/: colour palettes, font and zoom, hyperlinks, search/paste/drop, the session model, the session sidebar, the session agent, session types, preferences.

Keys
Ctrl+Shift+C / V / A copy, paste, select all
Ctrl+Shift+F find in output (Ctrl+Shift+G / H for next / previous)
Ctrl + / - / 0 zoom in, out, reset
Ctrl+Shift+N / W new window, close window
Ctrl+Shift+T / D new session, new folder
Ctrl+Shift+Alt+T new session, asking for a name
F2 rename the selected session
Ctrl+Shift+, / Ctrl+, session settings, application preferences
Ctrl+1Ctrl+9 jump to a session by position
Alt+Up / Alt+Down previous / next session
F9 show or hide the sidebar
Ctrl+Shift+P / O find a session, show all sessions
F11 fullscreen
Ctrl+Shift+? keyboard shortcuts
Ctrl-click open the link under the pointer

Build dependencies (Fedora 44)

sudo dnf install cargo rust rustfmt clippy rust-analyzer \
    gtk4-devel libadwaita-devel vte291-gtk4-devel glib2-devel \
    blueprint-compiler meson ninja-build \
    desktop-file-utils libappstream-glib

Minimum versions, enforced by meson.build: GTK 4.20, libadwaita 1.9, VTE 0.78, GLib 2.84, Rust 1.85 (edition 2024).

Running from a checkout

cargo run -p terminalko

No install step is needed. build.rs compiles the blueprint UI, embeds the resource bundle, and compiles the GSettings schema into OUT_DIR; a debug build points GSETTINGS_SCHEMA_DIR at it. A checkout build uses the application ID me.dusansimic.terminalko.Devel, so it never activates an installed copy — but it shares preferences with it, since the schema ID is deliberately profile independent.

mprocs starts the app alongside lint and test processes:

mprocs

build-aux/smoke.sh runs the app on a private D-Bus session with a throwaway settings backend and a session agent of its own, drives its actions over org.gtk.Actions, and fails if anything warns. It needs a display, so it is separate from ci.sh:

./build-aux/smoke.sh

Installing

meson setup build --prefix=/usr/local
meson compile -C build
meson install -C build

-Dprofile=development builds a debug binary with the .Devel application ID.

Repository layout

Path What it is
crates/terminalko GUI binary — application, window, terminal widget
crates/terminalko-config GSettings access and the session model, shared by every binary
crates/terminalko-agent Owns the pseudo-terminals so sessions outlive windows
crates/terminalko-proto The messages the two speak, and their framing
crates/terminalko-ctl terminalkoctl, for looking at and steering sessions
ui/*.blp Blueprint templates, compiled by build.rs
data/ GSettings schema, desktop entry, AppStream metainfo, icons
docs/spec/ Behaviour specs written before implementation (see CONTRIBUTING.md)
build-aux/ cargo-build.sh (meson glue), ci.sh, smoke.sh

Packaging

An rpm can be built from a distribution tarball:

meson setup build
meson dist -C build --no-tests          # tarball from git HEAD
rpmdev-setuptree
cp build/meson-dist/terminalko-*.tar.xz ~/rpmbuild/SOURCES/
rpmbuild -ba build-aux/terminalko.spec

Note that meson dist archives git HEAD, so uncommitted changes are not in the tarball, and that %build runs cargo, which fetches dependencies — fine locally, not acceptable in an offline build such as Fedora's koji. The spec says what to do about that.

A Flatpak manifest does not exist yet: the agent has to reach the host to spawn podman, toolbox and ssh, which is a design decision rather than a packaging detail.

Controlling sessions from a shell

terminalkoctl list                 # every session, and what it is doing
terminalkoctl start api            # by id, name, or an unambiguous prefix
terminalkoctl stop api
terminalkoctl signal api 2         # to the session's process group

Runtime operations only: creating, renaming and deleting sessions belong to the window, which is the only writer of the configuration. list still works with no agent running — it says so and shows what is configured.

Configuration

There is no configuration file. Preferences and, from M2, the session tree live in GSettings under /me/dusansimic/terminalko/, and the GUI is the only writer.

dconf dump /me/dusansimic/terminalko/     # inspect or back up

Folders and sessions are relocatable schema instances keyed by UUID, so they are scriptable too:

gsettings get me.dusansimic.terminalko sessions
gsettings get me.dusansimic.terminalko.session:/me/dusansimic/terminalko/sessions/UUID/ name

Licence

BSD-2-Clause. See LICENSE.

Terminalko links GTK, libadwaita and VTE, which are LGPL: they are linked dynamically so that users can replace them, and no code from any GPL/LGPL project is copied into this tree. CONTRIBUTING.md explains the rule and the process for features other terminals also have; NOTICE records every permissively licensed snippet that was adapted.