![]()
Local-only, AI-powered image cataloging and search for your NAS. Point it at a directory, and it classifies every image using a local vision LLM, extracts text via OCR, generates thumbnails, and indexes everything into a searchable SQLite database. Nothing leaves your machine.
qwen2.5vl:7b vision model (media type, description, anime/manga identification, document detection)face:name
The UI is loosely inspired by VSCode: custom titlebar, collapsible sidebar, thumbnail grid, media type filters, confidence slider, preview overlay, duplicate finder, and automatic light/dark theme.
Download the latest release from the Releases page: AppImage for Linux, DMG for macOS (Apple Silicon), MSI for Windows.
You also need Ollama installed and running (ollama serve). On first launch, the app prompts you to download the vision model if it isn't installed yet.
The MSI installer is not signed with a code-signing certificate. Windows SmartScreen may block it with a "Windows protected your PC" warning. Click "More info" and then "Run anyway" to proceed with installation.
ollama serve)# 1. Download native libraries for your platform
cd sherlock/desktop/src-tauri
bash scripts/download-pdfium.sh
bash scripts/download-onnxruntime.sh
# 2. Install frontend dependencies
cd sherlock/desktop
npm install
# 3. Start Ollama (in a separate terminal)
ollama serve
# 4. Run in dev mode
npm run tauri:dev
To produce a release binary (AppImage/DMG/MSI):
cd sherlock/desktop
npm run tauri:build
Output will be in sherlock/desktop/src-tauri/target/release/bundle/.
If the WebKit window is blank on Wayland with NVIDIA drivers:
WEBKIT_DISABLE_DMABUF_RENDERER=1 GDK_BACKEND=wayland,x11 npm run tauri:dev
# Rust (322 tests)
cd sherlock/desktop/src-tauri
cargo test
# Frontend (299 tests)
cd sherlock/desktop
npm run test
Covers classification JSON parsing, thumbnail generation, incremental scanning, database operations, scan cancellation, query parsing, duplicate detection, similarity scoring, video metadata, face detection/clustering, platform abstraction, and UI components.
Built for large NAS directories with 100k+ files:
filter_entry(). Progress is reported live to the UI every 500 files.Each phase supports cancel and resume independently, with progress checkpointed after every file.
Rescanning an unchanged 10k-image directory takes seconds.
Find and remove redundant copies to reclaim disk space:
Find and organize people across your photo library:
face:alice, face:"Full Name", or face:42 (by person ID) to find all photos of someone.Face detection runs per-folder from the context menu and shows progress in the status bar.
Each new image goes through several stages:
Full-text search across filenames, paths, descriptions, OCR text, and character/series names. Example queries:
anime ranmabank transfer 2024receipt santanderscreenshot confidence >= 0.8face:alice or face:"Full Name"sherlock/ <- Main application
desktop/
src-tauri/src/ <- Rust backend
classify.rs <- Ollama vision + Surya OCR pipeline
thumbnail.rs <- Thumbnail generation + dHash computation
scan.rs <- Incremental scanner (4-phase) with cancellation + resume
db.rs <- SQLite + FTS5 + duplicate queries
similarity.rs <- dHash + description similarity + Union-Find grouping
face.rs <- Native ONNX face detection (SCRFD) + recognition (ArcFace)
pdf.rs <- PDFium text extraction + page rendering
video.rs <- ffmpeg metadata, keyframe extraction, subtitle parsing
video_server.rs <- Localhost HTTP Range streaming for video preview
config.rs <- App paths
lib.rs <- Tauri commands, auto-cleanup
query_parser.rs <- NL query parsing
runtime.rs <- Ollama/GPU status
platform/ <- OS abstraction (clipboard, GPU, Python paths)
scripts/
surya_ocr.py <- Isolated OCR script (bundled as Tauri resource)
src/ <- React frontend
utils.ts <- Shared utilities (basename, errorMessage)
__tests__/fixtures.ts <- Shared test mock objects
_classification/ <- Python PoC of the classification pipeline
These directories contain the A/B testing research that informed model selection and pipeline design. They aren't part of the main application.
_research_ab_test/
scripts/ <- A/B benchmark scripts
docs/ <- Research notes (IDEA.md, RESULTS.md, etc.)
lib/ <- Shared Python helpers
results/ <- Generated benchmark outputs (gitignored)
test_files/ <- Test corpus (gitignored, see note below)
Note: The test files (images, audio, video, documents) used for benchmarking are not included. They contained copyrighted media and personal documents. To re-run the benchmarks:
- Add your own media files in
_research_ab_test/test_files/with subdirectories likeimages/,old_audio/,old_docs/,old_tvseries/- Update the ground truth JSON files in
_research_ab_test/docs/to match your corpus- Adjust the benchmark scripts as needed
The benchmark results (_research_ab_test/docs/RESULTS.md) show why qwen2.5vl:7b was chosen over llava:13b and minicpm-v:8b (80% type accuracy vs 33-50%), and why Surya was picked as primary OCR (95% reference similarity, better coverage than vision LLM alone).
All application data lives under ~/.local/share/frank_sherlock/:
db/index.sqlite <- SQLite database with FTS5
cache/thumbnails/ <- Generated thumbnails (mirrored path structure)
cache/classifications/ <- Classification cache
cache/tmp/ <- Temporary files (GIF frames, etc.)
surya_venv/ <- Isolated Python venv for Surya OCR
Source directories are never modified. Frank Sherlock is strictly read-only.
GitHub Actions runs on every push and PR against main:
cargo test, cargo clippy, cargo fmt --check, npm run build, npm run test, cargo audit (Linux only)Releases are built on v* tags for Linux (AppImage), macOS (Apple Silicon DMG), and Windows (MSI).
This project is licensed under the GNU General Public License v3.0.
$ claude mcp add FrankSherlock \
-- python -m otcore.mcp_server <graph>