An intent-aware curation companion for self-hosted Plex libraries.
CuratorX turns your homelab from a passive download queue into a context-aware curator. It knows what you own, learns taste within isolated curation lenses, and recommends hidden gems, collection gaps, and purge candidates — then adds titles to Radarr/Sonarr only after you confirm.
Dumb recommenders average everything you ever watched. CuratorX sandboxes taste by lens so a late-night comfort binge never poisons your director-study discovery lane.
- Why CuratorX
- Features
- Homelab stack
- Quick start
- Curation lenses
- Persona tuning
- Dual UI modes
- Screenshots
- Documentation
- Contributing
- License
| Typical recommender | CuratorX |
|---|---|
| One global taste profile | Lens isolation — separate contexts (General, Director Studies, 70s Exploitation, …) |
| “Top 10 on Netflix” vibes | Library-grounded RAG — answers from what you own and watch |
| Opaque scores | Explainable cards — every title carries a recommendation_reason |
| Auto-grab everything | *Confirmation-gated arr — Radarr/Sonarr writes need explicit approval |
| Vendor-locked AI | BYOP LLM — OpenAI, Anthropic, Ollama, or any OpenAI-compatible endpoint |
CuratorX complements disk tools like Reclaimspace: Reclaimspace quarantines duplicate files; CuratorX helps you decide what deserves the space.
- Chat-first curator — natural-language discovery, gap analysis, purge advice, and “what to watch tonight”
- Curation lenses — hard algorithmic walls between taste contexts; chat history and telemetry scoped by
lens_id - Dynamic persona — name your curator and tune tone sliders (bro↔professorial, diplomatic↔snarky, passive↔autonomous)
- Dual UI — compact Turnstyle command lane for fast intent entry; Immersive viewport for deep browsing
- RAG over Plex — semantic search with embeddings over your indexed library
- Metadata enrichment — TMDB, TVDB, Fanart.tv, optional Tautulli watch stats
- Safe automation — short-lived confirmation tokens for all Radarr/Sonarr mutations
- Unraid-ready — single Docker container, SQLite persistence, Community Applications template
flowchart TB
subgraph browser [Browser]
Turnstyle[Turnstyle widget]
Immersive[Immersive viewport]
end
subgraph curatorx [CuratorX container :8788]
API[FastAPI backend]
Agent[Curator agent + tools]
Jobs[Sync scheduler]
DB[(SQLite curatorx.db)]
end
subgraph homelab [LAN services]
Plex[Plex Media Server]
Radarr[Radarr]
Sonarr[Sonarr]
TMDB[TMDB API]
Tautulli[Tautulli optional]
Ollama[Ollama optional]
end
Turnstyle --> API
Immersive --> API
API --> Agent
API --> Jobs
Agent --> DB
Agent --> Ollama
Jobs --> Plex
Jobs --> Radarr
Jobs --> Sonarr
Agent --> TMDB
Jobs --> TMDB
Jobs --> Tautulli
Agent --> Radarr
Agent --> Sonarr
See Architecture for component diagrams, data flows, and security model.
git clone https://github.com/romwil/curatorx.git
cd curatorx
cp .env.example .env
docker compose up -d --buildOpen http://localhost:8788 and complete the setup wizard.
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e ".[web]"
cd frontend && npm install && npm run build && cd ..
DATA_DIR=./config python -m curatorx.webOpen http://localhost:8788.
Every chat session, taste vector, and telemetry event carries a lens_id. The default lens is general.
Lenses prevent context contamination: watch history and chat under a casual lens cannot drift recommendations in a curated study lens unless you explicitly bridge them.
# API examples (after setup)
curl http://localhost:8788/api/lenses
curl http://localhost:8788/api/lenses/active
curl -X PUT http://localhost:8788/api/lenses/active -H 'Content-Type: application/json' -d '{"lens_id":"general"}'Create custom lenses from Settings or POST /api/lenses. Full schema in Data model.
CuratorX hot-reloads your companion’s identity without redeploying:
| Slider | Range | Effect |
|---|---|---|
| Vocabulary density | Bro (0.0) → Professorial (1.0) | Word choice and depth |
| Interaction friction | Diplomatic (0.0) → Snarky (1.0) | Tone and pushback |
| Automation autonomy | Passive (0.0) → Autonomous (1.0) | How eagerly it proposes *arr actions |
Set curator name and sliders in Settings (/config) or via GET/PUT /api/persona.
| Mode | Purpose | Key UX |
|---|---|---|
| Turnstyle | Fast intent entry | Monospace command lane, lens prefix (⧉ [General] > _), thoughtstream feed |
| Immersive | Deep curation | Sidebar lens switcher, lens-scoped chat, visual title clusters |
Toggle with expansion hotkey, /expand, or viewport card click. Details in Design and Web UI.
Placeholders — replace with captures from your install.
| Turnstyle widget | Immersive viewport |
|---|---|
| Screenshot: compact command lane with lens prefix | Screenshot: sidebar + chat + title card grid |
| Setup wizard | Title detail |
|---|---|
| Screenshot: persona sliders and service validation | Screenshot: backdrop hero with purge note |
| Doc | Description |
|---|---|
| Product PRD | Vision, lens framework, persona, dual UI spec |
| Architecture | System context, data flows, deployment |
| Design | Principles, UX, agent tools, API surface |
| Data model | SQLite schema, lenses, persona tables |
| Configuration | Environment variables and settings |
| Onboarding | First-run checklist |
| Docker / Unraid | Container deployment |
| Web UI | Routes and API highlights |
Contributions welcome — especially lens presets, agent blueprints, connector hardening, and UI polish.
- Fork romwil/curatorx
- Create a feature branch:
git checkout -b feat/your-idea - Install dev deps:
pip install -e ".[web]"andcd frontend && npm install - Run tests:
python -m unittest discover -s tests -v - Open a PR with a clear description and test plan
Phase 1 ships the curatorx package, default general lens, persona API, and dual UI (Turnstyle + Immersive). Open issues for lens presets, agent blueprints, and connector hardening.
MIT — see LICENSE.