# Bookmark A camera-driven book intake and checkout inventory system, built for [Books in Hand](https://git.opensourcesolarpunk.com/books-in-hand), a nonprofit that keeps books out of landfills and in people's hands. Bookmark replaces manual book logging with a guided, camera-based workflow: a volunteer places a book on a marked platform, the system photographs the front and back, sorts it into a size category for tax/reporting purposes, and later backfills the catalogue with title, author, and ISBN — all running on local hardware, no cloud dependency. This project is fully open source and is being built and donated as volunteer/client work — it isn't part of any commercial product line. ## Status **Phase 1 (intake station) is built, unit-tested, and ready for real-hardware validation.** Phase 2 (batch OCR/ISBN backfill) and Phase 3 (checkout station) are planned for later. | Phase | What it does | Status | |---|---|---| | 1 — Intake station | Camera capture, guided front/back flow, deterministic size bucketing, CSV catalogue | Built, unit-tested — pending real-hardware validation | | 2 — Batch OCR/ISBN backfill | Barcode decode + local vision-LLM fallback to fill in title/author/ISBN | Planned | | 3 — Checkout station | Track books leaving inventory, reusing the intake identification pipeline | Planned | ## How it works (Phase 1) 1. A downward-facing webcam looks at a fixed platform with printed nested size-boundary markers (small / medium / large). 2. A volunteer centers the book; capture fires automatically or on a button press (configurable). 3. The system photographs the front, determines size — **deterministically**, by checking which physical markers are covered, not by any model inference step — then prompts the volunteer to flip the book and photographs the back. 4. Every book gets a row in a CSV catalogue: images, size bucket, and a status that later pipeline stages (OCR backfill, checkout) update. Full design rationale lives in `AGENTS.md` (also readable as `CLAUDE.md` — same file, symlinked for compatibility with different AI coding tools). ## Why this matters for a nonprofit - **No cloud costs, no vendor lock-in.** Everything runs on donated hardware; no per-book or per-scan fees. - **Deterministic where it counts.** Size-bucket counts feed Books in Hand's year-end tax and 501(c)(3) reporting — that number is computed from physical measurements, not inferred by a model, so it can't drift or hallucinate. - **Volunteer-friendly.** The intake flow is designed to be usable by volunteers with no technical background — guided steps, big buttons, no login required. ## Development Requires Python 3.11+. ### Setup 1. Create and activate a virtual environment: ```bash python3 -m venv .venv .venv/bin/pip install -e ".[dev]" ``` 2. Mount the USB webcam over the capture platform. See the design spec (`circuitforge-plans/books-in-hand/superpowers/specs/2026-07-13-inventory-system-design.md`) for physical setup details: nested size-boundary markers, guide box. 3. Run calibration once per physical install, with the platform empty: ```bash .venv/bin/python calibrate.py reference.jpg ``` This captures a reference image of the empty platform for marker detection. 4. Copy `config.example.json` to `config.json` and fill in: - `markers`: pixel coordinates (from the reference image) - `guide_box`: capture region boundaries - `trigger_strategy`: one of `manual`, `motion_stop`, or `stable_centered` 5. Run the backend: ```bash .venv/bin/python run.py config.json ``` 6. Open `http://:8000` in a kiosk-mode browser on the station's monitor. ### Running tests ```bash .venv/bin/pytest -v ``` All tests run without requiring real camera hardware — they use synthetic NumPy frames and mocked `cv2.VideoCapture`. ### End-to-end smoke test (manual, requires real hardware) This checklist is for whoever installs this system on real hardware. It verifies that the intake workflow functions end-to-end. 1. Boot the station per Setup above with `trigger_strategy: "manual"`. 2. Place a book on the platform, click "Capture" — confirm the status advances to "Front captured — flip it over" and a new row appears in `catalogue.csv` with a `size_bucket` value and populated `front_wide_path` / `front_cropped_path` columns pointing at real files under `captures//`. 3. Flip the book, click "Capture" again — confirm status advances to "Book complete!" and the same row now has `back_wide_path` / `back_cropped_path` populated. 4. Click "Next Book" — confirm status returns to "Waiting for book..." and the next capture gets a different `book_id`. 5. Repeat with a small book and a large book — confirm `size_bucket` differs correctly between them, matching which physical markers each book actually covers. 6. Switch `trigger_strategy` to `motion_stop` in `config.json`, restart, and confirm placing a book and holding it still triggers capture without pressing the button. 7. Switch to `stable_centered` and repeat, confirming capture fires once the book is centered and steady in the guide box. ## License MIT — see `LICENSE`.