# Project pack: Ryot @ 77190a6

Facts about **Ryot** for an AI following the [BespokeAI handover guide](https://handoff.bespokeai.software/guide/v2.md). This pack is pinned to one version and never changes after publication.

> Ryot is a private diary for your free time. Log the films and shows you watch, the books you read, the games you play and the podcasts you hear, rate them and keep a "to watch" list. It also logs gym workouts and body measurements, with graphs to show your progress. It reminds you when a new episode of a show you follow comes out. It runs on your own computer or server, so your history stays yours.

## Version and source
- Repository: https://github.com/IgnisDa/ryot
- Pinned commit: `77190a6193f41d00c73f7776434f62ce92eb3309`. Use exactly this version.
- Fresh checkout: use the setup below in an empty folder. If you already have this exact source checked out, keep your branch and use the development command instead; do not clone again or reset local changes.
- Or download a zip: https://github.com/IgnisDa/ryot/archive/77190a6193f41d00c73f7776434f62ce92eb3309.zip
- Official docs: https://docs.ryot.io
- Live demo: https://demo.ryot.io/_s/acl_vUMPnPirkHlT. Official public demo linked from the README. Data resets every 24 hours. Don't enter anything private.
- Licence: **GPL-3.0-only**. Free to use, change and share. If you give copies of the app (changed or not) to other people, you must also give them the source code under the same licence. Running it for yourself, or as a website for others, has no extra obligations. Some extra features ("Ryot Pro") need a paid key from the author; the free version works fully without it.

## Running the pinned source
- Fresh pinned-source setup (skip clone and checkout in an existing worktree):

  ```sh
  git clone https://github.com/IgnisDa/ryot bespoke-ryot
  cd bespoke-ryot
  git checkout --detach 77190a6193f41d00c73f7776434f62ce92eb3309
  # Prepare development requirements and local configuration first.
  # Setup notes: backend; then in other terminals: caddy run --config 'ci/Caddyfile' and yarn turbo run dev --filter=@ryot/frontend (open :8000). Needs a .env, see apps/docs/src/contributing.md
  cargo run
  ```

The commands below are a starting point from the reviewed source. Prepare the listed tools, local configuration and companion services before starting the app. These instructions have not yet been validated in participant sessions.

### Separate trial of the current release
This tries an upstream release, which may differ from the pinned source above. It does not run your source changes. Use only sample data and a separate data directory or volume. Check the upstream documentation before running it.

  ```sh
  Create docker-compose.yml with two services: ryot-db (image postgres:18-alpine, POSTGRES_PASSWORD=postgres, volume postgres_storage:/var/lib/postgresql) and ryot (image ignisda/ryot:v10, ports "8000:8000", SERVER_ADMIN_ACCESS_TOKEN set to a long random string, DATABASE_URL=postgres://postgres:postgres@ryot-db:5432/postgres). Run `docker compose up -d` and open http://localhost:8000 to create your account. (Full file in the README's Quick Start and at docs.ryot.io.)
  ```

- Needs: Docker with Docker Compose, For development, Rust (version in rust-toolchain.toml), Node 24 with Yarn 4, Caddy 2.7+ and PostgreSQL 15+
- Develop: `cargo run   # backend; then in other terminals: caddy run --config 'ci/Caddyfile' and yarn turbo run dev --filter=@ryot/frontend (open :8000). Needs a .env, see apps/docs/src/contributing.md`
- Test: `cargo build --release && yarn turbo run test --filter=@ryot/tests   # AGENTS.md asks agents to get the user's approval before running tests`
- Check/lint: `cargo clippy && yarn turbo run typecheck`
- Stack: rust, typescript (Axum, async-graphql, SeaORM, React Router 7, React 19, Mantine 8, Turborepo). Difficulty for a non-developer with an AI: **advanced**. Everyday changes (which media types you track, units, dashboard sections, notifications, imports) are settings in the app. Code changes mean a Rust backend (crates/**) plus a React frontend (apps/frontend/), joined by a GraphQL API with generated types, so builds are slow and need Rust, Node 24 and PostgreSQL. The author is rewriting Ryot in TypeScript on a separate branch, so code changes to this version will not carry over to the next major release.

## The project's own AI instructions
Read these in the repository before changing code: `AGENTS.md`, `apps/docs/src/contributing.md`.

## Customisation points (settings → extend → code)
- **preferences** [settings]: Hide media types you don't use, choose dashboard sections and their order, units (kg/lb, km/mi), rating scale and more. → `Settings → Preferences (apps/frontend/app/routes/_dashboard.settings.preferences.tsx)`
- **providers-env** [settings]: Turn on films, TV and games by adding free API keys; dashboard message, sign-up and telemetry switches. → `Environment variables (apps/docs/src/includes/backend-config-schema.yaml, apps/docs/src/configuration.md)`
- **notifications** [settings]: Get told about new episodes, release dates and reminders on Telegram, Discord, ntfy, Gotify, Pushover, Apprise, email and more. → `Settings → Notifications (apps/frontend/app/routes/_dashboard.settings.notifications.tsx)`
- **imports** [extend]: Bring your history in from Goodreads, Trakt, IMDb, Netflix, MyAnimeList, Strong, Hevy, Plex, Jellyfin and others. → `Settings → Imports and Exports (apps/docs/src/importing/overview.md)`
- **integrations** [extend]: Log what you watch automatically from Jellyfin, Plex, Emby or Kodi, or send updates to Radarr and Sonarr. → `Settings → Integrations (apps/docs/src/integrations/overview.md)`
- **graphql-api** [extend]: Write your own scripts, e.g. a yearly reading summary or a printed watchlist. → `GraphQL API at /backend/graphql on your instance (queries in libs/graphql/src/backend/)`
- **frontend-pages** [code]: New screens or a different look. Uses Mantine components. → `apps/frontend/app/routes/** and apps/frontend/app/components/** (theme in apps/frontend/app/root.tsx)`
- **backend** [code]: New data or behaviour. Regenerate frontend types afterwards (see AGENTS.md). → `crates/services/** (logic), crates/resolvers/** (GraphQL), crates/models/** (data), crates/migrations/sql/src/ (migrations), crates/providers/** (data sources)`

## Must keep working
- Your history, ratings, workouts and measurements. Back up the database before any upgrade or code change.
- Privacy between users on the same instance.
- Integration webhook URLs (/_i/...) already set up in Jellyfin, Plex or Kodi.
- Database changes need a forward-only migration in crates/migrations/sql/src/ (see AGENTS.md).
- Don't edit generated types in libs/generated/; regenerate them as AGENTS.md describes.

## Staying updatable
Preferences, environment variables, imports, integrations and the GraphQL API cover most needs without a fork. The author is rewriting Ryot (TypeScript, "ultra-rewrite" branch) and the current Rust code will leave the main branch, so keep any code changes small and expect to redo them. Follow AGENTS.md for style.

## Data, costs and safety
- Personal data: **yes**. Stored in: PostgreSQL (the postgres_storage volume). Uploaded images go to S3-compatible storage if configured. Your viewing, reading, workout and body-measurement history. Back it up with `docker exec -u postgres -i ryot-db pg_dump -Fc --no-acl --no-owner > ryot.dump` (see apps/docs/src/exporting.md). The in-app JSON export needs S3 storage set up.
- Service: TMDB (The Movie Database) (optional, free for personal use): Needed to track films and TV shows. You make a free account and paste its access token into MOVIES_AND_SHOWS_TMDB_ACCESS_TOKEN.
- Service: Twitch / IGDB (optional, free): Needed to track video games (VIDEO_GAMES_TWITCH_CLIENT_ID and VIDEO_GAMES_TWITCH_CLIENT_SECRET).
- Service: Other data providers (Open Library, AniList, MyAnimeList, Audible, iTunes, Spotify, Google Books, Hardcover, ListenNotes and more) (optional, free; some need a free API key): Look up books, anime, manga, music and podcasts. Open Library (books) works with no key.
- Service: Ryot Pro key (via Unkey) (optional, paid subscription or lifetime licence from ryot.io): Unlocks extra features such as profile sharing, recommendations and supercharged collections. The key is checked with Unkey's API.
- Service: S3-compatible file storage (e.g. MinIO) (optional, free if self-hosted): Needed for the in-app export and for uploading your own images.
- Service: Telegram, Discord, ntfy, Gotify, Pushover, Apprise or email (SMTP) (optional, free): Notifications about new episodes, release dates and reminders.
- Setting `DATABASE_URL` (**secret**: the person enters it themselves, never in chat): Address and password of the PostgreSQL database.
- Setting `SERVER_ADMIN_ACCESS_TOKEN` (**secret**: the person enters it themselves, never in chat): A long random string used for admin actions. Never paste it into an AI chat.
- Setting `FRONTEND_URL`: The address you open Ryot at (an IP address is fine).
- Setting `TZ`: Your time zone, used for scheduled jobs (e.g. Europe/London).
- Setting `USERS_ALLOW_REGISTRATION`: Whether new people can sign up. Set to false after creating your family's accounts.
- Setting `DISABLE_TELEMETRY`: Set to true to stop anonymous usage statistics being sent to the author's Umami server.
- Setting `MOVIES_AND_SHOWS_TMDB_ACCESS_TOKEN` (**secret**: the person enters it themselves, never in chat): TMDB "API Read Access Token". Needed for films and TV shows.
- Setting `VIDEO_GAMES_TWITCH_CLIENT_ID`: Twitch client ID. Needed for video games, together with VIDEO_GAMES_TWITCH_CLIENT_SECRET.
- Setting `VIDEO_GAMES_TWITCH_CLIENT_SECRET` (**secret**: the person enters it themselves, never in chat): Twitch client secret for video game lookups.
- Setting `FRONTEND_DASHBOARD_MESSAGE`: A message shown at the top of everyone's dashboard.
- Setting `SERVER_PRO_KEY` (**secret**: the person enters it themselves, never in chat): Your Ryot Pro licence key, if you bought one.
- Set a long random SERVER_ADMIN_ACCESS_TOKEN and change the example database password before real use.
- USERS_ALLOW_REGISTRATION is true by default. Turn it off once your accounts exist if Ryot is reachable from the internet.
- Anonymous usage statistics go to the author's Umami server unless you set DISABLE_TELEMETRY=true.
- Integration webhook URLs let anyone who has them add plays to your account. Keep them private.
- Looking up a title sends the search words to outside providers such as TMDB or Open Library. Your history stays on your server.

---

# Customising Ryot

Ryot is a Rust backend plus a React frontend, so code changes are heavy. **Most personal tweaks are settings, imports or integrations.** The author is also rewriting Ryot in TypeScript, so code changes to this version may need redoing later. Stay on levels 1 and 2 where you can.

## Level 1: Settings (no code)
- **What you track:** Settings → Preferences. Hide media types you never use (games, podcasts, fitness…), choose which dashboard sections show and in what order, pick units (metric or imperial) and the rating scale.
- **Turn on films, TV and games:** these need free API keys in environment variables (`MOVIES_AND_SHOWS_TMDB_ACCESS_TOKEN`, `VIDEO_GAMES_TWITCH_CLIENT_ID` / `_SECRET`). Books work out of the box with Open Library. Full list: `apps/docs/src/includes/backend-config-schema.yaml`.
- **Instance switches:** `USERS_ALLOW_REGISTRATION=false` once accounts exist, `DISABLE_TELEMETRY=true`, `FRONTEND_DASHBOARD_MESSAGE` for a note on everyone's dashboard.
- **Notifications:** Settings → Notifications. Telegram, Discord, ntfy, Gotify, Pushover, Pushbullet, Pushsafer, Apprise or email.
- **Collections and reminders:** the built-in Watchlist, Monitoring and Reminders collections control alerts (see `apps/docs/src/concepts/collections.md`). Make your own collections for anything else.

## Level 2: Extend (no fork)
- **Imports** (Settings → Imports and Exports): Goodreads, StoryGraph, Trakt, IMDb, Netflix, MyAnimeList, AniList, Strong, Hevy, Plex, Jellyfin, Audiobookshelf and more. Guides in `apps/docs/src/importing/`.
- **Integrations** (Settings → Integrations): log plays automatically from Jellyfin, Plex, Emby or Kodi; pull progress from Audiobookshelf or Komga; push to Radarr/Sonarr. Guides in `apps/docs/src/integrations/`.
- **GraphQL API** at `/backend/graphql` on your instance. Good for year-in-review pages, printed lists or syncing with other tools. Example queries live in `libs/graphql/src/backend/`.
- **Export:** JSON export from the app (needs S3-compatible storage), or a full `pg_dump` of the database.

## Level 3: Code
Read upstream `AGENTS.md` and `apps/docs/src/contributing.md` first. Summary:

| Change | Where |
|---|---|
| New page or view | `apps/frontend/app/routes/**` (React Router 7 file routes) and `apps/frontend/app/components/**` |
| Look and feel (Mantine theme) | `apps/frontend/app/root.tsx` (`createTheme`), styles in `apps/frontend/app/styles/` |
| Workout screen | `apps/frontend/app/routes/_dashboard.fitness.$action.tsx`, `apps/frontend/app/components/routes/fitness.action/` |
| Backend logic | `crates/services/**`, exposed through `crates/resolvers/**` |
| New data | `crates/models/**` + a forward-only migration in `crates/migrations/sql/src/` (name `m<YYYYMMDD>_changes_for_issue_<n>`) |
| New data source | `crates/providers/**` |
| Frontend types for new queries | Add `.gql` in `libs/graphql/src/backend/`, then `yarn turbo run backend-graphql --filter=@ryot/generated` with the backend running |

## Running locally
- **Just use it:** create the `docker-compose.yml` from the README (Postgres + `ignisda/ryot:v10`), set `SERVER_ADMIN_ACCESS_TOKEN`, run `docker compose up -d` and open http://localhost:8000.
- **Develop:**
  1. Install Rust, Node 24 with Yarn 4, Caddy and PostgreSQL (Docker is fine for Postgres).
  2. Create `.env` as shown in `apps/docs/src/contributing.md`.
  3. Run `cargo run`, `caddy run --config 'ci/Caddyfile'` and `yarn turbo run dev --filter=@ryot/frontend` in three terminals.
  4. Open http://localhost:8000.
- **Check:** `cargo clippy`, `yarn turbo run typecheck`. Tests: `cargo build --release && yarn turbo run test --filter=@ryot/tests` (AGENTS.md asks agents to get your OK first).

## Pitfalls
- Back up the database first (`pg_dump`, see `apps/docs/src/exporting.md`). Years of history are hard to rebuild.
- Films, TV and games show nothing until you add the provider keys. That is not a bug.
- The `develop` Docker tag is unstable and the docs warn it can lose data. Stay on `v10`.
- The Rust build is slow and needs a lot of memory. Prefer settings and the API.
- AGENTS.md has strict style rules (no comments, files under 500 lines, field ordering by line length). Follow them if you hope to share a change.

---
Machine-readable: [bespoke.yaml](https://handoff.bespokeai.software/p/ryot/77190a6/r2/bespoke.yaml) · Hosting options: [hosting.md](https://handoff.bespokeai.software/p/ryot/77190a6/r2/hosting.md) · Agent skill: [SKILL.md](https://handoff.bespokeai.software/p/ryot/77190a6/r2/SKILL.md)
