A design reference library that Claude Code reads before it designs anything.
Ask Claude Code for a landing page and it reaches for the same defaults every time. A taste vault gives it your references instead: sites you admire, measured down to the hex codes and easing curves; the component libraries you trust; and videos with the recipe that made them. A hook puts the right part of the vault into Claude's context whenever a prompt looks like design work. You can browse the same vault in a small local app.
This repo is the empty system. Fill it with your own references.
| Path | What it does |
|---|---|
hooks/taste-vault-recall.py |
Claude Code hook. Injects the vault index when a prompt is about a site, a UI piece, a video or a dither effect; stays silent otherwise |
server.py |
Serves the app. Supports HTTP range requests, so videos seek and play in Safari, and rebuilds the site list on every load |
app/ |
The browser app: Sites, Component Vault and Videos tabs (index.html, data.json, build_data.py) |
index.md |
The index the hook injects. One line per entry, kits at the top |
sites/ |
One folder per site reference |
components/index.md |
UI libraries to check before hand-rolling a piece |
videos/ |
One folder per video reference, with index.md matching briefs to styles |
templates/ |
notes.md templates for a site and a video |
hooks/com.example.taste-vault.plist |
Optional macOS login service that keeps the server running |
Python 3 is the only requirement. No packages, no build step.
git clone https://github.com/codeclawd/taste-vault ~/taste-vault
cd ~/taste-vault
python3 server.py 4180Open http://localhost:4180/. Use server.py rather than python3 -m http.server: the built-in server can't seek inside a video, and Safari won't play MP4 from it at all.
Add the hook to ~/.claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "python3 ~/taste-vault/hooks/taste-vault-recall.py" }] }
]
}
}The hook looks for the vault at ~/taste-vault. Set TASTE_VAULT_DIR if you keep it somewhere else.
It fires on prompts like "build a landing page", "add a pricing section", "make a promo video like X", "check the taste vault" or anything about dithering. It skips long pasted text and ordinary coding prompts. Site and UI prompts get index.md and components/index.md; video prompts get videos/index.md. Claude Code caps hook context at 10,000 characters, so each file is cut at 4,000 and a prompt never gets all three. Keep the important lines near the top of each file.
Test it:
echo '{"prompt":"build a landing page for my app"}' | python3 hooks/taste-vault-recall.py
echo '{"prompt":"fix the login bug"}' | python3 hooks/taste-vault-recall.py # prints nothing- Make
sites/<name>/and copytemplates/site-notes.mdinto it asnotes.md. Keep the first line as# Site Name - domain.com. - Save a screenshot as
screenshot-1440.png. - Add a line to
index.mdunder Entries:- **[name](sites/name/notes.md)** — domain.com — what to learn from it.
Reload the app and the site appears. build_data.py reads the folders, the index line and the first screenshot on every page load, so you never edit a list by hand. To file a site under a filter chip, add its folder name to COLLECTIONS in app/build_data.py.
Write notes Claude can act on. "Nice hero" gives it nothing to work with. "One accent #309CFC used five times; entrance curve cubic-bezier(.2,.7,.2,1); hero H1 at 72px / 1.05 / −0.035em" does.
Add a row to the table in components/index.md, which the hook reads. To show the library in the app too, add an object to components in app/data.json:
{ "name": "Magic UI", "url": "https://magicui.design/", "stack": "React · Tailwind · Motion",
"install": "shadcn registry", "cost": "Free · MIT", "use": "Marketing motion", "tags": ["motion"] }- Make
videos/<name>/with the.mp4, aposter.jpg, acontact-sheet.jpgandnotes.mdfromtemplates/video-notes.md. If you have the code that made it, put it inkit/. - Add a line to
videos/index.md, and a row to its picker table. - Add an object to
videosinapp/data.json(name,slug,src,poster,sheet,notes,kitornull,specs,descriptor,tags), using paths relative toapp/.
A contact sheet shows the whole video in one image, which is how Claude reads a video:
ffmpeg -i video.mp4 -vf "fps=20/DURATION,scale=384:-2,tile=5x4" -frames:v 1 contact-sheet.jpgScreen recordings often have a variable frame rate and can stall at 0:00 in Chromium. Re-encode them first: ffmpeg -i in.mp4 -vf fps=60 -movflags +faststart out.mp4.
Edit the path in hooks/com.example.taste-vault.plist, copy it to ~/Library/LaunchAgents/, then run launchctl load ~/Library/LaunchAgents/com.example.taste-vault.plist. The Xcode Python under launchd takes about 10 seconds to start, so give it a moment before you decide it's down. With portless, portless alias taste-vault 4180 gives you a named local URL.
A vault full of other people's screenshots and videos shouldn't live in a public repo. Copy it into a private repo of your own (GitHub forks of a public repo stay public), or keep your references out of git by adding sites/*/ and videos/*/ to .gitignore.
MIT. See LICENSE.