commit fa7144c78149400020778f3bc86de72da18a5ac5
Author: Quinta0 <0pietroquintavalle0@gmail.com>
Date: Sun Jul 12 01:59:55 2026 +0200
idea planning
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4432b51
--- /dev/null
+++ b/README.md
@@ -0,0 +1,101 @@
+# riptune
+
+*Rip and tune.* A terminal-native music client for [Subsonic-compatible](http://www.subsonic.org/pages/api.jsp) servers (Navidrome, Airsonic, Gonic), built for the [niri](https://github.com/YaLTeR/niri) scrollable-tiling compositor. Because if id Software's engine can run on a smart fridge, your music player can run on a compositor IPC socket.
+
+> **Status:** early scaffold — architecture and interfaces are in place, implementation is in progress. See [Roadmap](#roadmap).
+
+## Why
+
+Most terminal music clients treat the desktop as a black box: no MPRIS, no awareness of tiling layout, no way to hook into compositor-level keybinds. `riptune` is built the other way around — it assumes it's running inside a modern Wayland tiling setup and integrates accordingly.
+
+## Features
+
+- **MPRIS2 D-Bus interface** — waybar, GNOME/KDE media widgets, and hardware media keys control riptune out of the box, no riptune-specific config needed on their end.
+- **Decoupled async pipeline** — network I/O (tokio) and audio decode/playback (dedicated OS thread) never share a runtime, so a slow server response can't stutter playback or freeze the UI.
+- **niri IPC integration** — listens on niri's event-stream socket (not polling) to react to workspace changes; exposes a local control socket so niri keybinds can trigger in-app actions like favoriting a track.
+- **Local SQLite index** — the remote library is mirrored locally so the TUI opens instantly, even on servers with slow `getArtists`/`getAlbum` responses over large libraries.
+
+## Architecture
+
+```mermaid
+flowchart TB
+ subgraph Main["Main Thread"]
+ TUI["TUI (ratatui)
render loop, input handling"]
+ end
+
+ subgraph AudioThread["Dedicated OS Thread"]
+ Decoder["symphonia decoder"]
+ Sink["cpal output stream"]
+ Decoder --> Sink
+ end
+
+ subgraph Tokio["Tokio Runtime"]
+ Subsonic["Subsonic client
(reqwest)"]
+ Cache["SQLite cache
(sqlx)"]
+ Mpris["MPRIS2 server
(zbus)"]
+ Niri["niri IPC listener
(event-stream socket)"]
+ end
+
+ TUI <-- "AppEvent (mpsc)" --> Tokio
+ TUI <-- "reads local state" --> Cache
+ Tokio -- "AudioCommand (mpsc)" --> AudioThread
+ AudioThread -- "AudioEvent: position, buffering" --> TUI
+ Subsonic -- "sync_library()" --> Cache
+ Subsonic -- "authenticated stream URL" --> AudioThread
+ Mpris -- "translates D-Bus calls into" --> Tokio
+ Niri -- "WorkspaceChanged" --> TUI
+
+ External1["waybar / notification daemon"] -.->|D-Bus| Mpris
+ External2["niri compositor"] -.->|IPC socket| Niri
+```
+
+**Why three execution contexts instead of one?** Audio playback is latency-sensitive in a way that async task scheduling doesn't guarantee — a busy tokio runtime (e.g. mid-sync with the server) shouldn't be able to introduce a buffer underrun. Giving audio its own OS thread with a bounded channel as the only interface makes that impossible by construction, not by careful scheduling.
+
+## Repository layout
+
+```
+riptune/
+├── src/ # binary crate: wires everything together
+│ ├── main.rs
+│ ├── app.rs # async orchestration (tokio runtime)
+│ ├── audio.rs # audio thread entrypoint
+│ ├── config.rs
+│ └── events.rs
+├── crates/
+│ ├── riptune-core/ # Subsonic REST client, auth, models
+│ ├── riptune-cache/ # SQLite local index
+│ ├── riptune-mpris/ # MPRIS2 D-Bus server
+│ ├── riptune-niri/ # niri IPC event-stream listener
+│ └── riptune-tui/ # ratatui UI
+├── Cargo.toml # workspace root
+└── config.example.toml
+```
+
+## Configuration
+
+`~/.config/riptune/config.toml`:
+
+```toml
+[server]
+url = "https://music.example.com"
+username = "you"
+# Either a legacy Subsonic password (salted-token auth is computed at runtime,
+# never sent in the clear) or a Navidrome API key, depending on server support.
+password = "your-password-or-api-key"
+
+[niri]
+enabled = true
+workspace_notifications = true
+
+[cache]
+path = "~/.cache/riptune/library.sqlite"
+```
+
+## Building
+
+```sh
+cargo build --release
+```
+
+Requires a D-Bus session bus (for MPRIS) and, optionally, a running niri instance (for IPC features — riptune degrades gracefully without them).
+