← All work

Knowledge

Stash

I bookmarked things on every platform and could never find them again — often not even which app they were in. So I pooled them into one searchable place.

Year
2025~now
Role
Solo — extension, web app, retrieval pipeline
Status
Live — Chrome extension and web app
Capture, enrich, retrieve — the whole loop. The post at the start is answered back by name at the end.

The problem

Useful things arrive from everywhere now — Instagram, LinkedIn, YouTube, X, a random blog — so I got into the habit of screenshotting anything worth keeping. The habit worked. The retrieval did not. A screenshot is a dead end: it is pixels in a folder, and once there are a few thousand of them, saving something is indistinguishable from losing it.

Stash makes a capture into a record instead of an image. It runs OCR over the picture, analyses the text, and pulls the page's own metadata, then uses that to enrich, tag and categorise the item automatically. Everything saved is ingested into a retrieval pipeline, so you can ask your own library a question in plain language instead of scrolling it.

The name comes from `git stash` — set something aside without losing your place, and come back for it when you are ready.

How it changed

Each version below exists because the one before it was wrong about something specific.

  1. v1

    Put the whole library in the prompt

    Why
    The first version of asking your library a question was the simplest one that could work.
    Change
    Inject the full set of captures into the model's context and let a long-context model do the retrieval itself.
    Result
    Excellent answers, and completely unaffordable past a few hundred items. Accuracy was never the constraint — cost and context length were, and both scale with exactly the thing the product is designed to accumulate.
  2. v2

    Hybrid retrieval that switches on library size

    Why
    Small libraries genuinely are best served by full-context injection. Large ones cannot be. The product needs both without asking the user which.
    Change
    Built a hybrid RAG layer that switches between long-context injection and semantic embedding search based on library size, plus four server-enforced defence layers — rate limiting, quota, per-request caps and scope enforcement — so the assistant stays bounded and stays inside the user's own collage.
    Result
    Retrieval quality holds as the library grows, and cost stops tracking library size. The defence layers exist because an open chat box over an LLM is otherwise a free ChatGPT with my API key attached.
    Stash library in list view with tags and dates
    The same library, dense view.

From captures to something you own

The goal was never a better bookmark manager. It is that the gap between data and knowledge is retrieval — a capture you cannot find is worth exactly as much as one you never made.

Diagram: data to information to knowledge to insight to wisdom
The ladder the product is trying to move you up.

Built with

  • React
  • TypeScript
  • Chrome Extension
  • Supabase
  • OpenAI API
  • OCR
  • RAG

Deep dives

Individual pieces of this project, written up on their own.