A private memory library that never confuses an AI guess with a fact.
In development
- Suggestions onlyno face is auto-assigned to a person
- 512-Dface embeddings, never sent to an LLM
- 1 bank / userisolated long-term memory
- 0 brokersPostgres is the job queue
Why I built it
the problem, minus the buzzwordsPhoto apps can find faces, but they don’t know that this face is “Mummy” or that “bhai” and “elder brother” mean the same person. And AI tools that “remember” things mix up what you told them with what they guessed, so you can’t tell which answers to trust. Reject a wrong guess and it comes back next week.
I wanted a memory app where what you confirmed, what was only suggested and what you rejected stay separate all the way from upload to search.
How it works
upload once, the worker does the rest- Upload1
Next.js app; files stream through FastAPI into Oracle object storage, hashed on the way in.
#client
- Job queue2
Every change and its follow-up job commit in one Postgres transaction; workers claim jobs with SKIP LOCKED.
#postgres
- Worker3
EXIF + thumbnail, faces (YuNet + AuraFace), pgvector matching, scene descriptions, document text.
#pipeline
- Questions4
“Is this Mummy?” Answers are stored as confirmed, rejected or skipped, never merged.
#review
- Memory & search5
One Hindsight document per file and person, rendered from the database; results are re-checked before showing.
#recall
- +Sign-in with Better Auth (Google + email codes); FastAPI only trusts short-lived JWTs it verifies against the JWKS.
- +Every table carries user_id and child rows use composite (id, user_id) keys, so the database itself refuses cross-user references.
- +Each worker stage is independent: a failed scene description never loses the faces found in the same photo.
Built with Next.js, FastAPI, PostgreSQL, pgvector, Better Auth, Hindsight, YuNet + AuraFace, OpenAI, Oracle Object Storage, Docker.
Decisions I made
and why. mostly why.1.Guesses stay guesses
Unknown isn’t false, skipped isn’t rejected, inferred isn’t confirmed. Face matches are only ever suggestions, and a rejected fact is kept as a tombstone so it can’t be suggested again.
2.The database is the truth, memory is a projection
Hindsight never sees raw events. It gets one document per file and person, re-rendered from current state. Search results from stale or deleted documents are dropped, and a generated answer is shown only if every memory behind it still checks out.
3.Postgres as the queue
Jobs are enqueued in the same transaction as the change that needs them, so nothing is ever saved without its follow-up work. No extra broker to run or lose messages.
4.Understand how people actually talk
Relationship words like “bhai”, “jiju” and “Mummy” map to canonical relations, so “who is my bhai?” is answered straight from your records, even when the memory engine is down.