Installing OdyTTY

September 8, 2026 · View on GitHub

OdyTTY ships as a versioned release. Each release provides:

  • a git tag (vX.Y.Z) and source tarball;
  • a GitHub Release entry with SHA256SUMS for every artifact and, from v0.11.0 onward, a Minisign signature over that manifest;
  • native Linux .deb and .rpm packages via a one-line installer, a portable standalone tarball, and an x86_64 AppImage as a no-install fallback;
  • an AUR package (odytty) for Arch-family systems;
  • a prebuilt macOS .app zip for Apple Silicon (ad-hoc signed) plus a Homebrew tap;
  • an unsigned Windows x86_64 portable zip;
  • source-build instructions for Odyssey/LFS and other developer systems;
  • a desktop entry, AppStream metadata, and icon installed into Freedesktop locations.

Pick by system: on Linux the one-line installer picks a native .deb or .rpm for you (with the AppImage as a no-install single-file fallback and the AUR package on Arch-family systems), Homebrew on macOS, Scoop (or a direct zip download) on Windows, and a pacman-tracked source package on Odyssey itself so the install is versioned, owned, removable, and visible to Odyssey-Mon.

Contents

Release Artifact Names And Checksums

Packaged downloads are published under a stable always-latest alias and a version-pinned copy:

Always-latest aliasVersion-pinned copy
odytty-amd64.debodytty-<version>-amd64.deb
odytty-x86_64.rpmodytty-<version>-x86_64.rpm
odytty-linux-x86_64.tar.gzodytty-<version>-linux-x86_64.tar.gz
odytty-x86_64.AppImageodytty-<version>-x86_64.AppImage
odytty-macos-arm64.zipodytty-<version>-macos-arm64.zip
odytty-windows-x86_64.zipodytty-<version>-windows-x86_64.zip
odytty.tar.gzodytty-<version>.tar.gz
noneodytty-<version>-install.sh

Each alias and its version-pinned twin are byte-identical and therefore have matching hashes in SHA256SUMS. Durable links should use the aliases under releases/latest/download/; pinned names are for selecting one specific release.

Verify a signed release download

Releases from v0.11.0 onward include SHA256SUMS.minisig. Verify that signature before using SHA256SUMS, then check the downloaded artifact against the authenticated manifest. The public key is docs/keys/odytty-release.pub; its comment contains the key identifier published with signed release notes. Releases before v0.11.0 have checksums but no release-key signature.

On Debian or Ubuntu, install Minisign and verify a Linux download like this:

sudo apt install minisign
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
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS.minisig
curl -LO https://raw.githubusercontent.com/ghreprimand/odytty/master/docs/keys/odytty-release.pub
minisign -Vm SHA256SUMS -x SHA256SUMS.minisig -p odytty-release.pub
sha256sum -c SHA256SUMS --ignore-missing

Other Linux distributions can install Minisign through their package manager; the verification commands are the same. Substitute the chosen artifact name in the first download command. Stop if either Minisign or the checksum command fails.

On macOS, install Minisign with Homebrew, then verify the direct app download:

brew install minisign
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-macos-arm64.zip
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS.minisig
curl -LO https://raw.githubusercontent.com/ghreprimand/odytty/master/docs/keys/odytty-release.pub
minisign -Vm SHA256SUMS -x SHA256SUMS.minisig -p odytty-release.pub
shasum -a 256 -c SHA256SUMS --ignore-missing

On Windows, install Minisign with scoop install minisign or choco install minisign, then use PowerShell:

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
Invoke-WebRequest https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS.minisig -OutFile SHA256SUMS.minisig
Invoke-WebRequest https://raw.githubusercontent.com/ghreprimand/odytty/master/docs/keys/odytty-release.pub -OutFile odytty-release.pub
minisign -Vm SHA256SUMS -x SHA256SUMS.minisig -p odytty-release.pub
$match = Select-String -Path SHA256SUMS -Pattern '  odytty-windows-x86_64\.zip$'
if ($null -eq $match) { throw 'Artifact is missing from SHA256SUMS' }
$expected = ($match.Line -split '\s+')[0].ToLowerInvariant()
$actual = (Get-FileHash odytty-windows-x86_64.zip -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actual -ne $expected) { throw 'SHA-256 mismatch; do not run this download' }

Verify build provenance

Releases from v0.12.0 onward also carry a GitHub build provenance attestation, which binds each artifact's digest to the workflow, repository, and commit that produced it. It is additive to the Minisign signature above, not a replacement: the signature says who vouched for the manifest, the attestation says where the bytes were built.

There is nothing extra to download. Attestations are stored by GitHub against the repository and looked up by the artifact's digest, so verification is an online query. It needs the GitHub CLI, version 2.97.0 or newer, on any platform. Older releases contain known attestation-verification bypasses and must not be used for this check:

gh attestation verify odytty-x86_64.AppImage --repo ghreprimand/odytty

Substitute the artifact you downloaded. The always-latest alias and its version-pinned twin are byte-identical, so either name verifies against the same attestation, exactly as they share a hash in SHA256SUMS. Use odytty-x86_64.AppImage or the Linux tarball/package name on Linux, odytty-macos-arm64.zip on macOS, and odytty-windows-x86_64.zip in PowerShell on Windows; the command syntax is otherwise identical.

To also require that the attestation came from this project's release workflow and not merely from somewhere in the repository, add:

gh attestation verify odytty-x86_64.AppImage \
  --repo ghreprimand/odytty \
  --signer-workflow ghreprimand/odytty/.github/workflows/release.yml

Stop if verification fails. Releases before v0.12.0 have no attestation, and gh attestation verify correctly reports that rather than passing.

What signing does and does not cover

Neither the checksum-manifest signature nor the provenance attestation replaces operating-system code signing, and you will still see a warning on first launch:

  • macOS: the app is ad-hoc signed, not Developer ID signed or notarized. Gatekeeper refuses it on first launch; right-click the app and choose Open (or clear the quarantine attribute) to run it.
  • Windows: the executable has no Authenticode signature. SmartScreen shows an unknown-publisher warning; choose "More info" and then "Run anyway".
  • Linux: no platform signing authority is involved, so the manifest signature and the attestation are the whole trust chain.

The canonical platform-signing boundary and its cost rationale are recorded in the release guide. Verifying the manifest signature and the attestation establishes that a download is the artifact this project built; it does not suppress operating-system warnings.

Linux

Linux is the primary platform. OdyTTY prefers a Vulkan adapter, but accelerated OpenGL/GLES also works and software rendering remains a slow last resort. Wayland is the primary display target. X11 works through the current winit and GPU stack, with some window-manager-dependent behavior for borderless windows and OS theme detection.

The trusted path downloads a version-pinned release installer, authenticates the release manifest with Minisign, checks the installer against that manifest, then runs it. Paste this block to install or update to the latest release; no version substitution is needed (installer assets ship with v0.14.0 and later):

bash <<'ODYTTY_UPDATE'
set -euo pipefail
command -v minisign >/dev/null || { echo 'Install minisign first, then rerun this block.' >&2; exit 1; }
workdir=$(mktemp -d)
trap 'rm -rf "$workdir"' EXIT
cd "$workdir"
release=$(curl -fsSL -o /dev/null -w '%{url_effective}' https://github.com/ghreprimand/odytty/releases/latest)
version=${release##*/v}
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo 'Could not resolve the latest release.' >&2; exit 1; }
base="https://github.com/ghreprimand/odytty/releases/download/v${version}"
curl -fLO "${base}/odytty-${version}-install.sh"
curl -fLO "${base}/SHA256SUMS"
curl -fLO "${base}/SHA256SUMS.minisig"
minisign -Vm SHA256SUMS -x SHA256SUMS.minisig -P 'RWQcOPw3PisdAGt2Q2IF7W6P1sgyPs2b9rQvFJohmLC8/w+qJt+aXEev'
awk -v file="odytty-${version}-install.sh" '\$2 == file' SHA256SUMS | sha256sum -c -
bash "odytty-${version}-install.sh"
ODYTTY_UPDATE

The script chooses a native .deb on apt/dpkg systems, a native .rpm on dnf/rpm systems, or the portable binary tarball otherwise. It authenticates SHA256SUMS.minisig against its pinned copy of odytty-release.pub before accepting an artifact hash. System package managers need root, so the script uses sudo when you are not already root; the tarball path falls back to a per-user ~/.local install when no sudo is available. To preview the installation, add --dry-run to the final bash "odytty-${version}-install.sh" line inside the block before pasting it. This downloads and verifies the installer, then prints the plan without downloading or installing packages.

The older mutable curl | bash form is convenience-only and is not a trusted path: it executes a network response before signature verification. Do not use it when release-key authentication is required.

It is Linux x86_64 only: on macOS it prints the Homebrew command and on Windows the Scoop command instead of installing, and other architectures are pointed at the AppImage or a source build.

.deb (Debian, Ubuntu, Mint, Pop)

Download the always-latest .deb alias and its checksums, verify, and install with apt so dependencies resolve:

curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-amd64.deb
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
sudo apt install ./odytty-amd64.deb

The package installs the binary, desktop entry, AppStream metadata, and icons under dpkg ownership. OdyTTY does not publish an apt repository, so update by re-running the download-and-install above or the one-line installer.

.rpm (Fedora, RHEL, openSUSE, best-effort)

Download the always-latest .rpm alias, verify, and install with dnf:

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
sha256sum -c SHA256SUMS --ignore-missing
sudo dnf install ./odytty-x86_64.rpm

Like the AppImage, the .rpm is a best-effort artifact: it is cross-built on Ubuntu and its metadata is validated in CI, but it is not tested on every RPM distribution. If it does not install cleanly on your system, use the binary tarball or build from source.

Binary tarball (portable prebuilt)

The odytty-linux-x86_64.tar.gz is a prebuilt binary plus desktop-integration files and a bundled install.sh, for systems where a native package does not fit. Download, verify, extract, and run the bundled installer:

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
sha256sum -c SHA256SUMS --ignore-missing
tar -xzf odytty-linux-x86_64.tar.gz
cd odytty-*-linux-x86_64
./install.sh

The bundled install.sh copies the binary and desktop files into a prefix and refreshes the desktop and icon caches when those tools are present. PREFIX defaults to ~/.local for a no-root per-user install (make sure ~/.local/bin is on your PATH); set PREFIX=/usr/local and use sudo for a system-wide install. Remove a previous install with ./install.sh --uninstall (honoring the same PREFIX).

AppImage (x86_64)

Download the always-latest AppImage alias and checksum file, verify it, mark it executable, and run it:

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
./odytty-x86_64.AppImage

The executable bit is required because browsers normally omit it. Without chmod +x, the file may open in an archive viewer or fail with "permission denied".

The AppImage bundles OdyTTY's own dependencies but not the graphics driver: it uses the host's Vulkan ICD or accelerated OpenGL/GLES stack, the same graphics requirement as a source build. It is built on the oldest supported Ubuntu LTS for a wide glibc floor. This is a best-effort artifact; if GPU initialization fails, see No Vulkan adapter, accelerated GL, and virtual machines.

To integrate it into menus, tools like Gear Lever or appimaged register the bundled desktop entry and icon. The AppImage can be built locally with dist/appimage/build-appimage.sh.

Arch Linux (AUR)

Install the odytty package with an AUR helper:

paru -S odytty      # or: yay -S odytty

No AUR helper yet? paru and yay are themselves AUR packages, so a fresh Arch install does not ship them. Use the manual makepkg route below, which needs no helper; installing a helper is optional (see below).

Or install manually (no AUR helper needed):

sudo pacman -S --needed base-devel git
git clone https://aur.archlinux.org/odytty.git
cd odytty
makepkg -si

A helper is optional; it just makes future updates a single command. To install paru once:

sudo pacman -S --needed base-devel git
git clone https://aur.archlinux.org/paru.git
cd paru
makepkg -si

After that, paru -S odytty installs OdyTTY and paru -Syu handles updates. (yay installs the same way from https://aur.archlinux.org/yay.git.)

The package builds from the release source tarball and installs the binary, desktop entry, AppStream metadata, and icons under pacman ownership. The first install compiles from source (pulling in cargo/rust), so it takes a few minutes. The odytty AUR package is maintained by the project and auto-published on each release: the release pipeline pushes the updated package to the AUR as part of publishing a new version, so it tracks the GitHub releases closely. AUR packages are not vetted by Arch, so inspect the PKGBUILD before installing; AUR helpers show it by default.

To pick up the very latest immediately regardless of the AUR package's state, build from the release source tarball directly (the PKGBUILD template and its publish runbook live in dist/aur/), or use the always-latest download links below.

Updating

Use the same method that installed OdyTTY. The stable download aliases always point at the newest release.

Version-pinned installer. Download and authenticate the newer release's installer as above, then run it. The script downloads, signature-verifies, and installs the chosen artifact for the detected system:

bash "odytty-${version}-install.sh"

Direct .deb. OdyTTY does not publish an apt repository, so apt upgrade cannot discover a new release. Repeat the verified download and install:

curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-amd64.deb
curl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
sudo apt install ./odytty-amd64.deb

Direct .rpm. OdyTTY does not publish a dnf repository. Repeat the verified download and install:

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
sha256sum -c SHA256SUMS --ignore-missing
sudo dnf install ./odytty-x86_64.rpm

AUR. An AUR helper updates OdyTTY during the normal system upgrade:

paru -Syu
# or: yay -Syu

A manual AUR checkout updates in place:

cd odytty
git pull --ff-only
makepkg -si

Binary tarball. Download and verify the always-latest tarball, extract it into a new directory, and run the bundled installer with the same PREFIX used originally. Its default remains ~/.local:

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
sha256sum -c SHA256SUMS --ignore-missing
tar -xzf odytty-linux-x86_64.tar.gz
cd odytty-*-linux-x86_64
./install.sh

For a previous system-wide install, use the same system prefix again:

sudo env PREFIX=/usr/local ./install.sh

AppImage. Replace the old file with the always-latest alias, verify it, and restore the executable bit:

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

Source build. A release archive is a fixed snapshot; download the newest source archive into a new directory. A git checkout can instead run git pull --ff-only. Then rebuild and repeat the same user-local or system installation:

cargo build --release --locked

macOS (Apple Silicon)

macOS builds and passes the full test suite on every push, and the release ships a prebuilt OdyTTY.app for Apple Silicon (arm64). The binary is ad-hoc code-signed in CI (codesign -s -), which needs no Apple Developer account and no notarization - enough for the app to launch, but not an Apple Developer identity. There is no .dmg and no Gatekeeper-approved signature yet.

The Homebrew tap is the least-friction path; the cask handles Gatekeeper approval for you. Install it in two steps:

  1. Add the tap and install the cask:

    brew tap ghreprimand/odytty
    brew install --cask odytty
    
  2. If the install stops with Refusing to load cask ... from untrusted tap, trust the tap once and re-run the install:

    brew trust ghreprimand/odytty
    

    Use brew trust --cask ghreprimand/odytty/odytty to trust just this cask. This is a one-time per-machine trust.

The cask installs the prebuilt, ad-hoc-signed OdyTTY.app into /Applications:

  • The app is ad-hoc signed but not notarized, so macOS quarantines the download and Gatekeeper would otherwise block the first launch.
  • To spare you a manual step, the cask automatically clears the com.apple.quarantine attribute during install (the same xattr -dr com.apple.quarantine you would otherwise run by hand), so brew install --cask and brew upgrade launch cleanly.
  • This removes a macOS Gatekeeper safeguard on an ad-hoc-signed, un-notarized app; the cask's install-time caveats disclose it in the terminal. Notarization through the Apple Developer Program (deferred) is the only way to avoid needing that flag-clear at all.
  • Because the app lands in /Applications, it appears in Launchpad and Spotlight and can be dragged to the Dock to pin it, with no separate launcher step. (The source formula below installs only the odytty CLI on your PATH, with no GUI launcher.)

Prefer to compile locally instead? Use the source formula, which builds from the release tarball with your own toolchain:

brew install ghreprimand/odytty/odytty

Per release there is nothing to do on your side: CI bumps the tap's cask to each new version automatically shortly after the release publishes, so brew upgrade picks it up.

Updating

Cask (recommended): refresh to the newest release. brew update refreshes the tap first so a just-published version is visible:

brew update
brew upgrade --cask odytty
  • Source formula: brew upgrade odytty

The scoped commands update only OdyTTY; a plain brew upgrade refreshes everything Homebrew manages.

Direct .app zip download

If you download the .app zip straight from the GitHub Release instead of using Homebrew, macOS tags it with a quarantine attribute (because it arrived from the internet and the signature is ad-hoc, not notarized). Verify the checksum, unzip, move the app into place, then clear the quarantine flag once:

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/
xattr -dr com.apple.quarantine /Applications/OdyTTY.app

The xattr -dr com.apple.quarantine step is the one-time stopgap that lets an ad-hoc-signed app past Gatekeeper without notarization. The Homebrew cask runs the same quarantine-clearing step in its postflight, so this manual step is only needed for a direct (non-brew) zip download.

Build from source

A source build works with the standard Rust toolchain (rustup) and the Xcode Command Line Tools. Both Apple Silicon and Intel are supported through the target Cargo selects natively:

xcode-select --install   # once, if the Command Line Tools are not installed
cargo build --release --locked
./target/release/odytty

A locally compiled binary is not quarantined. To assemble a double-clickable OdyTTY.app, run:

version=$(./target/release/odytty --version | awk '{print \$2}')
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/

To run the source build as odytty from any shell:

mkdir -p "$HOME/.local/bin"
ln -sfn "$PWD/target/release/odytty" "$HOME/.local/bin/odytty"

Make sure $HOME/.local/bin is on PATH. The packaged release workflow also ad-hoc signs its app bundle; a local source build does not need that packaging step to run.

Signed / notarized builds

A signed, notarized .dmg (no xattr stopgap, no first-run friction on any download path) requires enrollment in the Apple Developer Program. That is deferred to if/when the project opts into that program; until then the ad-hoc signature plus Homebrew's quarantine strip is the account-free path.

Windows

Windows support is new and still maturing - it builds and runs the full terminal and is exercised on a Windows CI leg every push, but the polish bar is behind Linux. Bug reports for the Windows build are especially welcome; open an issue with your Windows version and a short repro.

The Windows release is an unsigned portable odytty.exe inside odytty-windows-x86_64.zip. There is no installer, and nothing is written outside your profile - configuration lives under %APPDATA%\odytty\. Scoop is the recommended install path because it puts odytty on your PATH, adds a Start-menu entry, and verifies the download checksum; you can also download the zip directly.

Scoop

Scoop is a per-user package manager for Windows (no admin rights). If you don't already have it, install it once in PowerShell:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression

Then add the in-repo bucket and install:

scoop bucket add odytty https://github.com/ghreprimand/odytty
scoop install odytty

After install:

  • Scoop creates a shim under ~\scoop\shims (on your PATH) so odytty launches from any shell, and adds an OdyTTY Start-menu entry.
  • The bucket manifest is bucket/odytty.json: it pins the release URL and hash, which is what scoop update odytty reads.
  • From your side there is nothing to do per release: CI bumps the manifest to each new version automatically shortly after the release publishes, so scoop update odytty picks up new versions on its own once that bump lands.

Portable zip

Download the always-latest zip alias and checksum file, verify the hash, and run the executable:

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
Expand-Archive odytty-windows-x86_64.zip -DestinationPath .\odytty
.\odytty\odytty.exe

Compare the hash with the odytty-windows-x86_64.zip row in SHA256SUMS; they must match before you run the binary.

Because OdyTTY is not code-signed yet, the first launch may raise a blue "Windows protected your PC" SmartScreen dialog naming an unknown publisher:

  • This is expected for unsigned open-source software and can appear however you install it; a package manager removes the browser-download friction but does not, on its own, guarantee the first-run prompt won't show.
  • Click More info, then Run anyway.
  • To clear the "downloaded from the internet" mark up front instead, run Unblock-File .\odytty\odytty.exe before launching.
  • Code-signed Windows binaries are a planned improvement.

OdyTTY can't yet be set as the Windows default terminal (the app Windows hands console programs to when launched from Explorer or another program) - that needs the Windows default-terminal handoff protocol, which OdyTTY doesn't implement yet. Launch it directly instead: from the Start menu, by typing odytty, or from a pinned shortcut. Detached/resumable session hosting is Unix-only in this release; the Windows build opens local ConPTY-backed tabs and panes.

Windows scope

The Windows build carries the full rendering, theme, effect, and inline-graphics stack. It opens local ConPTY-backed tabs and panes, stores persistent configuration under %APPDATA%\odytty\, discovers host fonts in %WINDIR%\Fonts and %LOCALAPPDATA%\Microsoft\Windows\Fonts, opens and reveals files through Explorer, and runs SSH connections inside local pseudoconsole-backed tabs.

Detached and resumable session hosting, detached SSH, and headless --interactive mode remain Unix-only. The full Open With application list is not available on Windows, and command-palette shell history currently degrades to empty. Hostname discovery uses GetComputerNameExW. Interactive behavior is covered by historical Windows device passes, blocking Windows CI, and a bounded post-release smoke check of the v0.10.0 portable package. That evidence does not cover every ConPTY application, IME, GPU, or Windows hardware configuration.

Updating

Scoop (recommended): refresh to the newest release. scoop update refreshes the bucket first so a just-published version is visible:

scoop update
scoop update odytty
  • Portable zip: re-download the always-latest odytty-windows-x86_64.zip, re-verify the hash against SHA256SUMS, and replace the old odytty.exe.

Build From Source

From outside a source checkout, download and verify the always-latest release archive first:

workdir=$(mktemp -d "${TMPDIR:-/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-*/

On macOS, use grep " odytty.tar.gz$" SHA256SUMS | shasum -a 256 -c - for the verification line.

Build the release binary:

cargo build --release --locked

Run from the source tree:

cargo run --release

After installation, plain odytty opens the native terminal. To print a parser/core smoke transcript and exit:

odytty --core-smoke

Check the installed version:

odytty --version

Run a command directly inside 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 --class=com.example.Monitor -e btop
odytty --hold -e sh -lc 'exit 7'

Command-Line Surface

Theming, fonts, and configuration are primarily driven by OdyTTY's in-app menus (the settings panel, theme/font pickers, and the Ctrl+Shift+P command palette), which change things live with a preview. These introspection commands are the scriptable alternative - they print a snapshot and exit, which is handy for verifying an install, automation, or wiring launchers:

odytty --version        # print the installed version
odytty --list-themes    # list built-in themes
odytty --list-fonts     # list discoverable font files, marking monospace rows
odytty --show-config    # print the effective configuration
odytty --core-smoke     # print a parser/core smoke transcript

--list-themes prints the 144 built-in themes as stable name/appearance/family rows. --list-fonts prints discoverable system font files. --show-config prints the stable effective-config subset, including symbol_fallback and the resolved symbol_font_source fallback chain. See the settings authority for every key, default, range, and environment variable.

On Linux, --app-id and --class are equivalent launch options. Both accept space and equals forms. The value overrides only that window's Wayland app_id and X11 WM_CLASS class; the X11 instance remains odytty. Without either option, the window keeps io.unfinished_works.odytty, and an override does not rename the installed desktop entry, icon, or StartupWMClass.

--hold, --hold=true, and --hold=false control the initial local command and default to false. A held exit remains visible with its numeric exit status, or an explicit unknown/possible-signal result, until the next keypress closes the exited pane. Later sessions do not inherit hold, and a dropped remote session's reconnect prompt retains precedence. The launch CLI reference gives the full lifecycle behavior.

On Unix, OdyTTY also hosts detached sessions that outlive the window:

odytty new --detached -e btop              # start a detached session, prints id=<id>
odytty new --app-id=com.example.Monitor    # parsed but not persisted
odytty list                                # list live detached sessions
odytty attach                              # reattach the only live session (or list choices)
odytty attach <id>                         # reattach a specific session in a native window
odytty attach --diagnostic <id>            # print one status line without attaching

For launcher compatibility, odytty new accepts both --app-id / --class aliases in space and equals forms. Detached creation has no window, so the value is not written into host metadata and does not affect a later odytty attach, which uses the packaged default identity.

On non-macOS Unix systems, detached sessions require XDG_RUNTIME_DIR to be set; their owner-private sockets live under $XDG_RUNTIME_DIR/odytty/. macOS falls back to its per-user temporary directory. The detached-session CLI reference covers metadata-only listings, reattachment, snapshot streaming, failure behavior, bounded scrollback, socket privacy, and the idle timeout.

Configuration Files

OdyTTY reads an optional config file at one of these platform locations:

Windows: %APPDATA%\odytty\odytty.conf
Unix:   $XDG_CONFIG_HOME/odytty/odytty.conf

On Unix it falls back to $HOME/.config/odytty/odytty.conf when XDG_CONFIG_HOME is unset. User themes are loaded from the theme directory alongside it:

Windows: %APPDATA%\odytty\themes
Unix:   $XDG_CONFIG_HOME/odytty/themes

The file is line-based key = value; environment variables set at startup override matching keys. See docs/runtime-knobs.md for every key, default, and range, docs/keybindings.md for the keyboard reference, and docs/accessibility.md for color-vision-deficiency modes, the minimum-contrast floor, and the bell.

User-Local Install

This is useful for quick testing on any Linux system:

cargo build --release --locked
install -Dm755 target/release/odytty "$HOME/.local/bin/odytty"
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

After this, odytty should work from a shell and OdyTTY should appear in app launchers that read Freedesktop desktop entries.

System Install

For a non-packaged system-wide install:

cargo build --release --locked
sudo install -Dm755 target/release/odytty /usr/bin/odytty
sudo install -Dm644 dist/linux/io.unfinished_works.odytty.desktop \
  /usr/share/applications/io.unfinished_works.odytty.desktop
sudo install -Dm644 dist/linux/io.unfinished_works.odytty.metainfo.xml \
  /usr/share/metainfo/io.unfinished_works.odytty.metainfo.xml
sudo install -d /usr/share/icons/hicolor
sudo cp -a dist/icons/hicolor/* /usr/share/icons/hicolor/
sudo update-desktop-database /usr/share/applications 2>/dev/null || true
sudo gtk-update-icon-cache /usr/share/icons/hicolor 2>/dev/null || true

Prefer a real package for machines where installed-file ownership matters.

Generic Versioned User Install

On any Linux system, a user can keep versioned OdyTTY builds without root by installing each release under a versioned directory and pointing ~/.local/bin/odytty at the selected version:

version=X.Y.Z
cargo build --release --locked
install -Dm755 target/release/odytty \
  "$HOME/.local/opt/odytty/$version/bin/odytty"
ln -sfn "$HOME/.local/opt/odytty/$version/bin/odytty" \
  "$HOME/.local/bin/odytty"
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
odytty --version

To roll back, repoint the symlink to an older directory under ~/.local/opt/odytty/.

Odyssey/LFS Versioned Install

Odyssey source builds are versioned by pacman, not by leaving build products in the source tree. Replace X.Y.Z with the release version; its vX.Y.Z tag should be archived into /sources/odytty-X.Y.Z.tar.gz, then built from ~/pkgbuilds/odytty/PKGBUILD with odyssey-build.

Example PKGBUILD:

# Maintainer: Unfinished Works <maintainers@odytty.unfinished-works.com>
pkgname=odytty
pkgver=X.Y.Z
pkgrel=1
pkgdesc="GPU-rendered Rust terminal emulator with an Odyssey visual identity"
arch=('x86_64')
url="https://github.com/ghreprimand/odytty"
license=('GPL-3.0-only')
depends=(
    'fontconfig'
    'freetype2'
    'vulkan-icd-loader'
    'libxkbcommon'
    'hicolor-icon-theme'
)
makedepends=('cargo')
source=("file:///sources/${pkgname}-${pkgver}.tar.gz")
sha256sums=('SKIP')

build() {
    cd "${pkgname}-${pkgver}"
    cargo build --release --locked
}

package() {
    cd "${pkgname}-${pkgver}"

    install -Dm755 target/release/odytty "$pkgdir/usr/bin/odytty"
    install -Dm644 dist/linux/io.unfinished_works.odytty.desktop \
        "$pkgdir/usr/share/applications/io.unfinished_works.odytty.desktop"
    install -Dm644 dist/linux/io.unfinished_works.odytty.metainfo.xml \
        "$pkgdir/usr/share/metainfo/io.unfinished_works.odytty.metainfo.xml"
    install -d "$pkgdir/usr/share/icons"
    cp -a dist/icons/hicolor "$pkgdir/usr/share/icons/"
    install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md"
    install -Dm644 docs/install.md "$pkgdir/usr/share/doc/$pkgname/install.md"
    install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
}

Build and install:

cd ~/pkgbuilds/odytty
odyssey-build

Verify pacman ownership and version tracking:

pacman -Qi odytty
pacman -Qo /usr/bin/odytty \
  /usr/share/applications/io.unfinished_works.odytty.desktop
odytty --show-config
odytty --version

Use pkgrel=1 for the first packaging revision of a source release. If the source does not change but the PKGBUILD does, keep pkgver at the source version and bump pkgrel.

What The Desktop Entry Does

dist/linux/io.unfinished_works.odytty.desktop registers OdyTTY as a GUI application in the System and TerminalEmulator categories:

Exec=odytty
Terminal=false
Categories=System;TerminalEmulator;
X-TerminalArgExec=-e
X-TerminalArgDir=--working-directory=
X-TerminalArgTitle=--title=
X-TerminalArgAppId=--app-id=
X-TerminalArgHold=--hold

The entry uses the OdyTTY icon name. Packages should install the SVG and PNG assets under the hicolor icon theme, for example:

/usr/share/icons/hicolor/scalable/apps/io.unfinished_works.odytty.svg
/usr/share/icons/hicolor/256x256/apps/io.unfinished_works.odytty.png

dist/linux/io.unfinished_works.odytty.metainfo.xml gives AppStream-aware tools a stable application id, license, summary, homepage, bug tracker, and release version. It belongs in:

/usr/share/metainfo/io.unfinished_works.odytty.metainfo.xml

Terminfo

OdyTTY runs child shells with:

TERM=xterm-256color
COLORTERM=truecolor
TERM_PROGRAM=odytty
TERM_PROGRAM_VERSION=<installed version>

This contract enables truecolor and program detection while keeping the widely-installed xterm terminfo entry for local shells, remote SSH hosts, and sudo environments. Do not package an OdyTTY-specific terminfo entry until the binary also starts using that TERM value and the release documents remote-host setup.

Default Terminal

Linux does not have one universal default-terminal mechanism. App launchers, file managers, desktop environments, and scripts use different conventions.

LFS Or Other Manual Systems

On a Linux From Scratch-style system, app launcher registration usually means installing the binary and .desktop file as shown above. To make shell scripts that respect $TERMINAL choose OdyTTY:

export TERMINAL=odytty

Put that in the environment setup used by the desktop session, not only an interactive shell startup file, if graphical applications need to see it.

For a keyboard shortcut such as Ctrl+Alt+T, configure the shortcut in the desktop environment or window manager to run:

odytty

xdg-terminal-exec

Some systems use the proposed xdg-terminal-exec default-terminal mechanism. That system selects terminal emulators from installed desktop entries and a preference file such as:

$HOME/.config/xdg-terminals.list

The desktop entry advertises OdyTTY's command execution arguments:

X-TerminalArgExec=-e
X-TerminalArgDir=--working-directory=
X-TerminalArgTitle=--title=
X-TerminalArgAppId=--app-id=
X-TerminalArgHold=--hold

xdg-terminal-exec can therefore translate an application-id request to --app-id=<value> and a keep-open request to --hold, alongside command, directory, and title requests. The app-id flag changes only that Linux window's Wayland app_id / X11 WM_CLASS class; it does not rename the installed desktop entry, icon, or StartupWMClass. With no application-id request, the window retains io.unfinished_works.odytty. Hold is off by default and applies only to the launched window's initial local command.

Then a user can prefer OdyTTY with:

printf 'io.unfinished_works.odytty.desktop\n' > "$HOME/.config/xdg-terminals.list"

Debian-Style x-terminal-emulator

Debian-family systems often use update-alternatives for x-terminal-emulator. A package can register OdyTTY as an alternative:

sudo update-alternatives --install \
  /usr/bin/x-terminal-emulator x-terminal-emulator /usr/bin/odytty 50
sudo update-alternatives --config x-terminal-emulator

On systems without update-alternatives, this mechanism does not exist unless the distribution or local system owner installs it.

macOS

macOS has no OS-level "default terminal" setting. Unlike the default browser or mail app, macOS exposes no system preference to replace Terminal.app as the terminal other applications hand console programs off to; Terminal.app remains the system default. Launch OdyTTY directly instead - from Launchpad, from Spotlight (⌘-Space, type "OdyTTY"), or from a Dock icon. A Homebrew cask install places OdyTTY.app in /Applications, so it appears in Launchpad and Spotlight automatically and can be dragged to the Dock to pin it.

Windows likewise cannot yet be set as the system default terminal - the Windows section above explains why (the default-terminal handoff protocol is not implemented). Launch it directly there too.

Troubleshooting

Slow rendering / software adapter

OdyTTY renders on the GPU through wgpu (Vulkan on Linux, Metal on macOS, Direct3D 12 on Windows, GL as a fallback). If the terminal feels very slow even with all visual effects turned off, the most common cause is that no hardware GPU adapter was available and the graphics stack silently fell back to a software rasterizer, which does all rendering on the CPU.

How to check which adapter is in use. Two ways report the same information:

  • The About panel (open the command palette with Ctrl+Shift+P and select About, or the settings panel's About tab) shows the active renderer's adapter name, backend, and device class.
  • On startup OdyTTY logs one line naming the adapter, backend, and device class, e.g. odytty: GPU adapter: llvmpipe (LLVM 17.0.6, 256 bits) (Vulkan, Cpu). It goes to the rotated log (~/.local/state/odytty/odytty.log on Linux) and to stderr when that is visible, so the adapter identity survives even when a launcher discards stderr. Accelerated GL reads a real renderer with backend Gl (for example a name containing virgl inside a VM); a software adapter reads llvmpipe or lavapipe, and OdyTTY adds a warning: odytty: WARNING: rendering in software (...); expect low performance.

What a software adapter means. Names such as llvmpipe or lavapipe (Mesa's software renderers), SwiftShader (Google's software renderer), or a device class of Cpu indicate CPU-only rendering. On Windows, Microsoft Basic Render Driver (WARP) is the equivalent software fallback. Software rendering works correctly but is far slower than a real GPU - especially on older hardware.

Common fixes.

  • Linux: install the Vulkan driver for your GPU. On Debian/Ubuntu that is mesa-vulkan-drivers (plus vulkan-tools for vulkaninfo); on Arch it is vulkan-icd-loader together with the vendor package (vulkan-radeon, vulkan-intel, or nvidia-utils). Verify with vulkaninfo | head - if it reports only llvmpipe, the hardware ICD is still missing. Over remote/SSH or in a VM without GPU passthrough, software rendering may be the only option.
  • Windows: install the latest GPU vendor driver (NVIDIA/AMD/Intel). WARP is usually selected only when no hardware driver is present, e.g. in a bare VM or a fresh install before drivers are added.
  • macOS: Metal is always hardware-backed on supported machines; a software adapter here is unusual and typically indicates a virtualized environment.

No Vulkan adapter, accelerated GL, and virtual machines

On Linux OdyTTY prefers a Vulkan adapter but does not require one:

  • When no Vulkan adapter is present it selects accelerated OpenGL/GLES (Mesa) instead of failing to start; a CPU software rasterizer (llvmpipe or lavapipe) is the last resort and is slow.
  • The accelerated backends are tried first and OpenGL is reached on a second attempt, so a machine with a working Vulkan driver never initializes the GL stack it will not draw through. This is a startup-cost decision only: GL remains a fully supported path, and a machine that needs it lands on it automatically, including when the first attempt finds nothing better than a software rasterizer.
  • Accelerated GL is a real GPU path: the About panel and the startup log show backend Gl with a hardware renderer name.
  • On this path text is drawn in grayscale rather than subpixel (accelerated GL has no dual-source blending) and a few effects may be unavailable; that is expected, not a fault.

Virtual machines. In a guest, OdyTTY needs either a Vulkan adapter or an accelerated GL stack:

  • If the guest exposes accelerated GL (virgl or virtio-gpu with a render node) OdyTTY uses it and runs on the GPU.
  • If the guest has neither, it falls back to software rendering, which works but is slow.
  • To exercise the Vulkan path in a guest without passthrough, install Mesa's software Vulkan (on Arch, sudo pacman -S vulkan-swrast provides lavapipe); note that is still CPU rendering and slow.
  • For hardware acceleration, enable virgl (GL) or Venus (Vulkan) in the hypervisor.

Forcing a backend. Standard wgpu environment overrides are honored, so a backend can be forced for debugging with WGPU_BACKEND=gl or WGPU_BACKEND=vulkan. An explicit request is used exactly as given: the staged bring-up above is skipped entirely, so a forced backend that cannot produce an adapter fails visibly instead of quietly succeeding through another one.