Self-hosted organizer for your TTRPG content and campaigns
See the codeA self-hosted web app for your tabletop RPG library. Point it at a folder of PDFs, maps, tokens, audio, and 3D models, and Grimoire turns it into a searchable library you can read from any device - every page of every book indexed, including scanned ones.
It runs as a single Docker container against a directory you already own, and by default never writes to it.
title:, author:, tag: and friends - see Searching your library.Building AND store OR shop), and named presets save to your account with one default per view..webm/.mp4), and Universal VTT maps all display in-app; large maps load through a downscaled preview while downloads stay untouched..uvtt files on the geometry they already carry..zip. Templates belong to the campaign, so downloaded ones are yours to edit. See Wiki note templates.Grimoire is for people who have bought a lot of TTRPG material and want it in one place. If your collection is a folder of PDFs from twenty Humble Bundles and three Kickstarters, spread across a NAS and a laptop, this is the problem it solves.
It is not a store, a pirate tool, or a PDF editor. Grimoire reads a library you already have, and by default never writes to it.
Docker, a folder of TTRPG files, and somewhere to run it - a NAS, a home server, a spare mini-PC, or your desktop. It is happy on a Raspberry Pi and scales up to libraries of thousands of books.
| Systems | System detail |
|---|---|
![]() | ![]() |
| Search | Tag browser |
|---|---|
![]() | ![]() |
| Favourites | |
|---|---|
![]() |
| Book view with table of contents | In-book search |
|---|---|
![]() | ![]() |
| Maps | Tokens |
|---|---|
![]() | ![]() |
| Token editor | 3D models |
|---|---|
![]() | ![]() |
| Universal VTT map editor | Token vision preview |
|---|---|
![]() | ![]() |
| Audio page with soundboard and playlist | |
|---|---|
![]() |
| Campaign overview | Campaign notes wiki |
|---|---|
![]() | ![]() |
New to Docker? See the Docker Installation Guide for a step-by-step walkthrough for Windows, macOS, and Linux.
Create a library/ folder with this structure:
library/
├── books/
│ └── Dungeons and Dragons 5e/
│ ├── core/
│ │ ├── Players Handbook.pdf
│ │ ├── Dungeon Masters Guide.pdf
│ │ └── monsters/ ← subfolder within a category
│ │ ├── Monster Manual.pdf
│ │ └── Mordenkainen's Monsters.pdf
│ ├── supplements/
│ ├── adventures/
│ │ ├── Curse of Strahd/ ← adventure path subfolder
│ │ │ ├── Curse of Strahd.pdf
│ │ │ └── Strahd DM Screen.pdf
│ │ └── Lost Mine of Phandelver/
│ │ └── Lost Mine of Phandelver.pdf
│ ├── character-sheets/
│ ├── handouts/
│ └── homebrew/
├── maps/
│ └── Sunken Temple (22x22)/
│ ├── Sunken Temple Basement.png
│ └── The Sunken Temple.png
├── tokens/
│ └── Monsters/
│ └── goblin.png
├── audio/
│ └── Ambient/
│ ├── cover.jpg
│ └── tavern-night.mp3
└── models/
└── Goblins/
├── Presupported/
│ └── goblin-archer.stl
└── Unsupported/
└── goblin-archer.stl
See Library structure for the full layout, category rules, and the marker files that group systems together.
Copy the default compose file, set your volume paths, then start:
cp docs/docker/docker-compose.yml docker-compose.yml
# Edit docker-compose.yml and set the volume paths
docker compose up -d
open http://localhost:9481
On first launch you'll be prompted to create an admin account, or you can pre-seed users automatically (see Pre-seeding users).
docker pull hunterreadca/grimoire:latest
Or pin to a specific release:
docker pull hunterreadca/grimoire:1.5.0
Image variants: the default tags (latest, 1.5.0, …) include the Tesseract OCR engine so image-only PDFs are searchable (see OCR). If you don't need OCR and prefer a smaller image, use the matching -slim tag (e.g. hunterreadca/grimoire:latest's slim counterpart :slim, or a pinned :1.5.0-slim), which omits Tesseract.
docker-compose.ymlservices:
grimoire:
image: hunterreadca/grimoire:latest
ports:
- "9481:9481"
volumes:
- /path/to/your/library:/app/library # add ":ro" to keep it read-only (see Volumes)
- /path/to/grimoire/data:/app/data
Ready-to-use compose files for common setups are in docs/docker/:
| File | What it runs |
|---|---|
docs/docker/docker-compose.yml | Grimoire (default, no extras) |
docs/docker/docker-compose.valkey.yml | Grimoire + Valkey page cache (recommended for large libraries) |
docs/docker/docker-compose.calibre.yml | Grimoire + Calibre full desktop (metadata editing, OPF export) |
docs/docker/docker-compose.calibre-web.yml | Grimoire + Calibre-Web (lightweight Calibre browser UI) |
Each file has inline comments explaining the options. Copy and edit the one that fits your setup:
cp docs/docker/docker-compose.valkey.yml docker-compose.yml
# Edit the volume paths, then:
docker compose up -d
The image ships a HEALTHCHECK that probes the unauthenticated GET /api/health
endpoint. It verifies the app is serving on port 9481 and can reach the database
(and Valkey, when configured), so docker ps shows (healthy) / (unhealthy)
rather than just "running". Orchestrators can gate startup on it:
depends_on:
grimoire:
condition: service_healthy
The database, search index, and rendered thumbnails are all stored under DATA_PATH (the /app/data volume). Back this directory up to preserve your library metadata and user accounts.
Pull the new image and restart (docker compose pull && docker compose up -d). Database schema changes are applied automatically on startup via Alembic - no manual action is required when upgrading, including from versions that predate Alembic. On first run under the new system, an existing database is detected and stamped at the correct baseline, so only genuinely new migrations run thereafter. Back up DATA_PATH before upgrading, as always.
Prefer to build the image yourself or run Grimoire directly on the host (Python 3.12+, Node 20+) without Docker? See Running from source.
📖 docs.grimoirecodex.org
The documentation site is the best place to read all of this - searchable, with a sidebar, and including an interactive Compose Generator that builds a
docker-compose.yml, a Podman Compose file, or systemd Quadlet units from your answers.See also the website, the live demo, and our Discord.
This page covers what Grimoire is and how to install it. Everything else lives in
docs/ alongside the code - the same material the documentation site publishes,
kept in the repo so it versions with the release you are running:
| Guide | What's in it |
|---|---|
| Docker installation | Step-by-step first install for Windows, macOS, and Linux |
| Library structure | How folders become systems and categories, supported formats, tags.json, .grimoireignore |
| Configuration | Every environment variable, and read-only vs writable mounts |
| Running from source | Building the image yourself, or running without Docker |
| Docker image tags | latest, nightly, -slim, and the supported architectures |
| Guide | What's in it |
|---|---|
| Searching your library | Field searches (title:, tag:, year:) and how ranking works |
| File management | The in-app file manager, duplicates and versions, and adding files from outside |
| Metadata sidecars | Reading .opf in, and writing metadata back out to your library |
| Campaigns | Characters, resources, the notes wiki, scheduling, and calendar export |
| Wiki note templates | Starting a campaign page from a template |
| Token editor | Turning any picture into a VTT-ready token |
| Universal VTT editor | Drawing walls, doors, and lights for dynamic lighting |
| Setting images | Campaign banners, system covers, and audio artwork |
| Themes | Light, dark, and installable colour themes |
| Guide | What's in it |
|---|---|
| Users and permissions | Roles, pre-seeding accounts, and restricting books |
| Security hardening | Rate limiting, security headers, sessions, and revocation |
| OpenID Connect | Delegating sign-in to Keycloak, Authentik, Authelia, and others |
| Performance and indexing | OCR tuning, page rendering, caching, and large galleries |
| Backups | Scheduling, retention, and what is not included |
| Restoring from a backup | The by-hand restore procedure |
| Community add-ons | Installable metadata scrapers |
| OPDS catalog | Connecting e-reader apps to your library |
| Guide | What's in it |
|---|---|
| FAQ | Common problems, and worked OIDC examples for Authentik and Google |
| API reference | Every endpoint, with roles and request bodies |
| Architecture | Module map, request lifecycle, auth flow - for contributors |
| Data model | ER diagram and table-by-table schema |
| CI/CD pipelines | Workflows, coverage gates, and the release checklist |
The live API is also self-documenting while the server is running:
/api/docs (Swagger UI),
/api/redoc, and
/api/openapi.json.
Grimoire is open source and contributions are welcome - bug reports, feature ideas, docs, and code.
See CONTRIBUTING.md for full details on reporting issues, submitting pull requests, and setting up a local development environment.
To report a security vulnerability privately, see SECURITY.md.
GNU General Public License v3.0 - see LICENSE for details.
JavaScript
52.9%
Python
46.8%
Self-hosted organizer for your TTRPG content and campaigns
See the codeA self-hosted web app for your tabletop RPG library. Point it at a folder of PDFs, maps, tokens, audio, and 3D models, and Grimoire turns it into a searchable library you can read from any device - every page of every book indexed, including scanned ones.
It runs as a single Docker container against a directory you already own, and by default never writes to it.
title:, author:, tag: and friends - see Searching your library.Building AND store OR shop), and named presets save to your account with one default per view..webm/.mp4), and Universal VTT maps all display in-app; large maps load through a downscaled preview while downloads stay untouched..uvtt files on the geometry they already carry..zip. Templates belong to the campaign, so downloaded ones are yours to edit. See Wiki note templates.Grimoire is for people who have bought a lot of TTRPG material and want it in one place. If your collection is a folder of PDFs from twenty Humble Bundles and three Kickstarters, spread across a NAS and a laptop, this is the problem it solves.
It is not a store, a pirate tool, or a PDF editor. Grimoire reads a library you already have, and by default never writes to it.
Docker, a folder of TTRPG files, and somewhere to run it - a NAS, a home server, a spare mini-PC, or your desktop. It is happy on a Raspberry Pi and scales up to libraries of thousands of books.
| Systems | System detail |
|---|---|
![]() | ![]() |
| Search | Tag browser |
|---|---|
![]() | ![]() |
| Favourites | |
|---|---|
![]() |
| Book view with table of contents | In-book search |
|---|---|
![]() | ![]() |
| Maps | Tokens |
|---|---|
![]() | ![]() |
| Token editor | 3D models |
|---|---|
![]() | ![]() |
| Universal VTT map editor | Token vision preview |
|---|---|
![]() | ![]() |
| Audio page with soundboard and playlist | |
|---|---|
![]() |
| Campaign overview | Campaign notes wiki |
|---|---|
![]() | ![]() |
New to Docker? See the Docker Installation Guide for a step-by-step walkthrough for Windows, macOS, and Linux.
Create a library/ folder with this structure:
library/
├── books/
│ └── Dungeons and Dragons 5e/
│ ├── core/
│ │ ├── Players Handbook.pdf
│ │ ├── Dungeon Masters Guide.pdf
│ │ └── monsters/ ← subfolder within a category
│ │ ├── Monster Manual.pdf
│ │ └── Mordenkainen's Monsters.pdf
│ ├── supplements/
│ ├── adventures/
│ │ ├── Curse of Strahd/ ← adventure path subfolder
│ │ │ ├── Curse of Strahd.pdf
│ │ │ └── Strahd DM Screen.pdf
│ │ └── Lost Mine of Phandelver/
│ │ └── Lost Mine of Phandelver.pdf
│ ├── character-sheets/
│ ├── handouts/
│ └── homebrew/
├── maps/
│ └── Sunken Temple (22x22)/
│ ├── Sunken Temple Basement.png
│ └── The Sunken Temple.png
├── tokens/
│ └── Monsters/
│ └── goblin.png
├── audio/
│ └── Ambient/
│ ├── cover.jpg
│ └── tavern-night.mp3
└── models/
└── Goblins/
├── Presupported/
│ └── goblin-archer.stl
└── Unsupported/
└── goblin-archer.stl
See Library structure for the full layout, category rules, and the marker files that group systems together.
Copy the default compose file, set your volume paths, then start:
cp docs/docker/docker-compose.yml docker-compose.yml
# Edit docker-compose.yml and set the volume paths
docker compose up -d
open http://localhost:9481
On first launch you'll be prompted to create an admin account, or you can pre-seed users automatically (see Pre-seeding users).
docker pull hunterreadca/grimoire:latest
Or pin to a specific release:
docker pull hunterreadca/grimoire:1.5.0
Image variants: the default tags (latest, 1.5.0, …) include the Tesseract OCR engine so image-only PDFs are searchable (see OCR). If you don't need OCR and prefer a smaller image, use the matching -slim tag (e.g. hunterreadca/grimoire:latest's slim counterpart :slim, or a pinned :1.5.0-slim), which omits Tesseract.
docker-compose.ymlservices:
grimoire:
image: hunterreadca/grimoire:latest
ports:
- "9481:9481"
volumes:
- /path/to/your/library:/app/library # add ":ro" to keep it read-only (see Volumes)
- /path/to/grimoire/data:/app/data
Ready-to-use compose files for common setups are in docs/docker/:
| File | What it runs |
|---|---|
docs/docker/docker-compose.yml | Grimoire (default, no extras) |
docs/docker/docker-compose.valkey.yml | Grimoire + Valkey page cache (recommended for large libraries) |
docs/docker/docker-compose.calibre.yml | Grimoire + Calibre full desktop (metadata editing, OPF export) |
docs/docker/docker-compose.calibre-web.yml | Grimoire + Calibre-Web (lightweight Calibre browser UI) |
Each file has inline comments explaining the options. Copy and edit the one that fits your setup:
cp docs/docker/docker-compose.valkey.yml docker-compose.yml
# Edit the volume paths, then:
docker compose up -d
The image ships a HEALTHCHECK that probes the unauthenticated GET /api/health
endpoint. It verifies the app is serving on port 9481 and can reach the database
(and Valkey, when configured), so docker ps shows (healthy) / (unhealthy)
rather than just "running". Orchestrators can gate startup on it:
depends_on:
grimoire:
condition: service_healthy
The database, search index, and rendered thumbnails are all stored under DATA_PATH (the /app/data volume). Back this directory up to preserve your library metadata and user accounts.
Pull the new image and restart (docker compose pull && docker compose up -d). Database schema changes are applied automatically on startup via Alembic - no manual action is required when upgrading, including from versions that predate Alembic. On first run under the new system, an existing database is detected and stamped at the correct baseline, so only genuinely new migrations run thereafter. Back up DATA_PATH before upgrading, as always.
Prefer to build the image yourself or run Grimoire directly on the host (Python 3.12+, Node 20+) without Docker? See Running from source.
📖 docs.grimoirecodex.org
The documentation site is the best place to read all of this - searchable, with a sidebar, and including an interactive Compose Generator that builds a
docker-compose.yml, a Podman Compose file, or systemd Quadlet units from your answers.See also the website, the live demo, and our Discord.
This page covers what Grimoire is and how to install it. Everything else lives in
docs/ alongside the code - the same material the documentation site publishes,
kept in the repo so it versions with the release you are running:
| Guide | What's in it |
|---|---|
| Docker installation | Step-by-step first install for Windows, macOS, and Linux |
| Library structure | How folders become systems and categories, supported formats, tags.json, .grimoireignore |
| Configuration | Every environment variable, and read-only vs writable mounts |
| Running from source | Building the image yourself, or running without Docker |
| Docker image tags | latest, nightly, -slim, and the supported architectures |
| Guide | What's in it |
|---|---|
| Searching your library | Field searches (title:, tag:, year:) and how ranking works |
| File management | The in-app file manager, duplicates and versions, and adding files from outside |
| Metadata sidecars | Reading .opf in, and writing metadata back out to your library |
| Campaigns | Characters, resources, the notes wiki, scheduling, and calendar export |
| Wiki note templates | Starting a campaign page from a template |
| Token editor | Turning any picture into a VTT-ready token |
| Universal VTT editor | Drawing walls, doors, and lights for dynamic lighting |
| Setting images | Campaign banners, system covers, and audio artwork |
| Themes | Light, dark, and installable colour themes |
| Guide | What's in it |
|---|---|
| Users and permissions | Roles, pre-seeding accounts, and restricting books |
| Security hardening | Rate limiting, security headers, sessions, and revocation |
| OpenID Connect | Delegating sign-in to Keycloak, Authentik, Authelia, and others |
| Performance and indexing | OCR tuning, page rendering, caching, and large galleries |
| Backups | Scheduling, retention, and what is not included |
| Restoring from a backup | The by-hand restore procedure |
| Community add-ons | Installable metadata scrapers |
| OPDS catalog | Connecting e-reader apps to your library |
| Guide | What's in it |
|---|---|
| FAQ | Common problems, and worked OIDC examples for Authentik and Google |
| API reference | Every endpoint, with roles and request bodies |
| Architecture | Module map, request lifecycle, auth flow - for contributors |
| Data model | ER diagram and table-by-table schema |
| CI/CD pipelines | Workflows, coverage gates, and the release checklist |
The live API is also self-documenting while the server is running:
/api/docs (Swagger UI),
/api/redoc, and
/api/openapi.json.
Grimoire is open source and contributions are welcome - bug reports, feature ideas, docs, and code.
See CONTRIBUTING.md for full details on reporting issues, submitting pull requests, and setting up a local development environment.
To report a security vulnerability privately, see SECURITY.md.
GNU General Public License v3.0 - see LICENSE for details.
JavaScript
52.9%
Python
46.8%