OdyTTY

A Linux-first GPU terminal emulator, written from scratch in Rust — for Linux, Windows, and macOS.

OdyTTY rendering a colorized git graph, project tree, and truecolor gradients under the default Odyssey theme with bloom.
OdyTTY under the default Odyssey theme — colorized git graph, project tree, and truecolor gradients with bloom.
release v0.10.0 render wgpu GPU theme odyssey visual crt # open source · no telemetry · Linux, Windows, macOS

$ odytty --demo — real captures

OdyTTY theme picker overlay listing odyssey themes over a full-screen truecolor gradient, odyssey-default selected.
the theme picker — arrows preview live, the whole terminal recolors behind it
OdyTTY command palette open over colorized cargo test output, fuzzy-filtering actions and shell history.
the command palette — everything fuzzy-filtered, live over the session
OdyTTY's image lightbox displaying the JWST Cosmic Cliffs nebula photograph inside the terminal.
the image lightbox — Ctrl+click a path on Linux/Windows or Cmd+click on macOS, Esc to dismiss, never upscaled
OdyTTY in-app settings panel open over a session, showing live CRT and bloom controls in the Effects section.
the 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.

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 …

$ 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
  • Configured in-app: settings panel, live theme picker + builder, command palette, keybinding editor
  • 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.

developer checks
cargo fmt --all -- --check
cargo build --locked
cargo clippy --all-targets --locked -- -D warnings
cargo test --locked
ODYTTY_FUZZ_ITERS=40000 cargo test --test protocol_fuzz -- --ignored --nocapture
cargo bench --bench perf

$ odytty --features — highlights

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.

PTYclean-room parserterminal modelrender geometrytext / emoji / image atlaseswgpu GPUpost-process

Workspaces, layouts & sessions

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.

$ act iv · man odytty — reference

$ odytty --install — release install

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:

Linux primary target · x86_64 deb / rpm / tarball / AppImage · AUR / source Wayland 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
Windows supported · x86_64 Scoop / zip Unsigned 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
macOS supported · Apple Silicon cask / source Apple 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.

One-line installer (quickest)
curl -fsSL https://raw.githubusercontent.com/ghreprimand/odytty/master/dist/install.sh | bash

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:

Debian / Ubuntu / Mint / Pop — .deb
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-amd64.deb
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
grep " odytty-amd64.deb$" SHA256SUMS | sha256sum -c -
sudo apt install ./odytty-amd64.deb
Fedora / RHEL / openSUSE — .rpm # best-effort, cross-built on Ubuntu
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-x86_64.rpm
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
grep " odytty-x86_64.rpm$" SHA256SUMS | sha256sum -c -
sudo dnf install ./odytty-x86_64.rpm

Prebuilt binary tarball

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.

portable tarball
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-linux-x86_64.tar.gz
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
grep " odytty-linux-x86_64.tar.gz$" SHA256SUMS | sha256sum -c -
tar -xzf odytty-linux-x86_64.tar.gz
cd odytty-*-linux-x86_64/
./install.sh                 # ~/.local
# system-wide instead: sudo PREFIX=/usr/local ./install.sh

AppImage (portable, no install)

A single self-contained file — nothing is installed system-wide. Handy for a quick try or a read-only system.

AppImage
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-x86_64.AppImage
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
chmod +x odytty-x86_64.AppImage   # required — browsers strip the exec bit
./odytty-x86_64.AppImage

Arch Linux (AUR)

The odytty AUR package builds from tagged GitHub source, compiles locally, and is maintained alongside tagged releases.

AUR helper
paru -S odytty      # or: yay -S odytty
…or manually
sudo pacman -S --needed base-devel git
git clone https://aur.archlinux.org/odytty.git
cd odytty
makepkg -si

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-//')
2. build
cargo build --release --locked
3. install for the current user
install -Dm755 target/release/odytty "$HOME/.local/opt/odytty/$version/bin/odytty"
mkdir -p "$HOME/.local/bin"
ln -sfn "$HOME/.local/opt/odytty/$version/bin/odytty" "$HOME/.local/bin/odytty"
4. register the app launcher, metadata & icon (optional)
install -Dm644 dist/linux/io.unfinished_works.odytty.desktop \
  "$HOME/.local/share/applications/io.unfinished_works.odytty.desktop"
install -Dm644 dist/linux/io.unfinished_works.odytty.metainfo.xml \
  "$HOME/.local/share/metainfo/io.unfinished_works.odytty.metainfo.xml"
install -d "$HOME/.local/share/icons/hicolor"
cp -a dist/icons/hicolor/* "$HOME/.local/share/icons/hicolor/"
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
gtk-update-icon-cache "$HOME/.local/share/icons/hicolor" 2>/dev/null || true

Updating

Re-running the one-line installer always fetches the newest release and re-verifies it before replacing the old build:

one-line installer — re-run to update
curl -fsSL https://raw.githubusercontent.com/ghreprimand/odytty/master/dist/install.sh | bash

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
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
Scoop — 2. add the bucket and install
scoop bucket add odytty https://github.com/ghreprimand/odytty
scoop install odytty
# update later with: scoop update odytty

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.

Portable zip (direct download)
Invoke-WebRequest https://github.com/ghreprimand/odytty/releases/latest/download/odytty-windows-x86_64.zip -OutFile odytty-windows-x86_64.zip
Invoke-WebRequest https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS -OutFile SHA256SUMS
Get-FileHash odytty-windows-x86_64.zip -Algorithm SHA256   # compare against SHA256SUMS
Expand-Archive odytty-windows-x86_64.zip -DestinationPath .\odytty
.\odytty\odytty.exe

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
optional: double-clickable OdyTTY.app
mkdir -p dist/build
cp target/release/odytty dist/build/odytty
bash dist/macos/make-app.sh "$version"
cp -R dist/build/OdyTTY.app /Applications/
optional: put odytty on your PATH
mkdir -p "$HOME/.local/bin"
ln -sfn "$PWD/target/release/odytty" "$HOME/.local/bin/odytty"

Updating

Refresh to the newest release with Homebrew:

Homebrew cask (recommended)
brew update
brew upgrade --cask odytty
…or the source formula
brew upgrade 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.

OdyTTY split into two panes: a colorized git graph on the left, green cargo test results on the right.
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.

Readability Controls

  • Minimum WCAG contrast-ratio floor, default 17.0 (range 1.0–21.0)
  • 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).

try inline images
kitty +kitten icat /path/to/image.png
img2sixel --width=200 /path/to/image.png

$ man odytty.conf — runtime knobs

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.

launch
odytty
odytty -e btop
odytty --working-directory /tmp -e sh -lc 'pwd; exec "$SHELL"'
odytty --title Monitor -e btop
odytty --app-id=com.example.Monitor -e btop
odytty --hold -e sh -lc 'echo complete; exit 7'

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
TERM=xterm-256color
COLORTERM=truecolor
TERM_PROGRAM=odytty
TERM_PROGRAM_VERSION=<installed version>
quick launch examples
# 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

ChordAction
Ctrl+Shift+T / WNew tab / close active tab
Ctrl+Shift+DDuplicate active tab — a fresh shell in the active pane's directory
Ctrl+Shift+NNew window (also in the right-click menu; inherits the active pane's working directory when one is tracked, falling back to the default)
Ctrl+PageDown / PageUpNext tab / previous tab
Ctrl+Shift+E / OSplit focused pane into columns / rows
Ctrl+b then % " ↑↓←→ o x z =tmux-style pane prefix: split, focus, cycle, close, zoom, equalize
Ctrl+Shift+EnterNew workspace (the rail's + slot does the same)
Ctrl+Shift+PageDown / PageUpNext workspace / previous workspace
Ctrl+Shift+Alt+DDuplicate active workspace — a fresh workspace in the active pane's directory
Ctrl+Shift+GWorkspace picker (rename, close, bind-to-host, and Save/Open Layout live in the right-click menus and palette)
Ctrl+Shift+AManage Sessions — Unix attach/rename/kill list; empty on Windows

Overlays & settings

ChordAction
Ctrl+Shift+PCommand palette (actions, settings, shell history, recent dirs)
Ctrl+Shift+SConnection manager (saved SSH hosts)
Ctrl+Shift+H / BTheme picker / theme builder
Ctrl+Shift+RSession replay overlay (opt-in recording)
Ctrl+Shift+,In-app settings panel (font, theme, cursor, all knobs)
Ctrl+S (in panel)Write changed rows back to odytty.conf (preservation-first)

Editing, navigation & mouse

ChordAction
Ctrl+Shift+FScrollback search (next/prev, match highlights)
Ctrl+Shift+C / VCopy selection / paste
Shift+PageUp / PageDownScroll local viewport
Ctrl+Shift+Up / DownJump to previous / next OSC 133 prompt mark
Ctrl+Shift+SpaceKeyboard copy mode (vim-style scrollback selection)
Ctrl+Shift+LKeyboard quick-select hints (URLs, paths, hashes)
Ctrl+Shift+KClear the shell input line (readline Ctrl+A then Ctrl+K; no shell integration required)
Double-clickSelect word · Triple-click selects line
Ctrl/Cmd+ClickOpen 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
  • Placements, z-index, source crop, cell scaling, offsets
  • Sixel (DCS q) — RGB/HLS, repeat, raster attrs, transparency, VT340 palette, DECSDM
  • Kitty animation and Unicode placeholders are not supported
  • iTerm2 graphics are deferred

Input & mouse

  • Kitty keyboard protocol (progressive enhancement)
  • IME composition input for CJK and compose-key/dead-key accents
  • Mouse modes 9 / 1000 / 1002 / 1003
  • Encodings 1005 / 1006 / 1015 / 1016 (SGR-pixel)
  • Alternate scroll mode 1007 maps wheel motion to cursor keys in full-screen TUIs
  • Focus reporting (DECSET 1004)
  • Bracketed paste with sanitization, queued as one atomic marker + text + marker transaction (32 MiB limit)
  • Program-defined clickable output buttons — master gate on by default, sticky lifetime off by default

OSC & dynamic color

  • OSC 0/2 window title
  • OSC 8 hyperlinks (hover underline, Ctrl+click on Linux/Windows or Cmd+click on macOS, allowlist)
  • OSC 7 working directory (advisory, localhost-only; shell integration percent-encodes paths safely)
  • OSC 52 clipboard write — per-session consent prompt (ask) by default; reads remain off
  • OSC 133 prompt marks for command-aware navigation
  • OSC 4 / 10 / 11 / 12 + resets (104/110/111/112)

Rendering & text

  • SGR 256-color + truecolor (colon & semicolon)
  • DEC G0/G1 designation, SO/SI selection, and Special Graphics mapping for ncurses line drawing
  • Extended underlines (4:04:5) + underline color (58/59)
  • Legacy SGR 21 double underline alongside the modern underline styles
  • Mouse cursor shape: I-beam over grid, hand over hyperlinks, arrow over chrome
  • Subpixel AA (dual-source) with grayscale fallback
  • Synchronized output (DEC 2026, 150 ms timeout)
  • XTGETTCAP, DECRQSS, DECRQM/DECRPM capability queries
  • 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.

not loaded
  1. Open this section to load the live devlog, or read it on GitHub →

$ man odytty — FAQ & colophon

What makes it different from other terminals?

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.