- Rust 97.3%
- Shell 1%
- Nix 0.8%
- Python 0.5%
- WGSL 0.2%
- Other 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
fuzz / cargo fuzz nightly long-run (push) Has been skipped
pr / cargo check (MSRV) (push) Waiting to run
build / build and cache felis (macos) (push) Has started running
build / build and cache felis (nix) (push) Successful in 5m57s
fuzz / cargo fuzz smoke (per target) (push) Successful in 1m42s
pr / nix flake check (push) Successful in 15s
pr / cargo build / clippy / test / deny (push) Failing after 1m26s
pr / generated code is current (push) Successful in 2s
pr / cargo check (Windows cross) (push) Has started running
`felis-web-core` became two repos: `felis-web-component` (the wasm core plus the `<felis-terminal>` view) and `felis-web-gateway` (the native attach that re-exposes a session over a WebSocket). felis's own docs and comments named one thing where there are now two, so every reference is re-pointed at whichever half it actually meant. Which half matters more than the rename does. `felis-grid::transcode`'s wire→JSON consumer is the gateway, not the browser; the "two downstream repos" the transcode was adopted for are now `felis-web-gateway` and `felis-fcast`; the workspace table's "Bridge required" column was describing the gateway without naming it, and now names it. One correction found along the way, unrelated to the split: `connect_with_encoding`'s doc named "the felis-web-core `.fcast` recorder" as its JSON-consuming caller. The recorder has lived in `felis-fcast` since that repo was carved out; the doc had simply not followed. Comments and prose only — no code, and nothing here builds differently. Assisted-by: Claude Code Opus 5 |
||
| .cargo | ||
| .claude | ||
| .config | ||
| .forgejo/workflows | ||
| crates | ||
| docs | ||
| fuzz | ||
| nix | ||
| scripts | ||
| share/terminfo | ||
| skills/felis | ||
| .gitignore | ||
| buf.gen.yaml | ||
| buf.yaml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| clippy.toml | ||
| deny.toml | ||
| flake.lock | ||
| flake.nix | ||
| justfile | ||
| LICENSE | ||
| README.md | ||
| rustfmt.toml | ||
felis
felis is a terminal that redraws the boundary of what a terminal is responsible for. Written in Rust, it draws on kitty for protocol fidelity, alacritty for simplicity, and Kakoune for design discipline.
State lives in a long-running daemon; the client owns only the window. Closing the window keeps the shell running, and the next client — local or across SSH — picks up exactly where the last one left off.
Quick start
felis ships from a Nix flake, so the fastest path needs only the Nix package manager with flakes enabled — no manual toolchain setup, no separate daemon to start.
# Try it without installing anything.
nix run git+https://git.natsukium.com/natsukium/felis
# Or install it to your profile, then just run `felis`.
nix profile install git+https://git.natsukium.com/natsukium/felis
felis
Launching felis opens a window and auto-spawns the background
daemon off $PATH — there is nothing else to start. Close the
window and your shell keeps running; the next felis reattaches
exactly where you left off.
From there:
- Persistent sessions — close the window, then
felis sessions listandfelis attach <id-prefix>to pick a detached shell back up. - Cross-host —
felis --host user@remoteopens a window backed by a remote daemon over plain SSH, orfelis ssh user@remotere-points the window you are in at that daemon (andfelis ssh --localbrings it back). - Scripting —
felis sessions {list, info, send, capture, search, spawn, kill}drives the daemon from shell scripts; see CLI and automation.
The end-user manual — install, getting started, configuration,
keybindings, CLI reference, troubleshooting — is published at
https://felis-docs.pages.dev and maintained in this repository
under docs/, organized on the
Diátaxis map (tutorials, how-to guides,
reference, explanation).
Prefer to build from source or hack on felis? See Building from source.
Features
- Persistent sessions. Closing the client window does not kill
the shell;
felis attach <id-prefix>rehydrates a detached one, and chords cycle or spawn sessions in-window (keybindings). - Cross-host attach over SSH.
felis --host user@remoteopens a window backed by a remote daemon — frames ride plain SSH stdio (ssh <host> felis-daemon relay), no listening network service and no auth layer beyond SSH itself. - CLI for scripted automation.
felis sessions {list, info, send, capture, spawn, search, kill}with first-class--json— see CLI and automation. - Scrollback search.
felis sessions search <id> <pattern>greps your session's history; in-window, Ctrl+Shift+F opens a search bar with highlighted matches andn/Nnavigation. - Modern terminal protocols. True colour, italics, the xterm underline range (curly / dotted / dashed, with underline colour), OSC 8 hyperlinks, mouse SGR, bracketed paste, focus tracking, synchronized output, the Kitty keyboard protocol, OSC 133 semantic prompts, Kitty graphics (animation and shared memory included) and text sizing.
- Real text shaping. Per-codepoint font fallback (CJK + symbols +
colour emoji + Nerd Font), opt-in OpenType features / ligatures,
platform-native IME (AppKit /
zwp_text_input_v3/ TSF / XIM), live font zoom with Ctrl+Wheel. - Familiar selection and scrolling. Linear / rectangle / word / line selection with xterm gestures; Linux PRIMARY auto-copy and middle-click paste (the gesture table).
- Hot config reload. Edit the config and save; theme and font changes apply without restarting the daemon or losing scrollback.
Configuration
One TOML file at the platform-native path, hot-reloaded on save
(and on Ctrl+Shift+R). Every field — font, theme, palette,
cursor, clipboard, window, keymap — is documented with its defaults
and failure behaviour in
the configuration page; the default chord
table and the deliberately-unbound session actions are in
keybindings. A generated JSON Schema
gives TOML-aware editors completion and validation.
Install with Nix
nix run / nix profile install above are the whole story for a
quick try. For a managed setup the flake also exposes the package,
a home-manager module (installs the binaries, writes config.toml
from Nix, wires TERMINFO_DIRS), and a
Stylix hook that drives the
palette, font, and background opacity from the active scheme — all
documented on the install guide.
CLI and automation
felis sessions <verb> exposes every IPC operation a daemon
accepts as a typed shell command — list, info, spawn, send,
capture, search, kill — with --json on every read verb and
exit codes under contract (0 ok, 1 operation-domain failure,
2 no daemon / protocol error). Common patterns — pre-warming a
session, grepping scrollback, snapshotting for a bug report,
reaping stale sessions, editor integration — are collected in
the how-to guides with the verb
table in the CLI reference; the full surface
contract and the wire it rides live in
docs/reference/ipc.md, which
cross-language clients can speak directly.
Status
felis is a prototype, and runnable as one.
Works today:
- Day-to-day shell + editor use. neovim, helix, lazygit, fish, fzf, and similar TUIs behave correctly: mouse, focus tracking, bracketed paste, OSC 8 hyperlinks, OSC 133 semantic prompts, the Kitty keyboard protocol, synchronized output, true colour, italics, and the full xterm underline range.
- Persistent sessions. Close the window, list with
felis sessions list, reattach withfelis attach <id>. - Cross-host attach.
felis --host user@remoteover plain SSH stdio. - CLI for scripted automation.
felis sessions {list, info, send, capture, spawn, search, kill}— see "CLI and automation" above. - Kitty graphics (yazi, mdcat, presenterm previews, mpv video):
protocol, daemon-side image store, renderer atlas, animation
(
a=a/f/c), and shared-memory transmission (t=s) all wired. - Kitty text-sizing protocol (OSC 66): renderer paints scaled multi-cell runs at integer and fractional sizes.
- Scrollback search (REQ-607): daemon-side substring + regex,
exposed via
felis sessions searchand the in-window Ctrl+Shift+F bar with highlighted matches andn/Nnavigation. - OpenType font features and programming-font ligatures, opt-in
via
font.features(defaults off so cell metrics never shift unasked). - IME on macOS / Wayland / Windows / X11; per-codepoint font fallback covering CJK, symbols, colour emoji, and Nerd-Font glyphs.
- xterm-flavoured selection, clipboard, scrollback, and font
zoom (
Cmd+*on macOS,Ctrl+Shift+*elsewhere). - Hot config reload — theme and font changes swap into the running client without restarting the daemon.
- Bidi-override visible markers (Trojan-Source protection).
Not yet (polish and backlog, not core-functionality gaps):
- Read-only attach (lifts the "session must be detached"
limitation on
felis sessions send / capture / search).
The full list of open work lives in
docs/backlog.md.
Design
felis is not defined by how many features it has — it redraws the line of what a terminal is responsible for, pulling inward what the conventional stack pushed out and pushing outward what a terminal conventionally pulls in:
- Pulled inward. Session ownership and persistence — felis's own daemon owns the PTY, grid, and scrollback, so the shell outlives the window — and full-fidelity rendering, because nothing sits between the shell and the screen to flatten Kitty graphics or text sizing.
- Pushed outward. Layout (tabs, panes, splits) to the window manager; extension to external processes over a versioned IPC, never an embedded Lua / Python / Wasm host; intent-guessing (URL detection, content sniffing, smart quoting) nowhere at all — the user's bytes stay the user's bytes.
Inside that boundary felis is maximalist — render everything, fast. At the boundary it is strict — delete before adding. No second system lives inside the terminal.
The full rationale is in docs/explanation/vision.md; the eight
non-negotiable principles, each paired with a concrete violation test, live
in docs/explanation/principles.md.
Building from source
felis is a prototype; to hack on it, build from cargo. The Nix
flake at the repo root is the single source of truth for the
toolchain (nightly Rust, the runtime libs wgpu / winit need, the
formatter, and the pre-commit hook).
# Drop into the dev shell — installs the pre-commit hook automatically.
nix develop
# Run the daemon, then the client.
cargo run -p felis-daemon -- serve &
cargo run -p felis-client
# List detached sessions and reattach by id prefix.
cargo run -p felis-cli -- sessions list
cargo run -p felis-cli -- attach <id-prefix>
# Cross-host attach over SSH.
cargo run -p felis-client -- --host user@remote
Documentation
All documentation — the end-user manual and the design docs — is
published at https://felis-docs.pages.dev and lives in this
repository under docs/ — next to the code it documents,
so it cannot rot; the
felis-docs
repository only holds the site machinery and vendors the content via
a submodule.
For contributors, docs/README.md is the entry
point. The design docs are the source of truth for every feature
decision — each records the rationale and the rejected alternatives
alongside the current design.
License
Apache-2.0. See LICENSE.