# whale **Repository Path**: ooeyusea/whale ## Basic Information - **Project Name**: whale - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-17 - **Last Updated**: 2026-07-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Whale — Desktop AI Agent (Pure Rust) A personal-MVP desktop AI agent for coding tasks, with multi-project isolation, single-Agent chat, and main-Agent-driven sub-Agent orchestration. Built as a **pure-Rust** desktop app — the UI shell is [Dioxus 0.7](https://dioxuslabs.com/) (renders to the native WebView), so there is **no Node.js, no Tauri, no React** in the stack anymore. > **Status:** feature-complete port of the previous Tauri+React app to the > pure-Rust architecture. The agent core, persistence layer, and Dioxus UI > are all implemented and covered by 414 unit/integration tests. The GUI > streaming, diff, and permission flows are ports of the React behaviour > and still need real-world validation against a live DeepSeek key. The > backend invariants from the design spec (§9.3) are all test-covered. > > Design spec: > [`docs/superpowers/specs/2026-07-04-whale-pure-rust-rewrite-design.md`](docs/superpowers/specs/2026-07-04-whale-pure-rust-rewrite-design.md) --- ## Tech stack | Layer | Technology | | ------------ | -------------------------------------------------------------------- | | Shell | Dioxus 0.7 (`desktop` + `router` features) → native WebView | | Frontend | Dioxus `rsx!` components (no HTML/JS framework) | | Markdown | `pulldown-cmark` + `syntect` (Rust-side rendering) | | Backend | Rust + `tokio` (async runtime, mpsc channels) | | Database | SQLite via `sqlx` 0.7 (compile-time-checked queries + `migrate!`) | | LLM | DeepSeek (`deepseek-v4-pro` default) | | Diffing | `similar` (line/word diff for file-tool renderers) | | Testing | `cargo test --workspace` | --- ## Prerequisites - **Rust ≥ 1.95** (install via [rustup](https://rustup.rs/)) - **WebView2 Runtime** (Windows 10/11 ships with it; other platforms need the system WebView — WebKitGTK on Linux, WKWebView on macOS) --- ## Getting started ```bash # Run the desktop app (from the repo root) cargo run -p whale-app ``` On first launch the app: 1. Creates its per-user data directory: - `$WHALE_DATA_DIR` if set, otherwise - `/whale` (e.g. `%APPDATA%\whale` on Windows, `~/.config/whale` on Linux, `~/Library/Application Support/whale` on macOS). 2. Writes a default `settings.json` (DeepSeek base URL, default model `deepseek-v4-pro`, theme `system`). 3. Opens the SQLite database and runs migrations. Add your DeepSeek API key in **Settings** (see below) before chatting. --- ## Build ```bash # Debug build cargo build -p whale-app # Release build cargo build --release -p whale-app ``` The release binary is `target/release/whale` (`[[bin]] name = "whale"`). ## Test ```bash # All crates (414 tests: core 337 + db 37 + integration 4 + app 36) cargo test --workspace ``` --- ## Configuration All configuration is done in-app under **Settings** — no manual file editing required. - **Global settings** — the `/settings` route. Fields: - `deepseek_api_key` - `deepseek_base_url` (default `https://api.deepseek.com`) - `default_model` (default `deepseek-v4-pro`) - `theme` (`system` / `light` / `dark`) - **Per-project settings** — the `/projects/:id/settings` route, scoped to a single project (e.g. project-specific model overrides). --- ## Architecture Three crates in a single Cargo workspace: ``` crates/ ├── whale-core/ # Pure domain logic: agent loop, tool system, render │ # reducer (apply_event), settings. No I/O / no UI. ├── whale-db/ # SQLite persistence (sqlx): pool, migrations, DAOs. └── whale-app/ # Dioxus desktop shell: router, UI components, services, # mpsc→Signal bridge. Depends on whale-core + whale-db. ``` **Event flow** (how an agent reply reaches the screen): ``` AgentCore (tokio task) │ emits AgentEvent ▼ tokio mpsc channel │ ▼ run_event_bridge (crates/whale-app/src/events.rs) │ calls whale_core::render::reduce::apply_event(current, ev, now) ▼ AGENT_STATE (Dioxus GlobalSignal) │ GlobalSignal mutation triggers re-render ▼ Dioxus components (read AGENT_STATE / APP_STATE / TODOS / PERMISSION_REQUEST) ``` The core's `apply_event` reducer is pure and unit-tested; the app layer only feeds it events and mirrors the result into Dioxus `GlobalSignal`s. Permission requests surface as a `PERMISSION_REQUEST` signal driving a modal dialog. --- ## File layout ``` . ├── Cargo.toml # workspace manifest ├── Cargo.lock # committed (binary crate present) ├── crates/ │ ├── whale-core/ # src/{agent, llm, render, tools, ...} │ ├── whale-db/ # src/{pool, dao/*}, migrations/ │ └── whale-app/ # src/{main, router, events, services, │ # state, ui/{app_shell, conversation, │ # permission, primitives, settings}}, │ # assets/ ├── docs/ # design specs + implementation plans └── design-analysis/ # original requirements analysis (reference) ``` --- ## Keyboard shortcuts | Shortcut | Action | | ------------------ | ------------------------------------------------- | | `Enter` | Send message | | `Shift+Enter` | Newline in the input | | `Ctrl+K` / `Cmd+K` | Focus the input textarea (layout-independent) | | `Esc` | Cancel the active run (if one is running) | --- ## Skills Whale integrates a ZCode/superpowers-style **skill system**. A skill is a Markdown file (`SKILL.md`) with a YAML-like frontmatter (`name`, `description`) and a body of behavioral instructions. Unlike normal tool output (data the model *uses*), a skill's body is a **directive** the model *follows* — it is never truncated. ### Where skills live Scanned at run start (project-level overrides global on name conflict): - **Project-level:** `/.whale/skills//SKILL.md` - **Global:** `/whale/skills//SKILL.md` (i.e. `%APPDATA%\whale\skills` on Windows, `~/.config/whale/skills` on Linux, `~/Library/Application Support/whale/skills` on macOS) ### How skills are used 1. **Passive (model-invoked):** at run start, available skills are listed in the system prompt (`# Available skills`). When the model's task matches a skill, it calls the `skill` tool to load the full body into context, then follows it. 2. **Active (user-invoked):** type `/ [context]` in the input bar (or click the **Skill** button to prefix `/`). The skill body is injected as a `` for that run. An unknown `/name` is sent as plain text. Sub-agents (`spawn_agent`) inherit the skill registry and may call the `skill` tool too. ### Example skill ``` .whale/skills/brainstorming/SKILL.md ``` ```markdown --- name: brainstorming description: "Use before any creative work. Ask one question at a time." --- # Brainstorming Ask the user clarifying questions one at a time before implementing. ``` --- ## Notes - `Cargo.lock` is committed because the workspace ships a binary crate. - Runtime data (`settings.json`, the SQLite DB) lives under the per-user data directory described above, **not** in the repo. - The legacy Tauri+React implementation (~11k lines across `src/` and `src-tauri/`) has been removed; this pure-Rust workspace supersedes it.