• v0.3.0 cad6442818

    v0.3.0
    All checks were successful
    fuzz / cargo fuzz nightly long-run (push) Has been skipped
    darwin / detect relevant changes (push) Successful in 9s
    darwin / darwin docs-only no-op (push) Has been skipped
    windows / detect relevant changes (push) Successful in 13s
    windows / windows docs-only no-op (push) Has been skipped
    fuzz / cargo fuzz smoke (per target) (push) Successful in 1m10s
    pr / nix flake check (push) Successful in 9s
    darwin / build felis (aarch64-darwin) (push) Successful in 1m38s
    pr / cargo build / clippy / test / deny (push) Successful in 5m1s
    pr / wire schema is compatible with the base (push) Successful in 5s
    windows / cargo nextest (Windows) (push) Successful in 6m28s
    pr / frontend smoke (x86_64-linux) (push) Successful in 4m26s
    windows / cargo clippy (Windows cross) (push) Successful in 32s
    release / the tag names this exact revision (push) Successful in 49s
    release / nix flake check (push) Successful in 10s
    release / package felis (aarch64-darwin) (push) Successful in 1m28s
    windows / frontend smoke (Windows) (push) Successful in 7m25s
    release / cargo nextest (Windows) (push) Successful in 3m45s
    release / cargo build / clippy / test / deny (push) Successful in 6m19s
    release / wire schema is compatible with the newest release (push) Successful in 10s
    release / frontend smoke (x86_64-linux) (push) Successful in 12s
    release / package felis (x86_64-linux) (push) Successful in 39s
    release / frontend smoke (Windows) (push) Successful in 2m7s
    release / publish the release page (push) Successful in 57s
    Stable

    natsukium released this 2026-10-20 19:07:25 +09:00 | 44 commits to main since this release

    Signed by natsukium
    SSH key fingerprint: SHA256:ByU5VseUJyH2UYFs65yNYhqJHhqJzP8BNBlvG0a6WOs

    felis v0.3.0, built from cad64428180091619514147ebcb9716471c6df88.

    Downloads

    • Linux (x86_64): felis-x86_64-linux.tar.gz. Unpack it anywhere and run bin/felis.
    • macOS (Apple silicon): felis-aarch64-darwin.tar.gz. Before the first run, clear the quarantine flag: xattr -dr com.apple.quarantine <directory>. Then run bin/felis or open felis.app.
    • Windows (x86_64): felis-x86_64-pc-windows-msvc.zip. Unpack its three executables into one directory on your PATH and run felis.exe.
    • Nix: nix run github:felis-terminal/felis/v0.3.0. The flake offers prebuilt binaries from https://nix-cache.natsukium.com.
    • Homebrew (macOS Apple silicon, Linux x86_64): brew install felis-terminal/tap/felis.

    Step-by-step instructions are in install.md.

    These three platforms are supported. ARM64 Linux (aarch64-linux) builds from source through the flake but is not supported.

    felis.proto and felis-config.schema.json are the IPC wire schema and the config schema of this build, for tools that talk to felis or validate its config.

    Changes

    Every felis crate is now on crates.io, sessions report more about what runs in them, and fonts and scrollback behave as
    on other terminals.

    • crates.io: every crate under crates/ is published, the libraries on their own versions from 0.1.0.
    • Session details: felis sessions list and felis sessions info show the directory a session was started in and
      the last OSC 9 ; 4 progress its program reported, such as cargo's.
    • Fonts: felis fonts list shows the family names font.family accepts; on macOS and Windows fonts resolve through
      the platform, and font.fallback adds to the system fallback instead of replacing it.
    • Scrollback that stays put: a window scrolled back keeps showing the same lines while the program prints, and quick
      scrolls no longer lose steps.
    • Kitty graphics: video through mpv --vo=kitty plays smoothly in a large window, and overlapping images stack in
      kitty's order.
    • Hardening: terminal replies, bracketed paste, Kitty graphics file reads and the Windows daemon pipe are tightened.

    Upgrading from 0.2:

    • felis daemon upgrade moves a 0.2 daemon to 0.3.0 in place, keeping every session.
    • Jumping to the top or bottom of the scrollback is now Ctrl+Shift+Home / Ctrl+Shift+End; see Changed to bring back
      Ctrl+Home / Ctrl+End.
    • A package that compiles the terminfo entry from a source checkout reads it from
      crates/felis-daemon/terminfo/felis.terminfo.

    Added

    • CLI: felis sessions list and felis sessions info report the directory a session's child was started in as
      spawn_cwd in --format json and as a spawned: line in info, so a session whose program never announces its
      directory with OSC 7 (a coding agent, a command spawned without a shell) still has one. It is the --cwd the session
      was created with, or the daemon's own directory when there was none.
    • Wire: protocol minor 2 adds SessionInfo.spawn_cwd. An older client skips it; a client facing an older daemon
      lists no spawn directory.
    • CLI: felis sessions list --format json and felis sessions info report the last ConEmu OSC 9 ; 4 progress a
      program in the session sent, as terminal_progress and as a progress: line in info (progress: error 71%). A new
      shell prompt clears it. felis draws nothing for it; cargo sends it with term.progress.term-integration = true.
    • Wire: protocol minor 2 adds SessionInfo.terminal_progress. An older client skips it; a client facing an older
      daemon lists no progress.
    • CLI: felis fonts list prints every family name font.family and the other family keys accept on this machine,
      with whether it is monospace and which weights and slants it has, so a name that would fall back to monospace can be
      checked before opening a window.
    • CLI: felis doctor report names the platform's per-character fallback after the fallback faces, and
      --format json adds it as fonts.system_fallback.
    • Library: a program that serves sessions from felis-daemon in its own executable can hand them the xterm-felis
      terminfo entry: felis_daemon::TERMINFO_SOURCE is the entry's source to compile with tic -x, and
      DaemonCaps::terminfo_dir names the compiled directory the daemon puts first in each session's TERMINFO_DIRS.
    • Library: every crate under crates/ is published on crates.io. The libraries carry their own versions, starting
      at 0.1.0; felis-cli, felis-client and felis-daemon carry the app version. felis itself installs from the
      packages in the install guide, which also ship the terminfo entry, desktop entry, man pages and shell completions.
    • Library: a program embedding felis-grid names itself in the XTVERSION and DA3 replies with
      Grid::set_reply_identity. With no identity set, XTVERSION goes unanswered and DA3 reports xterm's all-zero unit ID;
      felis-daemon sets felis's own.

    Changed

    • Logs: a daemon or window on a socket other than the default one logs into that socket's own 0700 directory
      instead of the user's log directory, so test and experiment daemons no longer interleave with, or rotate away, the
      real daemon's daemon.log.
    • The terminfo source moved from share/terminfo/felis.terminfo to crates/felis-daemon/terminfo/felis.terminfo; a
      package or a tic -x command that compiles it from a source checkout needs the new path.
    • Jumping to the top or bottom of the scrollback moves from Ctrl+Home / Ctrl+End to Ctrl+Shift+Home /
      Ctrl+Shift+End, as in kitty and Windows Terminal, so Ctrl+Home / Ctrl+End reach editors such as vim and nano
      again. "ctrl+home" = { kind = "scroll", step = "home" } under [keymap] (and step = "end" for ctrl+end) brings
      the old chords back.
    • On macOS and Windows, font.family resolves through the platform's font API, and a character the font misses draws
      from the face the platform picks for it, so Han takes the Japanese or the Chinese form your language list asks for. A
      symbols-only Nerd Font still comes first.
    • A font.fallback list now goes before the system's font fallback instead of replacing it, so listing one CJK font no
      longer turns emoji, symbols and other scripts into boxes. The listed fonts still win for every character they cover,
      except that a character shown as emoji by default (⭐) takes a color emoji font even when only monochrome fonts are
      listed.
    • The default font is your fixed-pitch font on macOS (Menlo unless you changed it) and Cascadia Mono on Windows.
    • A window scrolled back keeps showing the same lines while the program keeps printing, and the next scroll moves one
      line from them instead of jumping by the lines printed meanwhile; search highlights and a selection stay on their
      lines too. A resize, a cleared scrollback, a full reset, or a full-screen program starting or ending while scrolled
      back returns the window to the live bottom, and leaving a scrolled-back view clears a selection made there, since it
      no longer covers the rows on screen. The viewport messages and search hits carry the history point they count from, a
      protocol minor 2 addition; an older window keeps its frozen view, and a scroll it sends while a frame is still on its
      way can land off by that frame's output.

    Fixed

    • Video through Kitty graphics (mpv --vo=kitty) no longer stutters in a large window: the window uploads only the
      newest frame instead of every frame that arrived since its last redraw, and on a discrete GPU reuses its upload
      buffers. A 2500 × 1400 frame at 30 fps now paints every frame, where it painted about one in six.
    • When the daemon dies, open windows close without starting a new daemon on their way out. That replacement could only
      report the session gone, and on Linux, while the dead daemon's systemd unit was still shutting down, it started inside
      a window's own unit, where an out-of-memory kill of one shell later took it and every session down.
    • Scrolling faster than the window redraws no longer loses or undoes steps: two quick line scrolls move two lines, a
      scroll right after jumping to the bottom moves up from the bottom, and typing right after scrolling up returns to the
      prompt. The window sends each scroll as a step the daemon applies to its own view, a protocol minor 2 addition;
      against an older daemon the window scrolls as before.
    • A program asking for a palette color (OSC 4 ; n ; ?) now gets the color the window paints from [theme.palette] and
      [theme.palette.indexed], not the stock xterm one, so a program that picks readable colors from the palette picks
      against what you see. The window sends its palette in the theme report, a protocol minor 2 addition; against an older
      daemon or window, queries answer the stock palette as before.
    • After a full reset (ESC c, reset), color queries keep answering the window's configured colors and light/dark
      preference instead of xterm white, a window stops painting the colors the program had set and shows the default mouse
      pointer again, and pixel-size reports keep the window's size.
    • In the legacy encoding a session starts in, Ctrl+Space now sends NUL and Ctrl+Backspace sends BS, Ctrl+2 through
      Ctrl+8, Ctrl+/ and Ctrl+? send xterm's control bytes, and Alt keeps the case Shift gave a letter (Alt+Shift+B
      sends ESC B), so Emacs C-SPC, readline M-B and a shell's Ctrl+Backspace word delete receive the key they bind.
    • Overlapping Kitty graphics images at the same z= now draw, as in kitty, in the order they were created, where
      sending an image again under its id keeps its place, and one image's placements draw in the order they were first put;
      a window that reattaches draws them in the same order. The protocol minor is 2: ImageNew.serial and
      ImagePlacement.serial carry the two orders.
    • A Kitty graphics image drawn through Unicode-placeholder cells now sits between the cell backgrounds and the text,
      whatever z= it was placed with, as in kitty. An image re-sent under the same id disappears until the new data has
      arrived, rather than showing the old picture meanwhile.
    • XTGETTCAP, OSC 52, and OSC 99 replies no longer repeat query bytes outside the protocol's alphabet: an undecodable
      XTGETTCAP cap name is answered empty, and an OSC 52 selector or OSC 99 i= with such a byte gets no reply.
    • On Windows, a client refuses a daemon pipe whose server runs as another user before sending anything, as the Unix
      dialer already did with the listener's uid.
    • A Kitty graphics t=t transmission deletes its file only when the file sits under /tmp, /dev/shm, or $TMPDIR
      and its path contains tty-graphics-protocol, as kitty does; any other path is read and left in place.
    • Kitty graphics t=f and t=t refuse a path under /proc, /sys, or /dev (other than a file under /dev/shm)
      before opening it, and a FIFO without waiting on it, as kitty does. Once a t=f, t=t, or t=s command passes the
      checks on its own bytes, every failure, data that does not decode included, answers EBADF:Failed to read image file
      instead of a code naming the cause.
    • A bracketed paste drops every control byte but tab, LF, and CR before framing, as xterm and kitty do, so pasted text
      can no longer end the bracket early.
    Downloads