This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A macOS menu bar app that monitors and cleans unused Docker images. Built with Tauri v2 (Rust backend + React frontend). Runs as a tray icon (no dock icon), shows a popover window on click.
npm install # frontend deps (first time)
npx tauri dev # development with hot reload (Vite on :1420 + Rust rebuild)
npx tauri build # production .app bundle
cargo check --manifest-path src-tauri/Cargo.toml # Rust-only type check- hyperlocal 0.8 pins hyper to 0.14 — uses
hyper::Client::unix()andhyper::Bodywhich were removed in hyper 1.0. Do not upgrade hyper. - tauri-plugin-positioner
move_window()panics if the OS hasn't reported tray position yet — wrapped incatch_unwindintoggle_window(). - macOSPrivateApi is enabled in
tauri.conf.jsonfor transparent window support. - Docker socket detection checks
/var/run/docker.sockfirst, then$HOME/.docker/run/docker.sock(Docker Desktop on macOS).
Three modules under src-tauri/src/:
lib.rs— App entry point. Sets up tray icon, hides dock icon (ActivationPolicy::Accessory), manages window toggle/positioning viatauri-plugin-positioner, and runs a tokio background polling loop. The polling loop checks unused image size against the user's limit and either auto-cleans or sends a macOS notification (once per breach, reset when usage drops).docker.rs— Direct Docker Engine API client over Unix socket usinghyperlocal. No Docker CLI dependency. Provideslist_unused_images(),remove_image(),remove_all_unused(),get_storage_stats(). TheDockerImagestruct carriestagsand areasonfield ("dangling" | "untagged" | "unused"), butlist_unused_images()currently only ever emits dangling images (empty tags) — the other reasons are reserved for future use.get_storage_stats()sums only unused images, sototal_bytes == unused_bytes.commands.rs— Thin IPC bridge: each#[tauri::command]delegates directly todocker.rsor reads/writes settings viatauri-plugin-store.settings.rs—Settingsstruct withlimit_gb(f64),auto_clean,poll_interval_secs(u64, min 10s, defaults 60),breach_notified. Persisted via tauri-plugin-store assettings.json. Note:poll_interval_secsno longer has a UI control after the minimalist redesign, so the frontendSettingsinterface (types.ts) omits it — the field lives Rust-side only.
Source lives in src/. Vite dev server runs on :1420.
hooks/useDockerImages.ts— Central hook that owns allinvoke()calls. Fetches images, stats, settings in parallel on mount. Listens fordocker-stats-updatedevents from the backend polling loop to auto-refresh.App.tsx— Single-window app with three views switched via localviewstate (not tabs):dashboard(default),images,settings. Dashboard navigates to the other two and back.components/—Dashboard(landing view: storage summary + clean-all + nav),ImageList(per-image remove + remove-all),SettingsPanel(limit + auto-clean).TrayHeaderandStorageBarstill exist as files but are orphaned after the minimalist redesign — not imported anywhere. Don't extend them; fold any needed logic intoDashboard.types.ts— Shared TypeScript interfaces (DockerImage,StorageStats,Settings) mirroring the Rust structs.index.css— Complete dark-mode styling targeting macOS popover aesthetic. Uses CSS custom properties for theming.
- Backend polling loop (
lib.rs) runs on an interval, checksdocker.rsfor stats, emitsdocker-stats-updatedevent to frontend. - Frontend hook listens for that event and calls
refresh()which re-invokes all commands in parallel. - Settings are persisted via
tauri-plugin-storeand read by both the polling loop (Rust side) and the settings panel (frontend side).
tauri-plugin-store— JSON key-value persistence for settingstauri-plugin-positioner— Window positioning relative to tray icontauri-plugin-notification— macOS notifications for storage alerts
| Command | Args | Returns |
|---|---|---|
list_unused_images |
— | Vec<DockerImage> |
remove_image |
imageId: String |
() |
remove_all_unused |
— | usize (count removed) |
get_storage_stats |
— | StorageStats |
is_docker_running |
— | bool |
get_settings |
— | Settings |
save_settings |
settings: Settings |
() |