verso

Terminal EPUB reader · macOS & Linux

Read like you edit.

verso opens your library in the terminal, moves with the vim motions your hands already know, and turns the passages you mark into Markdown your notes app already understands. One static binary. No network, no telemetry, no daemon.

brew install romankhadka/tap/verso
verso — ~/Books
Click the window, then press j j/k page ]]/[[ chapter v then y highlight / search :toc :hl :export q library ? F1 help

The point

A passage in the terminal. A note in your vault.

Other terminal readers stop at reading. verso treats the highlight as the product: every one you take is stored with its surrounding context in SQLite, and :export projects the lot into a single Markdown file with YAML frontmatter — the shape Obsidian, Logseq and Zotero all already read.

The database is the source of truth and the Markdown is a projection, so re-running the export is always safe — it overwrites, never appends duplicates.

  1. Press v in the reader. The status line shows [VIS].
  2. Move with the same motion keys to extend the selection.
  3. Press y to yank it. verso stores the text plus ~80 characters either side.
  4. Run :export — or verso export book.epub from your shell.

Written to ~/Books/highlights/<slug>.md. The panel opposite is a port of the same renderer the binary ships. Highlight a passage in the demo above and it swaps this example for yours.

~/Books/highlights/the-time-machine.md example

        

Motions

Your hands already know this

Every binding is the one you would guess, and every one of them is rebindable in ~/.config/verso/config.toml. Bind a chord that collides with an existing prefix and verso refuses to start rather than silently swallowing a key.

jk· ↓ ↑

Move down or up one page.

spacef·b

Page forward, page back.

du· ^d ^u

Half a page at a time.

gg·G

First page, last page.

]]·[[

Next or previous chapter in the spine.

/?·nN

Search forward or back; jump between matches. Wraps at the ends.

vtheny

Visual select, then yank the passage as a highlight.

ma·'a

Set and jump to named marks, az, saved between sessions.

H·:hl

Highlights panel — jump to one, or delete it.

:toc

Jump anywhere: a floating list of the whole spine.

gt·z=

Cycle theme (dark → sepia → light) and column width (55 / 68 / 80).

q·F1

Back to the library; open the help overlay.

Durability

Highlights that survive the book changing

A highlight pinned to a byte offset dies the moment you replace the EPUB with a corrected edition. verso stores about eighty characters of context on either side of every passage and re-finds it on load.

Three outcomes, and verso tells you which one you got rather than quietly guessing. Ok — the passage was found exactly where the context says it should be. Drifted — the surroundings moved but a best-fit match was found, so the highlight still points somewhere sensible. Lost — the text is gone from the new edition.

Even a lost highlight keeps the words you captured. You lose the ability to jump to it in the book; you never lose the note. Both states are visible in the :hl panel and tagged in the exported Markdown as *(drifted)* or *(lost)*.

Try it: the panel opposite holds one highlight from chapter I. Re-import an edited edition and watch what happens to it.

the-time-machine.epub · edition 1 ok
Anchored on ±80 characters of context.

Scope

What it is, and what it is not

v1 does one format properly rather than four badly. Here is the whole truth about the edges, so nothing surprises you after you install it.

EPUB only, for now

PDF lands in v1.3, MOBI and AZW3 in v2.2 by way of Calibre's ebook-convert. Cover images and a grid view arrive in v1.2.

Text only, any terminal

No Kitty, Sixel or iTerm2 graphics protocol required — v1 renders text, so it works over SSH and in tmux. Cover rendering is opt-in later.

No network. At all.

Nothing is fetched, nothing is reported. No accounts, no sync in v1, no telemetry ever. Your library is a folder and one SQLite file.

No DRM removal

Out of scope permanently. Strip DRM from your own purchases with your own tools before importing.

One binary, no runtime

Static Rust. No Node, no Python, no daemon left running, nothing in your login items.

Sync is a v2 problem

Progress and highlights stay on the machine that made them until git-backed sync lands in v2.0.

3,557lines of Rust across 50 files
60tests, green on Linux and macOS
0network calls, ever
1static binary to install
4prebuilt targets per release

Install

Two commands, then drop in an EPUB

Pick a route. Then make a folder, put a book in it, and run verso — that is the whole of the onboarding.

Recommended

Homebrew

macOS and Linux, and the route that keeps itself updated.

brew install romankhadka/tap/verso

Rust toolchain

crates.io

The crate is published as verso-reader — the name verso was already taken. The installed binary is still verso.

cargo install verso-reader

No toolchain

Prebuilt binary

Every v* tag attaches macOS (Intel and Apple Silicon) and Linux musl (x86_64 and aarch64) builds. Extract it and put verso on your PATH.

Latest release

Then

First run

Drop EPUBs into the folder and launch. The library rescans on filesystem changes, so a book added from another terminal appears in about half a second.

mkdir -p ~/Books && verso

Requires a UTF-8 terminal — any modern one will do. Configuration is entirely opt-in at ~/.config/verso/config.toml; the database lives at ~/.local/share/verso/verso.db. Licensed MIT or Apache-2.0, your choice.