6ecdd43ed2
A dashboard at / joins the review page (now at /review): drag-and-drop photo upload (re-uploading a photo drops its raw cache so extract re-reads it), per-stage status cards fed by /api/pipeline (counts and key NAMES only — never values), and run buttons that execute stages one-at-a-time in a background JobRunner with captured output streamed to the page. The real upload sits behind a confirmation, defaults to dry-run at the API layer, and stays disabled while stub data is present. The CLI is unchanged and shares all state with the web UI. python-multipart joins the deps for the upload endpoint; RunBody lives at module scope because postponed annotations keep FastAPI from resolving function-local models. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5.7 KiB
5.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project
bggpipe — a resumable, idempotent CLI pipeline that turns shelf photos into a BoardGameGeek collection, in six stages:
| # | Command | What it does | Status |
|---|---|---|---|
| 1 | bggpipe extract |
Claude vision reads titles + edition cues from photos/ |
working |
| 2 | bggpipe resolve |
match titles to BGG IDs and versions via XML API2 | working (stub data — see hard rules) |
| 3 | bggpipe review |
human review of ambiguous/unmatched items; --web serves a FastAPI UI on port 8377 |
working |
| 4 | bggpipe diff |
diff approved matches against the existing BGG collection | working |
| 5 | bggpipe upload |
add games via a logged-in Playwright session | built; browser flows unverified until real data exists (--dry-run works now) |
| 6 | bggpipe enrich |
fetch full game/version metadata into games.json |
working |
Full design lives in bgg-shelf-pipeline-spec.md (read it before changing pipeline semantics); the upload-stage walkthrough is in docs/bgg-upload-flow.md.
Commands
uv sync— install deps (Python 3.12+, managed by uv; useuv add, never pip).uv run bggpipe inithandles first-run setup (folders, .env credentials, the one-timeplaywright install chromium).uv run bggpipe web— the full pipeline as a local web app (dashboard at/, review at/review); stage runs execute one-at-a-time in a background job.uv run bggpipe <stage>— run a pipeline stage. Non-secret settings come fromconfig.toml(username, dirs, vision model, rate limit);--configoverrides the path.uv run pytest— the suite runs fully offline against fixtures. Tests markedlivehit the real BGG API (read-only) and are skipped unless you pass--run-live.uv run ruff check/uv run ruff format— lint (rules E, F, I, UP, B, SIM) and format.
Layout
src/bggpipe/—cli.py(typer app), one module per stage (extract,resolve,review+webreview,diff,upload,enrich), plusbgg_client.py(rate-limited XML API2 client that caches responses todata/bgg_cache/),jobs.py(single-slot background stage runner for the web UI),normalize.py(title normalization),models.py(dataclasses),config.py,fsio.py(atomic writes),init_wizard.py(first-run setup).scripts/—write_stub_fixtures.py/write_photo_fixtures.pygenerate synthetic fixtures;record_fixtures.pyre-records real API responses once a token exists.tests/fixtures/bgg_cache/— stub XML fixtures the offline tests run against.data/— pipeline state (CSV/JSON artifacts are committed; caches are not — see Git).
Hard rules (from spec — never violate)
- ≤1 request every 2 seconds to any BGG endpoint; jittered backoff on 429/503. Upload stage: 2–4 s randomized delay between games.
- Credentials never touch disk or logs.
ANTHROPIC_API_KEY,BGG_USERNAME,BGG_PASSWORD,BGG_API_TOKENcome from env vars only. Playwright storage state is credential-adjacent — keep it gitignored. - The XML API requires a registered app token (
Authorization: Bearer, fromBGG_API_TOKEN) — unregistered requests get 401. Until Eric's registration at boardgamegeek.com/applications is approved, tests run on the stub fixtures intests/fixtures/bgg_cache/; re-record them withscripts/record_fixtures.pyonce the token exists. - Every stage is idempotent and resumable — killing mid-run and restarting must lose no work; re-runs skip already-processed items.
- Use only the XML API2 and the public website — no undocumented BGG endpoints (BGG tightened access policies in 2025).
- BGG has no write API: writes drive the real website with a logged-in Playwright session.
- Stub-resolved data is never upload-ready. All version_ids (and some game data) in
matches.csv,to_add.csv, andto_update.csvcurrently come from SYNTHETIC stub fixtures — placeholders until real fixtures exist. WhenBGG_API_TOKENarrives: delete both cache dirs, re-record fixtures,resolve --force, re-review. Two provenance markers guard this (both written by the fixture generators):data/bgg_cache/STUB_FIXTURES.marker(gitignored, travels with the stub XML) anddata/STUB_DATA.marker(committed, so a fresh clone stays guarded). The upload stage MUST refuse to run while either exists; deletedata/STUB_DATA.markeronly after re-resolving from real fixtures.
Domain gotchas
- Base game vs. expansion vs. new edition is the top failure mode — bias matching toward
ambiguousover auto-match ("Wingspan Europe" must not match base Wingspan). - Editions/versions matter: Eric owns multiple editions of some games — each is a separate collection entry (keyed by
collidon BGG). Never guess a version: no legible cues →version_unknownand a version-less collection entry. - Normalize titles (casefold, strip punctuation/articles, special chars like é/&/:) identically on both sides of a match; dedupe across photos but keep
source_photosprovenance. - Detailed BGG API behavior (202 queueing, collection-endpoint quirks, endpoints): use the
bgg-apiskill. If the spec's BGG behavior changes, update thebgg-apiskill to match — they must not drift.
Git
- Remote is self-hosted Gitea 1.26 (
git.kestrelsnest.social/eric/bggpipe), not GitHub —ghCLI does not work here. - Commit
data/matches.csv,data/to_add.csv,data/to_update.csv,data/upload_log.csv,data/titles.json,data/unidentified.json,data/unidentified_dismissed.json,data/games.json,data/STUB_DATA.marker(while it applies), and the collection snapshot XMLs. Never commitdata/bgg_cache/,data/extract_raw/,photos/, Playwright storage state, or.env.