Twenty-five crates, layered so the core depends on no source and the terminal front end never reaches the engine.
Kaeri is twenty-five crates. A title moves through them from stable to volatile and back:
metadata and the ID mapping are stable, the sources that find a stream are the volatile part,
and the player, the history and the trackers are stable again.
From a title to an episode playing, and from your history to your trackers. Each box names the crate that does the work; amber marks the one volatile layer.
kaeri-core (types and traits) · -net (HTTP and rate limiting) · -meta (AniList, the
metadata failover, ID mapping, filler) · -store (SQLite: the history and the sync outbox) ·
-providers (torrent, mock) · -player (mpv IPC, the companion-script protocol, the
bundled player files, track selection, aniskip) · -discord (Discord rich presence over its
local socket) · -playback (the pure half of playback: what to record, skip and pick for tracks) ·
-mpv-host (libmpv behind the engine’s hosted player protocol, for the desktop apps) · -party
(watch parties, a Syncplay protocol client) · -remote (a phone finds a Kaeri TV on the
local network, pairs with it and drives it) · -cast (sending an episode to a TV with
Chromecast built in, which the engine has and no app offers yet) · -i18n (the strings the terminal and Linux apps
show, from the shared catalogue) · -track (AniList, MAL, Kitsu,
Simkl, Trakt, sync) · -plugin (WASM host).
Sources change and disappear, so every volatile piece sits behind a trait and the core depends on
none of them.
Local history is the source of truth, and sync is a projection of it. The SQLite history works
with no account and no network, and trackers consume it through a durable outbox instead of being
consulted for it.
The metadata, mapping, player, tracker and plugin layers use documented public APIs. Only the
source layer chooses a content source, it is off by default, and every source is a
config edit away from being removed. Two playback-side paths then fetch from whatever host a
source named, sidecar subtitles and the HLS proxy, and both are source-agnostic. The proxy sends
a stream’s headers with every request and passes segments through unchanged.
Arrows point from a crate to what it depends on. The four plugin store crates and the test kit are left out; they are described below.
kaeri-model is the protocol between the engine and a front end: the commands a front end
sends, the events it gets back, the rows they carry, and the wording they are shown in. It
depends only on the core and does no I/O.
kaeri-engine does the work behind the screens: playback and the player’s setup, sources
and plugins, tracker sync, downloads, artwork, plugin stores, the HLS proxy, choosing the
upscaling, and the background jobs, such as the daily update check.
kaeri-tui is the terminal front end: the screens, the keymap and the theme, on ratatui.
kaeri is the binary. It holds the command line, self-update, and the terminal’s event
loop, which hands the front end’s commands to the engine and its events back.
kaeri-ffi is the engine for the native apps: SwiftUI on macOS and iOS, Jetpack Compose
on Android and Android TV, and WinUI 3 on Windows. It hands them the model’s own commands and
events through UniFFI, and takes links, notifications and the OS’s secret store from the app.
The Swift package that wraps it is in apple/. The Linux app, written in Rust, links the engine
itself.
kaeri-testkit is used only by tests: a fake AniList, fixture titles and golden files.
The engine and the model use no terminal library, not even through a dependency, so a front end
that is not a terminal can run on them. The terminal front end depends on the model and the core,
never on the engine. The engine’s desktop feature holds what only a computer can do: mpv, watch
parties, the browser sign-in redirect and desktop notifications. A phone build leaves it out.
tools/check-boundaries.sh checks all three rules against the resolved dependency tree in CI,
the last for iOS and Android.
Four more crates make up plugin stores. kaeri-plugin-store is the
store client and the reference server. kaeri-store-core holds the store’s protocol, rules,
storage traits and admin page, and builds natively and to WebAssembly. kaeri-store-server is
the kaeri store … commands and the standalone kaeri-store binary.
kaeri-store-wasm is the store for Cloudflare Workers and Vercel or Netlify functions.
Despite its name, kaeri-store is the local SQLite history and has nothing to do with them.