Skip to content
 
 

Latest commit

 

History

280 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Shelf

Release Docker Pulls CI Unit tests E2E tests License: AGPL-3.0

A self-hosted home library catalog with barcode scanning, multi-mode scanning workflows, automatic metadata lookup, cover art, and collection management — all in a single Docker container.

Photo Intake demo — a shelf photo is analyzed by AI vision, 11 books are detected and imported with covers and metadata

Photo Intake: snap a shelf, AI reads the spines, books land in your library with covers and metadata.

Why Shelf?

Most home library apps are cloud-hosted, mobile-only, or require you to manually enter every book. Shelf takes a different approach:

  • Scan and done — point your phone camera at a barcode or use a USB/Bluetooth barcode scanner and the book is cataloged in seconds, complete with cover art, author, series info, and description. Works out of the box with any scanner that sends Enter after the barcode (most do by default), and camera scanning works on iPhones and iPads as well as Android
  • Bulk-add from a photo — snap a picture of a full shelf, a stack, or books laid face-up, and a vision model reads the spines and recognizes the covers. Review the candidate list — each row carries the ISBN read off a back cover, a per-row media type, and a marker on rows the model recognized rather than read — then import them all. Set a row to DVD or Video Game and it is looked up on TMDb or IGDB at confirm, not merely filed, on an exact title match. Works with the Anthropic API, any OpenAI-compatible endpoint, or a fully local Ollama model
  • The barcode decides the media type — an ISBN is a book even if the dropdown still says DVD, and a game UPC reaches IGDB even if it says Book. Leave it on Auto and scan a mixed pile; the card says what it detected and why, and says plainly when a record came back thin — because a provider key is missing, was rejected, is rate-limiting you right now, has no source for that format yet, or simply had no match
  • 8 scan modes — Add, Wishlist, Lend, Return, Move, Inventory, Lookup, and Quick Rate. The scan tab adapts to whatever you're doing: adding new items, lending to a friend, reorganizing shelves, or auditing a room
  • Title search — don't have a barcode? Search by title across Open Library (books), TMDb (movies), and IGDB (video games) and add directly from results. Like the scan card, the result box says why it is empty — a rejected key, a rate-limited provider, one that could not be reached — so "No books found" means only that the provider answered and had nothing
  • Add by hand — a title is the only field required, for anything no lookup can find: a self-published book, a burned CD, a niche import, something you made yourself. Every media type, no barcode needed, and reachable from Home, from an empty title search, from a mistyped barcode, and from any item's page
  • Zero cloud dependency — runs entirely on your network in a single Docker container with a SQLite database. Your data never leaves your home
  • Works on any device — responsive web UI that works on phones, tablets, and desktops. No app store required
  • Multi-user — share with your household. Admins manage the catalog, viewers can browse and track what they're reading
  • More than books — catalog audiobooks, eBooks, DVDs, CDs, comics, manga, and video games. Link physical and digital formats together
  • Video game support — scan UPC barcodes for modern games or search IGDB by title for retro cartridges (Atari 2600, NES, SNES, etc.). Cover art, publisher, series, and platform tracking with a customizable platform list
  • Lend with confidence — track who borrowed what with the Lend/Return scan modes and a "Lent Out" filter on the browse page
  • Inventory auditing — pick a location, scan everything on the shelf, then see what's missing
  • Delete without fear — deleting an item or removing a copy moves it to Trash with its tags, loans, copies and history intact. Editors restore in one click; admins empty it, prompted once rows pass a retention window (180 days by default). Nothing is deleted on a timer
  • Know what you own — ISBNdb integration estimates your collection's value and generates a location-grouped, print-ready valuation report for insurance documentation

Screenshots

Browse Scan (Add Mode)
Browse Scan
Scan (Lend Mode) Item Detail
Lend Detail
Stats Admin Logs
Stats Logs
Valuation Report Browse (Tag Filter)
Valuation Report Tag Filter
Photo Intake Series
Photo Intake Series
Wrap-up
Wrap-up

Documentation

Full docs live in docs/:

Quick Start

docker compose up -d

Open https://localhost:18888 and create your admin account and pick a feature profile via the setup wizard. That's it.

Configuration

Create a .env file alongside docker-compose.yml for host-specific config:

# Add your machine's IP so you can access Shelf from other devices
CERT_SAN=IP:192.168.1.100,DNS:shelf,DNS:localhost
Variable Default Description
CERT_SAN DNS:shelf,DNS:localhost TLS certificate Subject Alternative Names
SECRET_KEY (auto-generated) JWT signing key. If unset, generated at data/signing.key (0600) on first start; an existing key from before 0.30 is moved there from the database on the first start after upgrading, so sessions survive. Set it explicitly to run several instances against one database
SHELF_ENCRYPTION_KEY (auto-generated) Encryption key for stored API credentials. Auto-generated at data/encryption.key if not set — never stored in the DB, so backups contain ciphertext only. Set it (e.g. openssl rand -hex 32) so the data directory alone can't decrypt credentials

Data

All persistent data lives in ./data/ (bind-mounted into the container):

data/
  shelf.db        — SQLite database
  covers/         — cached cover images
  certs/          — auto-generated TLS certificates
  encryption.key  — key for credentials stored in the DB (unless
                    SHELF_ENCRYPTION_KEY is set)
  signing.key     — signs login sessions (unless SECRET_KEY is set)

Keep both key files out of shared copies. The database holds no key material, so a database backup is ciphertext without anything that opens it — but a copy of this whole directory carries the keys next to the data they protect.

Features

Scanning and Metadata

  • Camera barcode scanning on mobile — tap to scan ISBNs and UPCs, from the Scan tab or from an item's edit form when you need to correct one ISBN
  • 8 scan modes — Add, Wishlist, Lend, Return, Move, Inventory, Lookup, and Quick Rate
  • Media-type detection — the barcode outranks the scan form's dropdown when it is certain; Auto reads the barcode and decides. It reads platform, format, medium and audio wording out of the retail title, and the product category behind it, so a music CD and a PC CD-ROM game are each filed as themselves rather than guessed at against a film database
  • Photo intake — bulk-add from a photo of your shelves using a vision model, snapped with the phone or webcam or uploaded. Rows typed DVD or Video Game are looked up on TMDb or IGDB at confirm, on an exact title match (see Photo Intake)
  • Title search — search Open Library, TMDb, or IGDB by title when you don't have a barcode; an empty result box names the reason when the search failed rather than missed
  • Add by hand — a title is the only field required, for anything no lookup can find: a self-published book, a burned CD, a niche import, something you made yourself. Every media type, no barcode needed, and reachable from Home, from an empty title search, from a mistyped barcode, and from any item's page
  • Cascading metadata lookup — Open Library, Hardcover, and Google Books, with national bibliographies consulted first for the groups they cover: German (978-3) ISBNs go to the Deutsche Nationalbibliothek (DNB), Italian ones (978-88 and 979-12) to the Servizio Bibliotecario Nazionale (SBN)
  • Edition language — captured on lookup, editable on items, filterable in Browse; a settings dropdown picks the preferred language for title searches
  • Cover art pipeline — Open Library, Hardcover, DNB (German ISBNs), Amazon, Google Books, IGDB, and manual search/upload/paste-a-URL/remove, on any item. A cover review queue walks every cover-less item one at a time — discs, games and music included, which the automatic sweep deliberately never touches — with the picker inline, and a Not available verdict that is remembered so the list converges on zero. Cover search is media-type aware: books search Google Books and Open Library, DVDs the film's TMDb poster set, video games IGDB cover art and artwork. The picker reports a missing key, a rejected key, a spent quota and an unreachable provider by name, so "No covers found for this title." is only ever a genuine miss
  • UPC support — scan DVDs and Blu-rays with TMDb lookup, and music discs, which are detected on Auto. A barcode Shelf can resolve on MusicBrainz brings back the release; one it cannot is still filed under its own title
  • Music by release, not by title — a Music page searches MusicBrainz by title, artist, barcode or catalogue number and catalogues the exact pressing: country, date, label, catalogue number, packaging and medium, with real track lists across multiple discs. Vinyl, Cassette, CD and Digital Music. Two pressings of one album stay distinct and are linked to each other automatically. Artwork is shown square and uncropped. See Music
  • Periodicals as publication plus issue — a magazine run is one publication with many issues, not many unrelated rows. A 977 barcode resolves the publication from its ISSN; the issue number and date stay yours to confirm. When the barcode does not resolve, search for the magazine by title instead. See Periodicals
  • Manga as its own media type — in the book family, so it carries an ISBN, belongs to a series, and filters separately from comics
  • Retail barcodes on the edit form — the Identifiers section takes a UPC/EAN as well as an ISBN, with the same camera scanner. UPC-A is canonicalised to EAN-13 and checksummed; 978/979 Bookland codes are refused, because they belong in the ISBN field. See Editing barcodes
  • Video game support — scan UPC barcodes for modern games or search IGDB by title for retro cartridges. Platform tracking with a customizable platform list (30+ platforms from Atari 2600 to PS5)

Scan Modes

Mode What it does
Add Scan barcodes to add items to your collection with full metadata lookup. Scanning something already on your wishlist marks it owned
Wishlist Scan at a bookstore to save items you want — adds them to your wishlist
Lend Select a borrower, then scan items to check them out
Return Scan items to check them back in
Move Select a target location, then batch-scan items to relocate them
Inventory Select a location, scan everything there, then check for missing items. Counts physical copies, so a book with copies in two rooms is expected in both; a scan that cannot say which copy reports instead of moving one
Lookup Scan to check if an item is in your collection — no changes made
Quick Rate Scan to mark items read, watched or played

Camera scanning picks its decoder to suit the device: iOS Safari drives the camera with ZXing, every other platform uses html5-qrcode. The scan page and Store Mode share one engine, so both behave the same everywhere. Retail barcodes are covered — EAN-13, EAN-8, UPC-A and UPC-E. USB and Bluetooth scanners bypass the camera entirely and work regardless.

Photo Intake

Photo Intake — reviewing books detected from a shelf photo

Snap a photo of a shelf — or of books stacked or laid face-up — and Shelf reads the spines it can read and recognizes the covers it can't. Open Photo Intake in the nav, take or upload the photo, and the detected books appear as an editable candidate list: title, author, the ISBN read off a back cover if one was in frame, a per-row media type, and a marker on rows identified from the cover rather than read. Nothing is imported until you confirm. Rows with an ISBN then get the same lookup a barcode scan does; books are matched on title and author behind an author-match guard; and a row set to DVD or Video Game is looked up on TMDb or IGDB, which fills in its year, description and cover when the title matches the catalogue exactly. The Done panel shows which rows found no metadata, and marks separately the rows whose lookup was declined because the title did not match.

Configure a vision backend under Settings → Integrations → Photo Intake:

  • Anthropic API — best accuracy; pay-per-photo (typically a few cents)
  • OpenAI-compatible — any endpoint that speaks the OpenAI Chat Completions API: OpenAI itself, OpenRouter, or a local server (vLLM, LM Studio, LocalAI). Set the base URL, an optional API key, and a vision-capable model
  • Ollama — free and fully local with any vision-capable model (gemma3, qwen2.5vl, llama3.2-vision, …); accuracy depends on the model

For high-resolution photos that exceed what the model actually ingests, Shelf shows a preview of what the model will see and offers to split the photo into overlapping tiles for better accuracy — with a cost estimate for each option before anything is sent.

Collection Management

  • Choose your features — the setup wizard starts you on Minimal, Standard or Everything, and Settings → Features turns any optional part (Lending, Sharing, Valuation, Price alerts, Photo Intake, the integrations, …) on or off later, one at a time or by applying a profile. A feature that is off leaves the pages you use, and its data is kept for when it comes back. See Configuration → Features
  • Home overview — Shelf opens on a page that answers "what is happening in my library?": catalogue, owned and wishlist totals, what is lent out, missing covers, a media-type breakdown and recent additions. Browse stays the place for searching, filtering and bulk editing. See Home
  • Filter and search — by media type, location, status (read, watched, played), ownership, lending status, source (which sync, provider or import an item arrived from), and free text
  • Reading tracking — want-to-read, reading, and read with start/finish dates
  • Custom tags — free-form tags (signed, first-edition, whatever you like) as chips on the item page and its edit page, applied to many items at once from the Browse bulk bar, with a tag filter and an optional Tags column on Browse. Admins rename, scope and delete tags in Settings, which shows how many items carry each. Set default tags for a scanning session on Scan, Shelf Fill or Photo Intake and every item you add is tagged as it arrives, with suggestions for the media type you are scanning
  • Synopses — item descriptions fetched automatically on add, plus a one-click backfill for your existing catalog (Open Library, Google Books, Hardcover)
  • Stats dashboard — books read per year, collection growth, top authors, and value-over-time charts (server-rendered SVG, no JS)
  • Wrap-ups — a shareable image of a month or a year: what you finished, what you added, your top author and a grid of covers. Drawn in your browser and never stored or published; download it, or share it from your phone. In January, Stats also links to last year's wrap-up ("2025 in Books"). See Stats → Wrap-ups
  • Locations — organize by room, shelf, or any system you like, and nest them: a shelf inside a bookcase inside a room. Rename or move a location and everything beneath it follows. See Locations
  • Shelf Fill — pick a room, bookcase or shelf and it stays selected while you scan item after item onto it. Items already catalogued move without a fresh metadata lookup; unrecognised barcodes fall through to the normal Add pipeline. See Shelf Fill
  • Physical copies — own two of something and track them apart: add a copy on the item page, give each its own location, condition, acquired date, source, price, provenance and barcode, and remove one when it goes. Removing the copy marked primary promotes the next one and the item's location follows it. A removed copy goes to Trash with its details, not away for good
  • Trash — deleted items and removed copies wait in Trash (account menu → Library) with everything attached to them: restore brings them back exactly as they were, and scanning one in Lend, Move or any other existing-item mode says In Trash and offers Restore instead of acting on it. Admins delete permanently or empty what has passed the retention window, and get a dismissable banner when there is something to empty. See Items → Trash
  • Arrange a shelf — any location gets an Arrange page where you drag the physical copies into the order they actually sit in, or order them automatically by title, creator, series, release or issue. The order belongs to the copy, so duplicates stay distinct and can sit side by side
  • Related media groups — connect the different forms of one work (a novel, its audiobook, its film adaptation) as format, related or adaptation. Every item shows its whole group in a panel on the item page, with direct links marked apart from the ones reached through a third item; editors search the catalogue to add a relationship, viewers see the group read-only. A group is the connected set of links, so linking A to B and B to C presents all three. Matching is manual by design. See Related Media
  • Game platforms — customizable list of platforms, add your own for niche or retro systems
  • Authors as links — every author on an item page links to everything by that person: Martin Fowler, Kent Beck is two authors, a translator is shown as one (Ken Liu · translator), and J.R.R. and J. R. R. Tolkien are the same author. Browse filters to one author and combines it with any other filter. The authors field stays exactly as stored — fix a mis-split by editing it. See Items
  • Checkout system — lend to borrowers with the Lend scan mode, filter by "Lent Out" in browse
  • Loan reminders — overdue loans get a red badge, and an optional daily digest (ntfy or webhook) nags you about them; configure under Settings → Library → Lending
  • Wishlist — a list of what you want, kept alongside your catalog. Owning and wishing are separate: an item can also be neither — a book you read from the library stays in your catalog, with its reading history, without being owned or wished for
  • Series tracking — a Series page groups your library by series with position numbers, flags likely gaps, and (with Hardcover configured) checks the full series and adds missing volumes to your wishlist in one click. Each series can carry its own synopsis, written inline or fetched from Hardcover. Rename a series (renaming onto an existing name merges the two — the quick fix for duplicate series records left by metadata lookup) or disband it entirely, right from the series card
  • Bulk editing — select multiple items in Browse to move them, change type or status, add them to or remove them from the wishlist, set and clear their series, or add and remove a tag in one go
  • Choose your columns — Browse's list view has a column picker (value, series, publisher, year, pages, language, added date, platform, ISBN/UPC, and more), on top of the author/type/location/status shown by default; the choice is remembered per browser, not per account
  • Valuation report — location-grouped, print-ready report of your collection's list-price value for insurance documentation (print view); prices via ISBNdb
  • Price alerts — Shelf checks the list price of wishlisted books nightly through ISBNdb and sends a digest when one drops past your threshold; list price, not used-market price. See Price alerts
  • Display currency — pick from 20 currencies under Settings → Collection and every value surface follows. This is formatting, not conversion: Shelf never converts amounts between currencies, so the figure ISBNdb returns is the figure shown
  • CSV import/export — bulk operations and backups
  • Portable archive — export your whole collection as a single zip (items, tags, locations, series, reading log, checkouts, physical copies, and your cover art) and merge it back into any Shelf instance without refetching a single cover. No credentials or instance-specific data are included, so it's the safe way to move servers or hand your library to someone else — unlike a database backup, which carries password hashes and encrypted API keys but no covers at all. Importing previews first: you see how many items are new, how many are already yours, how each duplicate was matched (exactly on ISBN, or heuristically on title and author), and you can leave parts of the archive out before anything is written. Trash travels too: what you deleted arrives in Trash on the other side, with its deletion date, and an import never moves a live item to Trash
  • Goodreads, StoryGraph, LibraryThing & Libib migration — upload your library export as-is (LibraryThing and Libib in beta); the format is auto-detected, reading statuses and owned/wishlist flags are mapped, and covers are fetched automatically
  • Store Mode (offline PWA) — scan barcodes in a bookstore with no signal and get an instant Owned / On wishlist / Not in library verdict; unknown books queue on-device and are added to your wishlist automatically when you're back online (see Store Mode)

Integrations

  • Hardcover — bidirectional reading status sync, import your library, discover new books
  • Audiobookshelf — sync selected libraries from your Audiobookshelf server, link physical + digital formats, and jump straight to an item in ABS from its Shelf page
  • IGDB — video game metadata, cover art, and platform info via Twitch developer credentials (free)
  • RomM — sync a self-hosted RomM server's digital game library. A RomM game gets its own record rather than being matched onto a physical cartridge you already own; link the two yourself. See RomM
  • Komga — sync a self-hosted Komga server's digital comics and manga, matching on ISBN where one exists. A library's Comic/Manga kind is kept apart from Shelf's own media type, so it never reclassifies an item you catalogued by hand. See Komga
  • ISBNdb — collection valuation with list prices for insurance documentation, and wishlist price alerts

Store Mode (Offline PWA)

Store Mode demo — three ISBNs checked in turn, returning Owned, On wishlist, and Not in library with the unknown book queued for sync

Standing in the shop: scan, and know instantly whether you already own it.

Open Store in the nav (or visit /store), and Shelf caches your library's ISBNs on the device. From then on, scanning a barcode answers instantly from the local cache — even with zero signal in a bookstore basement. Books you scan that aren't in your library are queued on-device and added to your wishlist (with metadata and cover) the next time you're online.

To install it as an app, use your browser's "Add to Home Screen" while on the store page. One requirement: service workers (the offline machinery) only run on an origin your phone trusts. Options, from simplest to cleanest:

  1. Trust the self-signed cert on your phone — download the cert from your Shelf server and install it (Android: Settings → Security → Install a certificate → CA certificate; iOS: install the profile, then enable full trust under Settings → General → About → Certificate Trust Settings).
  2. VPN home (WireGuard/OpenVPN/Tailscale) — the offline cache still does the work in the store; the VPN is only needed when syncing.
  3. A real certificate — reverse proxy with Let's Encrypt, or tailscale cert for a ts.net HTTPS name. Set SHELF_TRUST_PROXY to the proxy's address if a proxy sits in front.

Note that localhost is always trusted, so store mode works out of the box for local development.

Sharing

Create public read-only links under Settings → Data → Sharing — a wishlist link for gift ideas or a collection link for browsing. Anyone with the URL sees titles, authors, covers, and series only (never locations, loans, values, notes, or ISBNs). Links are unguessable 128-bit tokens, rate-limited, marked noindex, and revocable at any time.

Administration

  • Role-based access — admin, editor, and viewer roles
  • Web log viewer — monitor auth events, sync activity, and errors from the browser
  • HTTPS — self-signed TLS certificates generated on first run
  • Backup/restore — database backup and restore from the settings page, with optional passphrase-encrypted (AES) backup downloads that are safe to store off-site
  • Hardened by default — strict Content-Security-Policy (no unsafe-inline/unsafe-eval, no CDNs), CSRF protection on all mutating requests, write-only API credentials in Settings, encrypted credential storage

Tech Stack

Layer Technology
Backend Python 3.12, FastAPI, SQLite (WAL mode)
Frontend Jinja2, HTMX, Alpine.js, Tailwind CSS
Auth bcrypt, JWT in HTTP-only cookies, Secure whenever the browser connects over HTTPS
Container Docker, non-root user, self-signed HTTPS

Roles

Role Can do
Admin Everything: settings, users, locations, tag rename/scope/delete, sync, bulk ops, logs, delete permanently / empty Trash
Editor Add/edit items, delete to Trash and restore, scan (all modes), covers (find/upload/paste URL/remove, and the cover review queue), checkout/checkin, apply tags (one item or a Browse selection), import/export
Viewer Browse, search, set status (read, watched, played), export CSV, view stats

Metadata Sources

Shelf queries free, public APIs to look up book and game information — no API keys needed for core book functionality:

Source What it provides API key required?
Deutsche Nationalbibliothek German (978-3) ISBNs, consulted before the rest: title, author, publisher, year, language; cover art No
Servizio Bibliotecario Nazionale Italian (978-88, 979-12) ISBNs, consulted before the rest: title, subtitle, author, publisher, year, language No
Open Library Title, author, description, cover art, publish info, title search No
Google Books Fallback metadata and cover art; magazine title search (and the chosen result's cover) when a 977 barcode does not resolve No (optional key supported)
Amazon Images Fallback cover art via ISBN No
UPC Item DB Title lookup from UPC barcodes (games, DVDs) No
MusicBrainz Music releases by title, artist, barcode or catalogue number: pressing details, track lists, release groups No
ISSN Portal Periodical publications from an ISSN, resolved from a 977 barcode No

Metadata lookups send only the ISBN or UPC to these services. No personal data, account info, or collection details are transmitted.

Optional API Keys

Configure in Settings to unlock additional features:

Service Enables Link
Hardcover Reading status sync, richer metadata, import/export, Discover page hardcover.app
Google Books Optional credentialed metadata, synopsis, and cover requests; anonymous access remains available Google Books API
IGDB (Twitch) Video game metadata, cover art, and platform info — on UPC scan, title search, and Photo Intake confirm dev.twitch.tv/console
Discogs Pick the exact pressing of a Music item; Shelf keeps only the Discogs release ID discogs.com/settings/developers
ISBNdb Collection valuation with market prices; wishlist price alerts isbndb.com
TMDb DVD/Blu-ray metadata — on UPC scan, title search, and Photo Intake confirm themoviedb.org
Anthropic Photo Intake — reads spines and recognizes covers (best accuracy) console.anthropic.com
OpenAI-compatible Photo Intake via any OpenAI Chat Completions endpoint (OpenAI, OpenRouter, vLLM, LM Studio…) platform.openai.com
Ollama Photo Intake with a fully local vision model — no key needed ollama.com

Development

See docs/development.md for the full guide and CONTRIBUTING.md before opening a PR. The essentials:

# Rebuild after code changes
docker compose build && docker compose up -d

# View logs
docker compose logs -f shelf

# Access the database
sqlite3 data/shelf.db

# Rebuild the Tailwind stylesheet after changing templates or static/js
# (all JS/CSS is vendored locally — no CDNs; requires node/npx)
make css

QA Pipeline

Shelf ships with a Makefile that orchestrates a two-pass local QA workflow — no CI/CD required.

One-time setup:

pip install -r requirements-dev.txt
make install-playwright   # downloads headless Chromium

Common targets:

Target What it does
make test Unit and integration tests (pytest, excludes E2E)
make test-e2e Playwright E2E browser tests against a live local server
make test-contract Live UPC Item DB contract check — spends one trial lookup; run at release, never on a gate
make test-all test and test-e2e
make check-deps pip-audit vulnerability scan of requirements.txt
make check-licenses License compliance report
make check-secrets Scan tracked files for accidentally hardcoded secrets
make check-csrf Lint that raw fetch() calls send the CSRF token
make check-deleted Lint that every read of items goes through items_live, and every read of item_copies through copies_live
make check-alpine Verify templates stay compatible with the Alpine CSP build, and that the script load order in <head> is intact
make check-sw-version Verify the service worker's cache version matches what it caches
make check-tests Lint the test suite's own conventions
make checks All of the checks above
make report-review Code review report via Claude agent
make report-security Security audit report via Claude agent
make report-test Test coverage audit report via Claude agent
make reports All three reports
make qa Full Pass 1: test-all → checks → reports
make fix Pass 2a: interactive Claude session reads reports and applies fixes
make verify Pass 2b: re-run all tests after fixes
make release-check Alias for make qa
make install-hooks Install a pre-push git hook that runs make test-all

Typical pre-release workflow:

make qa          # run tests, checks, and generate reports
# review reports/CODE_REVIEW_*.md, SECURITY_AUDIT_*.md, TEST_AUDIT_*.md
make fix         # Claude reads reports and applies fixes interactively
make verify      # confirm all tests still pass

Reports land in reports/ with today's date (e.g. reports/CODE_REVIEW_2026-03-27.md) and are gitignored — they're regenerated each QA cycle, so keep a copy elsewhere if you want to compare against a previous run.

Report targets default to claude-sonnet-4-6. Override with MODEL= for a deeper pre-release audit:

make reports MODEL=claude-opus-4-6

License

AGPL-3.0 — free to use, self-host, and modify. If you offer a modified version of Shelf as a network service, you must make your changes available under the same license.

About

Self-hosted home library catalog — scan barcodes or photograph whole shelves (AI vision), auto-fetch metadata & covers, track lending, series, and reading. Offline bookstore mode (PWA). FastAPI + SQLite + HTMX, single Docker container.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages