<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Mohan's Engineering Journal]]></title><description><![CDATA[Mohan's Engineering Journal]]></description><link>https://mohanbuild.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 08 Nov 2026 08:25:15 GMT</lastBuildDate><atom:link href="https://mohanbuild.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[One Hindsight Memory Bank per Client, Zero Mix-ups]]></title><description><![CDATA[Learn how Client Desk uses Hindsight memory banks to keep client information separate and generate personalized drafts with Flask and Groq.]]></description><link>https://mohanbuild.hashnode.dev/one-hindsight-memory-bank-per-client-zero-mix-ups</link><guid isPermaLink="true">https://mohanbuild.hashnode.dev/one-hindsight-memory-bank-per-client-zero-mix-ups</guid><category><![CDATA[hindsight]]></category><category><![CDATA[ai agents]]></category><category><![CDATA[llm]]></category><category><![CDATA[Python]]></category><category><![CDATA[Flask Framework]]></category><dc:creator><![CDATA[Mohan D. S]]></dc:creator><pubDate>Sat, 07 Nov 2026 11:27:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6aeefe95935437b22b585993/b9f2a30a-60f1-4ee2-80e3-6e65f2b29de0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A freelancer’s assistant has one rule it can’t break: what it knows about one client must never leak into another client’s email. Mention a discount you gave one customer to a different customer and you can lose the contract.</p>
<p>So the first decision I made while building Client Desk, an assistant that writes emails, quotes and follow-ups for freelancers, wasn’t about prompts or models. It was about where memory lives.</p>
<p><strong>What it does</strong></p>
<p>Client Desk is a small Flask app. You pick a client, ask for a draft (“write a quote for the next phase”), and it writes one using everything it remembers about that client. You teach it new facts in plain sentences, and a Brief button summarizes a client before a call. Text generation runs on Groq’s openai/gpt-oss-120b. Memory runs on <a href="https://github.com/vectorize-io/hindsight"><u>Hindsight</u></a> through Hindsight Cloud. The code is in the <a href="https://github.com/mohands0810-debug/freelance-client-memory-agent"><u>project repository</u></a>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aeefe95935437b22b585993/6f3f1f27-2a24-4e55-b0d8-60ef6a60e97a.png" alt="" style="display:block;margin:0 auto" />

<p><strong>The decision: one bank per client</strong></p>
<p>Hindsight organizes memory into banks. Instead of one big bank where I’d have to filter by a client tag on every read, I give each client their own bank:</p>
<pre><code class="language-python">def bank(name):
    return "client-" + name.strip().lower().replace(" ", "-")
</code></pre>
<p>“Northwind” becomes client-northwind. Every read and write goes through that one function, so there is no code path where a recall can wander into another client’s facts. Isolation is built into the structure instead of being something I have to remember to enforce.</p>
<p><strong>Three calls run the whole app</strong></p>
<p>The app uses three Hindsight operations, all described in the <a href="https://hindsight.vectorize.io/"><u>Hindsight docs</u></a>.</p>
<p><strong>Retain</strong> runs when you save a note:</p>
<pre><code class="language-python">hs.retain(bank_id=bank(d["client"]), content=d["note"])
</code></pre>
<p>Hindsight turns a plain sentence into stored facts and links the people in it. I saved “Acme’s CEO Priya hates long emails and always wants a price breakdown” and got back separate facts: Priya is the CEO of Acme, she dislikes long emails, and she requires a price breakdown.\</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aeefe95935437b22b585993/711752d1-c762-429c-ad74-0ec344c24491.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Recall</strong> runs before every draft:</p>
<pre><code class="language-python">mem = hs.recall(bank_id=bank(client), query=msg)
facts = [r.text for r in mem.results]
</code></pre>
<p>The query is the user’s own request, so “write a quote” pulls budget and payment facts while “send the invoice” pulls PO-number and CC rules. According to the docs, recall runs semantic, keyword, graph and temporal search in parallel, and I didn’t have to build any of it.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aeefe95935437b22b585993/c2c55568-4f6e-4634-9593-fc250094053e.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Reflect</strong> powers the Brief button:</p>
<pre><code class="language-python">ans = hs.reflect(bank_id=bank(c), query=f"Give me a short briefing on {c}: ...")
</code></pre>
<p><strong>Before and after</strong></p>
<p>With an empty bank, the facts block in my prompt reads “(nothing known yet)” and the draft is generic, mostly placeholders. With memory, the same request, “Write a quote for the next phase”, produced very different results for two sample clients I seeded:</p>
<p><strong>Northwind:</strong> a formal email to Meera, a quote framed under the stored 2 lakh quarterly cap, and a request for a PO number.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aeefe95935437b22b585993/40f06d60-4935-4cc3-bd52-7f1edb749c17.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Bluepeak:</strong> a few casual lines with emoji, and an offer of the same 10 percent discount Dev got last time.</p>
<p>I didn’t change the prompt between them. Only the bank changed.</p>
<p><strong>Things I’d warn you about</strong></p>
<p>The bank key comes from the name you type. “Acme” and “Acme Ltd” become two banks, and a typo quietly creates a new empty one. A real deployment needs stable client IDs.</p>
<p>I had planned to self-host Hindsight with a free Groq key. The docs note that Groq’s free tier allows about 8,000 tokens per minute, far below what a single retain call needs, so I used Hindsight Cloud for memory and kept Groq only for writing drafts.</p>
<p>There is no authentication yet, so it’s a single-user tool.</p>
<h2>What happens when I click Write draft</h2>
<p>The important part of this workflow happens before the language model starts writing. When I click Write draft, the frontend sends the selected client name and my request to the Flask backend through the <code>/api/chat</code> endpoint.</p>
<p>The backend uses the selected client's bank name to call Hindsight's recall operation. It then collects the returned memory results and converts them into a facts list. If nothing relevant is returned, the application uses a simple message saying that nothing is known yet.</p>
<p>These facts are added to the system prompt along with instructions about how the assistant should behave. For example, it must follow the client's communication preferences, use only relevant information and avoid inventing invoice numbers, amounts or dates.</p>
<p>The request is then sent to Groq using the <code>openai/gpt-oss-120b</code> model. The generated response is returned to the frontend and displayed as a draft. The recalled facts are also sent back to the interface, where they appear in the "What I remember" panel.</p>
<p>I wanted this panel to be visible because memory should not feel like a hidden process. The user should be able to see which client information influenced the response and understand why the assistant produced a particular draft.</p>
<p><strong>Takeaways</strong></p>
<p>Make isolation structural: one bank per tenant beats a filter you must never forget.</p>
<p>Use the user’s request as the recall query.</p>
<p>Derive bank names from stable IDs, not typed names.</p>
<p>Check your LLM provider’s rate limits against your memory system’s needs before choosing a stack.</p>
<p>If you want the background on the idea, Vectorize has a good explainer on <a href="https://vectorize.io/what-is-agent-memory"><u>agent memory</u></a>.</p>
]]></content:encoded></item></channel></rss>