OdyTTY under the default Odyssey theme — colorized git graph, project tree, and truecolor gradients with bloom.
releasev0.10.0render wgpu GPUthemeodysseyvisualcrt# open source · no telemetry · Linux, Windows, macOS
$ act ii · showcase
$ odytty --demo — real captures
the theme picker — arrows preview live, the whole terminal recolors behind itthe command palette — everything fuzzy-filtered, live over the sessionthe image lightbox — Ctrl+click a path on Linux/Windows or Cmd+click on macOS, Esc to dismiss, never upscaledthe settings panel — live over the session, Ctrl+S saves back to odytty.conf
$ odytty --list-themes — theme gallery
OdyTTY ships 142 built-in themes, each a full
appearance profile: default fg/bg, the window clear color, the 16-color ANSI palette, and semantic
roles — with OS dark/light following and correct precedence over dynamic OSC color overrides.
Hover to try one on, click to wear it — the whole page reskins live,
including the CRT field's hue. That is the same data the terminal loads; the gallery is generated
from the real .theme files.
odytty:~$ cat themes.json █
The .theme file format
A theme is a plain text file of key = value lines. Drop one in
~/.config/odytty/themes/ and select it with theme = myname or point
ODYTTY_THEME at a path. A bad or missing theme never prevents startup — OdyTTY
falls back to odyssey-default and logs a warning.
~/.config/odytty/themes/example.theme
name = example
appearance = dark
foreground = #d6def4
background = #0c1224
clear = #070b18
cursor = #86c1ff
selection = #243352
search = #4a4018
color0 = #12182a # ANSI black
color1 = #e06b74 # red# … color2 – color15 …
$ act iii · the proof
$ man odytty — overview
OdyTTY is a Linux-first terminal emulator being built from scratch in Rust. It opens
real local shells, runs many of them at once across tabs, workspaces, and split panes, keeps them alive
in Unix-only detachable sessions and saveable layouts, connects to remote hosts over SSH, renders text and inline
media on the GPU, and is meant to stay practical for daily command-line work while carrying a stronger
visual identity.
The unusual part is what's underneath: OdyTTY owns the terminal byte path — parser, terminal
model, renderer, and shaders are OdyTTY code rather than a skin over an existing terminal core.
The crate-by-crate breakdown is in architecture.
written inRust
rendererwgpu GPU path + optional post stack
current releasev0.10.0 — deb / rpm / tarball / AppImage / zip / cask / source (install)
platformLinux primary · macOS supported · Windows supported
licenseGPL-3.0-only
built-in themes142
Runs on Linux (primary), Windows, and macOS — the honest per-platform state
lives with the install steps.
$ odytty --status — current release state
OdyTTY is a broad, working terminal with a public release (currently
v0.10.0). The current capabilities and boundaries below are the honest snapshot;
the release-by-release story lives in the devlog.
v0.10.0 is a reliability, security, and architecture convergence release.
It adds bounded visual feedback, tightens Windows keyboard behavior, makes native creation failures
visible, and applies explicit resource boundaries to externally influenced files, clipboard images,
graphics transports, and detached sessions. Read the
v0.10.0 release.
Resize And Zoom Feedback
Interactive window resize reports the settled terminal geometry as
columns × rows. With wheel_zoom enabled, an effective
Ctrl+wheel step reports the current font size. Both use one centered static readout,
replace repeated updates, clear after a bounded delay, and remain compatible with plain rendering
and reduced motion without adding idle animation.
Activity And Failure Notices
A static dot marks unseen bell activity in a background tab, and each workspace rail row
rolls up activity from its tabs. The marker clears when that tab or workspace is viewed and
coexists with the remote-binding badge. Workspace creation, duplication, and pane splitting now
surface PTY spawn failures through the existing notice area instead of appearing to do nothing;
a failed operation leaves the layout unchanged.
Windows Input Fidelity
Native Windows console applications can request ConPTY Win32 input records. v0.10.0
preserves keypad virtual-key identities and aligns the physical and neutral mappings for
Ctrl+Space and Ctrl+5, while retaining established
behavior for ordinary non-keypad keys. The focused translation assertions also run in blocking
Windows CI.
Bounded External Inputs
Session metadata, fonts, saved layouts, and connection-host files are read through explicit
size and file-type boundaries. Clipboard images are checked before PNG encoding and stop at the
10 MiB upload ceiling. Detached-session queues and client frames apply backpressure instead of
growing without limit. Optional named graphics transports remain off by default; Windows now
rejects reparse-point targets as Unix rejects redirected final components.
Works Today
Real local shells with tabs, workspaces, split panes, scrollback, search, and copy/paste
Detachable, resumable sessions on Unix, plus cross-platform saveable named layouts and whole-window restore
SSH connection manager with optional remote shell integration — long form in workflow
Inline media on the GPU: installed Noto Color Emoji in color on Linux and Windows, Apple Color Emoji in color on macOS, a stock-Windows monochrome fallback, Kitty graphics, Sixel, and an image lightbox
142 themes, OS dark/light following, a minimum-contrast floor, colorblind modes, and default-on window transparency at 80% opacity
DEC Special Graphics with G0/G1 and SO/SI, atomic bracketed-paste framing, and safely encoded OSC 7 working directories
Prompt-aware editing across Bash, Zsh, Fish, and PowerShell, with ConPTY Win32 keyboard fidelity on Windows
Settled terminal dimensions during interactive resize, font-size feedback during effective Ctrl+wheel zoom, and unseen-activity dots for background tabs and workspaces
Animated smooth scrolling (glide) with a pixel-precise touchpad lane — details in rendering
Default-on programming ligatures through the bundled font's contextual alternates (with an ligatures = off opt-out and a scalar fallback), plus a smooth animated Block cursor with shape-aware glow
Ships today on all three platforms — Linux x86_64 gets .deb, .rpm, binary tarball, and AppImage builds; Windows x86_64 gets a portable zip; macOS gets an Apple Silicon app
Linux launch integration: per-window Wayland/X11 identity, held initial commands, and the complete five-key desktop contract
A slice of the surface — the full set is in highlights
below and the folds after it.
Known Gaps
No macOS DMG, upstream Snap package, or upstream Nix package ships. Flatpak is a deliberate non-goal; AppImage is the single-file portable Linux option. The shipped RPM is cross-built and metadata-validated rather than tested across every RPM distribution
The Windows build is unsigned (expect a possible SmartScreen prompt) and the macOS .app is ad-hoc signed, not Developer ID signed or notarized. Those signing paths are unavailable for the current distribution; first-launch specifics live with the Windows and macOS install steps
Windows omits detachable/resumable sessions and session-host reattach on restore (layouts still reopen fresh shells), detached SSH, headless --interactive mode, the full “Open With” app list, and command-palette shell history. Installed Noto Color Emoji can render in color; stock Windows uses a monochrome fallback because Segoe UI Emoji is not discovered or rasterized
OdyTTY cannot register as the Windows system default terminal. Launch it directly through Scoop, the Start menu, a shortcut, or odytty; this is separate from choosing which shell opens inside OdyTTY
Multiple windows open today with Ctrl+Shift+N. The first window owns layout restore and autosave, while secondary windows run independently and do not restore or overwrite that saved workspace state. Coordinated multi-window persistence and management remain future work, as do named profiles and broadcast-to-panes
Restored remote panes reconnect fresh at the host's default directory — the recorded remote path is not re-entered in this version
Broader ligature and stylistic-set shaping beyond the shipped default-on ASCII programming-ligature path is deferred (a slashed/dotted zero is the near-term slice)
Kitty animation, Kitty Unicode placeholders, and iTerm2 graphics are not supported
COLR/CPAL and SVG-in-OpenType color fonts remain future work
$ odytty --architecture — owned byte path
OdyTTY is not a theme over another terminal. The owned path is already the production path.
The VT parser is a clean-room build from the primary specifications (vt100.net, ECMA-48,
xterm ctlseqs); external crates handle only font rasterization, the GPU API,
windowing, and clipboard transport — the same boundary mature independent terminals draw.
Owned Subsystems
src/pty/ owns Unix PTY allocation through rustix and the Windows
ConPTY backend. src/parser/
is a clean-room DEC/xterm parser. src/core/ owns terminal state. src/grid.rs
and src/render.rs build geometry. src/graphics/ routes Kitty/Sixel images.
src/native/ owns the app, GPU, and overlays.
Deliberate Dependencies
External crates stay below the product line: wgpu for the GPU API,
winit for windows/events, ab_glyph and swash for font and
emoji rasterization, arboard for clipboard transport, and Unicode width tables for
character width data.
Not In The Tree
vte, portable-pty, and crossterm are absent from the
dependency tree. Mature terminals are compatibility references, not implementation sources.
$ cargo test — evidence surface
The support claims are backed by bounded, deterministic tests where possible, with separate
compatibility, parser/graphics fuzzing, dynamic-analysis, PTY, rendering, and performance tiers.
blockingformat, build, Clippy, and test gates run in CI
3 OSGitHub-hosted CI matrix: Linux, macOS, and Windows
142built-in themes generated from app source
114runtime knobs generated from docs
Theme and knob counts regenerate from OdyTTY's source and docs; the blocking CI matrix
is documented in the repository's release and contribution guides. Release and scheduled checks run
cargo-audit against both locked dependency graphs. Scheduled lanes retain four bounded
coverage-guided parser/graphics fuzz targets and run the promoted Miri subset plus Linux
AddressSanitizer and ThreadSanitizer checks. A tag-triggered release publishes only after the exact tagged commit already has
a completed, successful CI run; missing, queued, failed, cancelled, or wrong-commit runs fail closed.
Compatibility Tests
Unit and integration tests cover parser state, terminal behavior, settings, themes, keybindings,
graphics placement, mouse protocols, cross-platform-safe harness paths, and CLI introspection.
A retained compatibility corpus, pinned conformance runner, and bounded real-application matrix
keep unavailable, skipped, unsupported, and executed surfaces distinct.
Smoke And Fuzz Tiers
PTY smoke, pixel smoke, GPU composite smoke, transcript smoke, protocol fuzz, and ignored deep
fuzz tiers are available for the paths that need real process, rendering, or randomized
evidence, and CI runs the matrix on every push.
Performance Evidence
cargo bench --bench perf tracks parser/feed/reflow/geometry behavior. The app also
carries optimized resize, retained-frame, reusable vertex storage, and lazy scrollback paths.
Dated implementation measurements are not presented as cross-terminal product comparisons.
A few things most terminals do not do all at once, especially on top of an owned parser, terminal model, and renderer.
Owns the whole byte path
Not a skin over another terminal. PTY allocation, escape parsing,
terminal state, render geometry, graphics placement, settings, and shaders are OdyTTY
code — the crate-by-crate breakdown is in architecture.
Group tabs into workspaces, then save the whole window as a named
layout and reopen it with Replace or Add. restore_workspaces
reopens the previous window shape at launch; Unix-only detachable sessions keep shells alive.
Details in workflow.
Remote terminals
SSH that feels native. Quick-connect saved hosts via the system
ssh (OdyTTY never stores passwords or private-key contents), with opt-in remote shell integration,
connection reuse on Unix clients, tmux persistence, and reconnect-on-drop —
long form in workflow.
Inline media on the GPU
Installed Noto Color Emoji renders in color on Linux and Windows, and Apple
Color Emoji renders in color on macOS — flags, ZWJ families, skin tones, keycaps. Stock Windows
uses a readable monochrome fallback because Segoe UI Emoji is not discovered or rasterized;
and icat a photo and it just appears: the supported Kitty APC still-image surface
plus a complete Sixel data language. Details in graphics
and rendering.
Kitty keyboard protocol — real press/repeat/release for TUIs; legacy bytes stay identical when its flags are off
OdyTTY v0.10.0
is the current release. The commands below use always-latest aliases so normal install and
update links remain durable; use the pinned release page only when an installation must stay on v0.10.0.
Each v0.10.0 release publishes seven artifact types
under both durable aliases and version-pinned names, plus SHA256SUMS — 15 assets total.
That is the source archive; four Linux x86_64 options (native .deb and .rpm,
portable binary tarball, and AppImage); an unsigned Windows x86_64 zip; and a prebuilt macOS Apple
Silicon/arm64 .app zip. No prebuilt Linux ARM, Windows ARM, or Intel macOS artifact is
published; those targets require a source build.
The repository's
full install guide
covers platform prerequisites, checksums, source builds, desktop integration, default-terminal setup,
and troubleshooting in more depth.
The in-app About view reports the build's source commit. Official release binaries
embed the exact tagged commit through the build-time-only ODYTTY_BUILD_SHA input. A live
Git checkout reports a short commit and adds -dirty when modified; a build from the
released source archive inherits the abbreviated commit from .git_archival.txt through
Git export-subst. If none is valid, the honest value is unavailable, never
the former unknown. This provenance input is not a configurable runtime setting.
Three targets, honestly labelled — Linux x86_64 ships native .deb/.rpm
packages, a binary tarball, and an AppImage (plus an
Arch AUR package); no official macOS DMG, upstream Snap, or
upstream Nix package ships, and Flatpak is a deliberate non-goal:
Linuxprimary target · x86_64 deb / rpm / tarball / AppImage · AUR / sourceWayland primary; X11 works through the current winit/GPU stack. The RPM is cross-built and metadata-validated, not tested across every RPM distribution. Linux ARM requires a source build. The project-maintained AUR package is maintained alongside tagged releases
Windowssupported · x86_64 Scoop / zipUnsigned portable x86_64 odytty.exe over ConPTY; no Windows ARM prebuilt or detached-session host. OdyTTY cannot register as the Windows system default terminal; launch it directly
macOSsupported · Apple Silicon cask / sourceApple Silicon/arm64 installs a prebuilt OdyTTY.app via a Homebrew cask (the postflight clears the quarantine attribute); Intel macOS has no prebuilt and uses the source formula or Cargo
install for:
Linux
Primary target. Prefers a Vulkan-capable GPU; falls back to accelerated OpenGL/GLES and then slow software rendering. The AppImage and source build still require a host graphics driver.
Auto-detects your package manager — apt/dnf get the matching
native package, everything else gets the portable tarball — and checksum-verifies the download
against SHA256SUMS before installing anything. Pass --dry-run to print the
planned actions without touching your system. (Run on macOS or Windows it just prints the Homebrew
or Scoop command instead.)
Native packages
Prefer your distro's package manager? Download the matching artifact from the
always-latest release and install it directly:
A distro-agnostic archive — the binary, desktop files, and a bundled
install.sh. It installs to ~/.local by default; set
PREFIX=/usr/local and use sudo for a system-wide install.
Project-maintained release channel. The project maintains the AUR odytty
package alongside tagged releases. Like every AUR package, it is not
vetted by Arch: the PKGBUILD is a build script that runs on your machine, so review it before
installing (your AUR helper shows it by default). The project's release channels are the AUR
package, the one-line installer and release artifacts above (.deb, .rpm,
tarball, AppImage), and the from-source build below.
Build from source instead
Needs Rust 1.96 or newer, including Cargo. The repository pins
1.96.0 in rust-toolchain.toml and declares
rust-version = "1.96"; use a rustup-managed toolchain so the pin is applied. Linux has
no additional link-time build dependency, but runtime font fallback uses fontconfig
and rendering needs a host graphics stack exposing Vulkan or OpenGL/GLES; software rendering is a
slow last resort.
1. download & verify v0.10.0 source
workdir=$(mktemp -d /tmp/odytty-install.XXXXXX)
cd "$workdir"
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty.tar.gz
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
grep " odytty.tar.gz$" SHA256SUMS | sha256sum -c -
tar -xf odytty.tar.gz
cd odytty-*/
version=$(basename "$PWD" | sed 's/^odytty-//')
A .deb/.rpm install updates by re-downloading the
always-latest package and reinstalling it (sudo apt install ./odytty-amd64.deb /
sudo dnf install ./odytty-x86_64.rpm). The AppImage and tarball have no package manager,
so updating is a re-download of the always-latest alias — it resolves to the newest release. The AUR
package updates with a normal paru -Syu / yay -Syu, and a from-source
install re-runs the build steps above against the new release.
Windows
Supported — an unsigned, portable x86_64 odytty.exe. No
installer or Windows ARM prebuilt; configuration and package-manager files stay under the user
profile. Detached sessions, detached SSH, and headless --interactive remain Unix-only.
OdyTTY cannot currently register as the Windows system default terminal — the host
Windows hands console programs to. Launch OdyTTY directly through Scoop, the Start menu, a shortcut,
or odytty. This does not limit which shell, such as PowerShell, opens inside OdyTTY.
Scoop (recommended) — 1. one-time bootstrap, if you don't already have it
Scoop is a per-user package manager for Windows — no admin rights, everything
under your profile. It puts odytty on your PATH (a shim under
~\scoop\shims), adds an OdyTTY Start-menu entry, and verifies the
download against the release checksum before unpacking it for you.
SmartScreen prompt. OdyTTY is not code-signed yet, so first launch may show
a blue “Windows protected your PC” warning naming an unknown publisher — expected for unsigned
open-source software, and it can appear however you install it (a package manager
doesn't guarantee otherwise). Click More info, then Run anyway;
or clear the “downloaded from the internet” mark up front with
Unblock-File .\odytty\odytty.exe. A signed Windows build is not available through
the current distribution path.
Updating
Scoop refreshes OdyTTY to the newest release:
Scoop (recommended)
scoop update
scoop update odytty
For the portable zip, re-download the always-latest
odytty-windows-x86_64.zip, re-verify the hash against SHA256SUMS, and
replace the old odytty.exe.
macOS
The prebuilt app is an Apple Silicon (arm64) build; Intel Macs use the source
formula (or a plain cargo build).
Homebrew cask (recommended) — prebuilt OdyTTY.app in Applications
brew tap ghreprimand/odytty
brew install --cask odytty
One-time tap trust, then it just works. Recent Homebrew versions require
trusting a third-party tap before its cask will load. If the install stops with
Refusing to load cask ... from untrusted tap, run
brew trust ghreprimand/odytty (or
brew trust --cask ghreprimand/odytty/odytty to trust just this cask) and re-run the
install — a one-time per-machine step.
The cask installs the prebuilt, ad-hoc-signed OdyTTY.app into
/Applications, so it appears in Launchpad and Spotlight and can be dragged to the
Dock. Because the app is ad-hoc signed but not notarized, macOS quarantines the download; the
cask's postflight runs xattr -dr com.apple.quarantine for you, so
first launch is Gatekeeper-clean with no user step. Developer ID signing and notarization are not
available through the current distribution path. brew upgrade picks up new releases
automatically.
Homebrew source formula — Intel Macs, or DIY from source
brew install ghreprimand/odytty/odytty
# installs the odytty CLI on your PATH; no .app bundle.# A binary compiled locally is never quarantined.
direct .zip download (no Homebrew) — needs one manual xattr step
curl -L -o odytty-macos-arm64.zip https://github.com/ghreprimand/odytty/releases/latest/download/odytty-macos-arm64.zip
curl -L -o SHA256SUMS https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
shasum -a 256 -c SHA256SUMS --ignore-missing
unzip odytty-macos-arm64.zip
mv OdyTTY.app /Applications/
# Safari/curl set the quarantine bit on downloads; strip it once so# Gatekeeper doesn't block first launch (the Homebrew cask does this# step for you automatically, so it's only needed on this direct path):
xattr -dr com.apple.quarantine /Applications/OdyTTY.app
open /Applications/OdyTTY.app
Build from source instead
Needs Rust 1.96 or newer through a
rustup-managed toolchain and the Xcode Command Line
Tools. The repository pin selects Rust 1.96.0. Both Apple Silicon and Intel are supported (whatever
cargo targets natively). A binary you compile locally is never quarantined, so it
launches with no Gatekeeper prompt.
download, verify & build v0.10.0 source
xcode-select --install # once, if needed
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty.tar.gz
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
grep " odytty.tar.gz$" SHA256SUMS | shasum -a 256 -c -
tar -xf odytty.tar.gz
cd odytty-*/
version=$(basename "$PWD" | sed 's/^odytty-//')
cargo build --release --locked
./target/release/odytty
The scoped commands update only OdyTTY; a plain brew upgrade refreshes
everything Homebrew manages. For the direct .zip download, re-download the always-latest
archive, re-verify against SHA256SUMS, and replace OdyTTY.app in
/Applications/.
$ odytty --workflow — native app surface
A terminal you can configure and operate from inside its own window — the config file
underneath, not the only UI.
real capture — Ctrl+Shift+E split: git graph one pane, cargo test the other
Tabs, Panes & Workspaces
Ctrl+Shift chords open, close, and split tabs and panes — the full
set is in keys — with a tmux-style Ctrl-b prefix on
top. A new tab or window inherits the active pane's working directory when one
is tracked (OSC 7), falling back to the configured default. The tab bar and a pinned workspace rail meet as one continuous, pixel-snapped chrome
surface with a single intentional resize seam and no exposed gutter; the active tab is marked by a
selection-role fill and a bright, bold label. The bar appears once a
second tab exists, and always_show_tab_bar pins it (a single tab you have
renamed always shows the bar; custom names last for the session).
Workspaces group whole tab strips, cycled from the keyboard, with a rail
listing them once a second exists (workspace_rail: auto default or
always, with workspace_rail_side picking left /
right; the rail can also auto-hide and be width-dragged). An optional
inactive_pane_dim (default 0.0; bypassed on
render_quality = plain) dims background panes. Single-pane, single-workspace
views stay byte-identical to a plain terminal. Configured padding applies at divider-facing
edges; collapsed panes keep a valid one-cell PTY backing model while clipping drawing and input,
and completed window/divider resizes settle affected panes to whole-cell geometry with one final
backend resize. Background bell activity appears as a static dot on the tab, rolled up to its
workspace rail row, and clears when that tab or workspace is viewed. Interactive window resize
reports the settled columns × rows geometry in a centered transient readout.
Saved Layouts & Restore
Save All Workspaces as Layout captures the whole application — every
workspace, tab, split, working directory, and host binding — while Save Workspace as
Layout… saves just one workspace on its own; both are reachable from the rail's
right-click menu, the terminal content menu, and the palette. Open a saved layout later with
Replace (tear down the current workspaces and install the saved set) or Add
(append it beside the current ones). With restore_workspaces on (off by default),
launching odytty reopens the previous window shape automatically. The first window
owns restore and autosave; secondary windows run independently and neither restore nor overwrite
that primary saved state. A companion
shell_exit_closes setting picks what happens when a shell exit would empty a
workspace — close that workspace (the default, matching the cascade) or quit OdyTTY — so
pairing "quit closes the app" with "next launch restores everything" is a two-knob
configuration. Snapshots record structure only: fresh shells at their directories, never
replayed output.
Remote Terminals
Ctrl+Shift+S opens the connection manager: quick-connect saved hosts via the
system ssh (keys stay with your agent), bind a workspace to a host, or edit
OdyTTY-owned entries in hosts.conf. Opt-in OpenSSH ~/.ssh/config
host-name import is read-only and name-only (imported rows can be connected to but not edited).
Opt-in knobs carry shell integration onto the remote, reuse one authenticated connection across
tabs on Unix clients (Windows authenticates each connection independently), persist it in
tmux, hold a dropped tab open with a reconnect prompt, and confirm-first paste an
image up to the host.
Command Palette
Ctrl+Shift+P opens a fuzzy command palette over actions, settings, shell history,
recent directories, workspace and layout commands, and saved hosts. A presentation-only overlay —
it never blocks or intercepts the PTY.
Settings Without Hand Editing
Ctrl+Shift+, opens Settings. Rows live-apply, / filters, and
Ctrl+S writes changed keys back to odytty.conf while preserving comments,
blank lines, unknown keys, and ordering. Invalid values are refused with diagnostics rather than
silently replacing the active resolved setting.
Pickers And Builders
The theme picker, font picker, keybinding editor, and theme builder are native overlays.
The theme builder can clone, tweak, live-preview, and save user themes through the same
dependency-free .theme format as the built-ins.
Prompt-Aware Actions
OSC 133 prompt marks power command navigation, clear editable input, context-menu actions,
and a per-command command-status gutter that
colors each command's left rail by its exit status in single, split, and nested pane layouts.
A core range helper exists for selecting one command's output, but no UI action exposes it yet.
Shell integration and the gutter are on by default. Clicking in the typed command line moves
the shell cursor there (rune-precise, on by default), and deleting a selection
inside the prompt edits the real command line — exact with the bundled zsh integration,
conservatively clamped elsewhere. On graphical Unix launches without SHELL, OdyTTY
resolves the effective user's login shell through passwd/NSS before its final /bin/sh
fallback, so the appropriate integration still loads. OdyTTY never sends edit bytes it cannot
justify. OdyTTY injects integration for Bash, Zsh, Fish, and Windows PowerShell/pwsh;
cmd.exe has no supported OSC 133 hook surface, while Nushell users configure its native
OSC 133/7/2 and Kitty-protocol support in Nushell itself.
Tab And Workspace Menus
Right-click a tab for New Tab, Rename Tab, Duplicate Tab
(clones the focused tab's shell and cwd; also a bindable duplicate-tab action),
Close Other Tabs, Connect to Host… (opens a saved SSH host
in a new tab), Replace with Host… (opens it in-place, confirming first if a
program is running), Move to Workspace… when more than one workspace exists,
and New Window. Right-click a rail slot for new, duplicate, rename, close,
Move Up / Move Down, bind/unbind host, layout-save, and
Settings actions. Bindable actions can be remapped in the keybinding editor; layout, host-binding,
and reorder actions remain palette- or menu-driven.
$ odytty --rendering — text, emoji, motion
OdyTTY's visual identity sits on a text-quality foundation: reliable default fonts, stable glyph
geometry, explicit fallbacks, and a hard direct-render profile when effects are the wrong trade-off.
Text Pipeline
Bundled Victor Mono ships as the default at 20 logical pixels, with JetBrains Mono also
bundled and selectable. Users can select system font families, direct font files, weight
variants, line height, synthetic styles, text gamma, stem darkening (on by default at
0.7), and optional RGB/BGR subpixel AA with grayscale fallback. Color composes in
linear light before glyph coverage is applied. Programming ligatures are on by
default: the bundled font's ASCII contextual alternates render through OpenType shaping
while the grid stays one logical cell per character, so copy, selection, search, and cursor
placement are unchanged; a font without them — or ligatures = off /
ODYTTY_LIGATURES=off — falls back to the plain per-cell renderer.
Glyph And Symbol Handling
The dynamic atlas uses bearing-aware glyph quads, HiDPI-aware rebuilds, wide-cell handling,
procedural box/block/shade, Braille, Powerline, and sextant/octant rendering, box-thickness tuning,
bundled Nerd Font v3/v2 symbol fallback, host fallback, and per-range symbol_map
overrides. Decomposed clusters — a base letter plus a zero-width combining accent — draw the accent
over the base cell and keep it when copied from scrollback and live selection alike (up to four
marks per cell, where the font provides them).
Color Emoji
Color emoji use swash and a dedicated premultiplied-RGBA atlas. Noto Color Emoji
CBDT/CBLC works on Linux and Windows when installed in a searched system or per-user font
directory, and Apple Color Emoji sbix works on macOS, with flags, keycaps, skin tones, variation
selectors, and common ZWJ clusters. Stock Windows uses the monochrome fallback because Segoe UI
Emoji is not discovered or rasterized by the current path. OdyTTY does not bundle Noto Color
Emoji on Windows. Emoji pixels are not SGR-tinted.
Cursor, Motion & Effects
The cursor is OdyTTY's v0.9 signature, and its motion ships on by default.
Fresh profiles open a blinking Block cursor that glides between adjacent cells and
snaps instantly on large jumps, resizes, and scrollback navigation. A jump beyond the short glide
range sends one cursor-shaped follower that stretches toward the target and settles, under a
subtle / balanced / expressive profile
(cursor_trail_strength, balanced by default) with a brief fading trail.
Blinking yields to typing — keyboard and IME activity hold it visibly on, blinking resumes after a
short quiet period, and it parks solid when idle so nothing keeps redrawing. A restrained
shape-aware glow traces the actual Block, Bar, or Underline geometry in the
resolved cursor color; its strength is adjustable on an independent cursor_glow_intensity
scale (0.0–1.0, default 0.5), separate from the whole-scene bloom. An
unfocused Block cursor becomes a hollow outline, and in a split every part of this runs only in the
focused pane and never wakes an idle one. All of it is presentation-only: the logical cursor,
selection, copy, and terminal input reach their destination immediately.
reduced_motion = on is one explicit switch that snaps the cursor slide, trail, glow,
blink fade, and new-output fade to static without overwriting their saved settings — a config
setting, not an OS preference, and it leaves cursor blinking, smooth scrolling, and ligatures
untouched.
Bloom, CRT, retro, curvature, padding, borders, and backgrounds are settings-backed too.
The retro preset keeps its scanlines, bloom, and vignette but does not force curvature:
crt_curvature = 0.0 is the flat default and is exposed only through config or
ODYTTY_CRT_CURVATURE, not the Settings panel.
Scrollback uses an animated glide
between wheel notches (default on, six rows per notch) with a pixel-precise continuous lane for
touchpads and high-resolution wheels; the glide follows split panes at sub-cell precision, and
copy across the full selection works cleanly across the scrollback. A bundled "Dark Waves"
background image ships behind the grid by default — set background_treatment = color
to turn it off. Window transparency
(window_transparency + window_opacity, translucent down to 20% opacity)
makes the background translucent while text, the cursor, selection, and every overlay stay
fully opaque (window_transparency = on and window_opacity = 80 by default;
needs a compositing window manager, and a configured background
image composes over the desktop too).
render_quality = plain bypasses post-processing and visual treatments.
When wheel_zoom is enabled and the running application has not claimed mouse
reporting, effective Ctrl+wheel steps show the current font size in the same static,
bounded readout used for terminal dimensions. Repeated steps replace the value; the readout
clears without an animation phase or idle wakeup.
$ odytty --readability — effects with guardrails
OdyTTY's visual layer is allowed to be expressive because it is bounded. Text legibility, input
correctness, and stable rendering stay above atmosphere.
OKLab/OKLCH perceptual color helpers for dimming, mixing, and contrast lift
Theme roles for cursor, selection, search, border, and inactive UI
Color-vision adaptation with cvd_mode and cvd_strength
Focus dimming applies before the contrast floor so text can be re-lifted
Low-opacity legibility: colored_bg_opacity = 0.9 preserves colored cells and text_brightness = 1.0 is the identity baseline
selection_opacity = 1.0 is fully opaque; 0.0..=1.5 adds bounded color emphasis above 1 without invalid GPU alpha
Effect Safety
Bloom adds light; scanlines and vignette are capped with a brightness floor
Background images use opacity, optional blur, and auto scrim to preserve contrast
Chrome uses tab_panel_strength = 0.8 with tab_seam = off; themed overlays stay opaque in single- and multi-pane layouts
new_output_fade = on fades new rows over new_output_fade_ms = 250; reduced motion makes it static without overwriting the preference
Adapters without filterable Rgba16Float support fall back to the direct plain path
Every atmospheric effect has an off switch or is bypassed by render_quality = plain
$ odytty --graphics — inline media
Kitty graphics and Sixel both land on OdyTTY-owned APC/DCS parser plumbing and share the GPU image layer.
Kitty Graphics & Sixel
The supported Kitty APC still-image surface (chunking, image and placement ids, crop, scaling, pixel
offsets) and a complete Sixel data language, with hard caps of 10,000 × 10,000 pixels or
40 million total pixels. The exact action / transport / placement matrix is in
protocols.
Draw Order
Render order follows the Kitty model: cell backgrounds, negative-z images, glyphs and
decorations, color emoji, then non-negative-z images. Primary and alternate screens maintain
independent placement scenes.
File Transport Safety
Kitty direct and chunked-inline transfers are always available. The named
file, temp-file, and POSIX shared-memory
transports are off by default behind kitty_named_transports — a local
host-I/O authority grant to enable only when the whole PTY session, including SSH output, is
trusted; with the gate off they are rejected before any file or shared-memory I/O. When enabled on
Unix they stay confined by a temp-directory allowlist, reject symlinks (O_NOFOLLOW) and
non-regular objects, require the protocol marker with delete-before-decode for temp files, validate
shared-memory objects before shm_unlink, and cap size before decode. Windows applies
the corresponding final-component reparse-point rejection. Full rationale is
in OdyTTY's
docs/graphics.md.
In-App Image Viewer
Separate from the wire protocols: Ctrl/Cmd+click opens a file
(path:line:col jumps an editor), right-click adds “Open With…” / Copy Path /
Reveal, and Ctrl/Cmd+click a resolved
png/jpg/jpeg/webp path (or pick “Open in OdyTTY”) and it opens in a presentation-only
lightbox drawn above the CRT/bloom post-pass, so effects never touch the photo. Decode is
bounded before it runs; Esc or a click outside dismisses. Opt-in, behind the
interactive_paths gate; clicking bare URLs is governed by the separate
interactive_urls knob (on by default).
Most of the time you won't come here — OdyTTY is configured from the in-app settings panel
(see workflow). Everything that panel touches is also a plain
key = value setting (and an environment variable); this canonical list is generated
straight from OdyTTY's docs/runtime-knobs.md.
Run & configure
Same commands everywhere once odytty is installed.
On Linux, --app-id and --class are equivalent and accept
space or equals forms. They change only that window's Wayland app_id or X11
WM_CLASS class; the X11 instance remains odytty and the packaged identity
remains io.unfinished_works.odytty. --hold, --hold=true, and
--hold=false control only the initial local command and default to off. A held exit reports
its status and closes through the normal pane/tab/workspace lifecycle on the next keypress; later
sessions do not inherit it and remote reconnect handling retains precedence.
child-shell environment — no custom terminfo required
# hard direct-render profile
ODYTTY_RENDER_QUALITY=plain odytty
# follow the desktop dark/light preference
ODYTTY_THEME=system odytty
# larger text with a custom font family
ODYTTY_FONT_SIZE=24 ODYTTY_FONT_FAMILY="Victor Mono" odytty
# RGB subpixel antialiasing
ODYTTY_SUBPIXEL=rgb odytty
# stronger phosphor reference look
ODYTTY_RETRO=on odytty
headless introspection (print and exit — no window)
odytty --list-themes # stable name / appearance / family rows
odytty --list-fonts # discoverable system font files
odytty --show-config # current stable config-dump subset
odytty --version
Configuration resolves defaults → ~/.config/odytty/odytty.conf → environment
on Linux/macOS, or defaults → %APPDATA%\odytty\odytty.conf → environment on Windows;
environment variables always win. (macOS quarantine notes live with the
macOS install steps.) The full knob reference follows below.
odytty:~$ cat knobs.json █
$ odytty --keys — bindings
The default local keyboard surface. Most named local actions — tabs, workspaces, panes, sessions,
and overlays — are rebindable through ODYTTY_KEYBINDS / the keybinds
config key, and the in-app keybinding editor covers the full bindable set. The direct first-split
chords and prompt-selection Delete/Backspace path are fixed. Most defaults are
Ctrl+Shift chords a TUI can't receive; documented exceptions include tab/page
navigation, workspace duplication, and the multi-pane prefix.
The set below tracks OdyTTY's own docs/keybindings.md, kept in sync at each release.
On macOS, Cmd+click is the open chord (the OS routes Ctrl+click as
a secondary click).
shell_integration = on and shell_key_enhancement = on are the defaults.
Bash and Zsh enable disambiguation only while their line editor owns the prompt; Bash 4.4+ removes it
through PS0, while macOS Bash 3.2 uses a prompt-guarded first-command DEBUG boundary.
Fish manages its keyboard protocol itself. PowerShell uses PSReadLine through app-requested ConPTY
Win32 input records, preserving modifier state, key-up events, Ctrl+Backspace, and
Shift+Enter. Linux normalizes compositor-dependent editing keys before dispatch,
including Ctrl+Backspace on KDE/Wayland.
With the default osc52_write = ask, the clipboard prompt uses
Ctrl+Shift+1 to allow once,
Ctrl+Shift+S to allow for the current PTY session,
Ctrl+Shift+D to deny for that session, and Esc to cancel.
Default-on smart Ctrl+C copies and clears a live local selection; otherwise it
remains the shell interrupt.
Tabs, panes, workspaces & sessions
Chord
Action
Ctrl+Shift+T / W
New tab / close active tab
Ctrl+Shift+D
Duplicate active tab — a fresh shell in the active pane's directory
Ctrl+Shift+N
New window (also in the right-click menu; inherits the active pane's working directory when one is tracked, falling back to the default)
Clear the shell input line (readline Ctrl+A then Ctrl+K; no shell integration required)
Double-click
Select word · Triple-click selects line
Ctrl/Cmd+Click
Open an OSC 8 hyperlink or interactive path (scheme allowlist, argv-safe)
$ odytty --protocols — support matrix
What OdyTTY understands on the wire, for reference. Everything ticked here is verified by the
test suite.
Graphics & images
Kitty graphics protocol — actions t/T/p/d/q
RGB/RGBA (f=24/f=32) & PNG (f=100)
Transports: direct and chunked-inline always on; named file / temp-file (all platforms) and POSIX shared memory (Unix) are default-off behind kitty_named_transports
COLR/CPAL and SVG-in-OpenType color fonts are future work
$ odytty --privacy — local by charter
OdyTTY runs on the local machine. The absence of network product plumbing is a design decision,
not an omitted settings toggle. This application privacy statement is separate from optional
Cloudflare site-level analytics on the project website.
No Product Data Path
No telemetry, analytics, crash-reporting service, account, cloud sync, or update ping
No cloud service; the Unix detached-session host communicates through an owner-private, per-user local socket
Settings and themes remain local; session replay is an opt-in, memory-only bounded ring and is never synced
Diagnostics stay local too: WARN+ by default in a bounded rotated log under the platform state/log directory; terminal content, PTY bytes, typed input, and window titles are excluded (an OS-authored error string can include a filesystem path)
On Unix, saved layouts, session state, and diagnostic logs live in owner-private 0700 directories and 0600 files validated through no-follow handles; a symlinked or foreign-owned path disables that file rather than being followed. macOS and Windows use their platform ACL behavior
Externally influenced session metadata, layouts, host records, fonts, clipboard images, and detached-session traffic have explicit size or queue boundaries; oversized inputs fail without partially rewriting the affected state
The source is GPL-3.0-only, so the privacy stance is inspectable
Intentional Network Edges
Ctrl+click on Linux/Windows or Cmd+click on macOS opens allowed links and paths through the platform opener
The connection manager launches the system ssh only when you choose a host; confirmed remote-image paste also transfers through ssh
OSC 52 clipboard writes default to ask: allow once, allow for the current PTY session, deny for that session, or cancel. Even on accepts writes only from the active session while the window has OS focus and fails closed otherwise; notices report the target and byte count, never content
OSC 52 clipboard read replies are off by default; enable only in trusted sessions
Kitty named file, temp-file, and POSIX shared-memory graphics transports are off by default (kitty_named_transports) and rejected before any host I/O, so remote or SSH output cannot read local files unless you grant that authority; direct and chunked-inline images still work
$ odytty --roadmap — horizons
This board is generated straight from OdyTTY's own
docs/full-build-roadmap.md
through the same awk → JSON pipeline as the theme gallery. Items are grouped by
horizon: the forward work leads,
the already-shipped foundation collapses below, and the deliberate non-goals are listed last.
Filter to one horizon with the controls, or read the long-form rationale in the
devlog.
odytty:~$ cat roadmap.json █
$ odytty --devlog — build journal
OdyTTY is built in the open with a running devlog: every change records what
landed and the known gaps. This is a build-time index of the repo's
DEVLOG.md;
entries expand inline, releases are badged, and releases only reads it as a changelog.
OdyTTY is menu-driven: settings, themes, fonts, and keybindings have in-app
overlays, while the underlying config file remains available. It also owns its pseudo-terminal
layer, parser, terminal model, render geometry, graphics routing, settings, and shaders rather than
wrapping a terminal library. The shipped surface includes workspaces, split panes, Unix-only
detachable sessions, SSH workflows, Kitty graphics, Sixel, modern keyboard and mouse protocols,
and 142 built-in themes. Detached sessions are Unix-only.
Installed Noto Color Emoji renders in color on Linux and Windows, and Apple Color Emoji renders in
color on macOS. Stock Windows uses a readable monochrome fallback because the current path does not
discover or rasterize Segoe UI Emoji.
Is it production ready?
Version v0.10.0 is a broad pre-1.0 release rather
than a finished 1.0 product. Real shells, tabs, workspaces, split panes, saveable layouts,
whole-window restore, Unix-only detachable sessions, SSH workflows, graphics, settings, and themes
work today. Bounded checks of the published Linux x86_64, macOS Apple Silicon, and Windows x86_64 packages
completed without a reported blocker, but they do not cover every GPU, compositor, IME, font,
application, or hardware combination. Linux ships .deb, .rpm, binary tarball,
AppImage, and AUR paths; Windows ships an unsigned x86_64 zip through Scoop or direct download;
macOS ships an ad-hoc-signed Apple Silicon app through Homebrew or direct download. Intel macOS
and other architectures require a source build.
Is it based on another terminal?
No. Mature terminals are compatibility references. OdyTTY's PTY layer, parser, terminal model,
render geometry, graphics routing, settings, and shaders are OdyTTY code. Lower-level crates still
handle focused infrastructure such as windowing, GPU API access, font rasterization, clipboard
transport, and Unicode width data.
What does it run on?
Linux, macOS, and Windows are shipped and supported, with Linux as the primary target. Linux
release packages are x86_64 and prefer Vulkan, fall back to accelerated OpenGL/GLES, and can use
slow software rendering; Wayland is primary and X11 is supported with some window-manager-dependent
behavior. Linux ARM requires a source build. Windows uses ConPTY and ships as an unsigned x86_64 build through Scoop or
a direct zip; Windows ARM has no prebuilt, detached sessions remain Unix-only, and OdyTTY cannot
register as the Windows system default terminal. Installed Noto Color Emoji can render in color on
Windows, while stock Windows uses a monochrome fallback because Segoe UI Emoji is not discovered or
rasterized. Apple Silicon installs a prebuilt, ad-hoc-signed OdyTTY.app through Homebrew
or direct download; Intel Macs use the source formula or Cargo. Blocking CI covers all three
operating systems, supplemented by bounded checks of the published v0.10.0 packages.
What happens on weak GPUs?
Post-process effects require a filterable Rgba16Float render target. If the adapter
cannot support that path, OdyTTY uses the plain direct renderer instead of failing startup.
What data leaves my machine?
The OdyTTY application sends no telemetry, analytics, crash reports, update pings, account data,
or cloud-sync data. Network activity is user-initiated: connecting through the system
ssh client, confirming a remote image upload, or opening an allowed link or path through
the platform opener. Detached-session transport is a per-user local Unix socket, not a network
service. The project website may use Cloudflare's separate site-level analytics.
Can I configure it without editing files?
Yes. Settings, themes, fonts, and keybindings are exposed through in-app overlays. The underlying
config remains a plain local odytty.conf, and Settings writes changed rows back with
preservation-first atomic writeback.
What is unsupported right now?
OdyTTY does not ship a macOS DMG, upstream Snap package, or upstream Nix package. Flatpak is a
deliberate non-goal; AppImage is the single-file portable Linux option. Windows binaries are
unsigned and may trigger SmartScreen. The macOS app is ad-hoc signed, not Developer ID signed or
notarized; those signing paths are not available for the current distribution. Multiple windows
open today with Ctrl+Shift+N. The first window owns layout restore
and autosave, while secondary windows run independently and do not restore or overwrite that saved
workspace state. Coordinated multi-window persistence and management remain future work. Other gaps
include named profiles and broadcast input to panes. On the protocol/text side: Kitty animation,
Kitty Unicode placeholders, iTerm2 graphics, COLR/CPAL and
SVG-in-OpenType color fonts, and broader ligature and stylistic-set shaping beyond the shipped
default-on programming ligatures are deferred.
How do I report issues or contribute?
OdyTTY is GPL-3.0-only and uses a DCO sign-off workflow. Open an issue before starting
non-trivial contribution work in the
issue tracker. Report
security vulnerabilities privately through the repository's
Security → Report a vulnerability
flow, not a public issue. The source and authoritative project documentation live in the
OdyTTY repository.
This page is a static site (Vite → Cloudflare Pages). The CRT field is a raw
WebGL shader; the theme gallery and knob table are generated from OdyTTY's real .theme
files and runtime-knobs.md by a small awk pipeline. It steals its tube from its sibling,
unfinished-works.com — same workshop,
different machine.