# kyusetzu/karasu architecture

> Architecture diagram of the GitHub repository kyusetzu/karasu, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-13). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/kyusetzu/karasu
- Repository: https://github.com/kyusetzu/karasu

## Overview

#### Purpose and Runtime
Karasu is a Windows/Linux desktop anime and manga tracker centered on AniList. It is a Tauri 2 application: a Rust native backend hosts a React/TypeScript WebView frontend. The backend executable starts through `src-tauri/src/main.rs` and app wiring lives in `src-tauri/src/lib.rs`; the frontend mounts from `src/app/main.tsx` into `src/app/App.tsx`.

#### UI, Navigation, and Client State
The React application presents dashboard, list, discovery, local-library, settings, statistics, and year-review screens. Pages consume API wrappers and maintain UI-local state through Zustand; server/list data is managed with TanStack Query. Core paths: `src/pages/Dashboard.tsx`, `src/pages/MediaList.tsx`, `src/pages/Settings.tsx`, `src/stores/auth.ts`, `src/stores/nowPlaying.ts`, and `src/api/queries.ts`. Virtualized list rendering is concentrated in `src/components/list/VirtualGrid.tsx`.

#### Frontend–Native Boundary
The UI calls Tauri-exposed Rust commands through frontend API modules rather than directly owning persistence, auth, playback, or OS integrations. The frontend boundary includes `src/api/anilist.ts`, `src/api/library.ts`, and `src/api/diagnostics.ts`; backend command groups are organized in `src-tauri/src/commands/auth.rs`, `src-tauri/src/commands/list.rs`, `src-tauri/src/commands/playback.rs`, and `src-tauri/src/commands/system.rs`. This boundary is the primary control path for mutations and platform-dependent features.

#### AniList, Local Lists, and Synchronization
AniList authentication and GraphQL/client behavior are backend-owned, with browser-based login plus token management. List operations support connected AniList data and local-only operation, backed by SQLite; failed remote writes are retained as an offline queue for later synchronization. Key paths: `src-tauri/src/anilist/auth.rs`, `src-tauri/src/anilist/client.rs`, `src-tauri/src/db.rs`, `src-tauri/src/commands/list.rs`, and `src/api/anilist.ts`. Tokens use the OS credential store except in portable-mode handling at `src-tauri/src/portable.rs`.

#### Playback Detection and Scrobbling Pipeline
Detection sources produce playback candidates, which are parsed and matched to AniList media, then evaluated for progress updates and scrobbled subject to thresholds, confirmation, gap protection, and anime relations. The orchestration is under `src-tauri/src/playback/mod.rs`; source adapters include Windows/Linux media sessions and Jellyfin in `src-tauri/src/playback/detection/media_session/mod.rs` and `src-tauri/src/playback/detection/jellyfin.rs`. Recognition and filename/title parsing are separated in `src-tauri/src/playback/recognition/matcher.rs` and `src-tauri/src/playback/recognition/parser.rs`; writes flow through `src-tauri/src/playback/scrobbler.rs`.

#### Native Services and Integrations
Rust owns desktop-specific behavior: system tray/window lifecycle, notifications, local filesystem library scanning/matching, Discord Rich Presence, diagnostics, logging, and update checks. Architectural modules are `src-tauri/src/library.rs`, `src-tauri/src/alerts/mod.rs`, `src-tauri/src/discord.rs`, `src-tauri/src/diagnostics.rs`, and `src-tauri/src/commands/update.rs`. External services are AniList, optional Jellyfin `/Sessions`, Discord, and OS media APIs: SMTC on Windows and MPRIS on Linux.

#### Build and Distribution
Vite builds the frontend while Tauri packages native installers/AppImages. Tauri capabilities and application settings are declared at `src-tauri/capabilities/default.json` and `src-tauri/tauri.conf.json`; Rust dependencies/build settings are in `src-tauri/Cargo.toml`. Release automation produces update artifacts via `scripts/release/generate-update-manifest.ps1`; CI/release workflows are ` .github/workflows/ci.yml` and `.github/workflows/release.yml`.

Main entry points: [`src-tauri/src/commands/list.rs`](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/commands/list.rs) (Native command boundary), [`src-tauri/src/anilist/client.rs`](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/anilist/client.rs) (AniList GraphQL client), [`src/app/App.tsx`](https://github.com/kyusetzu/karasu/blob/main/src/app/App.tsx) (App shell and screens), [`src-tauri/src/lib.rs`](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/lib.rs) (Application wiring)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_frontend["React frontend"]
  node_react_mount["React mount<br/>frontend entrypoint<br/>[main.tsx]"]
  node_app_shell["App shell and screens<br/>React UI<br/>[App.tsx]"]
  node_client_state["Client state and queries<br/>Zustand + TanStack Query<br/>[queries.ts]"]
  node_virtual_grid["Virtualized media grid<br/>React component<br/>[VirtualGrid.tsx]"]
  node_frontend_api["Frontend API wrappers<br/>Tauri command client<br/>[anilist.ts]"]
end

subgraph group_native["Tauri native backend"]
  node_tauri_bootstrap{{"Tauri bootstrap<br/>Rust entrypoint<br/>[main.rs]"}}
  node_app_wiring["Application wiring<br/>Rust composition<br/>[lib.rs]"]
  node_command_boundary["Native command boundary<br/>Tauri commands<br/>[list.rs]"]
  node_anilist_auth["AniList authentication<br/>OAuth token service<br/>[auth.rs]"]
  node_anilist_client["AniList GraphQL client<br/>remote client<br/>[client.rs]"]
  node_local_data[("SQLite lists and offline queue<br/>local persistence<br/>[db.rs]")]
  node_library_service["Local library service<br/>filesystem scanner<br/>[library.rs]"]
  node_desktop_integrations["Desktop integrations<br/>native services<br/>[mod.rs]"]
end

subgraph group_playback["Playback pipeline"]
  node_playback_orchestrator["Playback orchestration<br/>detection pipeline<br/>[mod.rs]"]
  node_detection_sources["Playback sources<br/>media adapters<br/>[mod.rs]"]
  node_recognition["Media recognition<br/>parser and matcher<br/>[matcher.rs]"]
  node_scrobbler["Progress scrobbler<br/>write policy<br/>[scrobbler.rs]"]
end

subgraph group_external["External services"]
  node_anilist(("AniList<br/>GraphQL service"))
  node_os_media(("OS media APIs<br/>SMTC / MPRIS"))
  node_jellyfin(("Jellyfin<br/>Sessions API"))
  node_discord(("Discord<br/>Rich Presence service"))
end

node_tauri_bootstrap -->|"starts"| node_app_wiring
node_app_wiring -->|"hosts WebView"| node_react_mount
node_react_mount -->|"mounts"| node_app_shell
node_app_shell -->|"uses"| node_client_state
node_app_shell -->|"renders lists with"| node_virtual_grid
node_client_state -->|"fetches and mutates through"| node_frontend_api
node_frontend_api -->|"invokes"| node_command_boundary
node_command_boundary -->|"auth commands"| node_anilist_auth
node_command_boundary -->|"list persistence"| node_local_data
node_command_boundary -->|"library operations"| node_library_service
node_command_boundary -->|"playback control"| node_playback_orchestrator
node_app_wiring -->|"initializes"| node_desktop_integrations
node_anilist_auth -->|"authorizes"| node_anilist_client
node_anilist_client -->|"GraphQL requests"| node_anilist
node_local_data -.->|"syncs queued writes"| node_anilist_client
node_library_service -->|"stores matches"| node_local_data
node_detection_sources -->|"playback candidates"| node_playback_orchestrator
node_os_media -->|"media sessions"| node_detection_sources
node_jellyfin -->|"sessions"| node_detection_sources
node_playback_orchestrator -->|"recognizes candidates"| node_recognition
node_recognition -->|"matched media"| node_scrobbler
node_scrobbler -->|"progress updates"| node_anilist_client
node_desktop_integrations -->|"Rich Presence"| node_discord

click node_tauri_bootstrap "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/main.rs"
click node_app_wiring "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/lib.rs"
click node_react_mount "https://github.com/kyusetzu/karasu/blob/main/src/app/main.tsx"
click node_app_shell "https://github.com/kyusetzu/karasu/blob/main/src/app/App.tsx"
click node_client_state "https://github.com/kyusetzu/karasu/blob/main/src/api/queries.ts"
click node_virtual_grid "https://github.com/kyusetzu/karasu/blob/main/src/components/list/VirtualGrid.tsx"
click node_frontend_api "https://github.com/kyusetzu/karasu/blob/main/src/api/anilist.ts"
click node_command_boundary "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/commands/list.rs"
click node_anilist_auth "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/anilist/auth.rs"
click node_anilist_client "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/anilist/client.rs"
click node_local_data "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/db.rs"
click node_library_service "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/library.rs"
click node_playback_orchestrator "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/mod.rs"
click node_detection_sources "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/detection/media_session/mod.rs"
click node_recognition "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/recognition/matcher.rs"
click node_scrobbler "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/scrobbler.rs"
click node_desktop_integrations "https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/alerts/mod.rs"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_react_mount,node_app_shell,node_client_state,node_virtual_grid,node_frontend_api toneBlue
class node_tauri_bootstrap,node_app_wiring,node_command_boundary,node_anilist_auth,node_anilist_client,node_local_data,node_library_service,node_desktop_integrations toneAmber
class node_playback_orchestrator,node_detection_sources,node_recognition,node_scrobbler toneMint
class node_anilist,node_os_media,node_jellyfin,node_discord toneRose
```

## Components

### React frontend

- [React mount](https://github.com/kyusetzu/karasu/blob/main/src/app/main.tsx): frontend entrypoint · `src/app/main.tsx`
- [App shell and screens](https://github.com/kyusetzu/karasu/blob/main/src/app/App.tsx): React UI · Hosts dashboard, lists, discovery, library, settings, statistics, and review screens. · `src/app/App.tsx`
- [Client state and queries](https://github.com/kyusetzu/karasu/blob/main/src/api/queries.ts): Zustand + TanStack Query · `src/api/queries.ts`
- [Virtualized media grid](https://github.com/kyusetzu/karasu/blob/main/src/components/list/VirtualGrid.tsx): React component · `src/components/list/VirtualGrid.tsx`
- [Frontend API wrappers](https://github.com/kyusetzu/karasu/blob/main/src/api/anilist.ts): Tauri command client · Keeps persistence, auth, playback, and OS integration behind the native boundary. · `src/api/anilist.ts`

### Tauri native backend

- [Tauri bootstrap](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/main.rs): Rust entrypoint · Starts the native host and wires application services. · `src-tauri/src/main.rs`
- [Application wiring](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/lib.rs): Rust composition · `src-tauri/src/lib.rs`
- [Native command boundary](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/commands/list.rs): Tauri commands · Receives frontend requests for auth, lists, playback, and system features. · `src-tauri/src/commands/list.rs`
- [AniList authentication](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/anilist/auth.rs): OAuth token service · Performs browser login and manages AniList tokens. · `src-tauri/src/anilist/auth.rs`
- [AniList GraphQL client](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/anilist/client.rs): remote client · `src-tauri/src/anilist/client.rs`
- [SQLite lists and offline queue](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/db.rs): local persistence · Stores local-only lists and failed remote writes for later synchronization. · `src-tauri/src/db.rs`
- [Local library service](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/library.rs): filesystem scanner · Scans and matches local media files. · `src-tauri/src/library.rs`
- [Desktop integrations](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/alerts/mod.rs): native services · Provides tray, windows, notifications, Discord presence, diagnostics, and updates. · `src-tauri/src/alerts/mod.rs`

### Playback pipeline

- [Playback orchestration](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/mod.rs): detection pipeline · Coordinates candidate detection, recognition, progress evaluation, and scrobbling. · `src-tauri/src/playback/mod.rs`
- [Playback sources](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/detection/media_session/mod.rs): media adapters · Consumes OS media sessions and optional Jellyfin sessions. · `src-tauri/src/playback/detection/media_session/mod.rs`
- [Media recognition](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/recognition/matcher.rs): parser and matcher · Parses filenames or titles and matches candidates to AniList media. · `src-tauri/src/playback/recognition/matcher.rs`
- [Progress scrobbler](https://github.com/kyusetzu/karasu/blob/main/src-tauri/src/playback/scrobbler.rs): write policy · Applies thresholds, confirmation, gap protection, and relations before updates. · `src-tauri/src/playback/scrobbler.rs`

### External services

- **AniList**: GraphQL service
- **OS media APIs**: SMTC / MPRIS
- **Jellyfin**: Sessions API
- **Discord**: Rich Presence service

## Connections

- Tauri bootstrap → Application wiring: starts
- Application wiring → React mount: hosts WebView
- React mount → App shell and screens: mounts
- App shell and screens → Client state and queries: uses
- App shell and screens → Virtualized media grid: renders lists with
- Client state and queries → Frontend API wrappers: fetches and mutates through
- Frontend API wrappers → Native command boundary: invokes
- Native command boundary → AniList authentication: auth commands
- Native command boundary → SQLite lists and offline queue: list persistence
- Native command boundary → Local library service: library operations
- Native command boundary → Playback orchestration: playback control
- Application wiring → Desktop integrations: initializes
- AniList authentication → AniList GraphQL client: authorizes
- AniList GraphQL client → AniList: GraphQL requests
- SQLite lists and offline queue → AniList GraphQL client: syncs queued writes
- Local library service → SQLite lists and offline queue: stores matches
- Playback sources → Playback orchestration: playback candidates
- OS media APIs → Playback sources: media sessions
- Jellyfin → Playback sources: sessions
- Playback orchestration → Media recognition: recognizes candidates
- Media recognition → Progress scrobbler: matched media
- Progress scrobbler → AniList GraphQL client: progress updates
- Desktop integrations → Discord: Rich Presence
