Skip to content

Repository files navigation

DuskRead

DuskRead

A reading list that keeps itself, ranked by what you actually read.
An AI agent checks your inbox and files what's worth keeping into Notion;
blogs you follow add their own posts the same way.

Curated through Notion Kotlin and Compose Multiplatform Android 12 and up MIT License

See every screen  ·  How it fits together  ·  Run it

Monochrome by default. One accent, spent on purpose.


Newsletters and blogs file themselves into one Notion database — ranked by what you actually read, not by when it arrived — then you set a twenty-five minute timer and read, on Paper Black or Ink, the same page with the colour drained out.

What it does

Three sources — Gmail, RSS feeds, and links you paste or share. Claude files the mail into Notion's Sources and Reading List, which syncs both ways with DuskRead; feeds and shared links reach the app directly, never touching Notion. The app caches everything, reads offline, and reads articles aloud on the phone

  • Curated through Notion. Claude files inbox newsletters straight into the reading list; blogs with a working feed are fetched by the app and never touch Notion. Either way, only rows ticked Saved reach the phone — see docs/architecture.md for the schema and sync rules. Following a blog writes it back to Notion too, so it's there to edit next time you open it.
  • Save it however it reaches you — the Chrome share sheet, or the paste field on Saved behind Add.
  • Reads offline. Every screen renders from local storage; a feed with full-content RSS is cached whole at sync time, so most articles were already on the phone before you tapped them.
  • Saved is a queue and a record. Unread leads; what you've read stays under its own heading. Filter to either, or search a title, host or topic.
  • On-device summaries and reading aloud. Long articles get a one-tap summary via Gemini Nano; the phone can also read one aloud with its own text-to-speech. Both are absent on hardware that can't run them, and a read that can't happen says why instead of staying silent.
  • A focus timer that behaves like an alarm, not a widget — a real system notification and vibration when the interval ends, phone face-down.

Getting started

Android is the app, built and tested day to day. Desktop, web and iOS compile from the same source to prove it travels.

git clone https://github.com/MKS-01/duskread.git && cd duskread
./gradlew :androidApp:installDebug      # ~5 s once warm

That's the whole setup — Notion is optional, and connecting it is one pasted token in Settings.

JDK 17 or newer
Android 12 and up (minSdk 31, compile/target 36)
Gradle 9.3.1, via the wrapper
For summaries A phone with AICore — Pixel 9+, Galaxy S24+ and similar. No emulator has it
For iOS Xcode, plus XcodeGen
Desktop, web and iOS
./gradlew :composeApp:runDistributable              # desktop — use this, not `run`
./gradlew :composeApp:wasmJsBrowserDevelopmentRun   # web, on :8080

cd iosApp && xcodegen generate && cd ..             # iOS needs an Xcode host
open iosApp/iosApp.xcodeproj

runDistributable, not run, for desktop — the embedded Chromium needs the packaged .app layout, or it segfaults on init. First iOS build is ten minutes or more; incremental after that.

How it's built

One commonMain source set feeds Android, desktop, web and iOS; storage, audio, the summariser and the HTTP client are expect/actual pairs behind it. UI is Compose Multiplatform 1.11 with Haze for the floating-bar blur, on Kotlin 2.3 and Ktor 3.1. Summaries run on-device via ML Kit GenAI / Gemini Nano; reading aloud is Android's own TextToSpeech; the optional Readback tab queries readback's library.db read-only. No navigation library, no ViewModel, no DI, no database — a ceiling chosen on purpose.

./gradlew ktlintCheck    # several rules deliberately off, see .editorconfig
./gradlew ktlintFormat

No tests yet — a build that succeeds is the start of checking a change, not the end of it.

The design system — Paper Black and Ink, and every token behind them. docs/architecture.md — how the pieces connect, the Notion schema, and the end-to-end flows.

Licence

MIT — see LICENSE.

A personal project, built for learning and for its own author to use
Built agent-first with Claude Code
The synced-audio Readback tab is a separate, optional open-source project: readback

About

A reading habit, automated around a Notion database — KMP app with feeds, offline reading, and a pomodoro timer.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages