{"owner":"Splode","repo":"pomotroid","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md"],"skills":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Overview\n\nPomotroid is a Pomodoro timer desktop app built with **Tauri 2 + Rust** (backend) and **SvelteKit + Svelte 5** (frontend). The app has been fully rewritten from Electron+Vue to this stack.\n\n## Commands\n\n```bash\n# Development (runs Vite dev server + Tauri)\nnpm run tauri dev\n\n# Production build\nnpm run tauri build\n\n# Frontend-only Vite dev (no Tauri IPC available)\nnpm run dev\n\n# Format all frontend source files\nnpm run format\n\n# Type-check Svelte + TypeScript\nnpm run check\n\n# Regenerate i18n types after editing inlang message files\nnpm run paraglide:compile\n```\n\nThere are no automated tests in this codebase.\n\n## Architecture\n\n### Two windows\n\n- **`main`** (`src/routes/+page.svelte`) — the timer window\n- **`settings`** (`src/routes/settings/+page.svelte`) — opened via `new WebviewWindow('settings', ...)` from `Titlebar.svelte`\n- **`stats`** (`src/routes/stats/+page.svelte`) — statistics window\n\n### IPC layer\n\nAll frontend↔backend communication goes through `src/lib/ipc/index.ts`. This module exports typed wrappers around `invoke()` and `listen()`. Never call `invoke()` directly in components — always go through this module.\n\nRust commands live in `src-tauri/src/commands.rs`. All commands return `Result<T, String>`.\n\n**Tauri events emitted by Rust:**\n\n- `timer:tick` — `{ elapsed_secs, total_secs }` — fires every second while running\n- `timer:paused` — `{ elapsed_secs }`\n- `timer:resumed` — `{ elapsed_secs }`\n- `timer:round-change` — full `TimerSnapshot`\n- `timer:reset` — full `TimerSnapshot` (used to sync frontend after settings changes)\n- `settings:changed` — full `Settings` object\n- `themes:changed` — `Theme[]`\n- `sessions:cleared`\n\n### TypeScript ↔ Rust type contract\n\n`src/lib/types.ts` mirrors Rust structs (snake_case field names). When modifying `Settings` in `src-tauri/src/settings/mod.rs` or `TimerSnapshot` in `src-tauri/src/timer/mod.rs`, update `types.ts` to match.\n\n**Important conversions** — Rust converts on load/save, frontend always sees the converted form:\n\n- Time: stored in DB as **minutes**, `Settings` struct holds **seconds**\n- Volume: stored in DB as **0–100**, `Settings` struct holds **0.0–1.0**\n\n### Settings storage\n\nSQLite key/value table. DB column names differ from Rust struct field names (e.g., DB key `work_rounds` → struct field `long_break_interval`). Mappings are in `src-tauri/src/settings/mod.rs`. New settings need a DB key mapping, a default value in `settings/defaults.rs`, and a corresponding `settings_set` key handler.\n\nSchema migrations are in `src-tauri/src/db/migrations.rs`. Add a new `MIGRATION_N` constant and increment the schema version check in `run()`.\n\n### Timer engine\n\nThe timer runs in a background thread. `TimerController` (`src-tauri/src/timer/mod.rs`) is the public API registered as Tauri state. `SequenceState` (`src-tauri/src/timer/sequence.rs`) tracks round type and count — it has its own `work_rounds_total` field that must be kept in sync via `apply_settings()` when settings change.\n\n### Theme system\n\nThemes are JSON files in `static/themes/` (built-in) and `{app_data_dir}/themes/` (custom, user-created). Each theme is a JSON object with `name` and `colors` (CSS custom property map with `--` prefix keys). The Rust `themes` module watches the custom directory for changes and emits `themes:changed`. `applyTheme()` in `src/lib/stores/theme.ts` sets CSS custom properties on `:root`.\n\n### Capabilities / permissions\n\n`src-tauri/capabilities/default.json` — all allowed Tauri APIs for both windows. Any new IPC command or API plugin used from the frontend must be allowlisted here.\n\n### Localization\n\nUses `@inlang/paraglide-js`. Message files are in `project.inlang/`. After editing messages, run `npm run paraglide:compile` to regenerate `src/paraglide/`. Import message functions from `$lib/locale.svelte.ts`.\n\n### UI conventions\n\n- Window is decoration-free; custom titlebar in `Titlebar.svelte`\n- Compact mode: `isCompact = w < 300 || h < 300` — hides footer/label/play-pause, shows only dial\n- `uiScale` applied via CSS `zoom` on `.timer` div (not `transform: scale`)\n- Slider track alignment: use `calc(frac * (100% - 14px) + 7px)` to match native thumb position\n\n### Rust modules\n\n| Module          | Purpose                                                                              |\n| --------------- | ------------------------------------------------------------------------------------ |\n| `audio`         | rodio-based audio playback, custom sound file management                             |\n| `db`            | SQLite connection, migrations, queries                                               |\n| `notifications` | OS notification wrapper                                                              |\n| `settings`      | Settings struct, DB load/save, defaults                                              |\n| `shortcuts`     | Global keyboard shortcut registration via tauri-plugin-global-shortcut               |\n| `themes`        | Theme loading, custom theme watching (notify crate), tray icon rendering (tiny-skia) |\n| `timer`         | Timer engine (background thread), sequence state, controller                         |\n| `tray`          | System tray icon, tray menu, timer display in tray                                   |\n| `websocket`     | Optional WebSocket server (axum) for external timer control                          |\n"},"files":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Overview\n\nPomotroid is a Pomodoro timer desktop app built with **Tauri 2 + Rust** (backend) and **SvelteKit + Svelte 5** (frontend). The app has been fully rewritten from Electron+Vue to this stack.\n\n## Commands\n\n```bash\n# Development (runs Vite dev server + Tauri)\nnpm run tauri dev\n\n# Production build\nnpm run tauri build\n\n# Frontend-only Vite dev (no Tauri IPC available)\nnpm run dev\n\n# Format all frontend source files\nnpm run format\n\n# Type-check Svelte + TypeScript\nnpm run check\n\n# Regenerate i18n types after editing inlang message files\nnpm run paraglide:compile\n```\n\nThere are no automated tests in this codebase.\n\n## Architecture\n\n### Two windows\n\n- **`main`** (`src/routes/+page.svelte`) — the timer window\n- **`settings`** (`src/routes/settings/+page.svelte`) — opened via `new WebviewWindow('settings', ...)` from `Titlebar.svelte`\n- **`stats`** (`src/routes/stats/+page.svelte`) — statistics window\n\n### IPC layer\n\nAll frontend↔backend communication goes through `src/lib/ipc/index.ts`. This module exports typed wrappers around `invoke()` and `listen()`. Never call `invoke()` directly in components — always go through this module.\n\nRust commands live in `src-tauri/src/commands.rs`. All commands return `Result<T, String>`.\n\n**Tauri events emitted by Rust:**\n\n- `timer:tick` — `{ elapsed_secs, total_secs }` — fires every second while running\n- `timer:paused` — `{ elapsed_secs }`\n- `timer:resumed` — `{ elapsed_secs }`\n- `timer:round-change` — full `TimerSnapshot`\n- `timer:reset` — full `TimerSnapshot` (used to sync frontend after settings changes)\n- `settings:changed` — full `Settings` object\n- `themes:changed` — `Theme[]`\n- `sessions:cleared`\n\n### TypeScript ↔ Rust type contract\n\n`src/lib/types.ts` mirrors Rust structs (snake_case field names). When modifying `Settings` in `src-tauri/src/settings/mod.rs` or `TimerSnapshot` in `src-tauri/src/timer/mod.rs`, update `types.ts` to match.\n\n**Important conversions** — Rust converts on load/save, frontend always sees the converted form:\n\n- Time: stored in DB as **minutes**, `Settings` struct holds **seconds**\n- Volume: stored in DB as **0–100**, `Settings` struct holds **0.0–1.0**\n\n### Settings storage\n\nSQLite key/value table. DB column names differ from Rust struct field names (e.g., DB key `work_rounds` → struct field `long_break_interval`). Mappings are in `src-tauri/src/settings/mod.rs`. New settings need a DB key mapping, a default value in `settings/defaults.rs`, and a corresponding `settings_set` key handler.\n\nSchema migrations are in `src-tauri/src/db/migrations.rs`. Add a new `MIGRATION_N` constant and increment the schema version check in `run()`.\n\n### Timer engine\n\nThe timer runs in a background thread. `TimerController` (`src-tauri/src/timer/mod.rs`) is the public API registered as Tauri state. `SequenceState` (`src-tauri/src/timer/sequence.rs`) tracks round type and count — it has its own `work_rounds_total` field that must be kept in sync via `apply_settings()` when settings change.\n\n### Theme system\n\nThemes are JSON files in `static/themes/` (built-in) and `{app_data_dir}/themes/` (custom, user-created). Each theme is a JSON object with `name` and `colors` (CSS custom property map with `--` prefix keys). The Rust `themes` module watches the custom directory for changes and emits `themes:changed`. `applyTheme()` in `src/lib/stores/theme.ts` sets CSS custom properties on `:root`.\n\n### Capabilities / permissions\n\n`src-tauri/capabilities/default.json` — all allowed Tauri APIs for both windows. Any new IPC command or API plugin used from the frontend must be allowlisted here.\n\n### Localization\n\nUses `@inlang/paraglide-js`. Message files are in `project.inlang/`. After editing messages, run `npm run paraglide:compile` to regenerate `src/paraglide/`. Import message functions from `$lib/locale.svelte.ts`.\n\n### UI conventions\n\n- Window is decoration-free; custom titlebar in `Titlebar.svelte`\n- Compact mode: `isCompact = w < 300 || h < 300` — hides footer/label/play-pause, shows only dial\n- `uiScale` applied via CSS `zoom` on `.timer` div (not `transform: scale`)\n- Slider track alignment: use `calc(frac * (100% - 14px) + 7px)` to match native thumb position\n\n### Rust modules\n\n| Module          | Purpose                                                                              |\n| --------------- | ------------------------------------------------------------------------------------ |\n| `audio`         | rodio-based audio playback, custom sound file management                             |\n| `db`            | SQLite connection, migrations, queries                                               |\n| `notifications` | OS notification wrapper                                                              |\n| `settings`      | Settings struct, DB load/save, defaults                                              |\n| `shortcuts`     | Global keyboard shortcut registration via tauri-plugin-global-shortcut               |\n| `themes`        | Theme loading, custom theme watching (notify crate), tray icon rendering (tiny-skia) |\n| `timer`         | Timer engine (background thread), sequence state, controller                         |\n| `tray`          | System tray icon, tray menu, timer display in tray                                   |\n| `websocket`     | Optional WebSocket server (axum) for external timer control                          |\n"},"items":[{"name":"CLAUDE.md","path":"CLAUDE.md","title":"CLAUDE.md","content":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Overview\n\nPomotroid is a Pomodoro timer desktop app built with **Tauri 2 + Rust** (backend) and **SvelteKit + Svelte 5** (frontend). The app has been fully rewritten from Electron+Vue to this stack.\n\n## Commands\n\n```bash\n# Development (runs Vite dev server + Tauri)\nnpm run tauri dev\n\n# Production build\nnpm run tauri build\n\n# Frontend-only Vite dev (no Tauri IPC available)\nnpm run dev\n\n# Format all frontend source files\nnpm run format\n\n# Type-check Svelte + TypeScript\nnpm run check\n\n# Regenerate i18n types after editing inlang message files\nnpm run paraglide:compile\n```\n\nThere are no automated tests in this codebase.\n\n## Architecture\n\n### Two windows\n\n- **`main`** (`src/routes/+page.svelte`) — the timer window\n- **`settings`** (`src/routes/settings/+page.svelte`) — opened via `new WebviewWindow('settings', ...)` from `Titlebar.svelte`\n- **`stats`** (`src/routes/stats/+page.svelte`) — statistics window\n\n### IPC layer\n\nAll frontend↔backend communication goes through `src/lib/ipc/index.ts`. This module exports typed wrappers around `invoke()` and `listen()`. Never call `invoke()` directly in components — always go through this module.\n\nRust commands live in `src-tauri/src/commands.rs`. All commands return `Result<T, String>`.\n\n**Tauri events emitted by Rust:**\n\n- `timer:tick` — `{ elapsed_secs, total_secs }` — fires every second while running\n- `timer:paused` — `{ elapsed_secs }`\n- `timer:resumed` — `{ elapsed_secs }`\n- `timer:round-change` — full `TimerSnapshot`\n- `timer:reset` — full `TimerSnapshot` (used to sync frontend after settings changes)\n- `settings:changed` — full `Settings` object\n- `themes:changed` — `Theme[]`\n- `sessions:cleared`\n\n### TypeScript ↔ Rust type contract\n\n`src/lib/types.ts` mirrors Rust structs (snake_case field names). When modifying `Settings` in `src-tauri/src/settings/mod.rs` or `TimerSnapshot` in `src-tauri/src/timer/mod.rs`, update `types.ts` to match.\n\n**Important conversions** — Rust converts on load/save, frontend always sees the converted form:\n\n- Time: stored in DB as **minutes**, `Settings` struct holds **seconds**\n- Volume: stored in DB as **0–100**, `Settings` struct holds **0.0–1.0**\n\n### Settings storage\n\nSQLite key/value table. DB column names differ from Rust struct field names (e.g., DB key `work_rounds` → struct field `long_break_interval`). Mappings are in `src-tauri/src/settings/mod.rs`. New settings need a DB key mapping, a default value in `settings/defaults.rs`, and a corresponding `settings_set` key handler.\n\nSchema migrations are in `src-tauri/src/db/migrations.rs`. Add a new `MIGRATION_N` constant and increment the schema version check in `run()`.\n\n### Timer engine\n\nThe timer runs in a background thread. `TimerController` (`src-tauri/src/timer/mod.rs`) is the public API registered as Tauri state. `SequenceState` (`src-tauri/src/timer/sequence.rs`) tracks round type and count — it has its own `work_rounds_total` field that must be kept in sync via `apply_settings()` when settings change.\n\n### Theme system\n\nThemes are JSON files in `static/themes/` (built-in) and `{app_data_dir}/themes/` (custom, user-created). Each theme is a JSON object with `name` and `colors` (CSS custom property map with `--` prefix keys). The Rust `themes` module watches the custom directory for changes and emits `themes:changed`. `applyTheme()` in `src/lib/stores/theme.ts` sets CSS custom properties on `:root`.\n\n### Capabilities / permissions\n\n`src-tauri/capabilities/default.json` — all allowed Tauri APIs for both windows. Any new IPC command or API plugin used from the frontend must be allowlisted here.\n\n### Localization\n\nUses `@inlang/paraglide-js`. Message files are in `project.inlang/`. After editing messages, run `npm run paraglide:compile` to regenerate `src/paraglide/`. Import message functions from `$lib/locale.svelte.ts`.\n\n### UI conventions\n\n- Window is decoration-free; custom titlebar in `Titlebar.svelte`\n- Compact mode: `isCompact = w < 300 || h < 300` — hides footer/label/play-pause, shows only dial\n- `uiScale` applied via CSS `zoom` on `.timer` div (not `transform: scale`)\n- Slider track alignment: use `calc(frac * (100% - 14px) + 7px)` to match native thumb position\n\n### Rust modules\n\n| Module          | Purpose                                                                              |\n| --------------- | ------------------------------------------------------------------------------------ |\n| `audio`         | rodio-based audio playback, custom sound file management                             |\n| `db`            | SQLite connection, migrations, queries                                               |\n| `notifications` | OS notification wrapper                                                              |\n| `settings`      | Settings struct, DB load/save, defaults                                              |\n| `shortcuts`     | Global keyboard shortcut registration via tauri-plugin-global-shortcut               |\n| `themes`        | Theme loading, custom theme watching (notify crate), tray icon rendering (tiny-skia) |\n| `timer`         | Timer engine (background thread), sequence state, controller                         |\n| `tray`          | System tray icon, tray menu, timer display in tray                                   |\n| `websocket`     | Optional WebSocket server (axum) for external timer control                          |\n","category":"root","tokens":1374}]}