ClawGallery
A friendly, agent-native gallery for all your screenshots and photos.
What is ClawGallery?
Your screenshots folder is a mess. Hundreds of Screenshot 2025-11-01 at 14.32.55.png and IMG_0034.jpg files, and no way to find the one you actually need.
ClawGallery is a small, fast command-line tool that turns that pile into a searchable gallery. Think of it as a tidy little lobster curator that:
- Indexes the image folders you point it at.
- Understands what's in each picture using a vision model, writing a title and caption for it.
- Searches by keyword or by visual meaning ("that login error screen") so you can find images even when the filename says nothing.
- Renames auto-generated filenames into human-readable ones — safely, with a dry-run by default.
- Deduplicates, finding exact and visually-similar copies.
Everything is stored as plain, append-only JSONL files on your own machine. No cloud, no database daemon, no lock-in. It's built to be driven by both humans and AI agents (every command speaks --json).
Supported formats: png, jpg, jpeg, webp, avif, gif, heic, heif. HEIC/HEIF images are converted to JPEG automatically before captioning (macOS uses sips by default; set CLAWGALLERY_HEIC_CONVERTER to use a different tool).
Install
# Build, test, and install into your PATH
Enjoying ClawGallery? Please star the repo! ⭐️ It genuinely helps the project grow. If you have the GitHub CLI installed, it's one command:
Quickstart
Get from zero to a searchable gallery in a few commands:
Want AI-generated titles and captions, then cleaner filenames? Preview first (everything below is a safe dry-run):
When you're happy, drop --dry-run (and add --apply to actually rename files).
Everyday usage
1. Point it at your images
2. Caption your images
Captioning asks a vision model to describe each image, which powers better search and renaming. It can call a paid API, so always preview first:
You'll need credentials for a provider (see Vision model setup).
3. Search
By default, search is hybrid: Reciprocal Rank Fusion over keyword matches, V-SPLADE lexical ranks (if you synced --backend vsplade), and dense VDR ranks (if you built a visual index).
Search understands fzf-style operators:
| Syntax | Meaning | Example |
|---|---|---|
foo bar |
Match both terms (fuzzy) | clawgallery search login error |
'foo |
Exact substring | clawgallery search "'github" |
^foo |
Starts with | clawgallery search ^Login |
foo$ |
Ends with | clawgallery search modal$ |
!foo |
Exclude | clawgallery search login !test |
\ |
Literal space | clawgallery search github\ actions |
Lowercase queries are case-insensitive; add an uppercase letter (or --case-sensitive) to match case exactly. If nothing matches, ClawGallery automatically retries with typo tolerance. Use --no-fuzzy for plain exact-substring output.
4. Rename messy filenames
ClawGallery only renames files that look auto-generated (like IMG_0034 or Screenshot 2025-…) and leaves your meaningful names alone. It never overwrites existing files and is dry-run by default:
More on how it stays safe in Rename safety.
5. Find duplicates
dedup only reports — it never deletes anything:
To remove a duplicate you chose yourself: clawgallery forget --file <path> --delete (or omit --delete to just stop tracking it).
6. Keep it up to date automatically
Poll a folder for new images on an interval:
--caption captions new images each pass; --sync then updates the visual index. Failures are logged to errors.jsonl and reported without stopping the loop.
Or run it as a background service (see Run as a background service).
Lexical search (V-SPLADE)
V-SPLADE encodes each page image into a sparse vocabulary vector. Queries are an inference-free lookup, then ClawGallery ranks by sparse dot product. This is the --mode lexical backend and one of the hybrid RRF lists.
CLAWGALLERY_PYTHON=/path/to/splade-mlx/.venv/bin/python \
The managed V-SPLADE server requires splade_mlx and its MLX dependencies in the
Python interpreter used to start it. If --python and CLAWGALLERY_PYTHON are
not set, ClawGallery first uses an active VIRTUAL_ENV interpreter and then the
platform default (python3 on macOS/Linux, python on Windows). It checks the
runtime before starting the server and prints the exact interpreter and
remediation when the dependency is missing. For example:
CLAWGALLERY_PYTHON=python3
On Windows, install the same package into the active environment and use:
python -m pip install git+https://github.com/NomaDamas/SPLADE-mlx.git
clawgallery vdr sync --backend vsplade
Default model: NomaDamas/v-splade-efficient-mlx (Apache-2.0, 50368-dim vocabulary). Sparse postings are stored in vdr.sqlite3 next to dense VDR rows and do not deactivate them.
Visual search (VDR)
"Visual Document Retrieval" is what lets ClawGallery find images by how they look, not just by their captions. It's optional — plain keyword search works without it — but it's what makes "find that screenshot of the error dialog" work even when the filename is garbage.
How it works
ClawGallery stores image embeddings in an embedded SQLite file (vdr.sqlite3) right alongside your other state. No separate vector database, no extra daemon to babysit. Building the index is incremental: unchanged images and captions are skipped, and only new or changed content is re-embedded.
The embedding model itself runs in Python (the best late-interaction ColQwen-family runtimes on macOS are MLX/Python-based), but ClawGallery starts, waits for, and shuts down that runtime for you.
Setup (macOS, recommended)
# Install the embedding runtime once
# Build the visual index — ClawGallery starts the model server automatically
CLAWGALLERY_PYTHON="/mlx-embeddings/bin/python"
Then just search — the query is embedded automatically:
The default model is qnguyen3/colqwen2.5-v0.2-mlx (128 dimensions). The first run downloads and caches model weights. If Hugging Face downloads stall on macOS, retry with HF_HUB_DISABLE_XET=1.
Jina v5 Omni retrieval on Apple Silicon
ClawGallery also packages the MLX conversion of jinaai/jina-embeddings-v5-omni-small-retrieval-mlx (1024 dimensions). It requires Apple Silicon and loads the immutable Hugging Face revision 049ae923674456656be891ebb22849dd58124994.
CLAWGALLERY_PYTHON=/.local/share/clawgallery/jina-mlx/bin/python \
The first sync downloads and caches the model weights. Later visual searches read the model ID and dimensions from the active index, so they automatically start the Jina MLX runtime without repeating --backend. Keep CLAWGALLERY_PYTHON pointed at the Jina environment when searching.
This Jina model is licensed under CC BY-NC 4.0 and is restricted to noncommercial use. Review the model license before using it in a product or service.
Using your own embedding server
To reuse a long-running server instead of the managed one, point ClawGallery at it and it won't auto-start anything:
# Terminal A: keep a server running
CLAWGALLERY_PYTHON="/mlx-embeddings/bin/python" \
# Terminal B: sync and search against it
You can also set CLAWGALLERY_VDR_EMBEDDING_URL instead of passing --embedding-url. The managed server binds to 127.0.0.1 and refuses non-loopback hosts unless you pass --allow-remote.
Legacy ColQwen2 (vidore/colqwen2-v1.0, 128 dims):
SentenceTransformer Jina Omni (jinaai/jina-embeddings-v5-omni-small, 1024 dims):
This external SentenceTransformer path is separate from the managed jina-mlx backend above. Search must use the same model and dimensions as the synced index. The server enables Hugging Face trust_remote_code; if xet downloads stall, retry with HF_HUB_DISABLE_XET=1.
The embedding server contract is a single POST /embed:
{"model":"vidore/colqwen2-v1.0","dimensions":128,"inputs":[{"kind":"image|text|caption","role":"document|query","value":"path or text"}]}
kind is image (path), text, or caption. For images, value is the file path (including .heic/.heif), so the server needs an HEIC decoder such as Pillow + pillow-heif.
Vision model setup
Captioning needs a vision-capable model. ClawGallery supports two providers.
OpenAI-compatible (default)
Uses /v1/responses-style requests.
OPENAI_API_KEY— your keyOPENAI_BASE_URL— defaults tohttps://api.openai.com/v1CLAWGALLERY_MODEL— defaults togpt-4.1-mini
It can also reuse Codex credentials from $CODEX_HOME/auth.json or ~/.codex/auth.json.
Google Gemini
GEMINI_API_KEY— your key- Default model:
gemini-2.5-flash
Choosing a provider
How your data is stored
Everything lives in ~/.config/clawgallery by default (override with CLAWGALLERY_CONFIG_DIR):
| File | What it holds |
|---|---|
config.json |
Your settings |
folders.jsonl |
Registered folders |
images.jsonl |
One record per discovered / pruned / renamed image |
captions.jsonl |
One record per successful caption |
renames.jsonl |
Rename history |
errors.jsonl |
Logged failures (API keys redacted) |
vdr.sqlite3 |
The visual embedding index |
The event logs are append-only and joined by image_id. This is deliberate: cheap, free, repeatable indexing (bootstrap) is kept separate from paid network calls (caption) and from irreversible file changes (rename --apply). Every command treats the newest record per file as the truth and ignores anything marked inactive.
Rename safety
Renaming files is the one thing that touches your disk, so it's cautious by design:
- Dry-run by default. You must pass
--applyto move files. Dry-runs never touch files or write history. - Meaningful names are left alone. Only auto-generated stems get renamed (
IMG_0034,PXL_20240316_080000123,Screenshot 2025-11-01 at 14.32.55,1696862563748,image (1), …). A local regex catches ~12 common camera/screenshot/messenger families for free; anything ambiguous triggers a text-only model check on the filename (no image content) whose answer is cached asfilename_meaningfulincaptions.jsonl. - No clobbering. Unsafe characters are stripped, extensions preserved, and existing files are never overwritten.
- Batch-safe. If a tracked file has vanished from disk, ClawGallery marks it inactive and keeps going. Per-file failures are logged and summarized (
renamed N, skipped M, failed K) instead of aborting.
Run as a background service
Install a user service that polls for new images continuously:
On macOS this is a LaunchAgent (~/Library/LaunchAgents); on Linux it's a systemd --user unit. Logs go to daemon.log in your config directory. Set CLAWGALLERY_DAEMON_DIR to write the service file elsewhere.
Command reference
clawgallery init
clawgallery folder add <path> [--recursive]
clawgallery folder remove <id-or-path>
clawgallery folder list
clawgallery bootstrap [--folder <id>] [--path <path>] [--prune]
clawgallery poll [--folder <id>] [--path <path>] [--once] [--interval <seconds>] [--prune] [--caption] [--sync] [--embedding-url <url>] [--vdr-model <model>] [--vdr-dimensions <n>] [--max-retries <n>]
clawgallery caption [--missing] [--file <path>] [--dry-run] [--model <model>] [--provider <provider>] [--concurrency <n>] [--max-retries <n>]
clawgallery rename [--apply] [--dry-run] [--file <path>] [--style title|caption|date-title] [--force]
clawgallery rename --undo [--last] [--file <path>] [--dry-run]
clawgallery forget --file <path> [--delete]
clawgallery dedup [--exact] [--similar] [--threshold <0..1>] [--json]
clawgallery search [--mode keyword|embedding|lexical|hybrid] <query...> [--limit <n>] [--json] [--case-sensitive] [--no-fuzzy] [--embedding-url <url>]
clawgallery vdr sync [--prune] [--embedding-url <url>] [--model <model>] [--dimensions <n>] [--max-retries <n>] [--auto-start|--no-auto-start] [--backend mlx|jina-mlx|vsplade] [--host <host>] [--port <port>] [--device auto|mps|cpu] [--python <path>] [--allow-remote]
clawgallery vdr serve [--backend mlx|jina-mlx|vsplade] [--host <host>] [--port <port>] [--model <model>] [--dimensions <n>] [--device auto|mps|cpu] [--python <path>] [--allow-remote]
clawgallery vdr status [--json]
clawgallery daemon install [--interval <seconds>] [--caption] [--sync] [--path <path>] [--folder <id>]
clawgallery daemon start|stop|status|uninstall|logs
clawgallery status
clawgallery skill path|print
jina-mlx supports --device auto|mps; cpu is available only with the
default mlx backend.
For AI agents
ClawGallery ships a skill so agents can drive it safely. Every command supports --json for stable, parseable output — prefer it. Run clawgallery skill print to load the guidance, and remember the safe defaults: rename never touches files without --apply, and bulk caption --missing may cost money, so preview with --dry-run first.
Community
- Contributing: CONTRIBUTING.md
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
- Changelog: CHANGELOG.md
License
Apache-2.0. See LICENSE.
If ClawGallery saved you from filename chaos, don't forget to ⭐️ star the repo — gh repo star NomaDamas/ClawGallery. Thank you!