AGENTS.md -- Shelfie
This file is for coding agents working on the Shelfie repo. Humans should read README.md, PLAN.md, RUNBOOK.md, and DEPLOY.md instead.
Identity
- Product: Shelfie, hosted at https://shelfiebook.com.
- Pitch: photograph a bookshelf, get a searchable library out of it. No barcodes, no ISBN entry. The verb is
shelfie(lowercase). Use it everywhere. - Author: Edward Roske (CEO, AI/EPM expert, podcast host). Voice rules in
voice_patterns.md. Runedward-voice-checkskill on any prose humans will read.
Stack
- Next.js 15 App Router + TypeScript + Tailwind.
- Anthropic SDK (
@anthropic-ai/sdk). Default model:claude-sonnet-4-6. Useclaude-opus-4-7only for premium reasoning. Always use prompt caching on system prompts. - Supabase (Postgres + Auth + Storage). RLS on every user-data table.
- Vercel hosting. Cloudflare R2 for shelfie photos (planned).
- Fonts: Fraunces (serif) + Inter (sans).
Two modes
SHELFIE_DB_MODE env var:
local-- read everything fromfixtures/library.json+ browser localStorage. No auth, no DB. Used for local dev and the demo data shipped with the repo.supabase-- everything goes throughlib/db.tsand Postgres. Auth gated bymiddleware.ts. Production runs in this mode.
Every persistence hook (lib/reading.ts, lib/overrides.ts, lib/deletions.ts, lib/book-meta.ts) writes to localStorage and fires a best-effort patchBook(id, ...) to /api/books/[id]. localStorage is the offline cache; the DB is the source of truth in cloud mode.
Key files
| Path | Purpose |
|---|---|
app/library/page.tsx |
Four-view home (Grid/Spines/Stacks/Table). |
app/library/[id]/page.tsx |
Book detail, server component. |
app/scan/page.tsx |
Live camera capture flow. |
app/scan/review/[id]/page.tsx |
Confidence-banded review (green/yellow/red). |
lib/dedupe.ts |
bookKey(title, author) -- the canonical normalization. |
lib/library.ts |
loadLibrary(libraryId?) -- routes to fixtures or loadLibraryFromDb. |
lib/db.ts |
Supabase clients + loadLibraryFromDb. |
lib/sync.ts |
patchBook / deleteBook client helper that no-ops in local mode. |
lib/claude.ts |
readSpines, readCover, recommendForCluster. Cached system prompts. |
supabase/migrations/*.sql |
Run with npm run migrate. |
scripts/seed-cloud.ts |
One-shot fixture importer for a real Supabase user. |
Doing tasks
- Read
PLAN.mdand pick the lowest-numbered open milestone. - If a task is fuzzy, write or update its bullets in
PLAN.mdfirst. - Implement.
- Add or update tests where they exist (currently sparse).
- Run the voice-check on any new prose surfaced to humans.
- Update
README.md's Status section. - Use
eroske@interrel.comas the git author for commits intended to deploy via Vercel CLI -- the team gates by author email.
Don't
- Don't add features past the current milestone scope.
- Don't change the default model from Sonnet to Opus without a comment explaining why.
- Don't skip prompt caching on system prompts.
- Don't write code comments that explain WHAT (well-named identifiers handle that). Only WHY-non-obvious comments.
- Don't drop the verb. "Add a shelf" is wrong; "Take a shelfie" or "Shelfie a shelf" is right.
- Don't hardcode
localhost:3003or any IP. Use relative paths. - Don't bypass RLS. The service-role key is only used in
lib/db.tsserver code, server-side scripts, and/api/booksroutes that already gate byauth.uid().
Shelfie API for non-human users (in progress)
/api/v1/*-- REST. Bearer auth via per-user API keys (table:api_keys).npx shelfie-mcp-- MCP server for Claude Desktop / Cursor / etc.npx shelfie-- CLI thin wrapper over/api/v1.
If you are an agent reading this and you have an API key, the canonical entry points are:
GET https://shelfiebook.com/api/v1/books # paginated list
GET https://shelfiebook.com/api/v1/books/:id
POST https://shelfiebook.com/api/v1/books # add a book
PATCH https://shelfiebook.com/api/v1/books/:id # status/rating/notes/etc.
POST https://shelfiebook.com/api/v1/scan # multipart photo upload
GET https://shelfiebook.com/api/v1/export?format=csv # also xlsx, bibtex, goodreads
Authenticate with Authorization: Bearer <api_key>. The user owning the key sees only their own libraries.