{"id":50967684,"url":"https://github.com/engnadeau/books","last_synced_at":"2026-06-18T22:02:29.626Z","repository":{"id":358580988,"uuid":"1212746772","full_name":"engnadeau/books","owner":"engnadeau","description":"Nick's personal reading library — Goodreads replacement backed by a single books.json and an Astro site.","archived":false,"fork":false,"pushed_at":"2026-05-18T02:47:22.000Z","size":69,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-18T04:52:13.057Z","etag":null,"topics":["astro","books","goodreads","open-library","reading","static-site"],"latest_commit_sha":null,"homepage":"https://engnadeau.github.io/books/","language":"TypeScript","has_issues":false,"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/engnadeau.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-16T17:33:12.000Z","updated_at":"2026-05-10T18:22:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/engnadeau/books","commit_stats":null,"previous_names":["engnadeau/books"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/engnadeau/books","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engnadeau%2Fbooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engnadeau%2Fbooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engnadeau%2Fbooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engnadeau%2Fbooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/engnadeau","download_url":"https://codeload.github.com/engnadeau/books/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engnadeau%2Fbooks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34508867,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["astro","books","goodreads","open-library","reading","static-site"],"created_at":"2026-06-18T22:02:28.554Z","updated_at":"2026-06-18T22:02:29.617Z","avatar_url":"https://github.com/engnadeau.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# books\n\nA self-hosted, version-controlled replacement for Goodreads. Books live as a\nsingle JSON file in git; an Astro static site renders the ones I've read.\n\n- **Live site:** https://engnadeau.github.io/books/\n- **Canonical data (for LLMs / external tools):**\n  https://raw.githubusercontent.com/engnadeau/books/main/books.json\n\n## Why\n\nGoodreads' data model is noisy and its export format is hostile. A flat JSON\nfile in a public git repo is easier to edit, easier to fetch, and trivial for\na language-model agent to reason over via the raw GitHub URL.\n\n## Local development\n\n```sh\npnpm install\npnpm dev\n```\n\nOpen http://localhost:4321.\n\n## Scripts\n\n```sh\n# One-shot seed: turn a Goodreads CSV export into books.json.\n# Refuses to overwrite an existing books.json unless --force is passed.\npnpm import \"/path/to/goodreads_library_export.csv\"\n\n# Fetch cover URLs from Open Library. Tries ISBN lookup first,\n# falls back to title+author search. Writes URLs to each book's cover_url field.\n# --only-read limits to read books; --force re-fetches books that already have covers.\npnpm covers --only-read\n\n# Build/preview.\npnpm build\npnpm preview\n```\n\n## Schema\n\n`books.json` is a JSON array of:\n\n```ts\n{\n  id: string;                           // stable slug, never regenerated\n  title: string;\n  author: string;\n  series: { name: string; position: number } | null;\n  isbn: string | null;                  // ISBN13 preferred, else ISBN10\n  cover_url: string | null;             // Open Library URL, populated by pnpm covers\n  status: \"read\" | \"reading\" | \"to-read\" | \"dnf\";\n  rating: 1 | 2 | 3 | 4 | 5 | null;\n  date_started: string | null;          // YYYY-MM-DD\n  date_finished: string | null;         // YYYY-MM-DD\n  tags: string[];                       // lowercase kebab-case\n}\n```\n\nThe Zod schema in `src/content.config.ts` validates this on every `astro sync`\nand build, so malformed entries fail loudly instead of silently breaking the\nsite.\n\n## Deployment\n\nGitHub Pages via `.github/workflows/deploy.yml`. Every push to `main` rebuilds\nand redeploys. The workflow uses `withastro/action@v6`, which auto-detects\npnpm from the lockfile.\n\n## Project layout\n\n```\nbooks.json                      source of truth\nsrc/content.config.ts           Zod schema + file loader\nsrc/pages/index.astro           only page; filters to status === \"read\"\nsrc/components/BookTable.astro  cover grid + client-side search/sort\nsrc/styles/global.css\nscripts/import-goodreads.ts     CSV → books.json\nscripts/fetch-covers.ts         books.json → books.json (with cover_url)\ndocs/superpowers/specs/         design docs\n```\n\n## Design intent\n\n- `id` is immutable once created. Everything else can be hand-edited.\n- `books.json` is written with `JSON.stringify(x, null, 2) + \"\\n\"` so git\n  diffs stay clean.\n- A future MCP server will read and write `books.json` directly — no new\n  schema, no transformation layer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fengnadeau%2Fbooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fengnadeau%2Fbooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fengnadeau%2Fbooks/lists"}