verso
A terminal EPUB reader with vim navigation, a Kindle-style library, and first-class Markdown highlight export to Obsidian / Logseq / Zotero.
Status: v1 (EPUB only). PDF, MOBI, covers, and sync arrive in later releases — see the Roadmap section below.
Why verso?
Existing terminal e-readers (epy, bk, baca, bookokrat) are either stale, EPUB-only without real note workflows, or Kitty-locked PDF viewers. verso fills the gap for the technical reader who lives in the terminal and takes notes in a PKM app: open a book in two keystrokes, move with vim motions, highlight a passage, get a Markdown file with YAML frontmatter you can drop straight into your vault.
Single static binary. No daemons, no telemetry, no network. Your library
lives in a folder on disk and a single SQLite file in ~/.local/share/verso/.
Install
Pre-built binaries for macOS (Intel + Apple Silicon) and Linux (musl,
x86_64 + aarch64) are attached to GitHub Releases for every v* tag.
Requirements: a terminal that handles UTF-8 (any modern terminal — verso does not require Kitty or Sixel in v1; it intentionally renders text only).
Quickstart
That's the whole onboarding: drop EPUBs into ~/Books/ (or whatever folder
you've configured), run verso, and the library appears.
Usage guide
1. The library view
Run verso with no arguments. You'll land on a dense table of every EPUB
under your watched folder:
┌─ verso · Library · 7 books · 3 ─────────────────────────────────────────┐
│ Title Author Pages Progress Left Last │
├─────────────────────────────────────────────────────────────────────────┤
│ ▸ Dune F. Herbert 688 ████░░ 12% 9h 2h │
│ SICP Abelson 657 ██████ 47% 11h 3d │
│ Zero to One ✓ P. Thiel 224 ██████ 100% — 60d │
│ Pragmatic Programmer Hunt & Tho. 320 ██░░░░ 23% 4h 5d │
│ Deep Work C. Newport 304 ░░░░░░ 0% — — │
└─────────────────────────────────────────────────────────────────────────┘
Library keys:
| Key | Action |
|---|---|
j / ↓ |
Select the next row |
k / ↑ |
Select the previous row |
enter |
Open the highlighted book in the reader |
s |
Cycle sort: last-read → title → author → progress → added |
f |
Cycle filter: all → reading → unread → finished → broken |
d |
Toggle a floating detail pane for the highlighted row |
q |
Quit verso |
The detail pane (d) shows file path, added date, finished date, parse
errors, and per-book counts of bookmarks and highlights. Esc or d again
closes it.
The library auto-rescans on filesystem changes — drop an EPUB into
~/Books/ from another terminal and it appears within ~500 ms with no
restart.
2. Reading a book
Press enter on a row. The reader opens on the first chapter with
auto-hiding chrome (a thin status line at the bottom). The full book is
available — ]] and [[ step through spine items and the :toc command
opens a jump-anywhere modal. Move with familiar vim motions:
| Key | Action |
|---|---|
j / ↓ |
Scroll down one page |
k / ↑ |
Scroll up one page |
<Space> / f / <C-f> |
Page down |
b / <C-b> |
Page up |
d / <C-d> |
Half page down |
u / <C-u> |
Half page up |
gg |
Jump to the first page of the chapter |
G |
Jump to the last page of the chapter |
]] / [[ |
Next / previous chapter |
gt |
Cycle theme: dark → sepia → light |
: |
Open the command prompt (see below) |
q |
Quit back to the library |
The chrome fades after 3 seconds of no input. Any keypress brings it back.
3. Bookmarks (m / ')
verso supports vim-style named marks per book.
masets bookmarkaat the current page. Any lettera–z.'ajumps back to bookmarka.
Bookmarks persist across sessions in SQLite and are tied to the book by its stable identifier — they survive renames and even content edits where re-anchoring succeeds.
4. Search (/foo, n, N)
/enters a forward-search prompt; type your query and press<Enter>.?enters a backward-search prompt.<Esc>cancels the prompt.njumps to the next match;Nto the previous.
Search is case-insensitive across the current book's plain text. The match cursor wraps at the ends.
5. Highlights (v, y)
Highlights are the differentiator. The flow:
- Press
vto enter visual mode (status line shows[VIS]). - Move with the same motion keys to extend the selection.
- Press
yto yank the selection as a highlight.
Each highlight stores the text, ~80 characters of context before and after, the spine item, and the chapter title. That context is what allows verso to re-anchor highlights when the EPUB file changes — e.g. you re-import a corrected edition. Drifted highlights surface in the highlights panel; lost ones keep their text but lose their pinned location.
<Esc> or another v exits visual mode without yanking.
6. The command prompt (:, :toc, :hl, :export, :w, :q)
Press : to open a single-line command prompt at the bottom. Type a
command name, press <Enter>, and <Esc> cancels.
| Command | Action |
|---|---|
:toc |
Jump-anywhere: floating list of every chapter in the spine. |
:hl |
Highlights panel for the current book (jump / delete). |
:export |
Write ~/Books/highlights/<slug>.md for the current book. |
:w |
Force an immediate progress write (bypasses the 5s debounce). |
:q |
Quit back to the library (same as q in Normal mode). |
In the :toc modal: j/k (or ↑/↓) move, <Enter> jumps, q/<Esc>
closes. In :hl: same movement; <Enter> jumps to the highlighted passage
(loads the right chapter and seeks to the character offset), d deletes
the selected highlight, q/<Esc> closes. Inline note editing arrives in
v1.1.
7. Exporting highlights to Markdown
Either :export inside the reader (shows a toast with the written path)
or the CLI subcommand:
# wrote /Users/you/Books/highlights/dune.md
The output is Obsidian / Logseq / Zotero-friendly Markdown with YAML frontmatter:
title: Dune
author: Frank Herbert
published: 1965
exported: 2026-04-20T14:32:00Z
source: /Users/you/Books/dune.epub
**Note:** Irulan's epigraph — thematic through-line about initial conditions.
Drifted highlights are tagged *(drifted)*; lost ones get *(lost)*.
Re-running verso export overwrites the file (the SQLite DB is the
source of truth, the Markdown is a projection).
8. Other CLI subcommands
Configuration
verso reads ~/.config/verso/config.toml if present. All settings have
sensible defaults — the file is purely opt-in.
[]
= "~/Books"
= "highlights"
= true # rescan on filesystem changes
[]
= 68 # 55 / 68 / 80
= "dark" # dark / sepia / light
= "autohide" # autohide / full / minimal
= 3000
= 250 # used to estimate "time left" in the library
= "scroll" # scroll / wrap (for <pre> blocks)
= 40
= 10
[]
# Override any binding. Each action maps to one or more key sequences.
# A sequence is a single key ("j"), a named key ("<Down>", "<Enter>", "<Esc>"),
# a Ctrl-chord ("<C-d>"), or a chord of two single keys ("gg", "]]").
= ["j", "<Down>"]
= "Q"
= ["gt", "<F5>"]
Conflicting chord prefixes (e.g. binding g while gg is also bound)
fail at startup with a helpful message. Unknown action names also fail
loudly. See docs/keymap.md for the full action catalog.
Where verso keeps its files
| What | Path |
|---|---|
| Library books | ~/Books/ (or wherever you configure) |
| Highlight exports | ~/Books/highlights/ |
| Database | ~/.local/share/verso/verso.db |
| Config | ~/.config/verso/config.toml |
| Logs (rotated) | ~/.local/state/verso/log/verso.log.* |
(macOS uses ~/Library/Application Support/verso/... for the data and
state dirs by way of XDG conventions.)
Troubleshooting
The library is empty even though I have EPUBs in ~/Books/.
verso scans on launch, but parse errors are reported (and surfaced under
the broken filter — press f to cycle to it). Check
~/.local/state/verso/log/verso.log.YYYY-MM-DD for details.
My terminal is too small.
Below 40 cols × 10 rows, verso pauses rendering with a banner. Resize
the terminal or set lower thresholds in [reader].
Highlights aren't following my book after I re-imported an edited copy.
verso re-anchors using ±80 chars of context. If the surrounding
paragraph changed too much, the highlight is marked drifted (best-fit
match) or lost (text not found). Both are visible in :hl. Lost
highlights still keep their captured text — you don't lose the note.
Set VERSO_LOG=debug to get verbose logs without rebuilding.
Keymap reference
The full action catalog with default bindings, key-sequence grammar, and
rebinding examples lives in docs/keymap.md.
A short summary: j k gg G ]] [[ / ? n N v y ma 'a gt z= : q, plus
:toc, :hl, :export, :w, :q at the command prompt.
Roadmap
| Release | Adds |
|---|---|
| v1.1 | ASCII cover thumbnails. Per-user wpm calibration. |
| v1.2 | Cover images (Kitty / Sixel / iTerm2) + grid view. Calibre import. |
| v1.3 | PDF support (MuPDF rasterise + text-extract toggle). |
| v2.0 | Git-backed sync of progress + highlights across machines. |
| v2.1 | OPDS catalogue browser. |
| v2.2 | MOBI / AZW3 import via Calibre's ebook-convert. |
DRM removal is and will remain out of scope. Run DeDRM on your own files before importing.
Contributing
Pull requests welcome. CI runs cargo fmt --all -- --check,
cargo clippy --all-targets -- -D warnings, and cargo test --all on
ubuntu and macos. Please keep both gates green and add tests for
behavioural changes.
Licence
MIT OR Apache-2.0 (your choice).