{"id":50056128,"url":"https://github.com/rjroy/shelf-judge","last_synced_at":"2026-05-21T13:17:48.902Z","repository":{"id":351217041,"uuid":"1199828248","full_name":"rjroy/shelf-judge","owner":"rjroy","description":"Board game collection curation. Multi-axis personal ratings combined with BGG community data produce a transparent fitness score for every game on your shelf, with a full breakdown of how each score was derived.","archived":false,"fork":false,"pushed_at":"2026-05-18T03:25:45.000Z","size":4005,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-18T04:58:03.406Z","etag":null,"topics":["bgg","board-games","boardgamegeek","boardgames","bun","cli","collection-management","nextjs","rating-system","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rjroy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-02T18:49:13.000Z","updated_at":"2026-05-18T03:18:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rjroy/shelf-judge","commit_stats":null,"previous_names":["rjroy/shelf-judge"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rjroy/shelf-judge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rjroy%2Fshelf-judge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rjroy%2Fshelf-judge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rjroy%2Fshelf-judge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rjroy%2Fshelf-judge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rjroy","download_url":"https://codeload.github.com/rjroy/shelf-judge/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rjroy%2Fshelf-judge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33301957,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T12:23:38.849Z","status":"ssl_error","status_checked_at":"2026-05-21T12:22:11.673Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bgg","board-games","boardgamegeek","boardgames","bun","cli","collection-management","nextjs","rating-system","typescript"],"created_at":"2026-05-21T13:17:47.825Z","updated_at":"2026-05-21T13:17:48.878Z","avatar_url":"https://github.com/rjroy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shelf Judge\n\n**Board game collection curation.** Shelf Judge combines personal, multi-axis ratings with Board Game Geek community data to produce a single, transparent fitness score for every game on your shelf — and every game you're considering adding.\n\n\u003e _A game earns its place for reasons unique to the owner. Shelf Judge makes those reasons legible._\n\n## What It Does\n\n- **Define rating axes that matter to you** — \"Date night playability,\" \"Hits the table,\" \"Visual design,\" anything. Each axis gets a weight that reflects how much you care about it.\n- **Rate your games** on those axes (1–10). BGG data fills in Community Rating and Complexity automatically.\n- **See a fitness score** (1.0–10.0) for every game, with a full breakdown showing exactly which axes drove the number, how each was weighted, and whether the value came from you or BGG.\n- **Run a tournament** to rank games head-to-head via an ELO comparison loop — useful when direct ratings feel hard to anchor.\n- **Score your wishlist** — predict fitness for games you haven't played yet, based on similarity to games you have rated.\n- **Spot redundancy** — games that overlap mechanically with better-rated alternatives on your shelf get a penalty surfaced in the score breakdown.\n- **Filter and sort your collection** by score, play count, mechanics, weight, player count, and more.\n\nThe fitness score is always honest about how it was derived. No score appears without its breakdown.\n\n## Architecture\n\nShelf Judge runs locally. There is no server, no cloud sync, no account.\n\n```\npackages/\n  shared/    TypeScript types and Zod schemas shared across all packages\n  daemon/    Hono server on a Unix socket (/tmp/shelf-judge.sock), JSON persistence (~/.shelf-judge/)\n  web/       Next.js 16 frontend, proxies to daemon via /api/daemon/[...path]\n  cli/       Bun CLI (shelf-judge / sj), communicates with daemon over Unix socket\n```\n\nThe daemon owns all data. The web UI and CLI are both clients of the daemon API. All state is stored as JSON files under `~/.shelf-judge/` — no database required.\n\n## Requirements\n\n- [Bun](https://bun.sh) ≥ 1.2\n- A BGG application token for BGG-dependent features (search, import, community data). The app works without one for manual entry and personal-only scoring.\n\n## Getting Started\n\n```bash\n# Install dependencies\nbun install\n\n# Start the daemon and web UI together\nbun run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000).\n\n### BGG Application Token\n\nTo search BGG, import your collection, or use Community Rating and Complexity axes, register a token at [https://boardgamegeek.com/using_the_xml_api](https://boardgamegeek.com/using_the_xml_api) and configure it:\n\n```bash\nshelf-judge config set bgg-token YOUR_TOKEN\n```\n\nThe app runs fully without a token — manual game entry, personal axes, and fitness scoring on personal ratings all work offline.\n\n## CLI\n\nThe `shelf-judge` binary (alias `sj`) connects to the daemon over its Unix socket.\n\n```bash\n# Games\nshelf-judge game search \"wingspan\"\nshelf-judge game add --bgg-id 266192\nshelf-judge game add --name \"Custom Game\"    # no BGG data\nshelf-judge game list\n\n# Rate a game\nshelf-judge game rate \u003cid\u003e --axis \"Wife will play it\" 8 --axis \"Visual design\" 9\n\n# Axes\nshelf-judge axis list\nshelf-judge axis create \"Wife will play it\" --weight 40\nshelf-judge axis update \u003cid\u003e --weight 50\n\n# Scores\nshelf-judge score list               # All games ranked by fitness\nshelf-judge score get \u003cid\u003e           # Full breakdown for one game\n\n# Import\nshelf-judge import bgg-collection \u003cbgg-username\u003e\n\n# Wishlist\nshelf-judge wishlist add --bgg-id 342942\nshelf-judge wishlist list\n\n# Tournament\nshelf-judge tournament start\nshelf-judge tournament next          # Next matchup\nshelf-judge tournament pick \u003cid\u003e    # Choose a winner\n\n# Configuration\nshelf-judge config set bgg-token \u003ctoken\u003e\n\n# Daemon management\nshelf-judge start\nshelf-judge stop\n```\n\nEvery command accepts `--json` for raw JSON output — useful for scripting and agent consumption.\n\n## Web UI\n\nThe web UI is the primary interface. Navigate from the sidebar:\n\n| Page | What you do there |\n|---|---|\n| **Collection** | Browse all games sorted by fitness, filter and sort, see the redundancy and prediction overlays |\n| **Game detail** | View fitness breakdown, rate axes, refresh BGG data, edit box dimensions |\n| **Search / Add** | Find games on BGG or add manually |\n| **Wishlist** | Games you want; predicted fitness scores shown alongside |\n| **Axes** | Create, edit, and delete personal rating axes and adjust weights |\n| **Tournament** | Run head-to-head ELO sessions; configure the bracket filters |\n| **Redundancy** | Configure the overlap-penalty settings |\n| **Previously Owned** | Games you've culled; keep a record without cluttering the active shelf |\n\n## Fitness Score\n\n```\nfitness = Σ(rating × weight) / Σ(weight)\n```\n\nOnly axes with a rating for that game contribute to the numerator and denominator. Unrated axes are listed in the breakdown as \"not rated\" — they do not silently drag the score down.\n\n**Example breakdown for Wingspan:**\n\n```\nFitness: 7.9\n\n  Wife will play it    8   × 40  →  320   [your rating]\n  Visual design        9   × 30  →  270   [your rating]\n  Complexity           5.8 × 20  →  116   [BGG weight 2.9 → 5.8]\n  Community Rating     8.1 × 10  →   81   [BGG]\n  ────────────────────────────────────────\n  Sum of contributions: 787  /  Sum of weights: 100  =  7.87  →  7.9\n```\n\nBGG-derived values that you've overridden show both your rating and the original BGG value.\n\n## Development\n\n```bash\nbun run dev          # daemon + web UI (hot reload)\nbun run test         # Bun test suite across all packages\nbun run typecheck    # TypeScript strict checking\nbun run lint         # ESLint\nbun run format       # Prettier\n```\n\nTests live alongside source files and in `packages/daemon/tests/`. BGG API tests use hand-crafted XML fixtures — no live network calls.\n\n## Data Storage\n\nAll data lives under `~/.shelf-judge/`:\n\n```\n~/.shelf-judge/\n  config.json          BGG token and settings\n  data/\n    collection.json    Games and ratings\n    axes.json          Personal axes and weights\n    bgg-cache/         Cached BGG API responses (7-day TTL)\n    tournaments/       ELO tournament sessions\n    wishlist.json      Wishlist games\n```\n\nWrites are atomic (write to temp file, rename into place). A crash mid-write cannot corrupt existing data.\n\n## Project Status\n\nShelf Judge is pre-1.0. All core features are implemented:\n\n- [x] Multi-axis fitness scoring with full breakdown\n- [x] BGG integration (search, import, community rating, complexity)\n- [x] Utility curves for non-linear axis scoring (plateau, S-curve, hard veto)\n- [x] Tournament-based ELO ranking\n- [x] Redundancy penalty (overlap-aware fitness)\n- [x] Prediction engine for wishlist / unrated games\n- [x] Collection filter and sort\n- [x] Collection profiling (taste profile inference)\n- [x] Wishlist management\n- [x] Previously-owned tracking\n- [x] Niche champion display\n- [ ] **Shelf capacity** — physical box dimensions, shelf configuration, and bin-packing overflow detection _(in progress → 1.0)_\n\n## Guiding Principles\n\n1. **Ownership is personal and specific.** Axes are user-defined because \"good\" is never one thing.\n2. **One number, honestly derived.** Every fitness score can be cracked open to see exactly what drove it.\n3. **Your collection has an identity.** The pattern of what you own and why encodes preferences you may never have articulated.\n4. **Data serves judgment, not replaces it.** BGG provides context. The owner decides.\n5. **The shelf has a carrying capacity.** Fitness is relative. A fifth worker-placement game isn't as fit as the first, even if it's individually excellent.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frjroy%2Fshelf-judge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frjroy%2Fshelf-judge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frjroy%2Fshelf-judge/lists"}