Skip to content

Repository files navigation

Grimoire Books

Warning

Pre-alpha. The initial feature set isn't finished. Schemas, APIs and screens change without migration paths or notice, and there is no authentication of any kind. Point it at a Calibre library you can afford to re-sync, and don't expose it to a network you don't trust.

A better way to organize and browse your books. Grimoire is a UI over your Calibre library and your hardcover.app shelves that runs as a native desktop app (Electrobun), a self-hosted web server, or a local web app, all from the same codebase.

The library as a wall of covers

Screenshots

Your whole library on one shelf. Filter, sort and group it, and every view is a URL you can send to someone. ⌘K searches every book from anywhere, so you never have to go find the filter box.

The command menu, searching for an author

A book you own and track is one card, not two. The flyout shows the Calibre row and the Hardcover row Grimoire matched it with, and lets you separate them if the match is wrong.

A book's details flyout, showing its Calibre and Hardcover rows

The same shelf as a table, here narrowed to what you've read and grouped by the year you finished it. Light and dark both ship.

The read shelf as a list, grouped by read year

Settings is where the sources live: point Grimoire at your Calibre content server, watch it sync, and link a Hardcover account per reader.

Settings, showing the Calibre content server and sync state

Sources

Grimoire keeps its own SQLite database and syncs into it, rather than reading a source live on every screen.

  • Calibre. Grimoire mirrors a running content server into grimoire.db, covers and all, and every library screen reads from there (ADR 0011). Calibre is still the source of truth for the files, and Grimoire never writes to it. The long-term goal is to grow Grimoire until it can replace Calibre as the backend.
  • Hardcover. The half Calibre has no idea about: what you've read, are reading, and want to read, plus editions, series and covers. Each reader links their own account with a personal API token, because a token is an account and the reading history behind it is theirs (ADR 0012). Tokens live server-side only. The browser never holds one, and Hardcover's GraphQL API refuses browser calls anyway.

A book you own in Calibre and track on Hardcover stays as two rows and renders as one card: book matching groups them under a works row (ADR 0013), and you can confirm or split a match by hand from the book's details flyout.

Grimoire supports several readers with no login between them (ADR 0008). It assumes a household, not the open internet.

Layout

apps/
  web/       React + Vite + Tailwind 4 + shadcn/ui + TanStack Router/Query — the
             UI, shared by every mode; Storybook for the components
  server/    Standalone Bun server: serves the API + built web UI (hosted mode)
  desktop/   Electrobun shell: embeds the API and loads the same UI natively
packages/
  core/      grimoire.db (Grimoire's own SQLite store) + shared Zod schemas
  api/       Hono app defining the HTTP API, embedded by server and desktop
docs/        OKF 0.2 knowledge bundle: adrs/ · features/ · workflows/ · external/

Every deployment mode speaks the same HTTP API (/api/...), so the UI doesn't care where it's running.

Requirements

  • Bun ≥ 1.3
  • A running Calibre content server. All library data comes from it, over HTTP. Start it with calibre-server, or from calibre's Preferences → Sharing over the net. Grimoire assumes http://localhost:8080 until you set a URL during first-run setup.
  • Optional: a hardcover.app API token per reader who wants their shelves in, from your Hardcover account settings. Paste it under Settings → Readers and test it before saving. Tokens expire after a year.

Development

bun install

# Web development: Vite dev server on :4746 (HMR) + API server on :4747
bun dev

# Desktop development: Vite HMR + Electrobun app window
bun run dev:desktop

# Component workshop on :4748
bun run storybook

Building / running for real

# Hosted mode: build the UI, then run the server (PORT to override :4747)
bun run build:web
bun run start:server

# Desktop app bundle
bun run build:desktop

# Self-hosted container (published releases are at ghcr.io/mikevalstar/grimoire)
docker build -t grimoire .
docker run --rm -p 4747:4747 \
  -v grimoire-data:/data \
  -e CALIBRE_SERVER=http://host.docker.internal:8080 \
  grimoire

The container runs as the unprivileged bun user, uid 1000, and writes grimoire.db plus the cover cache to /data. Docker creates the named volume above with the right ownership. A bind mount keeps the host directory's ownership, so give it to that uid first. Otherwise the container refuses to start and says so:

sudo mkdir -p /srv/grimoire && sudo chown -R 1000:1000 /srv/grimoire
docker run --rm -p 4747:4747 -v /srv/grimoire:/data grimoire

There is no PUID/PGID handling. Grimoire never needs root at runtime, and starting as root to chown and drop privileges is more machinery than a one-time chown on the host is worth.

Container environment variables:

Variable Default What it does
PORT 4747 Port the server listens on
GRIMOIRE_DATA_DIR /data Where grimoire.db and cached covers live (ADR 0007)
CALIBRE_SERVER http://localhost:8080 Fallback content server URL, until one is saved in settings

On Linux, add --add-host=host.docker.internal:host-gateway when Calibre runs on the Docker host.

Version tags matching vX.Y.Z publish Linux, Windows, and macOS desktop ZIPs, a multi-architecture GHCR image, and a GitHub Release with generated notes. See Cut a release for the release process. The desktop packages are not yet code-signed or notarized.

Other commands

bun run typecheck                  # typecheck every workspace
bun run docs:check                 # validate the docs/ OKF bundle (needs okq)
cd apps/web && bunx shadcn@latest add <component>   # add shadcn/ui components

About

UI for browsing and organizing a Calibre ebook library — desktop, self-hosted server, and local web app from one codebase

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages