{"id":50982861,"url":"https://github.com/ghreprimand/odytty","last_synced_at":"2026-06-28T06:01:00.450Z","repository":{"id":363485683,"uuid":"1262526767","full_name":"ghreprimand/odytty","owner":"ghreprimand","description":"Terminal emulator with GPU rendering and advanced graphics and input protocol support.","archived":false,"fork":false,"pushed_at":"2026-06-26T18:43:48.000Z","size":17397,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-26T19:23:14.511Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://odytty.unfinished-works.com","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ghreprimand.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-08T04:26:35.000Z","updated_at":"2026-06-26T18:44:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ghreprimand/odytty","commit_stats":null,"previous_names":["ghreprimand/odytty"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/ghreprimand/odytty","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghreprimand%2Fodytty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghreprimand%2Fodytty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghreprimand%2Fodytty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghreprimand%2Fodytty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ghreprimand","download_url":"https://codeload.github.com/ghreprimand/odytty/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghreprimand%2Fodytty/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34878963,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-19T16:04:48.125Z","updated_at":"2026-06-28T06:01:00.430Z","avatar_url":"https://github.com/ghreprimand.png","language":"Rust","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# OdyTTY\n\n**Website:** [odytty.unfinished-works.com](https://odytty.unfinished-works.com)\n\n![OdyTTY rendering a colorized git graph, project tree, and truecolor gradients under the default Odyssey theme with bloom](assets/demo.png)\n\nOdyTTY is a standalone, from-scratch, GPU-rendered Rust terminal emulator for\nLinux. It owns the terminal byte path from PTY allocation through escape\nparsing, terminal state, render geometry, and shaders, while relying on focused\nexternal crates for lower-level infrastructure such as `wgpu`, `winit`,\n`ab_glyph`, `swash`, `arboard`, and Unicode width tables.\n\nThe name and visual direction come from OdysseyOS, a companion Linux From\nScratch system. That system is inspiration, not a platform\nrequirement: OdyTTY is a public Linux application and does not require\nOdysseyOS or any custom distribution.\n\nThe project goal is not to skin an existing terminal. OdyTTY is testing whether\na terminal can carry a distinctive OdyTTY visual identity, richer in-app\nconfiguration, inline media, motion, and accessibility features while remaining\npractical for real command-line work. Terminal correctness, readable text,\ninput behavior, stable rendering, local privacy, and performance are the hard\nfloor.\n\nOdyTTY is in active development. It is already a broad prototype: a native\nwindow opens real local shells, supports multiple sessions with a tab bar,\nsplits each tab into panes, renders text and inline graphics on the GPU, and has\na substantial compatibility and smoke-test suite. It is still Linux-first and\npre-release; macOS is supported as an experimental build-from-source target (see\nthe macOS install notes below), while profiles remain a follow-up.\n\n## Highlights\n\n- **Owned terminal core:** Linux PTY layer via `rustix`, clean-room DEC/xterm\n  parser, OdyTTY terminal model, scrollback, alternate screen, mouse, keyboard,\n  OSC, DCS, APC, and render geometry.\n- **GPU renderer:** `wgpu`/Vulkan path with dynamic glyph atlas, bundled\n  Victor Mono (default) plus JetBrains Mono, bold/italic/weight faces, optional\n  synthetic styles, subpixel AA, HiDPI-aware atlas rebuilds, color emoji atlas,\n  and GPU image layer.\n- **Inline media:** Kitty graphics protocol and Sixel, including direct,\n  file/temp-file, and shared-memory Kitty transports with conservative local\n  file-safety restrictions.\n- **Modern input:** Kitty keyboard protocol, SGR pixel mouse mode 1016, focus\n  reporting, IME composition input (CJK / compose-key accents), configurable\n  local keybindings, keyboard hints, keyboard copy mode, and OSC 8 hyperlink\n  hover/open.\n- **Daily workflow:** search, refined selection, PRIMARY selection,\n  bracketed-paste hardening, chunked large paste, bounded scrollback history,\n  right-click context menu,\n  command-aware prompt navigation from OSC 133, configurable bell (visual flash\n  / window urgency), close confirmation, and tabs.\n- **Splits / panes:** split any tab into side-by-side or stacked panes, each\n  with its own shell, scrollback, selection, search, and cursor. A configurable\n  tmux-style prefix (default `Ctrl+b`) drives split, focus-move, close, zoom\n  (full-bleed the focused pane), and equalize once a tab has multiple panes;\n  dividers are drag-resizable. On a single-pane tab, `Ctrl+b` passes through to\n  the shell unchanged, and a single-pane tab renders exactly as before.\n- **Clickable paths and inline media:** opt-in interactive paths turn file paths\n  in output into Ctrl+click targets that open in your editor at the right line\n  and column, with an in-app image lightbox for image paths, an \"Open With…\"\n  picker, OSC 8 hyperlinks, and keyboard quick-select hints.\n- **Detached and managed sessions:** sessions that outlive the window — a local\n  CLI (`odytty new` / `list` / `attach`) plus an in-window Manage Sessions\n  overlay to attach, rename, and kill them, a New-tab/Replace attach prompt, and\n  detach-and-switch to hand the focused pane to a fresh managed session.\n- **Visual experience layer:** 100 built-in themes, user `.theme` files, live theme\n  picker, theme builder, semantic cursor/selection/search roles, optional\n  bloom/CRT/retro effects, background treatments, cursor motion, focus dimming,\n  new-output fade, window padding, and window border.\n- **Local configuration UX:** `odytty.conf`, live reload, in-app settings panel,\n  atomic preservation-first writeback, mouse-friendly controls, font picker,\n  keybinding editor, and first-run onboarding. Environment variables always win.\n- **SSH connection substrate:** an OdyTTY-owned local hosts list for the SSH\n  manager, default-off opt-in OpenSSH config host-name import, and a connect\n  action that opens `ssh` in a new tab/session. Imports are read-only,\n  name-only, bounded, and never surface key material; authentication remains\n  with the system `ssh` binary and agent.\n- **Privacy posture:** no telemetry, analytics, crash reporting, account,\n  cloud sync, or update ping. Network-capable actions are explicit and\n  user-initiated: Ctrl-click link and path opening through the platform opener\n  (`xdg-open` on Linux, `open` on macOS) with a scheme allowlist, and SSH\n  connect entries that exec the system `ssh` binary.\n\n## Install And Run\n\nOdyTTY ships as source. Linux is the primary, battle-tested target; macOS is an\nexperimental build-from-source target (see [macOS](#macos-experimental) below).\nBoth build from the same source archive with `cargo build --release`. Windows is\nnot yet supported.\n\n### Linux\n\nRequires Linux and a Vulkan-capable GPU. Wayland is the primary target; X11\nworks through the current `winit`/GPU stack with some window-manager-dependent\nbehavior for borderless windows and OS theme detection.\n\n#### AppImage (quickest)\n\nDownload the AppImage and `SHA256SUMS` from the latest release, verify it, make\nit executable, and run it:\n\n```sh\ncurl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty-x86_64.AppImage\ncurl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS\nsha256sum -c SHA256SUMS --ignore-missing\nchmod +x odytty-x86_64.AppImage\n./odytty-x86_64.AppImage\n```\n\nThe `chmod +x` is required — browsers download the AppImage without the\nexecutable bit, so without it the file opens in an archive viewer or fails with\n\"permission denied\". The AppImage needs a working host Vulkan driver (Mesa or a\nvendor driver); it deliberately does not bundle the GPU stack. This is a\nbest-effort x86_64 artifact — if it fails to start, build from source below.\n\nEach release attaches both version-less and version-pinned downloads:\n`odytty-x86_64.AppImage` / `odytty.tar.gz` are the always-latest names used\nabove (resolved by the `releases/latest/download/` URLs), while\n`odytty-\u003cversion\u003e-x86_64.AppImage` / `odytty-\u003cversion\u003e.tar.gz` are the\n**identical** copies for pinning a specific version. Both carry matching\nchecksums in `SHA256SUMS`.\n\n#### Build from source\n\nFor the current source release, install OdyTTY for the current user.\n\nDownload and verify the release archive:\n\n```sh\nworkdir=$(mktemp -d /tmp/odytty-install.XXXXXX)\ncd \"$workdir\"\ncurl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty.tar.gz\ncurl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS\ngrep \" odytty.tar.gz$\" SHA256SUMS | sha256sum -c -\ntar -xf odytty.tar.gz\ncd odytty-*/\n```\n\nBuild the release:\n\n```sh\ncargo build --release --locked\n```\n\nInstall a versioned binary and point `~/.local/bin/odytty` at it:\n\n```sh\ninstall -Dm755 target/release/odytty \"$HOME/.local/opt/odytty/$version/bin/odytty\"\nmkdir -p \"$HOME/.local/bin\"\nln -sfn \"$HOME/.local/opt/odytty/$version/bin/odytty\" \"$HOME/.local/bin/odytty\"\n```\n\nRegister the app launcher, metadata, and icon:\n\n```sh\ninstall -Dm644 dist/linux/io.unfinished_works.odytty.desktop \\\n  \"$HOME/.local/share/applications/io.unfinished_works.odytty.desktop\"\ninstall -Dm644 dist/linux/io.unfinished_works.odytty.metainfo.xml \\\n  \"$HOME/.local/share/metainfo/io.unfinished_works.odytty.metainfo.xml\"\ninstall -d \"$HOME/.local/share/icons/hicolor\"\ncp -a dist/icons/hicolor/* \"$HOME/.local/share/icons/hicolor/\"\nupdate-desktop-database \"$HOME/.local/share/applications\" 2\u003e/dev/null || true\ngtk-update-icon-cache \"$HOME/.local/share/icons/hicolor\" 2\u003e/dev/null || true\n```\n\nMake sure `$HOME/.local/bin` is on `PATH`, then launch OdyTTY as a normal\napplication:\n\n```sh\nodytty\n```\n\n### macOS (experimental)\n\nmacOS is experimental and not yet as battle-tested as Linux. OdyTTY is built\nfrom source: a binary you compile locally is never quarantined, so it launches\nwith no Gatekeeper warning and needs no signing, notarization, or workaround.\nThere is no prebuilt download — and that is deliberate, since an unsigned\nprebuilt would otherwise be blocked by Gatekeeper on first launch.\n\nRequires the Rust toolchain ([rustup](https://rustup.rs)) and the Xcode Command\nLine Tools. Both Apple Silicon and Intel are supported (whatever `cargo` targets\nnatively on your machine).\n\n```sh\nxcode-select --install   # once, if you don't already have the Command Line Tools\ncurl -LO https://github.com/ghreprimand/odytty/releases/latest/download/odytty.tar.gz\ncurl -LO https://github.com/ghreprimand/odytty/releases/latest/download/SHA256SUMS\ngrep \" odytty.tar.gz$\" SHA256SUMS | shasum -a 256 -c -\ntar -xf odytty.tar.gz\ncd odytty-*/\ncargo build --release --locked\n./target/release/odytty\n```\n\nTo get a double-clickable **OdyTTY.app** in Applications (a locally built bundle\nis also not quarantined, so it opens with no Gatekeeper prompt):\n\n```sh\nmkdir -p dist/build\ncp target/release/odytty dist/build/odytty\nbash dist/macos/make-app.sh \"$version\"\ncp -R dist/build/OdyTTY.app /Applications/\n```\n\nTo run it as just `odytty` from any shell (as the examples below show), symlink\nthe built binary onto your `PATH`:\n\n```sh\nmkdir -p \"$HOME/.local/bin\"\nln -sfn \"$PWD/target/release/odytty\" \"$HOME/.local/bin/odytty\"\n# Make sure ~/.local/bin is on PATH (add to ~/.zshrc if needed):\n#   export PATH=\"$HOME/.local/bin:$PATH\"\n```\n\nRun a command directly inside OdyTTY:\n\n```sh\nodytty -e btop\nodytty --working-directory /tmp -e sh -lc 'pwd; exec \"$SHELL\"'\nodytty --title Monitor -e btop\n```\n\nUseful launch examples:\n\n```sh\n# Use the hard plain renderer profile.\nODYTTY_RENDER_QUALITY=plain odytty\n\n# Follow the desktop dark/light preference with OdyTTY defaults.\nODYTTY_THEME=system odytty\n\n# Larger text with a named system font.\nODYTTY_FONT_SIZE=24 ODYTTY_FONT_FAMILY=\"DejaVu Sans Mono\" odytty\n\n# RGB subpixel antialiasing when supported by the GPU.\nODYTTY_SUBPIXEL=rgb odytty\n\n# Stronger phosphor reference look.\nODYTTY_RETRO=on odytty\n```\n\nFor system installs, Odyssey/LFS packaging, rollback, and default-terminal\nnotes, see [`docs/install.md`](docs/install.md). A quick source-tree smoke run\nis:\n\n```sh\ncargo build --release --locked\n./target/release/odytty\n```\n\nOdyTTY is driven primarily by its in-app menus: the settings panel, the theme\nand font pickers, and the `Ctrl+Shift+P` command palette all run live inside the\nterminal, so browsing themes, choosing fonts, and changing configuration happen\nvisually with an immediate preview — no command-line required. The introspection\ncommands below are a **scriptable alternative** to those menus for quick checks,\nautomation, and headless inspection; they print and exit without opening a\nwindow:\n\n```sh\nodytty --list-themes\nodytty --list-fonts\nodytty --show-config\n```\n\nDetached-session CLI commands are additive and local-only:\n\n```sh\nodytty new --detached\nodytty new --detached --title work -e bash\nodytty list\nodytty attach\nodytty attach \u003cid\u003e\nodytty attach --diagnostic \u003cid\u003e\n```\n\nThe same introspection works from the source tree before installing:\n\n```sh\n./target/release/odytty --list-themes\n./target/release/odytty --list-fonts\n./target/release/odytty --show-config\n```\n\n`--list-themes` prints the 100 built-in themes as stable\n`name`/`appearance`/`family` rows. `--list-fonts` prints discoverable system\nfont files. `--show-config` prints the current stable config-dump subset (including\n`symbol_fallback` and `symbol_font_source`, which reports the resolved\nsymbol/Nerd-font fallback **chain**, joined with ` \u003e ` — e.g.\n`bundled \u003e bundled \u003e host:\u003cpath\u003e`, or `disabled`); the full settings authority is\n[`docs/runtime-knobs.md`](docs/runtime-knobs.md).\n\n`odytty new --detached` starts a local session-host process and prints a stable\n`id=...` row. `odytty list` prints live detached sessions as metadata-only rows\nwith the session name first, pane count, age, and id when the name is distinct;\nit never dumps scrollback or command output. `odytty attach` with no id attaches\nthe only live session; if several are live, it prints the same readable list and\nasks you to choose `odytty attach \u003cid\u003e`; if none are live, it reports that there\nis nothing to attach. `odytty attach \u003cid\u003e` reattaches a detached session in a\nlive native window: the window opens its normal local shell, adds the hosted\nsession as a focused tab, repaints from the host snapshot, then streams live\noutput. If the id is missing or dead, the local shell still opens and stderr\nreports `odytty: attach session \u003cid\u003e failed: \u003cerr\u003e`. `odytty attach\n--diagnostic \u003cid\u003e` is the script/CI form: it prints a one-line status dump and\nexits without opening a window. The host keeps the PTY and bounded terminal\nmodel alive across attach/detach cycles until the child exits or the detached\nidle timeout reaps it.\n\n## Current Feature Surface\n\n### Terminal Compatibility\n\nThe owned parser and terminal core cover common shell and TUI behavior:\nprinting, UTF-8 chunking, SGR attributes including 256-color and truecolor,\ncursor movement, erase, insert/delete character and line, insert/replace mode\n(IRM), repeat, reverse index, scroll regions, origin mode, tab stops, bracketed\npaste, focus reporting,\nalternate screen modes 47/1047/1048/1049, OSC 0/2 titles, OSC 7 working\ndirectory tracking, OSC 8 hyperlinks, OSC 52 clipboard write plus opt-in read,\nOSC 133 prompt marks, OSC 4/10/11/12 dynamic colors, DECRQM/DECRPM, XTWINOPS,\nXTGETTCAP, DECRQSS, rectangle operations, selective erase, synchronized output\nmode 2026, and broad mouse reporting.\n\nMouse support includes X10/normal/button-event/any-event tracking, focus\nevents, UTF-8, SGR, urxvt, legacy encodings, and SGR-pixel mode 1016 with true\nphysical pixel coordinates from the native window. Alternate scroll mode (1007,\ndefault on) translates the wheel into cursor-key presses on the alternate\nscreen, so full-screen TUIs that do not track the mouse — pagers and similar —\nscroll with the wheel.\n\nKeyboard support includes mode-aware legacy encoding and the Kitty keyboard\nprotocol as a negotiated overlay. With no Kitty flags active, legacy bytes are\npreserved. IME composition is enabled: input-method pre-edit is rendered inline\nat the cursor and committed text is sent to the shell, so CJK input methods and\ncompose-key/dead-key accents work.\n\nThe bell (BEL) is configurable via the `bell` setting: `urgent` (default,\nrequests window attention when unfocused), `visual` (a brief readability-safe\nscreen flash), `all` (both), or `off`. There is no audible bell.\n\n### Text, Emoji, And Graphics\n\nText rendering uses bundled Victor Mono by default at 20 logical pixels with\nline height `1.0`. JetBrains Mono is also bundled and remains selectable via\n`font_family`. The font picker groups families into **Bundled Fonts** (Victor\nMono, JetBrains Mono — always available) and **System Fonts** (host monospace\nfamilies), and either resolves with zero config. The symbol/Nerd-font fallback\nis a **chain** of bundled faces — Nerd Fonts **v3** and **v2** — so PUA prompt\nicons render out of the box regardless of which Nerd Font era a config emits or\nwhether the host has any Nerd font installed. System font families, direct font\nfiles, font-weight variants, per-range symbol maps, synthetic styles, subpixel\nAA, glyph coverage gamma, stem darkening, and minimum-contrast enforcement are\nconfigurable.\n\nColor emoji uses `swash` and a dedicated premultiplied-RGBA atlas. Bitmap-strike\ncolor fonts are supported — Noto Color Emoji (CBDT/CBLC) on Linux and Apple Color\nEmoji (sbix) on macOS — including variation selectors, flags, keycaps, skin\ntones, and common ZWJ clusters. Text-default symbols stay on the monochrome\nfallback path, and missing color glyph coverage falls back there instead of\ntofu. Emoji pixels are not SGR-tinted. COLR/CPAL and SVG-in-OpenType expansion\nremain future work.\n\nKitty graphics support includes actions `t`, `T`, `p`, `d`, and `q`; raw RGB,\nraw RGBA, and PNG still images; direct, file, temp-file, and POSIX shared-memory\ntransports; chunking; image and placement ids; z-index; crop; cell scaling; and\npixel offsets. Sixel supports the DEC/xterm data language, RGB/HLS color\nintroducers, repeat, raster attributes, transparency, VT340 palette, and DECSDM.\nAnimation and Kitty Unicode placeholders are not supported.\n\n### Native App Workflow\n\nThe native app runs multiple sessions. `Ctrl+Shift+T` opens a new tab,\n`Ctrl+Shift+W` closes the active tab, and `Ctrl+PageDown` /\n`Ctrl+PageUp` switch tabs. Closing a tab closes the **whole** tab — every pane\nit holds — which is distinct from closing a single pane (see \"Close Pane\"\nbelow); closing the last remaining tab quits the app. The tab bar appears when\ntwo or more sessions exist; a single shell keeps the original full-grid view.\nThe active tab is framed with a thin themed outline so it stays legible over\nbackground images and treatments. Inline graphics are offset by the same\nreserved tab-bar row as text, so Kitty/Sixel placements stay aligned with the\nvisible grid while the bar is shown. Right-click a tab to rename it for the\nsession; the custom name overrides shell title updates until cleared.\n\nAny tab can be split into panes. The direct chords `Ctrl+Shift+E` (split into\ncolumns, new pane on the right) and `Ctrl+Shift+O` (split into rows, new pane\nbelow) create a split on a single-pane tab — they match Ghostty's Linux\ndefaults and work at both single-pane and multi-pane. You can also split from\nthe right-click menu's \"Split Right\" / \"Split Down\" items. When the active tab\nis already multi-pane, the right-click menu also offers a \"Close Pane\" item\n(labelled with the effective `Ctrl+b x` prefix chord) to close just the focused\npane; it is hidden in a single-pane tab, where closing the tab is the only\nclose. The right-click menu also has a launcher section at the bottom —\n\"Connection Manager\", \"Command Palette\", and \"Session Replay\" — each labelled\nwith its effective chord and opening the matching overlay. Once the active tab\nhas multiple panes, a tmux-style prefix (default\n`Ctrl+b`, configurable via\n`pane_prefix`) opens a transient pane-command mode; press the prefix then a pane\nkey:\n\n| After the prefix | Action |\n| --- | --- |\n| `%` | Split the focused pane into columns (side-by-side) |\n| `\"` | Split the focused pane into rows (stacked) |\n| `←` / `→` / `↑` / `↓` | Move focus to the neighbor pane |\n| `o` | Cycle focus to the next pane |\n| `x` | Close the focused pane |\n| `z` | Zoom / un-zoom the focused pane (full-bleed; layout is preserved) |\n| `Space` / `=` | Equalize split sizes |\n| `Ctrl+b` (prefix again) | Send a literal prefix to the focused pane (nested multiplexer) |\n\nEach pane owns an independent PTY, terminal model, scrollback, viewport,\nselection, search, and cursor. Drag a divider to resize the panes on either\nside. The prefix is captured only when the active tab has more than one pane; a\nsingle-pane shell receives `Ctrl+b` unchanged, preserving the byte-identical\ndefault input path. Set `pane_prefix=off` to disable the pane prefix entirely\nand free the chord in multi-pane tabs too. v1 cuts: inline\ngraphics render in single-pane tabs only, interactive overlays (selection /\nsearch) are painted for the focused pane only. Optional inactive-pane dimming is\nimplemented via `inactive_pane_dim`; it defaults to `0.0`, is disabled on\n`render_quality=plain`, and leaves the no-dim pane frame byte-identical.\n\nCore local shortcuts:\n\n| Shortcut | Action |\n| --- | --- |\n| `Ctrl+Shift+E` / `Ctrl+Shift+O` | Split the focused pane into columns / rows |\n| `Ctrl+Shift+F` | Search scrollback |\n| `Ctrl+Shift+,` | Settings panel |\n| `Ctrl+Shift+H` | Theme picker |\n| `Ctrl+Shift+B` | Theme builder |\n| `Ctrl+Shift+P` | Command palette |\n| `Ctrl+Shift+S` | Connection manager |\n| `Ctrl+Shift+R` | Session replay |\n| `Ctrl+Shift+A` | Manage Sessions (attach a detached session) |\n| `Ctrl+Shift+C` / `Ctrl+Shift+V` | Copy / paste |\n| `Shift+PageUp` / `Shift+PageDown` | Scroll local viewport |\n| `Ctrl+Shift+L` | Keyboard quick-select hints |\n| `Ctrl+Shift+Space` | Keyboard copy mode |\n| `Ctrl+Shift+Up` / `Ctrl+Shift+Down` | Jump to previous / next prompt mark |\n| `Ctrl+Shift+K` | Clear editable prompt input when shell integration allows it |\n\nThe command palette, connection manager, session replay, theme builder, and\nManage Sessions each ship with a default `Ctrl+Shift+\u003cletter\u003e` chord and a\ndiscoverable menu entry — the launcher actions appear in the right-click menu's\nlauncher section, and the theme builder is an \"Open Theme Builder\" entry in the\nSettings → Themes section. These chords are all `Ctrl+Shift+\u003cletter\u003e`, which a\nTUI cannot receive, so PTY input is unchanged. Prompt navigation is the\n`Ctrl+Shift+Up/Down` arrows. Rebind any of them, for example:\n\n```conf\n# odytty.conf\nkeybinds = ctrl+alt+p=command-palette\n```\n\nFor a one-off/dev override, run\n`ODYTTY_KEYBINDS=\"ctrl+alt+p=command-palette\" odytty`; env wins for that\nsession.\n\nThe palette fuzzy-filters local actions, bounded read-only shell history, and\nrecent OSC 7 directories. Selecting a history or directory row types that text\ninto the active pane without pressing Enter; selecting an action runs the local\naction after the overlay closes.\n\nOutput replay is available as the `session-replay` action, bound by default to\n`Ctrl+Shift+R`. Turn on recording with `session_replay = on` (or\n`ODYTTY_SESSION_REPLAY=on` as a one-off override) — off by default, so the plain\npath is unchanged — then rebind the scrub overlay if desired:\n\n```conf\n# odytty.conf\nsession_replay = on\nkeybinds = ctrl+alt+r=session-replay\n```\n\nFor a one-off/dev override, run\n`ODYTTY_SESSION_REPLAY=on ODYTTY_KEYBINDS=\"ctrl+alt+r=session-replay\" odytty`;\nenv wins for that session.\n\nThe ring is capped (600 frames and 24 MiB, whichever binds first) and\nlocal-only — frames never touch disk or the network. The overlay is\npresentation-only: `←`/`→` step, `PgUp`/`PgDn` jump ten, `Home`/`End` jump to\nthe ends, and the live session keeps running underneath untouched while you\nscrub.\n\nThe connection manager is available as the `connection-manager` action, bound by\ndefault to `Ctrl+Shift+S`. Rebind it to open a type-to-filter list of saved\nhosts and quick-connect with Enter:\n\n```conf\n# odytty.conf\nkeybinds = ctrl+alt+h=connection-manager\n```\n\nFor a one-off/dev override, run\n`ODYTTY_KEYBINDS=\"ctrl+alt+h=connection-manager\" odytty`; env wins for that\nsession.\n\nHosts come from the OdyTTY-owned `hosts.conf` and, only when\n`ssh_config_hosts = on`, name-only entries from your OpenSSH config. With the\nopt-in off, the overlay lists OdyTTY-owned hosts only and never references\n`~/.ssh`. The overlay is presentation-only; selecting a host spawns the system\n`ssh` in a new session.\n\nDetached sessions are managed from inside the window as well as from the CLI. The\n`session-attach` action (default `Ctrl+Shift+A`, also the **Manage Sessions**\nentry in the right-click menu) lists the live detached sessions; selecting one\nattaches it. If that session is already open it switches to its tab; otherwise a\nprompt offers a **New tab** or **Replace** (which closes the current tab).\nRight-click a session to kill it behind a confirmation, and the **Detach \u0026\nswitch** context-menu action hands the focused pane's working directory to a\nfresh managed session. Attaching reconnects the live PTY and terminal model; the\nhost keeps them alive across detach/attach cycles until the child exits or the\nidle timeout reaps it.\n\nInteractive paths are an opt-in layer (`interactive_paths`, off by default) that\nmakes file paths in command output actionable. With it on, Ctrl+click opens a\npath: a file opens in your configured editor, jumping to the right `line:col`\nwhen the path carries one, and an image path (png/jpg/jpeg/webp) opens in an\nin-app lightbox you dismiss with `Esc` or a click outside. A discoverable click\nhint, plus right-click \"Open\", \"Open With…\", \"Copy Path\", \"Copy File\", and\n\"Reveal in File Manager\", round out the menu. Opening goes through the platform\nopener (`xdg-open` on Linux, `open` on macOS) with a scheme allowlist; nothing is\never run through a shell.\n\nThe `keybinds` config key can rebind local actions: `search`, `settings`,\n`theme-picker`, `theme-builder`, `copy`, `paste`, `scroll-up`, `scroll-down`,\n`jump-prompt-prev`, `jump-prompt-next`, `copy-mode`, `hints`, `clear-input`,\n`command-palette`, `session-replay`, `connection-manager`, `session-attach`,\n`new-tab`, `next-tab`, `prev-tab`, and `close-tab`. The pane actions\n(`split-columns`, `split-rows`, `focus-pane-left` / `-right` / `-up` / `-down`,\n`focus-pane-next`, `close-pane`, `zoom-pane`, `equalize-panes`) are rebindable\ntoo — the chord is the key pressed *after* the prefix, e.g.\n`keybinds = ctrl+f=zoom-pane`. `ODYTTY_KEYBINDS` provides the same syntax as a\nsession-scoped override. See [`docs/keybindings.md`](docs/keybindings.md) for the\ncomplete keyboard reference — every default chord, the pane prefix, copy mode,\nhints, and rebinding.\n\n### Settings And Themes\n\nSettings load in this order:\n\n1. Built-in defaults.\n2. `$XDG_CONFIG_HOME/odytty/odytty.conf`, or\n   `~/.config/odytty/odytty.conf`.\n3. `ODYTTY_*` environment variables, which override config values for the\n   current session.\n\nThe config file is the primary place to set durable preferences. Its format is\n`key = value` with `#` comments. The native app polls the resolved file about\nonce per second; env-pinned keys stay pinned for the session and are best suited\nto one-off/dev overrides. The settings panel live-applies changes and writes\nonly changed keys back to `odytty.conf`, preserving comments, blank lines,\nunknown keys, and ordering via same-directory atomic rename.\n\n`theme = system` or `ODYTTY_THEME=system` follows the desktop dark/light\npreference using OdyTTY defaults (`odyssey` dark, `odyssey-light` light).\nExplicit `follow_os_theme`, `os_theme_dark`, and `os_theme_light` settings allow\ncustom mappings.\n\n#### Default background image (and how to turn it off)\n\nSince v0.6.0 OdyTTY ships with its OdysseyOS visual identity on by default: the\ndefault theme is `odyssey-default` (a deep forest-green palette; also reachable\nunder the `odyssey-jungle` alias), and an original \"Dark Waves\" background image\nis **bundled into the binary and shown by default** behind the grid. The image\nis embedded at build time, so it works identically on every install (source\nbuild, AppImage, and distro package) with no external file to manage. It carries\nthe repository license (see [`assets/backgrounds/LICENSE`](assets/backgrounds/LICENSE)).\n\nTo turn the background **off**, set either key in `odytty.conf`:\n\n```ini\n# odytty.conf — disable the bundled background entirely\nbackground_treatment = color   # draw the theme background only (no image)\n# — or —\nbackground_image = none        # keep image treatment available but use no image\n```\n\nTo use **your own** image instead, point `background_image` at a file:\n\n```ini\n# odytty.conf — use a custom background\nbackground_treatment = image\nbackground_image = /path/to/your/wallpaper.png   # png / jpeg / webp\nbackground_image_scrim = 0.5                      # 0 = none, 1 = opaque scrim; `auto` = floor-safe\n```\n\n`background_image = default` (the unset value) selects the bundled image again.\n\nSee:\n\n- [`docs/runtime-knobs.md`](docs/runtime-knobs.md) for every config key,\n  environment variable, range, default, and reload behavior.\n- [`docs/odytty.conf.example`](docs/odytty.conf.example) for an annotated config.\n- [`docs/themes.md`](docs/themes.md) for the theme format and built-in roster.\n- [`docs/effects.md`](docs/effects.md) for bloom, CRT, retro, background, and\n  motion effects.\n- [`docs/keybindings.md`](docs/keybindings.md) for the complete keyboard\n  reference and rebinding.\n- [`docs/accessibility.md`](docs/accessibility.md) for the minimum-contrast\n  floor, color-vision modes, dimming, and the bell.\n\n## Architecture\n\nThe terminal core and visual layer are deliberately separate:\n\n| Area | Path |\n| --- | --- |\n| PTY | `src/pty.rs` |\n| Parser | `src/parser/` |\n| Terminal model | `src/core/` |\n| Render geometry | `src/grid.rs`, `src/render.rs`, `src/boxdraw.rs` |\n| Text atlas and font resolution | `src/atlas/`, `src/text.rs`, `src/emoji/` |\n| Graphics protocols | `src/graphics/`, `src/core/graphics_routing.rs` |\n| Settings | `src/settings.rs`, `src/settings/` |\n| Theme system | `src/theme/`, `src/theme_author.rs`, `src/palette_gen.rs` |\n| Command palette | `src/fuzzy.rs`, `src/palette.rs`, `src/palette_catalog.rs`, `src/palette_sources.rs`, `src/native/palette_overlay.rs` |\n| Native app and GPU | `src/native/` |\n\nExternal crates do not own terminal semantics. `vte`, `portable-pty`, and\n`crossterm` are not in the dependency tree.\n\n## Testing\n\nThe repository carries unit, integration, fuzz-smoke, pixel-smoke, PTY-smoke,\nGPU-composite, and CLI tests. The default suite is intended to be deterministic\nand host-independent; PTY smoke and deep fuzz tiers are ignored by default.\n\n```sh\ncargo test\ncargo fmt --check\n\n# Parser/protocol deep tier when touching those paths:\nODYTTY_FUZZ_ITERS=40000 cargo test --test protocol_fuzz -- --ignored --nocapture\n\n# Evidence-only performance harness:\ncargo bench --bench perf\n```\n\nThe library test suite alone runs in the thousands of cases and is exercised on\nevery CI run; the current counts live in [`DEVLOG.md`](DEVLOG.md), with the full\ntree carrying additional integration and smoke suites. See\n[`CONTRIBUTING.md`](CONTRIBUTING.md) for the commit gate.\n\n## Status\n\n**Works today:** real shells, multi-session tabs, splits/panes with a\nconfigurable tmux-style prefix, scrollback, search, selection,\ncopy/paste, font/theme/settings overlays, theme builder, 100 themes, color\nemoji, Kitty graphics, Sixel, Kitty keyboard protocol, SGR-pixel mouse,\nclickable paths with an inline image viewer, detached and in-window managed\nsessions, a connection manager, command palette, session replay,\nOSC 8/52/133, dynamic colors, prompt navigation, command status gutter,\nreadability and accessibility settings, bloom/CRT/retro effects, background\ntreatments, and a large compatibility test surface.\n\n**Platforms:** Linux is the primary, battle-tested target. macOS is an\nexperimental build-from-source target (see Install And Run). Both are exercised\nin CI. Windows is not yet supported.\n\n**Known gaps:** Windows support, profiles, per-pane inline graphics, Kitty\nanimation, Kitty Unicode placeholders, iTerm2 graphics, COLR/CPAL color fonts,\nand broader ligature/stylistic-set shaping.\n\nThe running history lives in [`DEVLOG.md`](DEVLOG.md). The current public\nroadmap lives in [`TODO.md`](TODO.md) and\n[`docs/full-build-roadmap.md`](docs/full-build-roadmap.md).\n\n## Public Repository Safety\n\nThis repository is public. Do not commit secrets, credentials, API keys, tokens,\nprivate hostnames or URLs, personal data, `.env` files, local-only config, or\nmachine-specific notes. Before any commit or push, inspect staged changes for\nsensitive content.\n\nOdyTTY itself is local-first: no telemetry, no account, no cloud sync, no\nanalytics, no crash reporting, and no update pings.\n\n## Project Docs\n\n- [`SPEC.md`](SPEC.md) — product charter and architecture decisions.\n- [`TODO.md`](TODO.md) — current milestone checklist and remaining work.\n- [`DEVLOG.md`](DEVLOG.md) — reverse-chronological development record.\n- [`CONTRIBUTING.md`](CONTRIBUTING.md) — project stance on contributions, plus\n  testing and public-repo safety rules.\n- [`SECURITY.md`](SECURITY.md) — supported versions and private vulnerability\n  reporting.\n- [`PACKAGING.md`](PACKAGING.md) — downstream package install surface and\n  release packaging notes.\n- [`docs/install.md`](docs/install.md) — source builds, desktop launcher\n  registration, AppStream metadata, Odyssey/LFS packaging, and default-terminal\n  notes.\n- [`docs/release.md`](docs/release.md) — release artifact checklist and\n  Odyssey-Mon upstream tracking notes.\n- [`docs/runtime-knobs.md`](docs/runtime-knobs.md) — settings reference.\n- [`docs/keybindings.md`](docs/keybindings.md) — complete keyboard reference and\n  rebinding.\n- [`docs/accessibility.md`](docs/accessibility.md) — contrast floor, color-vision\n  modes, dimming, motion, and bell.\n- [`docs/themes.md`](docs/themes.md) — theme format and built-in library.\n- [`docs/graphics.md`](docs/graphics.md) — Kitty graphics and Sixel support.\n- [`docs/visual-architecture.md`](docs/visual-architecture.md) — renderer and\n  visual-layer architecture.\n- [`docs/hidpi-validation.md`](docs/hidpi-validation.md) — manual HiDPI checks.\n- [`docs/full-build-roadmap.md`](docs/full-build-roadmap.md) — long-range map.\n\n## License\n\nOdyTTY is licensed under **GPL-3.0-only**. See [`LICENSE`](LICENSE).\n\nYou may use, study, share, and modify the source under that license. If you\ndistribute a modified version, you must release your changes under the same\nlicense.\n\nCopyright (C) 2026 Unfinished Works and the OdyTTY contributors.\n\nThe OdyTTY name and branding are separate from the source license. Forks and\nmodified builds should use their own name and must not imply endorsement by\nUnfinished Works. See [`NOTICE`](NOTICE).\n\nContributions are accepted under the Developer Certificate of Origin. See\n[`CONTRIBUTING.md`](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghreprimand%2Fodytty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fghreprimand%2Fodytty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghreprimand%2Fodytty/lists"}