<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raj Gharat</title>
    <description>The latest articles on DEV Community by Raj Gharat (@gharatraj077).</description>
    <link>https://dev.to/gharatraj077</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F99mvlsfu5tfj9m7ku25d.png</url>
      <title>DEV Community: Raj Gharat</title>
      <link>https://dev.to/gharatraj077</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gharatraj077"/>
    <language>en</language>
    <item>
      <title>Keepsake: an offline memory companion I built for my grandmother</title>
      <dc:creator>Raj Gharat</dc:creator>
      <pubDate>Sat, 03 Oct 2026 14:49:51 +0000</pubDate>
      <link>https://dev.to/gharatraj077/keepsake-an-offline-memory-companion-i-built-for-my-grandmother-1407</link>
      <guid>https://dev.to/gharatraj077/keepsake-an-offline-memory-companion-i-built-for-my-grandmother-1407</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;Keepsake&lt;/strong&gt; for my grandmother — &lt;strong&gt;Dadi&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;Tiger Data&lt;/strong&gt; (Postgres + pgvector + full-text + Timescale), talks through &lt;strong&gt;Gemma 3 running locally via Ollama&lt;/strong&gt;, and gets a little more like &lt;em&gt;her&lt;/em&gt; every time we chat — because every conversation is written back into the archive.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Local-first by design: laptop + Ollama + Tiger Cloud. No cloud LLM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; keepsake seed
python &lt;span class="nt"&gt;-m&lt;/span&gt; keepsake chat &lt;span class="s2"&gt;"What dal does Dadi make on Sundays?"&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; keepsake chat &lt;span class="s2"&gt;"Who is Uncle Ravi?"&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; keepsake onthisday
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Real run excerpt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; What dal does Dadi make on Sundays?&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Keepsake:&lt;/strong&gt; 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.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hybrid search ranked &lt;code&gt;Dadi's Sunday Dal&lt;/code&gt; first (reciprocal rank fusion of vector + full-text). The reply stayed grounded in retrieved memory — no invented spices.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;onthisday&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;Architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy15pwvip4mjv0jvj956m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy15pwvip4mjv0jvj956m.png" alt="Keepsake architecture" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/rajgharat07" rel="noopener noreferrer"&gt;
        rajgharat07
      &lt;/a&gt; / &lt;a href="https://github.com/rajgharat07/keepsake" rel="noopener noreferrer"&gt;
        keepsake
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Offline AI memory companion for one grandparent — local Gemma 3 + Tiger Data hybrid search
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Keepsake&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;A private, offline AI companion that becomes the long-term memory of one grandparent.&lt;/p&gt;

&lt;p&gt;Built for a real person. Their stories, recipes, routines, and people live on your laptop — not on someone else's server. Local &lt;strong&gt;Gemma 3&lt;/strong&gt; (via Ollama) does the talking. &lt;strong&gt;Tiger Data&lt;/strong&gt; (Postgres + pgvector + full-text + Timescale) does the remembering.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why this exists&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/rajgharat07/keepsake/docs/architecture.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Frajgharat07%2Fkeepsake%2FHEAD%2Fdocs%2Farchitecture.png" alt="Keepsake architecture — ingest, hybrid Tiger memory, local Gemma, Sentry spans"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 1. Ollama with models already pulled&lt;/span&gt;
ollama pull gemma3:4b
ollama pull nomic-embed-text
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 2. Configure secrets (never commit&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/rajgharat07/keepsake" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Repo: &lt;a href="https://github.com/rajgharat07/keepsake" rel="noopener noreferrer"&gt;https://github.com/rajgharat07/keepsake&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Core pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/keepsake/db.py&lt;/code&gt; — Tiger schema, HNSW/pgvector, GIN &lt;code&gt;tsvector&lt;/code&gt;, Timescale hypertable, hybrid RRF search&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/keepsake/agent.py&lt;/code&gt; — retrieve → Gemma generate → store exchange&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/keepsake/tracing.py&lt;/code&gt; — Sentry agent transaction + spans&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.cursor/mcp.json&lt;/code&gt; — Tiger MCP pointed at the same database&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Open-source AI is not a decoration here — it is the runtime.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 3 (&lt;code&gt;gemma3:4b&lt;/code&gt;)&lt;/strong&gt; via Ollama for all chat. System prompt: only speak from retrieved memories; if missing, admit it and invite the family to add it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;nomic-embed-text&lt;/code&gt;&lt;/strong&gt; via Ollama for local embeddings (768-d) — no cloud embedding API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiger Data&lt;/strong&gt; as the memory substrate:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vector(768)&lt;/code&gt; + HNSW&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tsvector&lt;/code&gt; + GIN&lt;/li&gt;
&lt;li&gt;Timescale hypertable on &lt;code&gt;created_at&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reciprocal rank fusion of cosine similarity and full-text rank&lt;/li&gt;
&lt;li&gt;Every chat turn is written back so memory compounds&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry&lt;/strong&gt; wraps embed / hybrid_search / generate so latency and tokens are visible in traces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiger MCP&lt;/strong&gt; config so an agent can query the same memory store we built.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stack choice was deliberate: every closed API I skipped is a privacy promise I could keep for Dadi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Family memory is not a SaaS feature.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Tiger Data&lt;/strong&gt; (primary) — hybrid keyword + vector search, Timescale hypertable, growing episodic memory, Tiger MCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — local &lt;code&gt;gemma3:4b&lt;/code&gt; via Ollama as the only generator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Sentry Agent Tracing&lt;/strong&gt; — &lt;code&gt;keepsake.chat&lt;/code&gt; transaction with embed / retrieve / generate spans + token metadata&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hf26challenge</category>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
  </channel>
</rss>
