-
v0.2.0
StableAll checks were successfulpr / nix flake check (push) Successful in 9sdarwin / detect relevant changes (push) Successful in 8swindows / detect relevant changes (push) Successful in 10sdarwin / darwin docs-only no-op (push) Has been skippedwindows / windows docs-only no-op (push) Has been skippeddarwin / build felis (aarch64-darwin) (push) Successful in 1m35spr / cargo build / clippy / test / deny (push) Successful in 1m45spr / wire schema is compatible with the base (push) Successful in 4swindows / cargo nextest (Windows) (push) Successful in 3m7spr / frontend smoke (x86_64-linux) (push) Successful in 2m1swindows / cargo clippy (Windows cross) (push) Successful in 16srelease / the tag names this exact revision (push) Successful in 40swindows / frontend smoke (Windows) (push) Successful in 1m57srelease / package felis (aarch64-darwin) (push) Successful in 58srelease / nix flake check (push) Successful in 1m27srelease / cargo nextest (Windows) (push) Successful in 2m48srelease / cargo build / clippy / test / deny (push) Successful in 2m9srelease / wire schema is compatible with the newest release (push) Successful in 12srelease / frontend smoke (x86_64-linux) (push) Successful in 10srelease / package felis (x86_64-linux) (push) Successful in 30srelease / frontend smoke (Windows) (push) Successful in 1m55srelease / publish the release page (push) Successful in 15sreleased this
2026-10-14 11:37:33 +09:00 | 186 commits to main since this releasefelis v0.2.0, built from
d27c5ba88138912dbe2da5f6dcb63f7337c003bd.Downloads
- Linux (x86_64):
felis-x86_64-linux.tar.gz. Unpack it anywhere and runbin/felis. - macOS (Apple silicon):
felis-aarch64-darwin.tar.gz. Before the first run, clear the quarantine flag:xattr -dr com.apple.quarantine <directory>. Then runbin/felisor openfelis.app. - Windows (x86_64):
felis-x86_64-pc-windows-msvc.zip. Unpack its three executables into one directory on yourPATHand runfelis.exe. - Nix:
nix run github:felis-terminal/felis/v0.2.0. The flake offers prebuilt binaries fromhttps://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.protoandfelis-config.schema.jsonare the IPC wire schema and the config schema of this build, for tools that talk to felis or validate its config.Changes
The daemon can now replace itself with a new build without ending your sessions, and scripts and agents can do more in a
session.- In-place daemon upgrade:
felis daemon upgradereplaces the running daemon with the installed build on Linux and
macOS, keeping every session and its screen. - Mouse input from the command line:
felis sessions send --mouse click:12,4clicks, drags and scrolls in a
fullscreen program, at the cellsfelis sessions search --source visiblefinds on the live screen. - Program status: a program that reports its state over OSC 7501, such as a coding agent waiting on you, shows it in
felis sessions listandfelis sessions info. - Bug reports:
felis doctor reportprints the builds, platform, GPU, fonts and non-default config as Markdown to
paste into a report. - Fonts through fontconfig on Linux: the default face,
font.familyand the fallback order follow the host's
fontconfig. - Kitty graphics as in kitty: placement, deletion, scrolling, eviction and replies now follow kitty, and
kitten icatover ssh and yazi's previews draw whole.
Upgrading from 0.1:
- A 0.1 daemon predates the upgrade request, so restart it once after installing 0.2.0; for example,
felis daemon stop --when-emptystops it after its last session ends. - On Linux, felis now needs
libfontconfig.so.1on the host (libfontconfig1on Debian and Ubuntu).
Added
- CLI:
felis sessions send --mouse EVENT(repeatable) clicks, drags and scrolls in a fullscreen program at a
0-based cell,[MODS+]ACTION[-BUTTON]:COL,ROW(for example--mouse click:12,4), the cell numbers
search --source visiblereturns. The daemon encodes each event against the program's current mouse modes, and under
SGR-pixels (?1016) reports the middle of the cell. The verb exits1underinvalid_requestwith nothing sent when
the program has no reporting on for an event or the cell is off the grid.--keyand--mousego out in command-line
order. - CLI:
felis daemon upgradeasks the running daemon to replace its binary in place with thefelis-daemon
installed besidefelis, keeping every session. It runs on Linux and macOS; on Windows it refuses withunsupported.
A refusal leaves the daemon serving and names its reason (--format jsonputs it inerror.reason);
felis daemon stop --when-emptyremains the fallback. The verb never starts a daemon; with--hostit runs the
remote host's ownfelis daemon upgradeoverssh. - Wire: protocol minor 1 adds
Ops::UpgradeandOps::UpgradeReply, with the closed refusal enumUpgradeRefusal.
A client refuses to sendUpgradeto a minor-0 daemon, sofelis daemon upgradeagainst an older daemon exits2
withunsupported. - CLI:
felis sessions search --source visiblesearches only the live screen, including the alternate screen a
fullscreen program draws on, so itscol_spansgive the cell columns of on-screen text.--source scrollbacknames
the default, which is unchanged. The stdio bridge'ssessions.searchtakes the same values assource. - Wire: protocol minor 1 also adds
SearchQuery.sourcewith the closed enumSearchSource. A client refuses to
send a non-default source to a minor-0 daemon, which would ignore it and search scrollback, so--source visible
against an older daemon exits2withunsupported. - CLI:
felis doctornotes on thedaemonrow when the running daemon is a build other than the installed
felis-daemon, naming the installed one. - CLI:
felis doctor reportprints the doctor checklist plus the builds, OS, display server, GPU driver version,
resolved fonts, non-default config keys, and log paths as Markdown to paste into a bug report, or as JSON with
--format json. Paths under your home directory print as~, and keybinding commands and texts are redacted. - CLI:
felis doctor'sgpurow names the driver version where the backend reports one. - Protocol / CLI: programs that report their status over OSC 7501 (experimental, spec revision 0.4) show it in
felis sessions list --format jsonandfelis sessions info, so a script can find the session whose program is
waiting on you. felis answers theOSC 7501 ; ?detection query and draws nothing. - Wire: protocol minor 1 adds
SessionInfo.program_status; a minor-0 client skips it as an unknown field.
Changed
CSI 14 tandCSI 16 tnow answer the text area and the cell size in pixels from the PTY's winsize, instead of
0;0.CSI 13 tandCSI 15 t(window position, screen size) still answer0;0.- Kitty graphics replies now follow kitty: only a command with a non-zero
i=orI=is answered, a delete is never
answered even when it fails, a query is answered only when it carriesi=, and a malformed escape or an unknowna=
is dropped without a reply. A command with bothi=andI=is refused withEINVALbefore it runs. Ani=0or
I=0is the same as no id, soa=t,i=0stores an anonymous image instead of failing. Error codes match kitty's: a
t=f/t=t/t=ssource that cannot be read isEBADF(wasEIO), PNG data that does not decode isEBADPNG(was
EBADF), bad base64 or zlib data isEINVAL(wasEBADF), and raw pixel data shorter thans=×v=isENODATA
(wasEINVAL). - On Linux, fonts are chosen by the host's fontconfig: the default face is
fc-match monospace,font.familyand the
[font.bold]/[font.italic]families resolve through it (sofonts.confaliases apply), and withfont.fallback
unset the fallback order is fontconfig's ranked list for the primary, following its prefer lists, per-language rules
and rejected fonts and the locale's language. A text-presentation symbol takes a monochrome face before an
earlier-ranked color one. Bitmap (PCF, BDF) and Type 1 faces that fontconfig lists are left out, so a family with only
such faces counts as not installed. felis now needslibfontconfig.so.1on the host (libfontconfig1on Debian and
Ubuntu). - A
font.fallbacklist longer than 62 entries keeps the first 62, with a warning.
Fixed
- A new session's program sees the window's size from its first
TIOCGWINSZ; it used to see 24 × 80 until the resize
that followed the spawn landed. - On macOS, a session's shell no longer inherits the PTY master of a session created at the same moment.
- A Textual app with mouse support no longer crashes on its first click. The
?2048resize report now carries the PTY's
pixel extents instead of0, and reports a change of those extents alone; a session no window has sized gets 8 × 16
pixels per cell in its winsize and in the report. - A
felisverb piped into a reader that quits early (felis sessions capture <id> | head -1) no longer panics with
"failed printing to stdout: Broken pipe". It stops at that write and exits0. - A
felis bridgestream canceled by acancelop or by closing stdin no longer ends with a cleanendwhosecount
claims items it never wrote. Items that reach the bridge after the cancel are dropped, and the cleanendnow counts
only the item lines that preceded it. - A
pipeorrunkeybinding no longer gets refused with "this pipe/run visit still owes a return" on a session that a
runcommand switched the window to (a session picker runningfelis sessions switch, say). The refusal used to hold
until some other switch moved the window. - A Kitty graphics placement with only
c=or onlyr=now keeps the image's aspect ratio, as kitty does: the other
axis follows from the given one, and the image draws at that size instead of stretching to a box whose missing axis
came from the image's own size. - Searching a long soft-wrapped line with many matches (
felis sessions search, the search overlay) no longer stalls
the session: mapping each match to screen columns rescanned every row of the line, so a grid-sized line held the
session's lock, and froze its output, for billions of steps. - A case-insensitive search without
--regex(felis sessions search --case-insensitive, the search overlay) now
reportsbyte_spansandcol_spansat the match itself on a line where a character before it changes length when
lowercased, such asİor the Kelvin sign; they used to land shifted, sometimes past the end of the text. - Clearing the screen now treats Kitty graphics images as kitty does.
ED 2(clear),DECSED 2andRISdrop every
placement on the screen,C=1ones included, andED 3drops scrollback placements too; each then frees every image
nothing displays, so transmitted-but-unplaced images no longer pile up until the byte cap evicts them. Partial erases
(ED 0,ED 1,EL) and the soft resetDECSTRno longer remove images, so redrawing one line next to an image
keeps it. - A Kitty graphics image sent without
i=orI=is now freed once a delete or a scroll leaves it without a placement,
as in kitty; nothing could display it again, yet it used to hold its share of the byte cap until evicted. - When Kitty graphics images fill the session's byte cap, felis now evicts as kitty does: every image without a
placement first, then the least recently transmitted or placed. It used to evict strictly in transmit order, so an
image redrawn a moment ago could go before a stale one. - A Kitty graphics Unicode-placeholder cell colored with a 256-color foreground (
\e[38;5;Nm) now shows imageN, as
kitty does; only a 24-bit foreground used to name the image. - A Kitty graphics Unicode-placeholder cell with the default foreground no longer borrows the image id of the cell
before it; as in kitty its foreground counts as0in the id. A cell without the id's high-byte diacritic now takes
it from its run. - Kitty graphics file (
t=f) and temp-file (t=t) transmissions now read theS=bytes at offsetO=, as kitty does;
they used to read the whole file. - A reply to a Kitty graphics frame command (
a=f) now echoes itsr=, as kitty does. - A Kitty graphics placement with only some of
x,y,w,hnow crops as kitty does:xandydefault to 0 and
wandhto the image's size. It used to draw the whole image unless all four were given. - A Kitty graphics placement whose image was evicted in the same burst that placed it no longer lingers in the window.
- Kitty graphics images inside a scroll region (
DECSTBM) now scroll with its text, as in kitty, and so do images on a
reverse scroll (RI,SD). An image the scroll pushes partly past a margin is cut off there, and one pushed wholly
out of the region is removed. They used to stay put while the text moved under them. - The alternate screen now has a Kitty graphics image store of its own, as in kitty. A full-screen program can no longer
free the images on the shell screen it covers, whether by clearing its screen, deleting by id range, or filling the
byte cap, and an image it sends with an id the shell already used no longer replaces the shell's image. Leaving the
alternate screen with?47lkeeps its images along with its text for the next?47h, as in kitty. - Kitty graphics Unicode-placeholder placements of one image now stay apart by
p=, and a placeholder cell picks its
placement by its underline color, as in kitty; felis kept one per image, so a second placement resized the first's
tiles.d=i/I,d=n/N,d=r/Rand transmitting the image again now remove its placeholder placements too. - Kitty graphics image numbers (
I=) now work as in kitty. Each transmission withI=stores a new image under a free
id and answersi=<id>,I=<number>; a put or animation command byI=acts on the newest image with that number; and
thed=n/d=Ndeletes are supported. felis used to take the number as the image id, so a second transmission with
the same number replaced the first. - A Kitty graphics image shown through Unicode-placeholder cells now keeps its aspect ratio, centered in the placement's
c=byr=box, as kitty does; it used to be stretched to fill the box. - A Kitty graphics
d=aord=Adelete now leaves Unicode-placeholder images and images scrolled wholly into history
in place, as kitty does. It used to drop placeholder images in the daemon without telling the window, so they vanished
once the window reattached. - A Kitty graphics put, delete, compose or animation command sent while a chunked (
m=1) transmission is open now runs
at once, as kitty does; it used to be taken as the transmission's last chunk. A delete drops the open transmission;
the others leave it open. A non-zeroq=on a later chunk now overrides the first chunk's. - Placing the same Kitty graphics image twice without a placement id now shows two copies, as kitty does; the second put
used to move the first. A reply no longer echoesp=0. - Sending a Kitty graphics image again under the same id now removes its old placements, as kitty does; they used to
stay on screen showing the new pixels. - Deleting one placement of a Kitty graphics image with an uppercase delete (
d=Iwithp=, ord=P/Q/X/Y/Z/
C/R) now keeps the image while other placements still show it, as kitty does; it used to free the image and orphan
them. kitten icat --transfer-mode=stream, the mode icat uses over ssh, now shows its images. felis cut every Kitty
graphics command at 8 KiB, while kitty's own client sends up to 128 KiB at once; the limit is now kitty's 256 KiB.- An image that a program places one cell at a time, as yazi's previewer does, now draws whole. Past the first 64
placements in one write, the rest were dropped and the bell rang, leaving only a few strips of the image. - A program repeating Kitty graphics puts no longer grows the daemon and every attached window without bound. Each
screen keeps at most 16384 placements, and a put past that removes the oldest one.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Linux (x86_64):