diff --git a/CLAUDE.md b/CLAUDE.md
index 5656fb0..5d644b1 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -29,9 +29,9 @@ The Tauri dev server runs on port 1422 (`vite.config.ts` and `tauri.conf.json`).
Two-crate workspace (`resolver = "2"`, edition 2021) plus a Tauri app:
-- **onyx-core** — Pure Rust library. Storage trait with `FileSystemStorage` implementation, `TaskRepository` (main API), data models, config, error types. No CLI/UI dependencies.
+- **onyx-core** — Pure Rust library. Storage trait with `FileSystemStorage` implementation, `TaskRepository` (main API), data models, config, error types. No CLI/UI dependencies. `keyring` feature-gated behind `keyring-storage` (default on) for Android compatibility.
- **onyx-cli** — CLI frontend using clap. Commands are in `src/commands/` (init, workspace, list, task, group). Output formatting in `src/output.rs`.
-- **apps/tauri/** — Tauri v2 GUI. Svelte 5 frontend in `src/`, Rust backend in `src-tauri/` with Tauri commands that call into `onyx-core`.
+- **apps/tauri/** — Tauri v2 GUI. Svelte 5 frontend in `src/`, Rust backend in `src-tauri/` with Tauri commands that call into `onyx-core`. `notify` crate feature-gated for Android.
- **apps/flutter/** — Flutter GUI. Dart frontend in `lib/src/`, Rust backend in `rust/` via flutter_rust_bridge FFI into `onyx-core`.
### Key patterns
@@ -61,6 +61,7 @@ The GUI uses Svelte 5 runes mode (`$state`, `$derived`, `$effect`, `$props()`).
- **Phase 1** (Core + CLI): Complete
- **Phase 2** (WebDAV sync): Backend done, CLI done, GUI wired (settings auto-populates credentials)
- **Phase 3** (GUI MVP): Complete — both Tauri and Flutter GUIs at feature parity
+- **Phase 4** (Mobile): Tauri Android cfg-gated, needs `tauri android init` + build
### GUI features done
@@ -85,6 +86,7 @@ The GUI uses Svelte 5 runes mode (`$state`, `$derived`, `$effect`, `$props()`).
- Push/pull/full sync mode selection (session-only, in settings)
- Desktop packaging (Linux: AppImage + .deb)
- Flutter GUI at full parity with Tauri (WebDAV UI, has_time, sync status, sync mode)
+- Tauri desktop-only deps (notify, keyring) feature-gated for Android compilation
### GUI features NOT yet done
diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml
index 3752fda..19b69ec 100644
--- a/apps/tauri/src-tauri/Cargo.toml
+++ b/apps/tauri/src-tauri/Cargo.toml
@@ -19,14 +19,16 @@ tauri-plugin-dialog = "2"
tauri-plugin-os = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
-onyx-core = { path = "../../../crates/onyx-core" }
+onyx-core = { path = "../../../crates/onyx-core", default-features = false }
tokio = { version = "1", features = ["full"] }
uuid = { version = "1", features = ["serde", "v4"] }
chrono = { version = "0.4", features = ["serde"] }
-notify = "7"
-notify-debouncer-mini = "0.5"
+notify = { version = "7", optional = true }
+notify-debouncer-mini = { version = "0.5", optional = true }
[package.metadata.tauri]
[features]
+default = ["desktop"]
+desktop = ["notify", "notify-debouncer-mini", "onyx-core/keyring-storage"]
custom-protocol = ["tauri/custom-protocol"]
diff --git a/apps/tauri/src-tauri/src/lib.rs b/apps/tauri/src-tauri/src/lib.rs
index 75bf467..7cbe413 100644
--- a/apps/tauri/src-tauri/src/lib.rs
+++ b/apps/tauri/src-tauri/src/lib.rs
@@ -4,6 +4,7 @@ use std::time::Instant;
use chrono::Utc;
+#[cfg(not(target_os = "android"))]
use notify_debouncer_mini::{new_debouncer, DebouncedEventKind};
use serde::{Deserialize, Serialize};
use tauri::{Emitter, Manager, State};
@@ -17,10 +18,12 @@ use onyx_core::{
webdav,
};
+#[cfg(not(target_os = "android"))]
/// Active file watcher stored globally so it lives for the app lifetime.
static WATCHER: Mutex