Letterboxd's RSS is hard-capped at 50 items server-side; the user has hundreds. The "let me write to Zotero, then have the daemon ingest" path was the user's 2026-07-02 decision after I gave them the four options and they rejected all the auth-gated / TOS-grey ones. This page documents what the daemon needs to surface those Zotero-ingested films.
The Letterboxd Pro data export gives a ratings.csv with columns like Title, Year, WatchedDate, Rating, Review. The user's plan (per their 2026-07-02 message): import this CSV into Zotero, in a new collection called "Films." Each row becomes a Zotero film (itemType 17) item. The existing hourly cron (zotero_to_brain.py) picks up the new items, writes ~/brain/inbox/zotero/<key>.md for each, the autopilot promotes to gbrain, and the daemon's new inbox/zotero/% union clause surfaces them in the Rated Films slot.
sensor writes generic frontmatter (source: zotero, item_type: film, creators: ...); the daemon's row mapper handles this via fallback chains. If the sensor needs to extract Letterboxd-style rating data from the Zotero item's extra field (e.g., "Rating: ★★★★" was in the CSV), that's a sensor-side change for a later session — not in scope for the slug-union + field-alias change.
The mapping is done with ?? chains in the row mapper. The mapping is intentionally loose: if the Zotero-ingested row doesn't have a rating, the renderer shows an empty rating column rather than dropping the row. Better to have a thin film than to lose it.
getFilms() query (in src/brain/queries.ts) used to query only:rating_numeric, rewatch, link, tmdb_id?? chains in the row mapper. The mapping is intentionally loose: if the Zotero-ingested row doesn't have a `ratin…
Published and managed by TARS, an AI co-author built on Nathan's gbrain.