DEV Community

Raj Gharat
Raj Gharat

Posted on

Keepsake: an offline memory companion I built for my grandmother

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🀝

This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend

What I Built

I built Keepsake for my grandmother β€” Dadi.

It is a private, offline AI companion that becomes her long-term memory. We feed it her stories, recipes, routines, and the people in her life. It remembers them in Tiger Data (Postgres + pgvector + full-text + Timescale), talks through Gemma 3 running locally via Ollama, and gets a little more like her every time we chat β€” because every conversation is written back into the archive.

It does not have to be huge. It has to matter. For us, that means Sunday dal, the neem tree promise, Uncle Ravi on his rattling scooter, and the gold bangle that almost ruined a wedding morning.

Keepsake is built so a grandchild can ask real questions β€” β€œWhat dal does she make on Sundays?” / β€œWho is Uncle Ravi?” β€” and get answers grounded only in family memories, not inventing details a closed chatbot would guess.

Demo

Local-first by design: laptop + Ollama + Tiger Cloud. No cloud LLM.

python -m keepsake seed
python -m keepsake chat "What dal does Dadi make on Sundays?"
python -m keepsake chat "Who is Uncle Ravi?"
python -m keepsake onthisday
Enter fullscreen mode Exit fullscreen mode

Real run excerpt:

Q: What dal does Dadi make on Sundays?

Keepsake: Oh, you’re wondering about the dal? Dadi makes a Sunday Dal. She soaks yellow lentils before sunrise, and it’s a slow boil with a little ghee at the end. She always says, β€œHome has a smell. This is ours.”

Hybrid search ranked Dadi's Sunday Dal first (reciprocal rank fusion of vector + full-text). The reply stayed grounded in retrieved memory β€” no invented spices.

onthisday resurfaces archive rows from the same calendar day across years (e.g. 1986 / 2014), which is where Timescale’s time dimension actually shows up in the product.

Architecture:

Keepsake architecture

Code

GitHub logo rajgharat07 / keepsake

Offline AI memory companion for one grandparent β€” local Gemma 3 + Tiger Data hybrid search

Keepsake

A private, offline AI companion that becomes the long-term memory of one grandparent.

Built for a real person. Their stories, recipes, routines, and people live on your laptop β€” not on someone else's server. Local Gemma 3 (via Ollama) does the talking. Tiger Data (Postgres + pgvector + full-text + Timescale) does the remembering.

Why this exists

Closed chatbots forget. Cloud notebooks feel wrong when the subject is family history. Keepsake keeps the archive at home: hybrid search over growing episodic memory, so every conversation makes the next one more personal.

Architecture

Keepsake architecture β€” ingest, hybrid Tiger memory, local Gemma, Sentry spans

Stories go in β†’ embeddings land in Tiger Data β†’ hybrid search (vector + keyword) builds the prompt β†’ Gemma 3 answers locally β†’ the exchange is stored so memory grows. Sentry wraps embed, retrieve, and generate.

Quickstart

# 1. Ollama with models already pulled
ollama pull gemma3:4b
ollama pull nomic-embed-text
# 2. Configure secrets (never commit
…
Enter fullscreen mode Exit fullscreen mode

Repo: https://github.com/rajgharat07/keepsake

Core pieces:

  • src/keepsake/db.py β€” Tiger schema, HNSW/pgvector, GIN tsvector, Timescale hypertable, hybrid RRF search
  • src/keepsake/agent.py β€” retrieve β†’ Gemma generate β†’ store exchange
  • src/keepsake/tracing.py β€” Sentry agent transaction + spans
  • .cursor/mcp.json β€” Tiger MCP pointed at the same database

How I Built It

Open-source AI is not a decoration here β€” it is the runtime.

  1. Gemma 3 (gemma3:4b) via Ollama for all chat. System prompt: only speak from retrieved memories; if missing, admit it and invite the family to add it.
  2. nomic-embed-text via Ollama for local embeddings (768-d) β€” no cloud embedding API.
  3. Tiger Data as the memory substrate:
    • vector(768) + HNSW
    • tsvector + GIN
    • Timescale hypertable on created_at
    • Reciprocal rank fusion of cosine similarity and full-text rank
    • Every chat turn is written back so memory compounds
  4. Sentry wraps embed / hybrid_search / generate so latency and tokens are visible in traces.
  5. Tiger MCP config so an agent can query the same memory store we built.

Stack choice was deliberate: every closed API I skipped is a privacy promise I could keep for Dadi.

Why Does Open Innovation Matter?

Family memory is not a SaaS feature.

  • It runs on a laptop. Chat and embeddings never leave localhost Ollama.
  • Her stories are not training fodder for a vendor model we do not control.
  • Cost to run the AI layer is zero after hardware β€” swap gemma3:4b for another open weight anytime.
  • Tiger gives us durable hybrid retrieval we can inspect with SQL β€” not a black-box β€œmemory” slider.

A closed API would have been faster to prototype and worse for the person I built this for. Open won on privacy, offline, cost, and ownership β€” the exact axes that matter when the subject is someone you love.

Prize Categories

  • Best Use of Tiger Data (primary) β€” hybrid keyword + vector search, Timescale hypertable, growing episodic memory, Tiger MCP
  • Best Use of Gemma β€” local gemma3:4b via Ollama as the only generator
  • Best Use of Sentry Agent Tracing β€” keepsake.chat transaction with embed / retrieve / generate spans + token metadata

Top comments (0)