<?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: HemantAcharya</title>
    <description>The latest articles on DEV Community by HemantAcharya (@hemantacharya).</description>
    <link>https://dev.to/hemantacharya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4021774%2F03375495-ff48-4080-b5b4-a6845dbbb2ec.jpg</url>
      <title>DEV Community: HemantAcharya</title>
      <link>https://dev.to/hemantacharya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hemantacharya"/>
    <language>en</language>
    <item>
      <title>How I gave a self-hosted AI agent long-term memory, without a vector database</title>
      <dc:creator>HemantAcharya</dc:creator>
      <pubDate>Mon, 03 Aug 2026 19:33:09 +0000</pubDate>
      <link>https://dev.to/hemantacharya/how-i-gave-a-self-hosted-ai-agent-long-term-memory-without-a-vector-database-55gg</link>
      <guid>https://dev.to/hemantacharya/how-i-gave-a-self-hosted-ai-agent-long-term-memory-without-a-vector-database-55gg</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I added long-term memory to a self-hosted AI agent. The memory lives on the user's own server — no cloud, no vector database. Embeddings are stored as float32 blobs in SQLite and compared with a plain numpy cosine similarity. The easy part was storing memories; the hard part was consolidating them (add / update / delete), and two LLM bugs taught me the most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The constraint that shaped everything&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most "AI memory" tutorials start by spinning up a vector database and shipping your data to someone's cloud. I couldn't do either.&lt;/p&gt;

&lt;p&gt;The AI agent I work on &lt;strong&gt;AIDA by Autafy&lt;/strong&gt; is self-hosted — it runs on the user's own server, under their own API key. Its whole point is that your data never leaves your hands. So when I added memory, the memory had to live there too: on your box, in a file you can open, back up, or delete. That one constraint decided the whole design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two kinds of memory: semantic and episodic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most memory features only store facts — "prefers concise answers," "works in real estate." Useful, but flat. I wanted two layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic memory&lt;/strong&gt; — durable facts: preferences, projects, the people you work with.&lt;br&gt;
&lt;strong&gt;Episodic memory&lt;/strong&gt; — the moments worth remembering: "was excited about landing their first customer."&lt;/p&gt;

&lt;p&gt;The episodic layer is what makes an assistant feel like it knows you, instead of just holding a profile card. Both are just rows in SQLite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why no vector database?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At per-user scale, a vector database is overkill. One person accumulates a few hundred to a few thousand memories — not millions. So embeddings get stored as raw float32 blobs right next to the memory text, and retrieval is a brute-force cosine similarity in numpy:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
import numpy as np&lt;/p&gt;

&lt;h2&gt;
  
  
  memories store their embedding as a float32 blob in SQLite
&lt;/h2&gt;

&lt;p&gt;def cosine_search(query_vec, rows, top_k=3):&lt;br&gt;
    q = query_vec / np.linalg.norm(query_vec)&lt;br&gt;
    scored = []&lt;br&gt;
    for mem_id, blob in rows:&lt;br&gt;
        v = np.frombuffer(blob, dtype=np.float32)&lt;br&gt;
        scored.append((mem_id, float(np.dot(q, v / np.linalg.norm(v)))))&lt;br&gt;
    scored.sort(key=lambda x: x[1], reverse=True)&lt;br&gt;
    return scored[:top_k]&lt;/p&gt;

&lt;p&gt;At a few thousand rows this runs in well under a millisecond. What you get for free by skipping the vector database:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No second store to sync&lt;/strong&gt; — one SQLite file is the memory.&lt;br&gt;
&lt;strong&gt;Isolation&lt;/strong&gt; — memory embeddings never touch the document/RAG store; different file, different code path.&lt;br&gt;
&lt;strong&gt;Ownership is literal&lt;/strong&gt; — the entire memory is one portable file the user controls, not rows in a database they don't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hard part: consolidation, not storage&lt;/strong&gt;&lt;br&gt;
Anyone can append rows. The real problem is the tenth conversation, where you contradict yourself.&lt;/p&gt;

&lt;p&gt;"My favorite color is green." → store it.&lt;br&gt;
Later: "actually I hate green, blue's my color." → this should rewrite the row, not add a second one.&lt;br&gt;
"I'm not vegetarian anymore." → this should delete the fact, not store a weird negation.&lt;/p&gt;

&lt;p&gt;So a nightly job (a cron sweep — never on the hot path of a chat) reviews each day's conversations, extracts candidate facts, and asks an LLM to decide against the existing memories:&lt;/p&gt;

&lt;p&gt;Given a NEW fact and up to 3 EXISTING memories, choose ONE:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ADD    → genuinely new information&lt;/li&gt;
&lt;li&gt;UPDATE → same subject, changed info; rewrite that memory&lt;/li&gt;
&lt;li&gt;DELETE → new fact contradicts and replaces nothing&lt;/li&gt;
&lt;li&gt;NOOP   → duplicate or not worth keeping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every decision — the op and the distances to the nearest existing memories — gets logged, so thresholds can be tuned later from real data instead of guessed up front.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two bugs that taught me the most&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The model that silently returned nothing.&lt;/strong&gt; Consolidation kept defaulting to ADD — contradictions never deleted, updates never updated. The cause: I was running a cheap reasoning model with max_tokens capped low. Reasoning models spend tokens thinking before they answer, so the budget got burned on reasoning, the response came back truncated to nothing, my JSON parse failed, and the fallback quietly chose ADD. Three sweeps ran that way because nothing errored. Lessons: give reasoning models room, log the full API response body when debugging, and never let a fallback hide a failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The feedback loop.&lt;/strong&gt; The extractor started reading the assistant's own replies as new facts — memory-informed answers getting laundered back into memory as fresh "facts," and even user questions becoming false facts. The fix was one load-bearing rule in the extraction prompt: only the user's statements count as a source. Assistant turns are never facts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory you can audit and delete&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because this runs on the user's own server, the pitch isn't "trust us with your data" — it's auditability. So every control ships with it: memory is off by default, every memory is visible and editable, each one shows its source, there's an incognito mode per conversation, and a forget-everything button. Memory without control is just surveillance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaways&lt;/strong&gt;&lt;br&gt;
For per-user memory at human scale, SQLite blobs + numpy cosine beat a vector database on simplicity and portability.&lt;br&gt;
Storing memories is easy; consolidating them (add / update / delete / noop) is the real work.&lt;br&gt;
Beware silent fallbacks — a parse failure that defaults to the harmless-looking action can hide a broken pipeline for days.&lt;br&gt;
If your extractor reads a conversation, make sure it can't treat the assistant's own words as ground truth.&lt;/p&gt;

&lt;p&gt;This is built into AIDA, a self-hosted AI agent at autafy.ca — but the approach works for any assistant where you'd rather own the memory than rent it. I'd genuinely like to compare notes on consolidation; it's the part I'm least sure I've nailed.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>sqlite</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a self-hosted AI assistant that runs on your own server — here's why</title>
      <dc:creator>HemantAcharya</dc:creator>
      <pubDate>Wed, 08 Jul 2026 23:13:38 +0000</pubDate>
      <link>https://dev.to/hemantacharya/i-built-a-self-hosted-ai-assistant-that-runs-on-your-own-server-heres-why-1ln0</link>
      <guid>https://dev.to/hemantacharya/i-built-a-self-hosted-ai-assistant-that-runs-on-your-own-server-heres-why-1ln0</guid>
      <description>&lt;p&gt;I came out of the oil patch — years of non-destructive testing, not software. A year back I started a small automation agency called &lt;strong&gt;Autafy AI Automation&lt;/strong&gt;, mostly building n8n workflows for people, the kind of behind-the-scenes automation that quietly saves hours every week.&lt;/p&gt;

&lt;p&gt;But I kept running into the same wall. The tools were scattered. A workflow here, an integration there, an AI model somewhere else. Even when the automation worked, the person I built it for often didn't really understand what it did, or what &lt;em&gt;else&lt;/em&gt; was possible. They had power they couldn't see or reach.&lt;/p&gt;

&lt;p&gt;So I wanted to build something different: one place where all the tools live together, that a normal person can actually use, where you can see what the AI agent is doing and start imagining what more you could do with it.&lt;/p&gt;

&lt;p&gt;That became &lt;strong&gt;AIDA - "Autafy's Intelligence Driven Agent"&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AIDA&lt;/strong&gt; is a personal AI agent you run on your own server. You install it with one command, and manage everything from a web dashboard — no terminal, no code after setup.&lt;br&gt;
Here's a 2-minute demo of it actually doing things:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/92G_A57jQr8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Once it's running, it does the kind of work that eats your day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It sends me a &lt;strong&gt;morning briefing on Telegram before I even wake up&lt;/strong&gt; — my calendar, the emails that actually need a reply, the weather, my tasks for the day. I roll over, check my phone, and I already know what my day looks like.
&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%2Fg0ivnp5fidbufrq21nq6.jpg" alt="AIDA morning briefing in Telegram showing calendar, urgent emails, tasks, and weather" width="800" height="2518"&gt;
&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;triages my inbox all day&lt;/strong&gt;, flagging what's urgent based on rules I set, and can even draft the reply.&lt;/li&gt;
&lt;/ul&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%2Fyz9nw32sowx7jqb19v5c.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%2Fyz9nw32sowx7jqb19v5c.png" alt="Inbox-triage" width="489" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It &lt;strong&gt;answers questions from my own documents&lt;/strong&gt; — upload a PDF or a spreadsheet, ask a question, and it answers with a citation back to the source.
&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%2Fhgduwtahjjzfv7xtd0v3.png" alt="AIDA answering a question from an uploaded document with a citation to the source" width="800" height="508"&gt;
&lt;/li&gt;
&lt;li&gt;It connects to the tools I already use — Gmail, Calendar, Drive, Outlook, Notion, Slack, Stripe, and more.
&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%2Fz2fd8o0jndqvax88rhw5.jpg" alt="AIDA tools and integrations screen showing Notion, Slack, Stripe, and other connectors" width="800" height="2983"&gt;
&lt;/li&gt;
&lt;li&gt;And it runs on whatever AI model I want — including fully local models, so nothing has to leave my machine at all.
&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%2Fgnm41v0c8o8ft2ampe88.png" alt="LLM Providers" width="799" height="500"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who it's for
&lt;/h2&gt;

&lt;p&gt;Honestly, most working professionals.&lt;/p&gt;

&lt;p&gt;Solo entrepreneurs and freelancers who are doing the work &lt;em&gt;and&lt;/em&gt; running the business, and don't have time to babysit their inbox. Consultants who live out of their calendar. Even students — you can drop your study materials into the knowledge base and ask the agent questions, and it answers from your own notes.&lt;/p&gt;

&lt;p&gt;It's not built for one narrow niche. It's built for anyone who has more to do than hours in the day and wants a capable assistant that's actually theirs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why self-hosted, and why pay once
&lt;/h2&gt;

&lt;p&gt;This is the part I care about most.&lt;/p&gt;

&lt;p&gt;Most AI assistants run on someone else's servers. That means your email, your files, your calendar — your clients' data — all pass through a company you have to trust. I didn't want that, and I didn't think my clients should have to accept it either.&lt;/p&gt;

&lt;p&gt;So AIDA runs on &lt;em&gt;your&lt;/em&gt; server. Your data stays with you. The only thing that ever leaves is the call to whichever AI provider you choose and if you run a local model, not even that.&lt;/p&gt;

&lt;p&gt;And it's a one-time price, not a subscription. You buy it once and own it for life. I'd rather have customers who feel like they own something than customers I'm billing forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest part
&lt;/h2&gt;

&lt;p&gt;It took a few months to build, mostly solo. The hardest part wasn't the AI, it was the plumbing. Wiring up all those tools and integrations so they work together reliably, from one place, took far longer than I expected. Every service has its own quirks, its own auth, its own edge cases. Making it feel simple on the outside meant a lot of unglamorous work on the inside.&lt;/p&gt;

&lt;p&gt;But that was the whole point. The value isn't any single feature, It's that everything finally lives in one place a normal person can actually use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;AIDA is live now. It installs on any small VPS with one command, there's a free trial (no credit card), and it's a one-time founding license for the first customers before the price goes up.&lt;/p&gt;

&lt;p&gt;If you've ever wanted a capable AI assistant that runs on your own machine and keeps your data yours, I'd genuinely love for you to try it and I'm around to answer any questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://autafy.ca" rel="noopener noreferrer"&gt;https://autafy.ca&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>agents</category>
      <category>selfhosted</category>
    </item>
  </channel>
</rss>
