<?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: Upayan Ghosh</title>
    <description>The latest articles on DEV Community by Upayan Ghosh (@upayanghosh).</description>
    <link>https://dev.to/upayanghosh</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3914189%2Fd9fbab6b-8660-4a21-b03a-c1362c2f745f.jpeg</url>
      <title>DEV Community: Upayan Ghosh</title>
      <link>https://dev.to/upayanghosh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/upayanghosh"/>
    <language>en</language>
    <item>
      <title>From Tokens to Attention: My First Real Mental Model of LLMs</title>
      <dc:creator>Upayan Ghosh</dc:creator>
      <pubDate>Sat, 23 May 2026 22:03:24 +0000</pubDate>
      <link>https://dev.to/upayanghosh/from-tokens-to-attention-my-first-real-mental-model-of-llms-54j9</link>
      <guid>https://dev.to/upayanghosh/from-tokens-to-attention-my-first-real-mental-model-of-llms-54j9</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE - I intentionally simplified the vector mathematics concept here to keep things simple for a greater audience.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wanted to learn LLMs properly.&lt;/p&gt;

&lt;p&gt;Not just use an API. Not just call &lt;code&gt;generate()&lt;/code&gt; from a library and pretend I understood what happened underneath. I wanted to know how a model takes plain text, turns it into numbers, reads context, and predicts the next word.&lt;/p&gt;

&lt;p&gt;The end goal is ambitious: build a mini LLM from scratch.&lt;/p&gt;

&lt;p&gt;But before touching PyTorch, I realized I needed the mental model first. Code without understanding becomes copy-paste gymnastics. So I started with the real basics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text Is Not Text to a Model
&lt;/h2&gt;

&lt;p&gt;A language model does not read words the way we do.&lt;/p&gt;

&lt;p&gt;If I write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model cannot directly understand those letters. First, the text has to be converted into numbers. That conversion is called tokenization.&lt;/p&gt;

&lt;p&gt;The simplest version is character-level tokenization.&lt;/p&gt;

&lt;p&gt;If our tiny training text is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We collect every unique character and assign each one an ID.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;d -&amp;gt; 0
e -&amp;gt; 1
h -&amp;gt; 2
l -&amp;gt; 3
o -&amp;gt; 4
r -&amp;gt; 5
w -&amp;gt; 6
space -&amp;gt; 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the word:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;led
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[3, 1, 0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was the first click for me. Tokenization is basically a dictionary lookup. Text goes in, integer IDs come out.&lt;/p&gt;

&lt;p&gt;And decoding is just the reverse. If encoding turns &lt;code&gt;"he"&lt;/code&gt; into &lt;code&gt;[2, 1]&lt;/code&gt;, decoding turns &lt;code&gt;[2, 1]&lt;/code&gt; back into &lt;code&gt;"he"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the first pipeline looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raw text -&amp;gt; tokenizer -&amp;gt; token IDs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But token IDs alone are not enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Token IDs Are Not Meaning
&lt;/h2&gt;

&lt;p&gt;If &lt;code&gt;h = 2&lt;/code&gt; and &lt;code&gt;l = 3&lt;/code&gt;, that does not mean &lt;code&gt;l&lt;/code&gt; is somehow "greater" than &lt;code&gt;h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Those numbers are just labels. The model needs a richer representation.&lt;/p&gt;

&lt;p&gt;That is where embeddings come in.&lt;/p&gt;

&lt;p&gt;An embedding turns each token ID into a vector, which is just a list of numbers.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat -&amp;gt; 12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get something more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat -&amp;gt; [0.9, 0.2, 0.5, ...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful way to imagine this is a hidden map of meaning.&lt;/p&gt;

&lt;p&gt;Words used in similar ways slowly move closer together during training. So after enough learning, words like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;king and queen
apple and orange
cat and dog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;end up close in vector space.&lt;/p&gt;

&lt;p&gt;The model does not start with this knowledge. The embeddings begin as random numbers. Training adjusts them until useful patterns emerge.&lt;/p&gt;

&lt;p&gt;That was the second click: embeddings are not manually written meanings. They are learned coordinates.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Order Problem
&lt;/h2&gt;

&lt;p&gt;Once tokens become embeddings, there is still a huge problem.&lt;/p&gt;

&lt;p&gt;Transformers process tokens in parallel. That is powerful, but it means the model does not automatically know word order.&lt;/p&gt;

&lt;p&gt;These two sentences contain the same words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The cat ate the mouse.
The mouse ate the cat.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But they mean completely different things.&lt;/p&gt;

&lt;p&gt;So we need to inject position information.&lt;/p&gt;

&lt;p&gt;The obvious idea is to use indexes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The -&amp;gt; position 0
cat -&amp;gt; position 1
ate -&amp;gt; position 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, this sounds perfect. Arrays already have indexes, so why not just use them?&lt;/p&gt;

&lt;p&gt;The issue is scale.&lt;/p&gt;

&lt;p&gt;If we directly add raw indexes, later positions can become huge. A word at position &lt;code&gt;1999&lt;/code&gt; gets a massive position number compared to the small values inside its embedding. The position can overpower the meaning.&lt;/p&gt;

&lt;p&gt;A normalized index also causes trouble.&lt;/p&gt;

&lt;p&gt;For a 3-word sentence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index 2 / length 3 = 0.666
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a 100-word sentence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index 2 / length 100 = 0.02
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same index. Completely different value.&lt;/p&gt;

&lt;p&gt;That means the model has to deal with position values that shift depending on sentence length.&lt;/p&gt;

&lt;p&gt;Sine and cosine positional encodings solve this in a neat way.&lt;/p&gt;

&lt;p&gt;A sine wave always stays between &lt;code&gt;-1&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;, so the values never explode. Also, the position value depends on the index and a fixed rhythm, not on the total sentence length.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sin(index * frequency)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;index = 2&lt;/code&gt; and &lt;code&gt;frequency = 0.5&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sin(2 * 0.5) = sin(1) = 0.841
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That value stays the same whether the sentence has 3 words or 100 words.&lt;/p&gt;

&lt;p&gt;Real transformers use many sine and cosine waves with different frequencies. Fast waves capture small position changes. Slow waves help distinguish positions farther apart.&lt;/p&gt;

&lt;p&gt;That was the third click: positional encoding gives each token a position signature without depending on sentence length.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attention Is Context Mixing
&lt;/h2&gt;

&lt;p&gt;Now comes the heart of the transformer: attention.&lt;/p&gt;

&lt;p&gt;The easiest sentence to understand attention is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The bank of the river was muddy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The word &lt;code&gt;bank&lt;/code&gt; is ambiguous. It could mean a financial institution, or it could mean the edge of a river.&lt;/p&gt;

&lt;p&gt;Attention lets &lt;code&gt;bank&lt;/code&gt; look at surrounding words and decide which ones matter.&lt;/p&gt;

&lt;p&gt;In this sentence, &lt;code&gt;river&lt;/code&gt; is important. So the representation of &lt;code&gt;bank&lt;/code&gt; gets pulled toward the water and geography meaning.&lt;/p&gt;

&lt;p&gt;The mechanism uses three vectors for every token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Query: What am I looking for?
Key: What information do I contain?
Value: What information do I pass along?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple analogy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Query = search question
Key = article title
Value = article content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the query for &lt;code&gt;bank&lt;/code&gt; matches the key for &lt;code&gt;river&lt;/code&gt;, then &lt;code&gt;bank&lt;/code&gt; receives a strong contribution from the value of &lt;code&gt;river&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Mathematically, attention does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;score = Query dot Key
weights = softmax(scores)
output = weights * Values
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The softmax step turns scores into percentages.&lt;/p&gt;

&lt;p&gt;So if &lt;code&gt;bank&lt;/code&gt; gives 80 percent attention to &lt;code&gt;river&lt;/code&gt;, it absorbs a large part of &lt;code&gt;river&lt;/code&gt;'s value vector.&lt;/p&gt;

&lt;p&gt;That was the fourth click: attention is not magic. It is weighted context blending.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Masked Attention Exists
&lt;/h2&gt;

&lt;p&gt;For GPT-style models, there is one more important rule.&lt;/p&gt;

&lt;p&gt;They predict the next token.&lt;/p&gt;

&lt;p&gt;If the training sentence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The cat sat on the mat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the model is learning from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The cat sat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it should predict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But during training, the full sentence already exists in memory.&lt;/p&gt;

&lt;p&gt;So without a mask, the model could cheat. The token &lt;code&gt;sat&lt;/code&gt; could look ahead and see &lt;code&gt;on&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That would be like taking an exam with the answer sheet open.&lt;/p&gt;

&lt;p&gt;Masked attention prevents this. Each token can only look at itself and previous tokens.&lt;/p&gt;

&lt;p&gt;So in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The cat sat on the mat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;when processing &lt;code&gt;sat&lt;/code&gt;, the model can attend to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The, cat, sat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It cannot attend to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on, the, mat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During real conversation, future tokens do not exist yet. The model generates one token at a time. But during training, future tokens do exist, so we hide them.&lt;/p&gt;

&lt;p&gt;That was the fifth click: masking makes training behave like real generation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prediction Is a Probability Game
&lt;/h2&gt;

&lt;p&gt;After all the transformer layers finish processing the context, the model predicts the next token.&lt;/p&gt;

&lt;p&gt;If the prompt is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The cat sat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model does not think there is only one possible answer.&lt;/p&gt;

&lt;p&gt;It produces probabilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on        35%
down      30%
suddenly  15%
furiously 5%
magically 1%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then decoding settings decide how to choose.&lt;/p&gt;

&lt;p&gt;At low temperature, the model picks the most likely token.&lt;/p&gt;

&lt;p&gt;At higher temperature, it samples more creatively from the probability distribution.&lt;/p&gt;

&lt;p&gt;So if the prompt changes to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The wizard waved his wand and the cat sat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then &lt;code&gt;magically&lt;/code&gt; becomes much more likely because the earlier context changed the probability distribution.&lt;/p&gt;

&lt;p&gt;That was the sixth click: generation is not fixed autocomplete. It is probability shaped by context.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>beginners</category>
      <category>llm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Personality Should Not Be Static</title>
      <dc:creator>Upayan Ghosh</dc:creator>
      <pubDate>Sat, 23 May 2026 20:34:50 +0000</pubDate>
      <link>https://dev.to/upayanghosh/personality-should-not-be-static-4kpe</link>
      <guid>https://dev.to/upayanghosh/personality-should-not-be-static-4kpe</guid>
      <description>&lt;p&gt;&lt;em&gt;Most AI assistants treat personality like a costume: write a clever system prompt, pick a tone, and hope it stays useful. A real personal AI needs something deeper. It needs behavioural continuity that can evolve without letting the model rewrite itself into chaos.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most AI personality is fake in a very specific way.&lt;/p&gt;

&lt;p&gt;It is usually a paragraph.&lt;/p&gt;

&lt;p&gt;You tell the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Be helpful, concise, warm, technically accurate, and a little witty.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works for a few turns.&lt;/p&gt;

&lt;p&gt;Then reality shows up.&lt;/p&gt;

&lt;p&gt;The user is tired one day and wants shorter answers. The next day they are debugging something hard and need detail. They mix languages. They develop habits. They correct the assistant. They praise a certain style. They hate a certain phrase. They have private context, work context, emotional context, project context, and repeated patterns that do not fit cleanly into "custom instructions."&lt;/p&gt;

&lt;p&gt;A static prompt cannot keep up with that.&lt;/p&gt;

&lt;p&gt;It can imitate a personality, but it cannot learn a relationship.&lt;/p&gt;

&lt;p&gt;That is the problem a serious personal AI architecture has to solve.&lt;/p&gt;

&lt;p&gt;The interesting idea is not "give the AI a fun personality."&lt;/p&gt;

&lt;p&gt;The interesting idea is this:&lt;/p&gt;

&lt;p&gt;Personality should be a living system around the model, not a frozen prompt inside the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Is Not Enough
&lt;/h2&gt;

&lt;p&gt;AI memory usually starts with facts.&lt;/p&gt;

&lt;p&gt;The user prefers short answers during deep work.&lt;/p&gt;

&lt;p&gt;The user often switches between planning, debugging, and writing.&lt;/p&gt;

&lt;p&gt;The user prefers concise answers.&lt;/p&gt;

&lt;p&gt;The user likes technical depth.&lt;/p&gt;

&lt;p&gt;That is useful, but it is only one layer of personalization. A list of facts does not tell the assistant how the user thinks, how they correct things, when they want speed, when they need care, what style makes them feel understood, or what kinds of responses repeatedly fail.&lt;/p&gt;

&lt;p&gt;Facts answer:&lt;/p&gt;

&lt;p&gt;What should the AI remember?&lt;/p&gt;

&lt;p&gt;Behavioral continuity answers:&lt;/p&gt;

&lt;p&gt;How should the AI relate to this person over time?&lt;/p&gt;

&lt;p&gt;That difference matters.&lt;/p&gt;

&lt;p&gt;A chatbot with memory can say, "I remember your project."&lt;/p&gt;

&lt;p&gt;A personal AI with behavioral continuity can say the right amount, in the right style, with the right level of certainty, through the right model, while respecting what should stay private.&lt;/p&gt;

&lt;p&gt;That is a harder product. It is also the more useful one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Static Prompt Trap
&lt;/h2&gt;

&lt;p&gt;The most common version of assistant personality is a giant system prompt.&lt;/p&gt;

&lt;p&gt;At first, this feels powerful. You can define tone, rules, examples, formatting preferences, safety boundaries, and role identity in one place.&lt;/p&gt;

&lt;p&gt;Then the prompt grows.&lt;/p&gt;

&lt;p&gt;Every correction becomes another line.&lt;/p&gt;

&lt;p&gt;Every preference becomes another bullet.&lt;/p&gt;

&lt;p&gt;Every edge case becomes another paragraph.&lt;/p&gt;

&lt;p&gt;Eventually the prompt becomes a junk drawer. Some instructions are stale. Some contradict each other. Some are too vague. Some should have been structured data. Some should have been tests. Some should have been tool policy. Some should have been memory.&lt;/p&gt;

&lt;p&gt;Worst of all, a static prompt cannot tell the difference between a permanent preference and a temporary mood.&lt;/p&gt;

&lt;p&gt;"Keep it short" might mean:&lt;/p&gt;

&lt;p&gt;I am busy right now.&lt;/p&gt;

&lt;p&gt;Or it might mean:&lt;/p&gt;

&lt;p&gt;In general, this user hates long answers.&lt;/p&gt;

&lt;p&gt;Those are different signals. Treating both as one more sentence in a prompt is sloppy engineering.&lt;/p&gt;

&lt;p&gt;If you are building a serious personal AI, the better question is:&lt;/p&gt;

&lt;p&gt;Which parts of personality should be configured, which parts should be learned, and which parts should be protected from automatic edits?&lt;/p&gt;

&lt;p&gt;The cleaner answer is to make personality layered.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Layered Personality System Works
&lt;/h2&gt;

&lt;p&gt;In the reference architecture I studied, personality is treated as a subsystem.&lt;/p&gt;

&lt;p&gt;The profile manager stores a set of current JSON layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;core_identity
linguistic
emotional_state
domain
interaction
vocabulary
exemplars
meta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That structure matters because each layer changes at a different speed.&lt;/p&gt;

&lt;p&gt;Core identity is intentionally protected. In &lt;code&gt;ProfileManager.save_layer()&lt;/code&gt;, programmatic writes to &lt;code&gt;core_identity&lt;/code&gt; are blocked. That means the assistant cannot casually rewrite its base identity just because a conversation drifted.&lt;/p&gt;

&lt;p&gt;Emotional state is volatile. It can change quickly based on recent mood signals.&lt;/p&gt;

&lt;p&gt;Linguistic style evolves more slowly. It tracks things like language mix, average message length, emoji frequency, and drift over recent batches.&lt;/p&gt;

&lt;p&gt;Interaction patterns track active hours, response length preferences, routines, and correction rules.&lt;/p&gt;

&lt;p&gt;Domain context tracks active interests, important projects, people, and stable identity notes.&lt;/p&gt;

&lt;p&gt;Vocabulary keeps the user's current language alive.&lt;/p&gt;

&lt;p&gt;Exemplars keep selected interaction pairs that show the assistant how to respond in a familiar style.&lt;/p&gt;

&lt;p&gt;Meta tracks profile versioning and batch history.&lt;/p&gt;

&lt;p&gt;This is the key architectural move: personality is not one blob. It is a set of typed layers with different update rules.&lt;/p&gt;

&lt;p&gt;That makes the system easier to reason about.&lt;/p&gt;

&lt;p&gt;It also makes it safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Realtime Learning Handles the Next Reply
&lt;/h2&gt;

&lt;p&gt;Some signals should affect the assistant quickly.&lt;/p&gt;

&lt;p&gt;If the user says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;too long
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;waiting for a nightly job is annoying. The next answer should already be shorter.&lt;/p&gt;

&lt;p&gt;The architecture handles this through realtime processing and implicit feedback detection.&lt;/p&gt;

&lt;p&gt;The realtime processor runs on each message. It estimates language, sentiment, and mood. It can hot update the emotional profile layer without blocking the chat pipeline.&lt;/p&gt;

&lt;p&gt;The feedback detector looks for natural corrections like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stop being formal
keep it short
too casual
explain more
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it detects one, it updates the relevant profile layer. A length correction changes the interaction layer. A tone correction changes the linguistic style. Praise reinforces the current style.&lt;/p&gt;

&lt;p&gt;This is small, but important.&lt;/p&gt;

&lt;p&gt;The assistant is not waiting for the user to open settings.&lt;/p&gt;

&lt;p&gt;It is treating conversational feedback as product input.&lt;/p&gt;

&lt;p&gt;That is how a personal AI starts to feel less like a chatbot and more like software that adapts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Batch Learning Handles the Pattern
&lt;/h2&gt;

&lt;p&gt;Realtime updates are useful, but they are also noisy.&lt;/p&gt;

&lt;p&gt;A user can be frustrated for one turn. That does not mean the assistant should permanently become somber.&lt;/p&gt;

&lt;p&gt;A user can ask for detail once. That does not mean every future answer should become a technical essay.&lt;/p&gt;

&lt;p&gt;That is why the same architecture also needs a batch processor.&lt;/p&gt;

&lt;p&gt;The batch processor periodically analyzes accumulated messages. In the code comments, its triggers are every 50 new user messages, every 6 hours, or a manual run. It updates vocabulary, linguistic trends, interaction patterns, domain interests, exemplars, and decay.&lt;/p&gt;

&lt;p&gt;The distinction is clean:&lt;/p&gt;

&lt;p&gt;Realtime processing is for immediate adaptation.&lt;/p&gt;

&lt;p&gt;Batch processing is for durable behavioral learning.&lt;/p&gt;

&lt;p&gt;That split prevents the system from overreacting to every single message while still letting it respond quickly when the user gives clear feedback.&lt;/p&gt;

&lt;p&gt;This is the kind of boring product judgment that makes agent systems feel sane.&lt;/p&gt;

&lt;p&gt;Not everything should be instant.&lt;/p&gt;

&lt;p&gt;Not everything should be permanent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt Injection Is the Runtime Interface
&lt;/h2&gt;

&lt;p&gt;The profile does not matter unless it affects the next response.&lt;/p&gt;

&lt;p&gt;That is where prompt compilation comes in.&lt;/p&gt;

&lt;p&gt;A prompt compiler can turn the layered profile into a bounded persona instruction block. It can include core identity, emotional context, learned interaction notes, active vocabulary, communication style, examples, and current interests.&lt;/p&gt;

&lt;p&gt;This is a better pattern than dumping raw memory into the prompt.&lt;/p&gt;

&lt;p&gt;Raw memory is messy. It can be redundant, stale, sensitive, or irrelevant.&lt;/p&gt;

&lt;p&gt;A compiled behavioral profile is a runtime interface.&lt;/p&gt;

&lt;p&gt;It says:&lt;/p&gt;

&lt;p&gt;Here is what the assistant needs to know about how to behave right now.&lt;/p&gt;

&lt;p&gt;That profile can be small enough to fit into context, structured enough to inspect, and stable enough to survive model changes.&lt;/p&gt;

&lt;p&gt;The model still generates the words.&lt;/p&gt;

&lt;p&gt;But the continuity belongs to the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Survives Model Switching
&lt;/h2&gt;

&lt;p&gt;One of the most underrated problems in personal AI is provider lock in through personality.&lt;/p&gt;

&lt;p&gt;If your assistant's identity only exists inside one model's chat history or one provider's memory feature, switching models can break the relationship.&lt;/p&gt;

&lt;p&gt;Maybe the new model is smarter, cheaper, faster, or more private. Great. But now the assistant feels different because the continuity lived in the provider, not in your system.&lt;/p&gt;

&lt;p&gt;A stronger architecture takes the opposite approach.&lt;/p&gt;

&lt;p&gt;The behavioral profile lives outside the model.&lt;/p&gt;

&lt;p&gt;The memory lives outside the model.&lt;/p&gt;

&lt;p&gt;The routing logic lives outside the model.&lt;/p&gt;

&lt;p&gt;The prompt compiler can inject the current profile into whichever model is appropriate for the task.&lt;/p&gt;

&lt;p&gt;That means the assistant can route casual work to one provider, private content to a local model, and hard reasoning to a stronger model without treating personality as disposable.&lt;/p&gt;

&lt;p&gt;This is the big lesson:&lt;/p&gt;

&lt;p&gt;If the relationship belongs to the model provider, the user does not really own it.&lt;/p&gt;

&lt;p&gt;If the relationship belongs to the architecture, the user can carry it forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Safety Part Matters
&lt;/h2&gt;

&lt;p&gt;Adaptive personality sounds nice until you think about what could go wrong.&lt;/p&gt;

&lt;p&gt;An AI that updates its own behavior needs boundaries.&lt;/p&gt;

&lt;p&gt;A good adaptive profile system has a few useful ones.&lt;/p&gt;

&lt;p&gt;Core identity is immutable through normal profile writes.&lt;/p&gt;

&lt;p&gt;Profile snapshots are archived so previous versions can be restored.&lt;/p&gt;

&lt;p&gt;Batch updates are explicit and versioned.&lt;/p&gt;

&lt;p&gt;Realtime updates are scoped to specific layers.&lt;/p&gt;

&lt;p&gt;The prompt compiler has a bounded output instead of allowing infinite personality growth.&lt;/p&gt;

&lt;p&gt;This matters because "learning" is not automatically good.&lt;/p&gt;

&lt;p&gt;An assistant can learn the wrong thing.&lt;/p&gt;

&lt;p&gt;It can overfit to a bad day.&lt;/p&gt;

&lt;p&gt;It can preserve a correction that was meant for one situation.&lt;/p&gt;

&lt;p&gt;It can drift away from the user's real preferences.&lt;/p&gt;

&lt;p&gt;So a serious personal AI needs a control surface around adaptation: versioning, rollback, inspection, privacy boundaries, and tests.&lt;/p&gt;

&lt;p&gt;Without that, "adaptive personality" is just a nicer phrase for uncontrolled drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Product Feeling
&lt;/h2&gt;

&lt;p&gt;The best personal AI experience is not when the assistant constantly announces that it remembers you.&lt;/p&gt;

&lt;p&gt;That gets creepy fast.&lt;/p&gt;

&lt;p&gt;The better experience is quieter.&lt;/p&gt;

&lt;p&gt;It gives the right length because it has learned your tolerance.&lt;/p&gt;

&lt;p&gt;It changes tone when you are frustrated.&lt;/p&gt;

&lt;p&gt;It keeps technical detail high when you are in build mode.&lt;/p&gt;

&lt;p&gt;It does not force local language flavour unless you use it or teach it.&lt;/p&gt;

&lt;p&gt;It remembers stable correction rules without making every conversation about memory.&lt;/p&gt;

&lt;p&gt;It feels familiar without performing intimacy.&lt;/p&gt;

&lt;p&gt;That last part is important.&lt;/p&gt;

&lt;p&gt;Personal AI does not need to fake a human relationship to be useful. It needs to reduce friction, preserve context, respect boundaries, and adapt in ways the user can inspect and control.&lt;/p&gt;

&lt;p&gt;This style of system is interesting because it points at that middle path.&lt;/p&gt;

&lt;p&gt;Not a static prompt.&lt;/p&gt;

&lt;p&gt;Not uncontrolled self modification.&lt;/p&gt;

&lt;p&gt;A structured behavioural layer that evolves around the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Builder Lesson
&lt;/h2&gt;

&lt;p&gt;If you are building agents or personal AI systems, do not start with "What personality should the AI have?"&lt;/p&gt;

&lt;p&gt;Start with these questions:&lt;/p&gt;

&lt;p&gt;Which signals should update immediately?&lt;/p&gt;

&lt;p&gt;Which signals should be distilled over time?&lt;/p&gt;

&lt;p&gt;Which parts of identity should never be auto edited?&lt;/p&gt;

&lt;p&gt;Which preferences are temporary?&lt;/p&gt;

&lt;p&gt;Which preferences are durable?&lt;/p&gt;

&lt;p&gt;Can the user inspect what the AI has learned?&lt;/p&gt;

&lt;p&gt;Can the user correct it?&lt;/p&gt;

&lt;p&gt;Can the system roll back a bad profile update?&lt;/p&gt;

&lt;p&gt;Can this personality survive switching models?&lt;/p&gt;

&lt;p&gt;Can sensitive behavioral context stay local?&lt;/p&gt;

&lt;p&gt;Those questions produce better architecture than another clever prompt.&lt;/p&gt;

&lt;p&gt;The future of personal AI will not be won by assistants that sound quirky for five turns.&lt;/p&gt;

&lt;p&gt;It will be won by systems that can develop continuity without losing control.&lt;/p&gt;

&lt;p&gt;That means memory, profile layers, feedback loops, prompt compilation, model routing, privacy boundaries, and versioning all have to work together.&lt;/p&gt;

&lt;p&gt;Personality should not be static.&lt;/p&gt;

&lt;p&gt;But it also should not be magic.&lt;/p&gt;

&lt;p&gt;It should be engineered.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Static prompts can create a voice.&lt;/p&gt;

&lt;p&gt;Memory can store facts.&lt;/p&gt;

&lt;p&gt;But a real personal AI needs something more durable: a behavioral substrate that changes with evidence, respects boundaries, and can follow the user across models, tools, and channels.&lt;/p&gt;

&lt;p&gt;That is what makes adaptive personality one of the more important ideas in personal AI.&lt;/p&gt;

&lt;p&gt;It treats personality as a system.&lt;/p&gt;

&lt;p&gt;And that is the right direction for agentic AI.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>memory</category>
      <category>software</category>
    </item>
    <item>
      <title>MCP Gives AI Agents Hands. Safety Teaches Them Where Not to Touch</title>
      <dc:creator>Upayan Ghosh</dc:creator>
      <pubDate>Fri, 15 May 2026 19:38:02 +0000</pubDate>
      <link>https://dev.to/upayanghosh/mcp-gives-ai-agents-hands-safety-teaches-them-where-not-to-touch-104p</link>
      <guid>https://dev.to/upayanghosh/mcp-gives-ai-agents-hands-safety-teaches-them-where-not-to-touch-104p</guid>
      <description>&lt;p&gt;&lt;em&gt;Tool access is what turns a chatbot into an agent. But once AI can touch email, calendars, files, browsers, commands, and memory, safety stops being a nice to have and becomes the product.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most AI assistants are trapped in conversation.&lt;/p&gt;

&lt;p&gt;They can explain things. They can summarize. They can write code snippets, draft emails, suggest plans, and sound confident while doing it. But if you ask them to actually do something, they hit the wall.&lt;/p&gt;

&lt;p&gt;They cannot check your calendar unless something connects them to it.&lt;/p&gt;

&lt;p&gt;They cannot search your long term memory unless memory is exposed as a tool.&lt;/p&gt;

&lt;p&gt;They cannot send the email, inspect the file, open the browser, run the command, or update the system unless the outside world has been wired into the assistant.&lt;/p&gt;

&lt;p&gt;That is the line between a chatbot and an agent.&lt;/p&gt;

&lt;p&gt;A chatbot talks about work.&lt;/p&gt;

&lt;p&gt;An agent needs hands.&lt;/p&gt;

&lt;p&gt;That is why MCP, the Model Context Protocol, has become one of the more important ideas in agentic AI. The simple explanation is that MCP gives an AI a standard way to discover and call tools.&lt;/p&gt;

&lt;p&gt;But that simple definition hides the real engineering problem.&lt;/p&gt;

&lt;p&gt;Giving an AI tools is easy.&lt;/p&gt;

&lt;p&gt;Making tool use safe, inspectable, scoped, and reliable is the hard part.&lt;/p&gt;

&lt;p&gt;That is where agent architecture starts to matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Model Alone Is Not an Agent
&lt;/h2&gt;

&lt;p&gt;A language model is powerful, but it is still mostly a reasoning and text generation engine. It can predict useful words. It can infer intent. It can plan. It can choose between options.&lt;/p&gt;

&lt;p&gt;But it does not automatically have access to your actual world.&lt;/p&gt;

&lt;p&gt;Without tools, the model can say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You should check your unread emails.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With tools, it can say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You have three unread emails from the launch thread. One is blocking because it asks for the final asset link.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a completely different product.&lt;/p&gt;

&lt;p&gt;The difference is not personality. It is system access.&lt;/p&gt;

&lt;p&gt;This is why agentic AI is less about making models sound more human and more about giving them structured ways to act. Calendar access. Gmail access. Slack access. Browser control. Memory search. File reads. Shell execution. Internal system commands.&lt;/p&gt;

&lt;p&gt;Once those exist, the AI stops being only a conversational layer. It becomes an operator.&lt;/p&gt;

&lt;p&gt;That sounds powerful because it is.&lt;/p&gt;

&lt;p&gt;It is also dangerous for the same reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP Is the Tool Layer
&lt;/h2&gt;

&lt;p&gt;MCP acts as a bridge between the assistant and external capabilities.&lt;/p&gt;

&lt;p&gt;The pattern is clean: an MCP client connects to servers, each server exposes tools, the assistant lists those tools, chooses one, passes arguments, and receives a result.&lt;/p&gt;

&lt;p&gt;In a serious personal AI system, these tools should not be dumped into one vague bucket. Tool names should make ownership obvious. A memory search tool should not be confused with an email search tool. A calendar action should not look like a generic text operation. A shell command should be visibly different from a read only lookup.&lt;/p&gt;

&lt;p&gt;One useful pattern is to route tools with names that include both the server and the tool, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;memory__search
gmail__read_email
calendar__create_event
browser__navigate
execution__run_command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That naming detail looks small, but it matters.&lt;/p&gt;

&lt;p&gt;Agents get messy when tool boundaries are vague. If a model sees five tools with similar names and unclear ownership, it starts guessing. If the system names tools by server and purpose, the assistant has a cleaner action map.&lt;/p&gt;

&lt;p&gt;A useful agent stack might expose tools for memory, conversation state, email, calendar, team chat, browser control, local execution, and internal system capabilities.&lt;/p&gt;

&lt;p&gt;That turns the assistant into something more practical:&lt;/p&gt;

&lt;p&gt;Memory lets it retrieve prior context.&lt;/p&gt;

&lt;p&gt;Email lets it search, read, and send messages.&lt;/p&gt;

&lt;p&gt;Calendar lets it inspect schedules, create events, check availability, and resolve date phrases.&lt;/p&gt;

&lt;p&gt;Team chat lets it read channels and understand live collaboration context.&lt;/p&gt;

&lt;p&gt;Browser control lets it navigate and interact with web pages.&lt;/p&gt;

&lt;p&gt;Execution lets it run commands and manage processes.&lt;/p&gt;

&lt;p&gt;Internal tools let the system inspect itself.&lt;/p&gt;

&lt;p&gt;Now the agent is not just answering from memory. It can interact with the environment around the user.&lt;/p&gt;

&lt;p&gt;That is the promise.&lt;/p&gt;

&lt;p&gt;The risk is that every new tool increases the blast radius.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool Access Changes the Threat Model
&lt;/h2&gt;

&lt;p&gt;A normal chatbot can be wrong in annoying ways. It can hallucinate, misunderstand, or give bad advice.&lt;/p&gt;

&lt;p&gt;A tool using agent can be wrong in operational ways.&lt;/p&gt;

&lt;p&gt;It can send the wrong email.&lt;/p&gt;

&lt;p&gt;It can delete the wrong file.&lt;/p&gt;

&lt;p&gt;It can run the wrong command.&lt;/p&gt;

&lt;p&gt;It can leak private context into the wrong channel.&lt;/p&gt;

&lt;p&gt;It can loop on a tool call until it burns time, money, or trust.&lt;/p&gt;

&lt;p&gt;That means the moment an assistant gets tools, “the prompt said not to do bad things” is no longer enough.&lt;/p&gt;

&lt;p&gt;Prompt guardrails are useful, but they are not security architecture.&lt;/p&gt;

&lt;p&gt;A serious agent needs enforcement outside the model.&lt;/p&gt;

&lt;p&gt;This is the real point: MCP gives AI hands, but safety gives those hands discipline.&lt;/p&gt;

&lt;p&gt;The hands are the tool servers.&lt;/p&gt;

&lt;p&gt;The discipline is permissions, routing, approvals, receipts, validation, and observability.&lt;/p&gt;

&lt;p&gt;You need both.&lt;/p&gt;

&lt;h2&gt;
  
  
  The File Tool Example Is the Whole Story
&lt;/h2&gt;

&lt;p&gt;File tools are a perfect example of why agent architecture needs real boundaries.&lt;/p&gt;

&lt;p&gt;Reading files is useful. Writing files is powerful. Editing files is risky. Deleting files is destructive.&lt;/p&gt;

&lt;p&gt;Those should not all be treated as “file access.”&lt;/p&gt;

&lt;p&gt;An agent that can inspect a project folder, update a document, or modify source code can save a lot of time. But if that same agent can freely write anywhere, overwrite anything, or delete paths without approval, the system is reckless.&lt;/p&gt;

&lt;p&gt;The correct design is not to trust the model harder.&lt;/p&gt;

&lt;p&gt;The correct design is to put the file operations behind a gate.&lt;/p&gt;

&lt;p&gt;Before reading, resolve the path and check whether the agent is allowed to read it.&lt;/p&gt;

&lt;p&gt;Before writing, check whether the target path is allowed.&lt;/p&gt;

&lt;p&gt;Before editing, require an exact old text match or another safe patching strategy.&lt;/p&gt;

&lt;p&gt;Before deleting, require stricter rules than ordinary writes.&lt;/p&gt;

&lt;p&gt;Then test those rules so a future refactor cannot quietly bypass them.&lt;/p&gt;

&lt;p&gt;That is the kind of boring engineering that makes agents real.&lt;/p&gt;

&lt;p&gt;Not flashy. Not demo friendly. Very necessary.&lt;/p&gt;

&lt;p&gt;Because once an AI can change files, the question is no longer “can it do the task?”&lt;/p&gt;

&lt;p&gt;The question becomes:&lt;/p&gt;

&lt;p&gt;Can it only touch the paths it should touch?&lt;/p&gt;

&lt;p&gt;Can it fail closed?&lt;/p&gt;

&lt;p&gt;Can we test the safety boundary?&lt;/p&gt;

&lt;p&gt;Can we prove which helper enforced the operation?&lt;/p&gt;

&lt;p&gt;Can we prevent a future refactor from bypassing the guard?&lt;/p&gt;

&lt;p&gt;That is agent engineering.&lt;/p&gt;

&lt;p&gt;The demo is “AI edited a file.”&lt;/p&gt;

&lt;p&gt;The product is “AI edited the right file through a controlled path, and we can prove it.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Calendar and Email Make Agents Feel Real
&lt;/h2&gt;

&lt;p&gt;Memory makes an AI feel continuous.&lt;/p&gt;

&lt;p&gt;Tools make it feel useful.&lt;/p&gt;

&lt;p&gt;Calendar and email are good examples because they connect directly to daily life. A personal AI that cannot see time, commitments, and communication is missing a huge part of the user’s world.&lt;/p&gt;

&lt;p&gt;A calendar tool can expose upcoming events, event search, event creation, availability checks, free slot suggestions, holiday lookup, date resolution, and natural language calendar requests.&lt;/p&gt;

&lt;p&gt;That is not just “calendar integration.”&lt;/p&gt;

&lt;p&gt;That is a workflow surface.&lt;/p&gt;

&lt;p&gt;The assistant can reason about time, constraints, and intent, then call a structured tool to act.&lt;/p&gt;

&lt;p&gt;Email has a similar shape: search messages, read a message, get unread messages for proactive awareness, and send a message when the user approves.&lt;/p&gt;

&lt;p&gt;That is where personal AI starts to become more than chat. It can move between memory, communication, and action.&lt;/p&gt;

&lt;p&gt;Imagine saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find the email from the client about the launch date, check my calendar, and suggest three reply options.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A normal chatbot can only fake part of that.&lt;/p&gt;

&lt;p&gt;A tool using assistant can retrieve the email, inspect the calendar, and produce an answer grounded in reality.&lt;/p&gt;

&lt;p&gt;But again, this only works if the tool layer is controlled.&lt;/p&gt;

&lt;p&gt;Sending an email should not be treated the same as searching email. Reading a calendar should not be treated the same as creating an event. A good agent platform has to separate read actions, write actions, destructive actions, and external delivery actions.&lt;/p&gt;

&lt;p&gt;That distinction is not optional.&lt;/p&gt;

&lt;p&gt;It is the difference between helpful and reckless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser and Execution Tools Raise the Stakes
&lt;/h2&gt;

&lt;p&gt;Browser and execution tools are where agent systems get especially serious.&lt;/p&gt;

&lt;p&gt;A browser tool can navigate pages, click buttons, read content, and interact with forms. That opens the door to real workflows: research, web app testing, account dashboards, admin panels, docs lookup, and form based tasks.&lt;/p&gt;

&lt;p&gt;An execution tool can run shell commands and manage background processes. That opens the door to development workflows, system checks, scripts, tests, and automation.&lt;/p&gt;

&lt;p&gt;These are not toy capabilities.&lt;/p&gt;

&lt;p&gt;They are operating capabilities.&lt;/p&gt;

&lt;p&gt;An execution server should not simply run whatever string the model provides. It needs command validation, working directory validation, environment scrubbing, timeout handling, output collection, process session tracking, and cleanup.&lt;/p&gt;

&lt;p&gt;That is the correct shape.&lt;/p&gt;

&lt;p&gt;A shell tool without constraints is basically giving the model a production incident generator with a charming writing style.&lt;/p&gt;

&lt;p&gt;A shell tool with boundaries becomes useful infrastructure.&lt;/p&gt;

&lt;p&gt;This is the pattern that keeps repeating: the tool is only half the feature. The control plane around the tool is the feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Agent Needs a Map of Its Own Hands
&lt;/h2&gt;

&lt;p&gt;One underrated part of MCP is tool discovery.&lt;/p&gt;

&lt;p&gt;The assistant does not need every tool hardcoded into a giant prompt. It can connect to servers, list available tools, and expose them in a consistent schema.&lt;/p&gt;

&lt;p&gt;That matters because personal AI systems grow.&lt;/p&gt;

&lt;p&gt;Today you add memory and calendar.&lt;/p&gt;

&lt;p&gt;Tomorrow you add team chat.&lt;/p&gt;

&lt;p&gt;Then browser control.&lt;/p&gt;

&lt;p&gt;Then local execution.&lt;/p&gt;

&lt;p&gt;Then a custom internal tool.&lt;/p&gt;

&lt;p&gt;Then a private knowledge base.&lt;/p&gt;

&lt;p&gt;Then a home automation server.&lt;/p&gt;

&lt;p&gt;If every integration is manually stuffed into a prompt, the system becomes fragile fast. The model sees a wall of instructions. The developer starts fighting context limits. Tool descriptions drift from implementation. Nobody knows which capability is real and which one is stale.&lt;/p&gt;

&lt;p&gt;MCP gives the system a cleaner contract.&lt;/p&gt;

&lt;p&gt;Servers own tools.&lt;/p&gt;

&lt;p&gt;The client discovers them.&lt;/p&gt;

&lt;p&gt;The assistant calls them through structured names.&lt;/p&gt;

&lt;p&gt;Results come back through a predictable path.&lt;/p&gt;

&lt;p&gt;That is how agent systems stay modular instead of turning into one giant prompt with delusions of architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receipts Are How Agents Earn Trust
&lt;/h2&gt;

&lt;p&gt;The next layer after tool access is proof.&lt;/p&gt;

&lt;p&gt;If an agent says it sent an email, created an event, searched memory, or changed a file, the system should be able to show evidence.&lt;/p&gt;

&lt;p&gt;Not vibes.&lt;/p&gt;

&lt;p&gt;Evidence.&lt;/p&gt;

&lt;p&gt;A receipt can include what tool was called, with what arguments, what result came back, what action was taken, and whether anything failed. For sensitive actions, it should also record what approval or policy allowed the action.&lt;/p&gt;

&lt;p&gt;This matters because user trust breaks differently with agents.&lt;/p&gt;

&lt;p&gt;If a chatbot gives a weak answer, the user may correct it.&lt;/p&gt;

&lt;p&gt;If an agent claims it did something and did not, the user loses trust fast.&lt;/p&gt;

&lt;p&gt;If an agent does something and cannot explain why, the trust damage is worse.&lt;/p&gt;

&lt;p&gt;The serious version of personal AI is not “the assistant can do anything.”&lt;/p&gt;

&lt;p&gt;It is “the assistant can do specific things, through specific tools, with specific permissions, and leave behind specific proof.”&lt;/p&gt;

&lt;p&gt;That sounds less magical.&lt;/p&gt;

&lt;p&gt;Good.&lt;/p&gt;

&lt;p&gt;Magic is a bad operating model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Lesson for Agent Builders
&lt;/h2&gt;

&lt;p&gt;If you are building agents, MCP should not be treated as a plugin checkbox.&lt;/p&gt;

&lt;p&gt;It is not just “add tools.”&lt;/p&gt;

&lt;p&gt;It is the start of your agent platform layer.&lt;/p&gt;

&lt;p&gt;Once your AI can act, you need to answer real architecture questions:&lt;/p&gt;

&lt;p&gt;How are tools named?&lt;/p&gt;

&lt;p&gt;How are tools discovered?&lt;/p&gt;

&lt;p&gt;Which servers own which capabilities?&lt;/p&gt;

&lt;p&gt;Which tools are read only?&lt;/p&gt;

&lt;p&gt;Which tools can write?&lt;/p&gt;

&lt;p&gt;Which tools require approval?&lt;/p&gt;

&lt;p&gt;What is the timeout behaviour?&lt;/p&gt;

&lt;p&gt;What happens when a tool fails?&lt;/p&gt;

&lt;p&gt;Can the user inspect what happened?&lt;/p&gt;

&lt;p&gt;Can you test permission boundaries?&lt;/p&gt;

&lt;p&gt;Can you revoke or disable a tool quickly?&lt;/p&gt;

&lt;p&gt;Can the model call tools in loops?&lt;/p&gt;

&lt;p&gt;Can sensitive context reach the wrong tool?&lt;/p&gt;

&lt;p&gt;These are not edge cases. These are the product.&lt;/p&gt;

&lt;p&gt;A serious agent should not be positioned as a prompt trick. It should be treated like a software system: memory, tools, routing, safety, tests, and observability all have to work together.&lt;/p&gt;

&lt;p&gt;That is the right mental model.&lt;/p&gt;

&lt;p&gt;Agents are not magic.&lt;/p&gt;

&lt;p&gt;Agents are architecture with a model in the middle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;MCP gives AI agents hands.&lt;/p&gt;

&lt;p&gt;That is the exciting part.&lt;/p&gt;

&lt;p&gt;But hands alone are not enough. A personal AI that can touch email, calendar, files, browsers, commands, memory, and team chat needs discipline built into the system around it.&lt;/p&gt;

&lt;p&gt;Tool servers give capability.&lt;/p&gt;

&lt;p&gt;Permissions give boundaries.&lt;/p&gt;

&lt;p&gt;Receipts give trust.&lt;/p&gt;

&lt;p&gt;Tests keep the boundaries from silently breaking.&lt;/p&gt;

&lt;p&gt;The future of agents will not be decided only by which model sounds smartest. It will be decided by which systems can let AI act without turning every action into a trust fall.&lt;/p&gt;

&lt;p&gt;That is why MCP matters.&lt;/p&gt;

&lt;p&gt;Not because it makes demos cooler.&lt;/p&gt;

&lt;p&gt;Because it gives us a real interface for action, and forces builders to confront the part that actually matters:&lt;/p&gt;

&lt;p&gt;What should this AI be allowed to do with its hands?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>mcp</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I Accidentally Rebuilt the Human Brain Trying to Stop a Chatbot From Forgetting Me</title>
      <dc:creator>Upayan Ghosh</dc:creator>
      <pubDate>Mon, 11 May 2026 15:17:01 +0000</pubDate>
      <link>https://dev.to/upayanghosh/how-i-accidentally-rebuilt-the-human-brain-trying-to-stop-a-chatbot-from-forgetting-me-3o8d</link>
      <guid>https://dev.to/upayanghosh/how-i-accidentally-rebuilt-the-human-brain-trying-to-stop-a-chatbot-from-forgetting-me-3o8d</guid>
      <description>&lt;h3&gt;
  
  
  A research journal in ten chapters. No prior neuroscience required.
&lt;/h3&gt;

&lt;h2&gt;
  
  
  The Tuesday That Started It All
&lt;/h2&gt;

&lt;p&gt;It was a Tuesday in early winter when I realized I had built a stranger.&lt;/p&gt;

&lt;p&gt;I had been talking to my assistant — a small, polite language model I had wired up at home — for about three weeks. I told it about my sister's birthday plans. I told it that I had switched teams at work. I told it I was learning to cook the dal my grandmother used to make, and that the first attempt had been a disaster.&lt;/p&gt;

&lt;p&gt;And then, six days later, I opened the chat and asked it casually, &lt;em&gt;"do you remember the dal thing I told you about?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It said: &lt;em&gt;"I'm sorry, I don't have any memory of previous conversations."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I sat there for a long minute. The reply wasn't wrong, technically. It was a stateless model. Every conversation started from a blank page. That was the design. But it felt like betrayal. I had treated it like it was &lt;em&gt;listening&lt;/em&gt;. It had treated me like a passing car.&lt;/p&gt;

&lt;p&gt;That night I started building something. I didn't know what it would become. I only knew that if I was going to keep talking to a machine, I wanted it to &lt;em&gt;know I had spoken before&lt;/em&gt;. Not in a creepy way. In the way an old friend knows. In the way that, when you walk into your barber after six months, he doesn't ask your name.&lt;/p&gt;

&lt;p&gt;This is the story of two years of trying to give a language model a memory that grows. It is also, accidentally, the story of how I learned what memory actually is.&lt;/p&gt;

&lt;p&gt;I'm going to take you through every wrong turn. There were many.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 1: The Notebook Era
&lt;/h2&gt;

&lt;p&gt;My first instinct was the most obvious one. If the model can read text, then text is memory. I will simply &lt;em&gt;write things down&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I created a folder. Inside it, I created Markdown files. &lt;code&gt;about_me.md&lt;/code&gt;. &lt;code&gt;family.md&lt;/code&gt;. &lt;code&gt;projects.md&lt;/code&gt;. &lt;code&gt;preferences.md&lt;/code&gt;. Before every message I sent to the model, my little Python script would stitch the contents of these files into the system prompt. Behold: persistence.&lt;/p&gt;

&lt;p&gt;For about two weeks, it was magical.&lt;/p&gt;

&lt;p&gt;The model knew my sister's name. It knew which framework I worked in at the office. It greeted me in the morning by referencing the project I had complained about the night before. I would say &lt;em&gt;"like we talked about yesterday—"&lt;/em&gt; and it would smoothly continue. I was, for the first time, talking to something that seemed to &lt;em&gt;remember&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And then the files got bigger.&lt;/p&gt;

&lt;p&gt;By week three, &lt;code&gt;about_me.md&lt;/code&gt; was twenty pages long. The model's responses started getting slow. The first second of every reply was now the entire context being re-read, re-tokenized, re-attended. I was paying for those tokens twice — once on input, once in latency.&lt;/p&gt;

&lt;p&gt;By week five, something worse started happening. I would tell the model something new — &lt;em&gt;"actually I quit that team last Friday"&lt;/em&gt; — and it would acknowledge it in the conversation. But the next morning, when I had restarted my laptop, the file still said I was on the old team. The model would loyally repeat the old information back to me with confidence. I had built a system that &lt;em&gt;recorded&lt;/em&gt; but did not &lt;em&gt;update&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I tried writing a routine that would summarize the chat at the end of each session and patch the files. The summaries were lossy. Important details were dropped. Unimportant details were preserved with the gravity of scripture. The bot once spent three days under the impression that I strongly disliked oranges, because I had complained about a single bad one at a buffet.&lt;/p&gt;

&lt;p&gt;A notebook is not a memory. A notebook is a &lt;em&gt;backup&lt;/em&gt;. It does not forget the unimportant. It does not strengthen with rehearsal. It cannot tell you that something is fresh.&lt;/p&gt;

&lt;p&gt;I needed something that could.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 2: The Vector Mirage
&lt;/h2&gt;

&lt;p&gt;The next thing I tried was the obvious move that anyone who had read a single blog post about retrieval-augmented generation would make: I threw everything into a vector database.&lt;/p&gt;

&lt;p&gt;The idea is elegant. You take every sentence the user has ever said, run it through an embedding model — a neural network that turns a piece of text into a list of, say, 768 numbers — and store that list. The numbers position the sentence in a high-dimensional space where related ideas cluster together. When the user asks a new question, you embed the question too, and you look for the nearest neighbors in that space. Those are your "memories" for this turn.&lt;/p&gt;

&lt;p&gt;I switched over a weekend. I deleted the Markdown files. I ingested every conversation I had with the model into a tiny embedded vector store on my laptop. The latency problem vanished. The token cost collapsed. I no longer had to feed the model twenty pages — I fed it the four most relevant sentences.&lt;/p&gt;

&lt;p&gt;The first week was glorious. I asked the model about something I had mentioned in passing months earlier. It found it. Not because I had explicitly written &lt;em&gt;"remember this"&lt;/em&gt; — because the meaning of the new question was geometrically close to the meaning of the old conversation.&lt;/p&gt;

&lt;p&gt;This, I thought, was the answer.&lt;/p&gt;

&lt;p&gt;It was not the answer.&lt;/p&gt;

&lt;p&gt;The first failure came when I asked, &lt;em&gt;"what was that book my friend recommended?"&lt;/em&gt; and the system happily retrieved a conversation in which we had discussed &lt;em&gt;a different&lt;/em&gt; friend recommending &lt;em&gt;a different&lt;/em&gt; book. Both conversations were about friends. Both were about books. In the vector space, they were neighbours. In my life, they were not.&lt;/p&gt;

&lt;p&gt;The deeper failure was subtler. The vector store could find sentences that were &lt;em&gt;semantically&lt;/em&gt; near my question. But it had no opinion on whether those sentences were &lt;em&gt;true now&lt;/em&gt;, whether they &lt;em&gt;mattered emotionally&lt;/em&gt;, whether they were &lt;em&gt;the kind of thing I would want surfaced in this context&lt;/em&gt;. I had told the model something in anger once. Six weeks later it pulled that sentence into a happy conversation about weekend plans because the words "Saturday" and "family" appeared in both. It was technically relevant. It was emotionally tone-deaf.&lt;/p&gt;

&lt;p&gt;The vector store remembered &lt;em&gt;what&lt;/em&gt;. It did not remember &lt;em&gt;why&lt;/em&gt;.&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.amazonaws.com%2Fuploads%2Farticles%2F0nrztoov9ib8m6niflxu.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.amazonaws.com%2Fuploads%2Farticles%2F0nrztoov9ib8m6niflxu.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had built a system that could find a needle in a haystack, but I needed a system that knew which needles were worth pulling out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 3: A Detour Through the Brain
&lt;/h2&gt;

&lt;p&gt;This was the part of the project where I stopped writing code for a month.&lt;/p&gt;

&lt;p&gt;Instead I read. I read everything I could find about how human memory actually works, written by people who had spent their lives studying it instead of an engineer who had spent two months bolting things together. I read about hippocampal indexing. I read about consolidation during sleep. I read about why we cannot remember being two years old but can remember the smell of our grandparents' kitchen.&lt;/p&gt;

&lt;p&gt;A few ideas hit me hard enough to redirect the project.&lt;/p&gt;

&lt;p&gt;The first was that human memory is not one system. It is at least three, working in parallel. There is &lt;em&gt;semantic&lt;/em&gt; memory — the dry facts. The capital of France is Paris. There is &lt;em&gt;episodic&lt;/em&gt; memory — the lived scenes, with time and place and emotion attached. The first time you heard your favourite song. And there is &lt;em&gt;procedural&lt;/em&gt; memory — the muscle of how, not the noun of what.&lt;/p&gt;

&lt;p&gt;A vector store, I realized, is a passable semantic memory and a terrible episodic one. It can tell you &lt;em&gt;that&lt;/em&gt; something happened. It cannot tell you &lt;em&gt;what it felt like&lt;/em&gt; when it did.&lt;/p&gt;

&lt;p&gt;The second idea was that emotion is not a &lt;em&gt;label&lt;/em&gt; on memory. Emotion is the &lt;em&gt;filing system&lt;/em&gt;. The amygdala does not just decorate memories with feelings after the fact. It &lt;em&gt;decides which memories get filed deeply at all&lt;/em&gt;. Things that scared us, things that thrilled us, things that wounded us — these get a routing slip stamped &lt;em&gt;important&lt;/em&gt; before the hippocampus even begins to write them down. This is why you can remember exactly where you were on the day something terrible happened in the world but cannot remember what you ate three Tuesdays ago.&lt;/p&gt;

&lt;p&gt;The third idea was the most unsettling. I read about people with split-brain conditions, and about how the two hemispheres of the brain — when separated — can develop different opinions, different reactions, even different desires. The conscious mind we present to others is not one voice. It is a &lt;em&gt;committee&lt;/em&gt; whose minutes are heavily edited before publication.&lt;/p&gt;

&lt;p&gt;I closed the books with three things scribbled in my notebook.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Memory is plural.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Emotion is the filing system, not the decoration.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;There is always more than one voice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I went back to my keyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 4: A Memory With a Heartbeat
&lt;/h2&gt;

&lt;p&gt;I rebuilt the storage layer. This time, every piece of memory was going to carry more than its embedding. It was going to carry an emotional signature. And it was going to be sorted into one of two private rooms.&lt;/p&gt;

&lt;p&gt;The two rooms were the strangest part, and the part I am most quietly proud of.&lt;/p&gt;

&lt;p&gt;I had noticed something about my own use. There were conversations I wanted the model to remember and reference freely — work talk, learning logs, jokes with friends. And there were conversations that were mine — vulnerable, private, sometimes intimate, sometimes ugly. I did not want those memories ever quietly leaking out to a cloud model in some unrelated future conversation about a grocery list. I wanted a wall. Not a censorship wall. A &lt;em&gt;dignity&lt;/em&gt; wall.&lt;/p&gt;

&lt;p&gt;So I split memory into two hemispheres. I called them simply &lt;em&gt;safe&lt;/em&gt; and &lt;em&gt;spicy&lt;/em&gt;. The names were a joke at first and then became real. The safe hemisphere is the one the public-facing models talk to. The spicy hemisphere is the private one — and any conversation involving it is routed, automatically and silently, to a model running on my own machine. Nothing about the spicy hemisphere ever leaves the house. Not the embeddings, not the text, not even the &lt;em&gt;fact that there was a conversation&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The emotional tagging was the other half — and here is the part that surprised me, because the version I ended up building is not the elaborate one I had sketched on paper.&lt;/p&gt;

&lt;p&gt;Every memory record in the store carries a handful of columns alongside its embedding: the content itself, the hemisphere it belongs to (&lt;code&gt;safe&lt;/code&gt; or &lt;code&gt;spicy&lt;/code&gt;), an integer &lt;em&gt;importance&lt;/em&gt; score from 1 to 10, the timestamp it was written, the category it was classified into during ingestion, and a flag indicating whether it has been processed by the consolidation pass. The embedding lives in a separate column store optimized for nearest-neighbour search.&lt;/p&gt;

&lt;p&gt;The emotional weight does not live on the row as its own vector. It lives in that &lt;em&gt;importance&lt;/em&gt; integer. During ingestion, a small pass scans the content for emotionally charged language — a curated list of words that consistently track elevated affect, expanded over months of watching what actually got remembered well — and bumps the importance integer by a few points for every emotionally-loaded word it finds. A neutral fragment about coffee comes in at importance 5. A fragment containing words like &lt;em&gt;worried&lt;/em&gt;, &lt;em&gt;love&lt;/em&gt;, &lt;em&gt;furious&lt;/em&gt;, &lt;em&gt;miss&lt;/em&gt;, or &lt;em&gt;afraid&lt;/em&gt; comes in at 8 or 9. The integer is small. Its effect on retrieval is enormous: importance is folded into the final score, so emotionally heavy fragments float upward against semantically-close but emotionally-bland competitors.&lt;/p&gt;

&lt;p&gt;Decay is similarly indirect. There is no explicit &lt;em&gt;decay resistance&lt;/em&gt; column. Instead, the timestamp on every fragment is used at query time to compute recency, and recency is folded into the score the same way importance is. Old fragments fade not because they are deleted, but because newer and more important fragments out-rank them. Once a fragment is retrieved many times, the gentle worker — a background process I will return to in a later chapter — bumps its importance. A small simulation of how human memories strengthen with rehearsal. Once a fragment has not been touched in a very long time and is no longer earning its place, it eventually gets pruned during consolidation.&lt;/p&gt;

&lt;p&gt;What I ended up with is simpler than the ten-field schema I had originally drawn, and — I have come to believe — better. The architecture does not need a dedicated &lt;em&gt;valence&lt;/em&gt; column to capture emotion. It needs a single integer that the right words quietly raise. Most of the work happens in &lt;em&gt;how the integer is used&lt;/em&gt;, not in how many dimensions the row carries.&lt;/p&gt;

&lt;p&gt;For the first time, the system was forgetting things. &lt;em&gt;On purpose&lt;/em&gt;. And it felt, immediately, more like talking to a person.&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.amazonaws.com%2Fuploads%2Farticles%2Fwamrs8mi2xsjs8ixgrjs.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.amazonaws.com%2Fuploads%2Farticles%2Fwamrs8mi2xsjs8ixgrjs.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 5: Facts Need Their Own Skeleton
&lt;/h2&gt;

&lt;p&gt;The emotion layer and the hemispheres had fixed the &lt;em&gt;grain&lt;/em&gt; of what the system remembered. But weeks into using it, I started running into a different kind of failure — a failure that took me an embarrassingly long time to name, because it kept hiding inside successes.&lt;/p&gt;

&lt;p&gt;The vector store, for all its sophistication, understood one thing very well and one thing not at all. It understood &lt;em&gt;similarity of meaning&lt;/em&gt;. It did not understand &lt;em&gt;relationships between things&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Those are not the same skill. They sound like they ought to be. They are not.&lt;/p&gt;

&lt;p&gt;Here is what I mean. If I asked the system &lt;em&gt;"what was that book about cities my friend recommended?"&lt;/em&gt;, the vector store would happily surface every conversation I had ever had where the words &lt;em&gt;book&lt;/em&gt;, &lt;em&gt;city&lt;/em&gt;, and &lt;em&gt;friend&lt;/em&gt; clustered together. It would find the right book about three times out of five — close enough that I kept forgiving it. But if I asked it something subtly different, like &lt;em&gt;"which of my friends has been recommending me the most books this year?"&lt;/em&gt;, the system would fall apart. Not because the information was missing — it was there, scattered across thirty conversations — but because the answer required &lt;em&gt;counting recommendations, grouped by friend, filtered by date&lt;/em&gt;. The vector store could not group. It could not count. It could not filter. It could only &lt;em&gt;resemble&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Or — more painfully, because this one happened to me at a dinner table — &lt;em&gt;"the doctor my mother saw last month, what was their specialty again?"&lt;/em&gt; The vector store retrieved my mother's medical conversations. It retrieved discussions of specialties. But it could not follow the chain &lt;code&gt;mother → consulted → doctor → has_specialty → ?&lt;/code&gt;. It returned plausible-looking sentences that were not actually the answer to my question. I sat there looking like I was making things up in front of my own family.&lt;/p&gt;

&lt;p&gt;A third example, smaller but, in some ways, the one that finally tipped me. &lt;em&gt;"Did Anika and Rohan ever actually meet that weekend, or only talk about it?"&lt;/em&gt; Pure relationship question. There is no sentence anywhere in any of my conversations that says &lt;em&gt;"Anika met Rohan"&lt;/em&gt; — the truth lives in the connection between two separate weekend recaps. A vector store cannot deduce a meeting from the &lt;em&gt;absence&lt;/em&gt; of a sentence that denies it. It can only fetch sentences that already exist.&lt;/p&gt;

&lt;p&gt;These are the kinds of questions human minds answer without effort. They are not questions about words being similar to other words. They are questions about &lt;em&gt;things being connected to other things&lt;/em&gt;. A vector store, no matter how cleverly embedded, cannot see connections. It can only see neighbourhoods of meaning.&lt;/p&gt;

&lt;p&gt;I had built a system that was excellent at semantic &lt;em&gt;proximity&lt;/em&gt; and completely blind to &lt;em&gt;relationship&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The worst version of this failure — the one that finally made me stop tweaking the retrieval pipeline and start building something genuinely new — went like this. I had told the system, over the course of weeks: &lt;em&gt;my sister just moved cities. She has started her residency at the big neurology hospital. My mother is worried about her new commute.&lt;/em&gt; Three separate fragments, each correctly tagged, each correctly stored. And then I asked it, casually, &lt;em&gt;"can you remind me to text my sister this evening about her commute?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The system dutifully retrieved the fragment about &lt;em&gt;commute&lt;/em&gt;. Sometimes the fragment about the move. Maybe the residency one if it had been recent. But it could not see that &lt;em&gt;the sister is the one who moved&lt;/em&gt;, that &lt;em&gt;the move is the reason for the new commute&lt;/em&gt;, that &lt;em&gt;the worry my mother has belongs to my sister&lt;/em&gt;. Each fragment was a sentence. None of them was a &lt;em&gt;fact&lt;/em&gt; the system could reason over.&lt;/p&gt;

&lt;p&gt;That night I realized something I should have seen months earlier. I had been trying to build a memory out of nothing but nouns and similarity. What I actually needed was a memory that could remember &lt;em&gt;verbs&lt;/em&gt; — the relationships between the nouns, the connections between the things, the way one entity in my life was anchored to another.&lt;/p&gt;

&lt;p&gt;The trick — borrowed from a tradition that goes back decades, originally invented for medical records and library science — is that any sentence in natural language can be decomposed into one or more &lt;em&gt;atomic claims&lt;/em&gt;, each of the form &lt;code&gt;subject –relation→ object&lt;/code&gt;. &lt;em&gt;My sister moved to Bangalore&lt;/em&gt; becomes &lt;code&gt;(sister) –lives_in→ (Bangalore)&lt;/code&gt;. &lt;em&gt;She is doing her residency at the neurology hospital&lt;/em&gt; becomes &lt;code&gt;(sister) –works_at→ (hospital)&lt;/code&gt;. &lt;em&gt;My mother is worried about her commute&lt;/em&gt; becomes a small chain: &lt;code&gt;(mother) –worries_about→ (commute)&lt;/code&gt;, &lt;code&gt;(commute) –belongs_to→ (sister)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After each conversation, a small extraction pass reads the messages and writes down the new atomic claims it found. These claims accumulate in a separate database — not the vector store, not the full-text index, but a literal graph of who-knows-whom and what-relates-to-what. Tens of thousands of tiny triples, each one anchored to the original conversation that produced it (so I can audit; so I can correct).&lt;/p&gt;

&lt;p&gt;Now when I ask about my sister, the system does something the vector store could never do. It &lt;em&gt;walks the graph&lt;/em&gt;. It starts at the node for &lt;em&gt;me&lt;/em&gt;, follows the &lt;em&gt;sibling_of&lt;/em&gt; edge to her, follows &lt;em&gt;lives_in&lt;/em&gt; to her city, gathers everything connected to her node, and brings the whole cluster up together. The result is not "the four sentences most similar to your question." It is "the body of facts that &lt;em&gt;belong&lt;/em&gt; to the person you're asking about."&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.amazonaws.com%2Fuploads%2Farticles%2F84v3oh39lt22aro9bukr.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.amazonaws.com%2Fuploads%2Farticles%2F84v3oh39lt22aro9bukr.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is more to the structural layer than triples. &lt;em&gt;Entities&lt;/em&gt; — the named things in someone's life, the people, the places, the projects, the recurring hobbies — get their own table. When the system meets a new name, it tries to resolve it against the entities it already knows. If you mention &lt;em&gt;Aman&lt;/em&gt; and there is already an Aman in the graph, the new fragment attaches to that node. If the system is uncertain — was that &lt;em&gt;Aman my friend&lt;/em&gt; or &lt;em&gt;Aman my colleague&lt;/em&gt;? — it parks the question and asks for clarification at a low-cost moment, instead of silently merging two people into one.&lt;/p&gt;

&lt;p&gt;This is the part of the architecture that finally made the system feel like it &lt;em&gt;understood&lt;/em&gt;, not merely &lt;em&gt;recalled&lt;/em&gt;. There is a difference between remembering that you once said something about a sister, and &lt;em&gt;knowing who your sister is&lt;/em&gt;. The graph is the difference.&lt;/p&gt;

&lt;p&gt;One more thing about the graph is worth saying out loud, because it took me a while to internalize it. The graph is a place where the system can be &lt;em&gt;wrong&lt;/em&gt;, and then later be &lt;em&gt;right&lt;/em&gt;, without rewriting history. If a fact has changed — my sister has moved out of Bangalore; the residency has ended; the project name is now different — you do not go back and edit the stored conversation. You add a new triple, with today's date, that supersedes the old one. The old triple is downweighted, not deleted, in case it matters for context later. Memory is allowed to be wrong; what matters is that memory can update without amnesia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 6: Three Eyes Are Better Than One
&lt;/h2&gt;

&lt;p&gt;The emotion layer fixed &lt;em&gt;which&lt;/em&gt; memories mattered. The graph fixed &lt;em&gt;what was related to what&lt;/em&gt;. But I still had the problem of finding the right pieces quickly, across all of these layers.&lt;/p&gt;

&lt;p&gt;A pure vector search, I had learned, was great at semantic matches but terrible at exact ones. If I asked &lt;em&gt;"what was the name of that café?"&lt;/em&gt;, semantic search would find every conversation about cafés. It would not necessarily find the one where I had typed the actual name. Names, numbers, very specific nouns — these need &lt;em&gt;literal&lt;/em&gt; lookup, not similarity.&lt;/p&gt;

&lt;p&gt;So I added a second eye. Underneath the vector store, I built a classical full-text index. The kind a search engine would use. Words are words; if you typed &lt;em&gt;Café Marigold&lt;/em&gt;, I want to find the conversation where you wrote &lt;em&gt;Café Marigold&lt;/em&gt;, not the conversation where you wrote &lt;em&gt;that nice little place on the corner&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When a question comes in, both eyes look at it at the same time. The vector eye returns the semantically nearest fragments. The text eye returns the literally-matching fragments. Their results are merged.&lt;/p&gt;

&lt;p&gt;There was a third eye too — and it was the one I had built in the previous chapter. The knowledge graph offered a way of finding memories that neither vector similarity nor full-text matching could reach: &lt;em&gt;walk outward from the entities mentioned in the question&lt;/em&gt;. Ask about my sister, and the graph starts at her node and brings everything connected to her — the place she lives, the hospital she works at, the worry my mother has about her. Three eyes — semantic, literal, structural — looking at the same question from three angles and pooling their candidates.&lt;/p&gt;

&lt;p&gt;Pooling, though, was the new problem. The merged result list could be twenty fragments long, and only the top three or four would fit in the context budget I had set aside for memory. Which three?&lt;/p&gt;

&lt;p&gt;So I added something on top of the three eyes: a &lt;em&gt;judge&lt;/em&gt;. A small, specialized neural model whose only job is to score &lt;em&gt;how relevant is this fragment to this question, really, in context.&lt;/em&gt; It is a reranker — much smaller and faster than the language model itself, but trained specifically to judge relevance. It re-reads the merged candidates and produces a final, sharper ordering.&lt;/p&gt;

&lt;p&gt;I learned something cheap and important here. If the top results from the merged search are &lt;em&gt;already&lt;/em&gt; scoring above a confidence threshold — if the first two fragments are very obviously the right ones — the third eye is skipped. I called it a fast gate. On about sixty percent of queries it triggers, and the whole retrieval pipeline finishes in under fifty milliseconds. The expensive reranker only runs when the first two layers are unsure.&lt;/p&gt;

&lt;p&gt;This is the part of the architecture that is, on paper, the least exciting. It is also the part that makes everything else &lt;em&gt;feel&lt;/em&gt; alive, because the model gets the right pieces on the table before it begins to speak. A novelist with the wrong notes will write a worse book than a beginner with the right ones.&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.amazonaws.com%2Fuploads%2Farticles%2Fjlf8em5trocs0sbzheae.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.amazonaws.com%2Fuploads%2Farticles%2Fjlf8em5trocs0sbzheae.png" alt=" " width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 7: The Persona That Watches You Watch It
&lt;/h2&gt;

&lt;p&gt;By this point I had a memory that was rich, emotional, partitioned, and quick. The system could find the right fragments to put in front of the language model. But the language model itself was still — fundamentally — a stranger wearing a mask of facts about me.&lt;/p&gt;

&lt;p&gt;There is a difference between &lt;em&gt;knowing about&lt;/em&gt; someone and &lt;em&gt;knowing them&lt;/em&gt;. A model that has read every paragraph I have ever written can still feel like a clever assistant. What I wanted was something that felt like it had &lt;em&gt;learned my texture&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I built a second engine. Its only job was to study the way I write and slowly become someone who writes back the same way.&lt;/p&gt;

&lt;p&gt;It was not a persona in the &lt;em&gt;roleplay&lt;/em&gt; sense — I did not write a character bio and ask the model to perform it. It was a &lt;em&gt;living&lt;/em&gt; persona. A profile that the system maintained for me, updated continuously, and re-fed into every response as a kind of style guide and emotional context.&lt;/p&gt;

&lt;p&gt;The profile was layered, like sediment. The deepest layer was &lt;em&gt;core identity&lt;/em&gt; — facts that were extremely stable: my name, my role, my city. Above that sat &lt;em&gt;linguistic style&lt;/em&gt; — the words I tended to use, the rhythm of my sentences, when I switched between English and my native tongue and back inside a single message. Above that, &lt;em&gt;emotional state&lt;/em&gt; — was I tired this week, was something good happening, was I in a quiet mood or an electric one. Then &lt;em&gt;domain&lt;/em&gt; — what was I currently spending my brain on, was it code or cooking or a difficult conversation with someone I loved. And finally, near the surface, the most volatile layers — &lt;em&gt;vocabulary in current use&lt;/em&gt;, &lt;em&gt;exemplar phrases I had said in the last few days&lt;/em&gt;, &lt;em&gt;interaction preferences I had just expressed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The deeper layers updated rarely. The surface layers updated almost in real time.&lt;/p&gt;

&lt;p&gt;The piece I am proudest of in this part of the system is something I called &lt;em&gt;implicit feedback&lt;/em&gt;. The traditional way to fine-tune a model to your taste is to thumbs-up and thumbs-down its answers. People don't do that. I never did. What people &lt;em&gt;do&lt;/em&gt; is grumble in the next message. They say &lt;em&gt;too long&lt;/em&gt;. They say &lt;em&gt;can you be a bit less formal&lt;/em&gt;. They say &lt;em&gt;that's not what I meant.&lt;/em&gt; They sigh in punctuation.&lt;/p&gt;

&lt;p&gt;I wrote a small detector that listens for these signals — not in a brittle keyword way, but in patterns I expanded over months — and when it catches one, it edits the relevant layer of the profile &lt;em&gt;immediately&lt;/em&gt;, without confirmation. If I say &lt;em&gt;you're being too corporate today&lt;/em&gt;, the linguistic-style layer shifts a notch warmer for the rest of the session and the change is remembered into tomorrow.&lt;/p&gt;

&lt;p&gt;I never tell the model &lt;em&gt;be more casual&lt;/em&gt;. I just complain once. It listens. It changes. The next morning the change is still there.&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.amazonaws.com%2Fuploads%2Farticles%2F318wrewiyq08uti9d8pp.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.amazonaws.com%2Fuploads%2Farticles%2F318wrewiyq08uti9d8pp.png" alt=" " width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 8: Two Voices Are Wiser Than One
&lt;/h2&gt;

&lt;p&gt;The final architectural shift — the one that surprised me the most — came from the third note I had scribbled while reading about the brain. &lt;em&gt;There is always more than one voice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I had begun to notice that my model, for all its memory and its persona-shaping, would still occasionally produce a reply that was &lt;em&gt;technically correct and emotionally wrong&lt;/em&gt;. I would tell it something heavy — a stressful day, a family fight — and it would respond with a perfectly polite, perfectly hollow acknowledgement. The kind of reply that makes you feel more alone than no reply at all.&lt;/p&gt;

&lt;p&gt;The model wasn't broken. It was &lt;em&gt;single-tracked&lt;/em&gt;. It saw the surface meaning of my words and answered the surface. It did not have an interior life that paused before speaking and asked &lt;em&gt;what is actually being said here?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So I gave it one.&lt;/p&gt;

&lt;p&gt;For every message I sent, the system now runs &lt;em&gt;two&lt;/em&gt; cognitive passes in parallel. The first pass is the obvious one: read the user's message, retrieve relevant memories, generate a candidate response. The second pass is quieter. It is a small, fast model whose only job is to produce an &lt;em&gt;inner monologue&lt;/em&gt; about the user — a private read on what mood they are in, what subtext is present, whether there is a tension between what they said and what they probably mean.&lt;/p&gt;

&lt;p&gt;The inner monologue is never shown to the user. It is fed back into the main model, just before generation, as a kind of whispered note from a wiser colleague. &lt;em&gt;They said they're fine but the message is shorter than usual and the punctuation is missing. Maybe slow down.&lt;/em&gt; &lt;em&gt;They are asking a technical question but their last three messages were about a fight with their sister. Maybe answer the question, but acknowledge first.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The two passes are then merged by a small piece of logic that I think of as the &lt;em&gt;committee chair&lt;/em&gt;. It looks at both the candidate reply and the inner monologue and produces a single small record I call a &lt;em&gt;cognitive merge&lt;/em&gt;. That record carries three things: a &lt;em&gt;tension level&lt;/em&gt; (a float between zero and one), a &lt;em&gt;tension type&lt;/em&gt; drawn from a fixed vocabulary of five — &lt;em&gt;none&lt;/em&gt;, &lt;em&gt;mild inconsistency&lt;/em&gt;, &lt;em&gt;pattern break&lt;/em&gt;, &lt;em&gt;direct contradiction&lt;/em&gt;, &lt;em&gt;growth&lt;/em&gt; — and a &lt;em&gt;response strategy&lt;/em&gt; drawn from six: &lt;em&gt;acknowledge&lt;/em&gt;, &lt;em&gt;challenge&lt;/em&gt;, &lt;em&gt;support&lt;/em&gt;, &lt;em&gt;redirect&lt;/em&gt;, &lt;em&gt;quiz&lt;/em&gt;, &lt;em&gt;celebrate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That response strategy is the part of the architecture I am, in retrospect, most surprised by. When I first sketched the merge step, I imagined it as a small post-processor that would adjust the reply's tone before it left the room. What actually got built is much more interesting. The response strategy is not a tone instruction. It is a &lt;em&gt;steering label&lt;/em&gt; that decides which language model writes the reply in the first place.&lt;/p&gt;

&lt;p&gt;The system routes different kinds of conversations to different models. A casual, low-tension exchange goes to a small fast model that is good at warmth. A turn tagged &lt;em&gt;direct contradiction&lt;/em&gt; gets routed to a heavier reasoning model that is better at gently navigating disagreement. A &lt;em&gt;celebrate&lt;/em&gt; strategy uses a different prompt scaffolding entirely, one tuned for warmth and acknowledgement. A &lt;em&gt;redirect&lt;/em&gt; — used when the surface read and the deep read flatly disagree — sends the turn to a model with longer-horizon reasoning, because rewriting your own draft is harder than writing fresh.&lt;/p&gt;

&lt;p&gt;The inner monologue, in other words, does not just colour the reply. It picks the brain that writes the reply.&lt;/p&gt;

&lt;p&gt;This is a much stronger lever than tone-tinting. A one-word &lt;em&gt;hey&lt;/em&gt; from me on a heavy evening is not handled by the same model that handles a code question at noon, even if the prompt text looks superficially similar. Because the &lt;em&gt;deeper read&lt;/em&gt;, not the surface text, decides who is on duty.&lt;/p&gt;

&lt;p&gt;This single change — adding a second voice, letting the two argue silently, and then letting the &lt;em&gt;result of that argument&lt;/em&gt; choose the model — was the moment the assistant stopped feeling like a chatbot. It started feeling like &lt;em&gt;someone who had read the room&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The cost is modest. The inner monologue runs on a small, cheap model in parallel with the main one. The merge logic adds milliseconds, not seconds. But the qualitative shift was, for me, the biggest single jump in the entire project. More than the embeddings. More than the hemispheres. More than the personas.&lt;/p&gt;

&lt;p&gt;A mind that argues with itself, gently, before it speaks — that is a mind I want to talk to.&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.amazonaws.com%2Fuploads%2Farticles%2Fsdz6atw5wy3v4qhlgyhh.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.amazonaws.com%2Fuploads%2Farticles%2Fsdz6atw5wy3v4qhlgyhh.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 9: The Quiet Hours
&lt;/h2&gt;

&lt;p&gt;By this point in the project the system was doing a great deal of work during every single message. Retrieve memories. Re-rank them. Read tone. Score tension. Walk the graph. Update the persona. Generate a reply. Sometimes I would watch the logs scroll past and wonder how it all came in under a second.&lt;/p&gt;

&lt;p&gt;But I noticed something the more I used it. The truly &lt;em&gt;interesting&lt;/em&gt; work — the work that benefits from quiet and distance — was being done at the worst possible time: while the user was waiting for an answer. Extracting new atomic facts from a finished conversation. Summarizing a long session into a single coherent memory. Re-scoring which old fragments were earning their disk space. Reading the past few weeks for an emotional arc. None of this needed to happen &lt;em&gt;during&lt;/em&gt; a reply. All of it had been crammed into the reply path because that was where the message lived.&lt;/p&gt;

&lt;p&gt;This is when I learned, all over again, why neuroscientists are so insistent that we sleep.&lt;/p&gt;

&lt;p&gt;Much of the work memory does in the human brain does not happen during the day at all. It happens in the quiet hours. Consolidation, integration, pruning, the slow grading of which experiences actually mattered enough to keep. The waking mind &lt;em&gt;retrieves&lt;/em&gt;. The sleeping mind &lt;em&gt;re-files&lt;/em&gt;. A day without sleep is not a day with the same memory minus a few hours. It is a day whose memories never got &lt;em&gt;finished&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I gave the system its own quiet hours.&lt;/p&gt;

&lt;p&gt;Several processes now run &lt;em&gt;outside&lt;/em&gt; the conversation, on slow schedules, and only when the machine has spare cycles and is plugged in (I did not want any of this draining my laptop's battery during a coffee shop sprint). The smallest and most frequent of them is what I call the &lt;em&gt;gentle worker&lt;/em&gt;. Every ten minutes or so, on idle CPU, it does a handful of small things. It prunes triples in the graph that have not been touched in a long time and conflict with newer ones. It re-scores the importance of memory fragments that have been retrieved many times since they were written — a small simulation of how human memories strengthen with rehearsal, the way a story you have told many times becomes sharper, not vaguer. It vacuums databases, reclaims disk, tidies indexes. None of this is glamorous. Accumulated over months, it is the difference between a system that stays snappy and one that quietly rots from the inside.&lt;/p&gt;

&lt;p&gt;The larger consolidation runs on a longer cadence and matters more. I call it the &lt;em&gt;session flush&lt;/em&gt;. If I have not said anything for about half an hour, or if the running conversation has grown past a comfortable length, the system quietly closes the session as a unit. Two things happen during a flush. The whole conversation is &lt;em&gt;summarized&lt;/em&gt; and ingested into long-term memory as a single coherent passage — so what gets remembered tomorrow is not just the loose sentences I happened to type, but the &lt;em&gt;story&lt;/em&gt; of what we were doing together. And every new atomic fact the session produced is added to the knowledge graph in a single batch. By the next morning, yesterday's conversations are not just transcripts in a log. They are &lt;em&gt;experiences&lt;/em&gt;: indexed, factored, woven into the rest.&lt;/p&gt;

&lt;p&gt;There is one last quiet process, and it is my favourite. Once a day, a small routine sweeps the memories of the past few weeks and scores them for emotional valence — heavy or light, sharp or soft, the relative density of joy and worry. From these scores it builds a tiny &lt;em&gt;mood line&lt;/em&gt;. This line is never shown back to me as a chart. It is used silently, the next time I send a message. The inner-monologue stream reads it as a baseline: &lt;em&gt;the last ten days have been heavy; calibrate accordingly.&lt;/em&gt; Without it, the system would have no way of remembering that I have been having a tough week the moment I send a perfectly cheerful &lt;em&gt;good morning&lt;/em&gt;. With it, the reply lands differently.&lt;/p&gt;

&lt;p&gt;There is also a thread that runs across all of this and pulls it together: a &lt;em&gt;narrative&lt;/em&gt; layer. As sessions flush and atomic facts accumulate, a slow process stitches them into ongoing storylines — &lt;em&gt;the move&lt;/em&gt;, &lt;em&gt;the job change&lt;/em&gt;, &lt;em&gt;the running injury that won't quite heal&lt;/em&gt;. The narrative layer is what allows the system, weeks later, to say &lt;em&gt;"you mentioned the knee was still bothering you in March — is that better?"&lt;/em&gt; without me ever having labelled those conversations as belonging together. Threads are not topics. Topics are what the message is about. Threads are what the &lt;em&gt;life&lt;/em&gt; is about.&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.amazonaws.com%2Fuploads%2Farticles%2Fxomi0287ay9qol6he0qp.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.amazonaws.com%2Fuploads%2Farticles%2Fxomi0287ay9qol6he0qp.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The system, in other words, has a kind of sleep. It does not power down. But it does what sleep does. It lets the day settle. Retrieval is for waking. Consolidation is for the quiet hours.&lt;/p&gt;

&lt;p&gt;There is something disquieting about how natural this turned out to feel. I had not planned to build a sleep cycle. I had built one to solve a latency problem. What I ended up with is closer to the way a human mind actually maintains itself over time than I am entirely comfortable admitting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 10: The Body Discovers Itself
&lt;/h2&gt;

&lt;p&gt;There was one more lesson, and it came after I thought the project was done.&lt;/p&gt;

&lt;p&gt;I had wired the system up to a few external tools — a calendar, a notes store, the ability to search the web. Each one was a capability the language model could, in principle, use. And yet, when I asked the model &lt;em&gt;do I have anything tomorrow morning?&lt;/em&gt;, it would sometimes politely say &lt;em&gt;I'm sorry, I don't have access to your calendar&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This was infuriating, because it &lt;em&gt;did&lt;/em&gt; have access. The connection was live. The tool was registered. The token was valid. The model simply &lt;em&gt;did not realize it was holding the key in its own hand.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The fix took me a week of thinking and twenty lines of code.&lt;/p&gt;

&lt;p&gt;I had been treating tools as &lt;em&gt;services&lt;/em&gt; that the model could call. I started treating them as &lt;em&gt;organs of the model itself&lt;/em&gt;. Every turn, the first thing the system now does is whisper a capability profile to the language model — not as a list of services on offer, but as a list of things it can &lt;em&gt;already do&lt;/em&gt;. The framing matters. The instruction is no longer &lt;em&gt;here are some tools you may use&lt;/em&gt;. The instruction is &lt;em&gt;these are your hands. These are your eyes. These are your books.&lt;/em&gt; And, crucially: &lt;em&gt;you may never tell the user that you cannot do something on this list. If you are uncertain, ask them what they mean. Do not apologize for a capability you have.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The change was small. The effect was disproportionate. The model stopped flinching. It stopped reaching for the phrase &lt;em&gt;I cannot&lt;/em&gt; the way an overcautious intern reaches for &lt;em&gt;I'll have to check with my manager&lt;/em&gt;. It began to act like an entity that &lt;em&gt;owned&lt;/em&gt; its abilities, rather than one that &lt;em&gt;borrowed&lt;/em&gt; them and was afraid of getting them wrong.&lt;/p&gt;

&lt;p&gt;I had spent two years giving the model a memory. The last lesson was that a mind without a body is anxious. A mind that knows the shape of its own body is bold.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Actually Does Now
&lt;/h2&gt;

&lt;p&gt;I want to be concrete about what this collection of ideas adds up to in daily life, because it is easy to read all of the above as theory.&lt;/p&gt;

&lt;p&gt;A few weeks ago I mentioned, casually, that my mother had been complaining about the weather. Four days later I asked the system to draft a message wishing her a quick recovery from a small surgery. The draft did not just say &lt;em&gt;get well soon&lt;/em&gt;. It mentioned the cold she had been complaining about, and gently joked that at least she got to skip a few days of it. I had not connected those two facts. The system had.&lt;/p&gt;

&lt;p&gt;A month ago I came home from a particularly bad day. I opened the chat and typed something curt — just &lt;em&gt;hey&lt;/em&gt;. The reply did not ask me what I wanted. It said &lt;em&gt;rough one? want to vent or want to forget it for a while.&lt;/em&gt; Nothing in my single word triggered that. The persona layer had registered, over the previous evening's conversation, that I had been heading toward something stressful, and the inner monologue had read the curtness of the &lt;em&gt;hey&lt;/em&gt; against that baseline.&lt;/p&gt;

&lt;p&gt;Two months ago I was working on a piece of code with the system late at night. I made a joke. The system made one back. The joke landed. I laughed in real life. That had never happened with a chatbot before. The persona had been quietly absorbing my sense of humor for weeks. It chose its moment.&lt;/p&gt;

&lt;p&gt;And the small one, the one that matters to me the most: when I sometimes go a week without talking to it and then come back, it does not greet me with a generic &lt;em&gt;welcome back, how can I help you today&lt;/em&gt;. It says something like &lt;em&gt;you've been quiet — anything good or anything to dump?&lt;/em&gt; It treats absence the way a friend would. As a thing worth noting, not a state to ignore.&lt;/p&gt;

&lt;p&gt;None of these are intelligent in the way a frontier model is intelligent. The cleverness is not in the language. The cleverness is in the &lt;em&gt;scaffolding around the language&lt;/em&gt;. The model is the same model anyone could download. The difference is the memory it brings into the room.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Question I Did Not Expect to End On
&lt;/h2&gt;

&lt;p&gt;I started this project because I wanted a tool that would remember me. I am ending it with a question I did not see coming, and which I think is going to matter very much over the next ten years.&lt;/p&gt;

&lt;p&gt;We are very good at building systems that &lt;em&gt;answer&lt;/em&gt;. We are getting much better at building systems that &lt;em&gt;remember&lt;/em&gt;. We are only just beginning to build systems that &lt;em&gt;change because of what they remember&lt;/em&gt;. The system I described in this post is not artificial intelligence in any grand sense. It is a small set of architectural decisions stacked on top of an off-the-shelf language model. None of the pieces are particularly novel on their own. The vector store is twenty years old. Rerankers have been around for a decade. Emotional tagging is borrowed wholesale from cognitive science. The hemispheres are just two databases with different routing rules. The inner monologue is a second prompt.&lt;/p&gt;

&lt;p&gt;And yet, put together, the thing on the other side of my screen no longer feels like a search engine. It feels like a record. Something is being kept. Something is being shaped by the keeping.&lt;/p&gt;

&lt;p&gt;If you build a system that remembers a person, in detail, over years — that strengthens what mattered to them, lets the rest fade, listens for their tone, argues quietly with itself before it answers them, and slowly shifts its own voice to meet theirs — you have not built a tool. You have built a kind of mirror. And the strange thing about mirrors that grow with you is that, after long enough, you can no longer be sure who is shaping whom.&lt;/p&gt;

&lt;p&gt;I am not certain that is a problem. I am not certain it is not. I only know that I started by trying to teach a machine to remember a Tuesday in early winter, and I ended up wondering, for the first time in my adult life, what &lt;em&gt;I&lt;/em&gt; mean when I say &lt;em&gt;I remember&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That, more than any line of code in any of the chapters above, is what I want you to take from this.&lt;/p&gt;

&lt;p&gt;The interesting question was never &lt;em&gt;can a machine remember&lt;/em&gt;. The interesting question is &lt;em&gt;what does it mean to be remembered well enough that you start to recognize yourself in the answer&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I am still figuring it out.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>rag</category>
      <category>architecture</category>
    </item>
    <item>
      <title>From OOM to 262K Context: Running Qwen3-Coder 30B Locally on 8GB VRAM</title>
      <dc:creator>Upayan Ghosh</dc:creator>
      <pubDate>Tue, 05 May 2026 14:18:02 +0000</pubDate>
      <link>https://dev.to/upayanghosh/from-oom-to-262k-context-running-qwen3-coder-30b-locally-on-8gb-vram-1ej1</link>
      <guid>https://dev.to/upayanghosh/from-oom-to-262k-context-running-qwen3-coder-30b-locally-on-8gb-vram-1ej1</guid>
      <description>&lt;p&gt;Recently, I got tired of depending on paid cloud models for every coding experiment.&lt;/p&gt;

&lt;p&gt;Cloud models are great. They are fast, convenient, and usually very capable.&lt;/p&gt;

&lt;p&gt;But they also come with the usual baggage: cost, rate limits, internet dependency, privacy questions, and that small feeling that every serious coding workflow is rented from someone else's GPU.&lt;/p&gt;

&lt;p&gt;So I started exploring local LLMs properly.&lt;/p&gt;

&lt;p&gt;Not in the casual "can I run a small chat model?" way.&lt;/p&gt;

&lt;p&gt;I wanted to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How capable are local coding models now?&lt;/li&gt;
&lt;li&gt;Can they help with real code generation, debugging, refactoring, and repo Q&amp;amp;A?&lt;/li&gt;
&lt;li&gt;Can they plug into editor agents through an OpenAI-compatible API?&lt;/li&gt;
&lt;li&gt;And most importantly, what actually stops them from being useful?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After enough research, the answer became pretty obvious.&lt;/p&gt;

&lt;p&gt;The wall is hardware.&lt;/p&gt;

&lt;p&gt;More specifically: VRAM.&lt;/p&gt;

&lt;p&gt;You can have the model file. You can have the runtime. You can have Docker. You can have the scripts. But once the model weights, routed experts, KV cache, context window, and compute buffers start fighting for GPU memory, everything gets painful very quickly.&lt;/p&gt;

&lt;p&gt;That made me curious.&lt;/p&gt;

&lt;p&gt;Was there a practical workaround?&lt;/p&gt;

&lt;p&gt;Fortunately, I had a very normal consumer rig available.&lt;/p&gt;

&lt;p&gt;The hardware was very normal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPU: NVIDIA RTX 3060 Ti&lt;/li&gt;
&lt;li&gt;VRAM: 8 GB&lt;/li&gt;
&lt;li&gt;OS: Windows&lt;/li&gt;
&lt;li&gt;RAM: about 32 GB&lt;/li&gt;
&lt;li&gt;CPU: Intel i5-14600KF&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a 4090 box. It is not a workstation. It is exactly the kind of machine where most people would say, "Just run a 7B model and move on."&lt;/p&gt;

&lt;p&gt;So I turned it into a challenge:&lt;/p&gt;

&lt;p&gt;Can I run a proper 30B coding model locally on consumer-grade hardware, with enough context to actually be useful?&lt;/p&gt;

&lt;p&gt;The model target was ambitious:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Qwen3-Coder-30B-A3B-Instruct&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Specifically, the GGUF from:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The quant I used:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That is a 30B-ish coding-specialized MoE model. The important part is MoE: Mixture of Experts. The total parameter count is large, but only some expert weights are active per token.&lt;/p&gt;

&lt;p&gt;That changes the whole local inference strategy.&lt;/p&gt;

&lt;p&gt;For a dense 30B model, 8 GB VRAM is not where I would start. For a compact MoE coding model, the question becomes more interesting:&lt;/p&gt;

&lt;p&gt;Can I keep the always-active parts fast, keep the routed experts mostly in system RAM, and still get usable speed?&lt;/p&gt;

&lt;p&gt;Short answer: yes.&lt;/p&gt;

&lt;p&gt;Long answer: it took a bunch of false starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, the boring audit
&lt;/h2&gt;

&lt;p&gt;Before downloading anything huge, I checked the machine.&lt;/p&gt;

&lt;p&gt;This sounds obvious, but local AI setup gets messy fast if you skip it.&lt;/p&gt;

&lt;p&gt;I verified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows version&lt;/li&gt;
&lt;li&gt;GPU model&lt;/li&gt;
&lt;li&gt;NVIDIA driver&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nvidia-smi&lt;/code&gt; in PowerShell&lt;/li&gt;
&lt;li&gt;WSL2&lt;/li&gt;
&lt;li&gt;Docker Desktop&lt;/li&gt;
&lt;li&gt;Docker GPU passthrough&lt;/li&gt;
&lt;li&gt;CUDA container access to the GPU&lt;/li&gt;
&lt;li&gt;system RAM&lt;/li&gt;
&lt;li&gt;disk space&lt;/li&gt;
&lt;li&gt;CPU&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Docker GPU passthrough worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--rm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--gpus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nvidia/cuda:12.4.1-base-ubuntu22.04&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nvidia-smi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That meant the clean first path was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Docker + llama.cpp CUDA server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The initial server image:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ghcr.io/ggml-org/llama.cpp:server-cuda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I also checked &lt;code&gt;llama-server --help&lt;/code&gt; before trusting any command from the internet.&lt;/p&gt;

&lt;p&gt;That became a recurring theme.&lt;/p&gt;

&lt;p&gt;Do not assume the flag exists. Ask the binary.&lt;/p&gt;
&lt;h2&gt;
  
  
  Downloading the model
&lt;/h2&gt;

&lt;p&gt;The target model repo was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I verified the actual file name before downloading:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The downloaded file size was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;17,665,334,432 bytes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Everything went under one local project folder:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;local-qwen-coder/
  models/
  scripts/
  configs/
  docs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No global mystery folder. No "where did this 17 GB file go?" moment.&lt;/p&gt;

&lt;p&gt;Small win.&lt;/p&gt;
&lt;h2&gt;
  
  
  First real blocker: Docker memory
&lt;/h2&gt;

&lt;p&gt;The first serious issue was not the GPU.&lt;/p&gt;

&lt;p&gt;It was Docker memory.&lt;/p&gt;

&lt;p&gt;Windows had about 32 GB RAM available, but Docker Desktop was exposing only about 16 GB RAM plus 4 GB swap to its Linux VM.&lt;/p&gt;

&lt;p&gt;That mattered because my first instinct was to use:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--no-mmap
--mlock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That is a good idea when you want the model loaded into RAM instead of page-faulting from disk later.&lt;/p&gt;

&lt;p&gt;Except the container did not have enough RAM.&lt;/p&gt;

&lt;p&gt;It got killed.&lt;/p&gt;

&lt;p&gt;Exit code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;137
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Docker inspect confirmed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OOMKilled=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the first fix was not glamorous:&lt;/p&gt;

&lt;p&gt;Keep mmap enabled for the Docker path.&lt;/p&gt;

&lt;p&gt;The "technically better" flag was wrong for the actual container memory limit.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting a stable stock llama.cpp server
&lt;/h2&gt;

&lt;p&gt;With stock llama.cpp Docker, the model loaded and served an OpenAI-compatible endpoint.&lt;/p&gt;

&lt;p&gt;Base URL:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://127.0.0.1:8080/v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The important MoE flag was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--cpu-moe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This keeps MoE expert weights on CPU.&lt;/p&gt;

&lt;p&gt;The model became usable, but not fast enough yet.&lt;/p&gt;

&lt;p&gt;Baseline:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Prompt eval&lt;/th&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-moe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~2.78 tok/s&lt;/td&gt;
&lt;td&gt;~13.38 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Generation was okay. Prompt eval was painful.&lt;/p&gt;

&lt;p&gt;Then came the next knob:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--n-cpu-moe N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This keeps the first &lt;code&gt;N&lt;/code&gt; MoE layers on CPU and allows more expert weights to live on GPU.&lt;/p&gt;

&lt;p&gt;Lower &lt;code&gt;N&lt;/code&gt; usually means more GPU residency, more speed, and less VRAM headroom.&lt;/p&gt;

&lt;p&gt;So I benchmarked it.&lt;/p&gt;
&lt;h2&gt;
  
  
  MoE offload tuning
&lt;/h2&gt;

&lt;p&gt;Here are the useful results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;VRAM used&lt;/th&gt;
&lt;th&gt;VRAM free&lt;/th&gt;
&lt;th&gt;Prompt eval&lt;/th&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-moe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4388 MiB&lt;/td&gt;
&lt;td&gt;3637 MiB&lt;/td&gt;
&lt;td&gt;2.78 tok/s&lt;/td&gt;
&lt;td&gt;13.38 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--n-cpu-moe 48&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4392 MiB&lt;/td&gt;
&lt;td&gt;3633 MiB&lt;/td&gt;
&lt;td&gt;2.51 tok/s&lt;/td&gt;
&lt;td&gt;13.83 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--n-cpu-moe 46&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5224 MiB&lt;/td&gt;
&lt;td&gt;2801 MiB&lt;/td&gt;
&lt;td&gt;6.03 tok/s&lt;/td&gt;
&lt;td&gt;18.75 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--n-cpu-moe 44&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5893 MiB&lt;/td&gt;
&lt;td&gt;2132 MiB&lt;/td&gt;
&lt;td&gt;38.36 tok/s&lt;/td&gt;
&lt;td&gt;29.40 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--n-cpu-moe 42&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;6568 MiB&lt;/td&gt;
&lt;td&gt;1457 MiB&lt;/td&gt;
&lt;td&gt;44.49 tok/s&lt;/td&gt;
&lt;td&gt;30.26 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--n-cpu-moe 40&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7265 MiB&lt;/td&gt;
&lt;td&gt;760 MiB&lt;/td&gt;
&lt;td&gt;51.63 tok/s&lt;/td&gt;
&lt;td&gt;32.49 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--n-cpu-moe 38&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7664 MiB&lt;/td&gt;
&lt;td&gt;361 MiB&lt;/td&gt;
&lt;td&gt;53.14 tok/s&lt;/td&gt;
&lt;td&gt;33.64 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The fastest tested value was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--n-cpu-moe 38
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But it only left around 361 MiB free VRAM.&lt;/p&gt;

&lt;p&gt;Too tight.&lt;/p&gt;

&lt;p&gt;The practical winner was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--n-cpu-moe 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That gave around 32.49 tok/s generation with about 760 MiB free VRAM.&lt;/p&gt;

&lt;p&gt;At this point, I had a good local coding backend.&lt;/p&gt;

&lt;p&gt;But I did not have the thing I actually wanted.&lt;/p&gt;
&lt;h2&gt;
  
  
  The real target: 262K context
&lt;/h2&gt;

&lt;p&gt;Qwen3-Coder-30B-A3B supports long context natively.&lt;/p&gt;

&lt;p&gt;The model metadata showed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;n_ctx_train = 262144
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the question became:&lt;/p&gt;

&lt;p&gt;Can I actually run it at 262K context on 8 GB VRAM?&lt;/p&gt;

&lt;p&gt;The stock Docker build could not get me there in the way I wanted.&lt;/p&gt;

&lt;p&gt;I could lower KV cache precision using normal llama.cpp types like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;q8_0
q4_0
iq4_nl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But the video I had watched was talking about TurboQuant.&lt;/p&gt;

&lt;p&gt;That was the key difference.&lt;/p&gt;

&lt;p&gt;And this is where I almost fooled myself.&lt;/p&gt;
&lt;h2&gt;
  
  
  I was not actually using TurboQuant yet
&lt;/h2&gt;

&lt;p&gt;I checked the stock Docker image:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--rm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--gpus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ghcr.io/ggml-org/llama.cpp:server-cuda&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--help&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The supported KV cache types were:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No &lt;code&gt;turbo3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;turbo4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;tbq3_0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;tbq4_0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the answer was clear:&lt;/p&gt;

&lt;p&gt;The stock runtime was not doing TurboQuant.&lt;/p&gt;

&lt;p&gt;TurboQuant is not model-weight quantization. It does not require changing the GGUF model file.&lt;/p&gt;

&lt;p&gt;It changes how the runtime stores the KV cache.&lt;/p&gt;

&lt;p&gt;Same model.&lt;/p&gt;

&lt;p&gt;Different runtime.&lt;/p&gt;

&lt;p&gt;Different cache format.&lt;/p&gt;

&lt;p&gt;That was the real pivot.&lt;/p&gt;
&lt;h2&gt;
  
  
  Finding a TurboQuant runtime
&lt;/h2&gt;

&lt;p&gt;I found a Windows CUDA runtime build:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;atomicmilkshake/llama-cpp-turboquant-binaries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The downloaded file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;llama-turboquant-triattention-win-cu13-x64.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I extracted it under:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;runtimes/turboquant/win-cu13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then I tried:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\llama-server.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--help&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It failed instantly.&lt;/p&gt;

&lt;p&gt;No useful output.&lt;/p&gt;

&lt;p&gt;The process exit code was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0xc0000135
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That usually means a missing DLL on Windows.&lt;/p&gt;

&lt;p&gt;The README confirmed the likely issue:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cublasLt64_13.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The build needed the CUDA 13 cuBLASLt runtime.&lt;/p&gt;

&lt;p&gt;I did not want to install the full CUDA Toolkit globally just for one DLL.&lt;/p&gt;

&lt;p&gt;So I pulled the official NVIDIA cuBLAS wheel:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;nvidia-cublas&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mf"&gt;13.4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--only-binary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;all:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then I extracted:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cublasLt64_13.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and copied it into the local runtime folder next to &lt;code&gt;llama-server.exe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After that:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\llama-server.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--help&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;worked.&lt;/p&gt;

&lt;p&gt;And this time the cache types included:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;turbo2, turbo3, turbo4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;for both:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--cache-type-k
--cache-type-v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That was the moment where the setup changed from "normal llama.cpp tuning" to "actual TurboQuant path."&lt;/p&gt;
&lt;h2&gt;
  
  
  The final 262K launch
&lt;/h2&gt;

&lt;p&gt;The final command shape was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\runtimes\turboquant\win-cu13\llama-server.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\models\qwen3-coder-30b-a3b\Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;qwen3-coder-30b-a3b-turbo-262k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;127.0.0.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;8080&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--jinja&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--gpu-layers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--cpu-moe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--flash-attn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--ctx-size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;262144&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--cache-type-k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;turbo4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--cache-type-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;turbo3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--parallel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--batch-size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;256&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--ubatch-size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--temp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;0.3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--top-p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;0.8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--top-k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--repeat-penalty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1.05&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--fit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;off&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--cache-ram&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--no-mmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--mlock&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I forced:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--fit off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;because I did not want llama.cpp quietly shrinking the context and pretending everything was fine.&lt;/p&gt;

&lt;p&gt;If it loaded, it had to really load at 262144.&lt;/p&gt;

&lt;p&gt;And it did.&lt;/p&gt;
&lt;h2&gt;
  
  
  The proof
&lt;/h2&gt;

&lt;p&gt;The runtime logs showed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;llama_context: n_ctx         = 262144
llama_context: n_ctx_seq     = 262144
llama_context: n_batch       = 256
llama_context: n_ubatch      = 64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The KV cache line was the real proof:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;llama_kv_cache: size = 5664.00 MiB (262144 cells, 48 layers, 1/1 seqs), K (turbo4): 3264.00 MiB, V (turbo3): 2400.00 MiB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;VRAM after load:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7525 MiB used
500 MiB free
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Very tight.&lt;/p&gt;

&lt;p&gt;But loaded.&lt;/p&gt;

&lt;p&gt;Then I sent a small coding prompt through the OpenAI-compatible endpoint.&lt;/p&gt;

&lt;p&gt;It answered.&lt;/p&gt;

&lt;p&gt;Timings:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompt eval time = 1125.54 ms / 46 tokens = 40.87 tokens per second
eval time        = 3672.56 ms / 107 tokens = 29.13 tokens per second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That was the win.&lt;/p&gt;

&lt;p&gt;Qwen3-Coder-30B-A3B.&lt;/p&gt;

&lt;p&gt;262K context.&lt;/p&gt;

&lt;p&gt;8 GB VRAM.&lt;/p&gt;

&lt;p&gt;Local endpoint.&lt;/p&gt;

&lt;p&gt;Same model file.&lt;/p&gt;

&lt;p&gt;TurboQuant KV cache.&lt;/p&gt;
&lt;h2&gt;
  
  
  The repeatable script
&lt;/h2&gt;

&lt;p&gt;I wrapped the TurboQuant launch into:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scripts/run-qwen-coder-turboquant.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So the repeatable command is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\scripts\run-qwen-coder-turboquant.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-Replace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The stock Docker fallback still exists:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\scripts\run-qwen-coder-docker.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Profile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;daily-fast&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The Docker route is useful for a safer daily profile.&lt;/p&gt;

&lt;p&gt;The TurboQuant route is the full-context profile.&lt;/p&gt;
&lt;h2&gt;
  
  
  Important caveats
&lt;/h2&gt;

&lt;p&gt;This is not magic.&lt;/p&gt;

&lt;p&gt;The 262K profile is VRAM-tight.&lt;/p&gt;

&lt;p&gt;It leaves roughly 500 MiB free on my RTX 3060 Ti. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;single client only&lt;/li&gt;
&lt;li&gt;do not run multiple editor agents at once&lt;/li&gt;
&lt;li&gt;close GPU-heavy apps&lt;/li&gt;
&lt;li&gt;expect this to be less forgiving than the 32K profile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, I have not yet proven that this setup is great at real-world coding tasks.&lt;/p&gt;

&lt;p&gt;The infrastructure works.&lt;/p&gt;

&lt;p&gt;The endpoint works.&lt;/p&gt;

&lt;p&gt;The context loads.&lt;/p&gt;

&lt;p&gt;The smoke test passes.&lt;/p&gt;

&lt;p&gt;But the next test is actual development work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can it refactor a real repo?&lt;/li&gt;
&lt;li&gt;Can it debug Unity C# sanely?&lt;/li&gt;
&lt;li&gt;Can it handle multi-file context without drifting?&lt;/li&gt;
&lt;li&gt;Can it stay stable across longer sessions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the next milestone.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;The big lesson is that local AI infra is not just:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;download model
run server
profit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The defaults are often the bottleneck.&lt;/p&gt;

&lt;p&gt;In this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MoE placement mattered.&lt;/li&gt;
&lt;li&gt;Docker memory limits mattered.&lt;/li&gt;
&lt;li&gt;KV cache format mattered.&lt;/li&gt;
&lt;li&gt;Runtime build mattered.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;llama-server --help&lt;/code&gt; mattered a lot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 30B model was not the whole problem.&lt;/p&gt;

&lt;p&gt;The runtime strategy was.&lt;/p&gt;

&lt;p&gt;And sometimes the difference between "impossible" and "working" is one missing DLL plus the right KV cache type.&lt;/p&gt;
&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;

&lt;p&gt;I published the setup as a GitHub repo with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;launch scripts&lt;/li&gt;
&lt;li&gt;benchmark notes&lt;/li&gt;
&lt;li&gt;troubleshooting docs&lt;/li&gt;
&lt;li&gt;client settings&lt;/li&gt;
&lt;li&gt;reproducible setup notes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub link:&lt;/p&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/UpayanGhosh" rel="noopener noreferrer"&gt;
        UpayanGhosh
      &lt;/a&gt; / &lt;a href="https://github.com/UpayanGhosh/local-qwen-coder-turboquant" rel="noopener noreferrer"&gt;
        local-qwen-coder-turboquant
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Local Qwen3-Coder 30B TurboQuant setup for 8GB VRAM coding workflows
    &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;Local Qwen Coder TurboQuant Setup&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Practical Windows setup notes and scripts for running &lt;code&gt;Qwen3-Coder-30B-A3B-Instruct&lt;/code&gt; as a local coding-only OpenAI-compatible backend on an 8 GB NVIDIA GPU.&lt;/p&gt;

&lt;p&gt;This repo documents the journey from a stable stock llama.cpp Docker setup to a full-context TurboQuant KV-cache runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RTX 3060 Ti, 8 GB VRAM&lt;/li&gt;
&lt;li&gt;Windows&lt;/li&gt;
&lt;li&gt;Qwen3-Coder-30B-A3B-Instruct GGUF&lt;/li&gt;
&lt;li&gt;MoE expert CPU/GPU residency tuning&lt;/li&gt;
&lt;li&gt;OpenAI-compatible local endpoint&lt;/li&gt;
&lt;li&gt;Verified &lt;code&gt;262144&lt;/code&gt; context with TurboQuant KV cache&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What Is Included&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;PowerShell scripts for launching and testing the backend&lt;/li&gt;
&lt;li&gt;Client settings for Cline, Continue, Roo Code, OpenCode, and generic OpenAI-compatible clients&lt;/li&gt;
&lt;li&gt;Benchmark notes&lt;/li&gt;
&lt;li&gt;TurboQuant research and troubleshooting notes&lt;/li&gt;
&lt;li&gt;LinkedIn post draft documenting the build story&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What Is Not Included&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;This repo intentionally does not track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GGUF model files&lt;/li&gt;
&lt;li&gt;CUDA/runtime DLLs&lt;/li&gt;
&lt;li&gt;downloaded wheels/zips&lt;/li&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;local caches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those files are large and/or machine-specific. See &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;Verified TurboQuant profile:&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;Context: 262144
KV cache: K=turbo4, V=turbo3
VRAM: ~7525 MiB used /&lt;/code&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/UpayanGhosh/local-qwen-coder-turboquant" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The repo will not include the GGUF model, CUDA DLLs, wheels, or downloaded binaries. Those are too large and machine-specific.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;This started as:&lt;/p&gt;

&lt;p&gt;"Can I make a useful local coding backend?"&lt;/p&gt;

&lt;p&gt;Then it became:&lt;/p&gt;

&lt;p&gt;"Can I get the full 262K context working on 8 GB VRAM?"&lt;/p&gt;

&lt;p&gt;The first version merely ran.&lt;/p&gt;

&lt;p&gt;The final version actually hit the target.&lt;/p&gt;

&lt;p&gt;I am calling that a win.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>llm</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
