verso-reader 0.1.0

A terminal EPUB reader with vim navigation, a Kindle-style library, and Markdown highlight export
Documentation

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

cargo install verso

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

mkdir -p ~/Books
cp some-book.epub ~/Books/
verso

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.

  • ma sets bookmark a at the current page. Any letter az.
  • 'a jumps back to bookmark a.

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.
  • n jumps to the next match; N to 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:

  1. Press v to enter visual mode (status line shows [VIS]).
  2. Move with the same motion keys to extend the selection.
  3. Press y to 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:

verso export ~/Books/dune.epub
# 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
---

## Chapter 4

> A beginning is the time for taking the most delicate care that the
> balances are correct.

**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

verso scan            # rescan the library folder explicitly (rare; the app does this on launch)
verso config          # print the effective merged config as TOML
verso purge-orphans   # permanently remove soft-deleted books and their notes (asks first)
verso open <path>     # open a single EPUB without going through the library
verso --help

Configuration

verso reads ~/.config/verso/config.toml if present. All settings have sensible defaults — the file is purely opt-in.

[library]
path          = "~/Books"
export_subdir = "highlights"
watch         = true            # rescan on filesystem changes

[reader]
column_width  = 68              # 55 / 68 / 80
theme         = "dark"          # dark / sepia / light
chrome        = "autohide"      # autohide / full / minimal
chrome_idle_ms = 3000
wpm           = 250             # used to estimate "time left" in the library
code_wrap     = "scroll"        # scroll / wrap (for <pre> blocks)
min_term_cols = 40
min_term_rows = 10

[keymap]
# 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", "]]").
"move_down"       = ["j", "<Down>"]
"quit_to_library" = "Q"
"toggle_theme"    = ["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).