<?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: Savindu Thathsara</title>
    <description>The latest articles on DEV Community by Savindu Thathsara (@savinduthathsara).</description>
    <link>https://dev.to/savinduthathsara</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F481859%2F46560e15-e7a5-4c9c-9b85-dd3a5dd0d716.png</url>
      <title>DEV Community: Savindu Thathsara</title>
      <link>https://dev.to/savinduthathsara</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/savinduthathsara"/>
    <language>en</language>
    <item>
      <title>I Tried to Build an Offline AI Assistant for an 8GB Laptop, and the CPU Said No</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 11:44:28 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/i-tried-to-build-an-offline-ai-assistant-for-an-8gb-laptop-and-the-cpu-said-no-5aea</link>
      <guid>https://dev.to/savinduthathsara/i-tried-to-build-an-offline-ai-assistant-for-an-8gb-laptop-and-the-cpu-said-no-5aea</guid>
      <description>&lt;h1&gt;
  
  
  I Tried to Build an Offline AI Assistant for an 8GB Laptop, and the CPU Said No
&lt;/h1&gt;

&lt;p&gt;I kept waiting for the memory to fill up. A question sat there for three seconds, and 13 GB was still free.&lt;/p&gt;

&lt;p&gt;I am Savindu Thathsara. I live in London, and this is a Hearthlen note. Hearthlen is an offline AI assistant on a lightweight Linux laptop: you say “hey Hearthlen,” ask something, and a model on that machine answers. Nothing in the question goes to a cloud API. The plan was written for an &lt;a href="//03-local-ai-on-8gb-ram.md"&gt;8GB laptop&lt;/a&gt;. The ThinkPad I am actually building on has 16 GB. That extra room did not save the reply.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I thought would break
&lt;/h2&gt;

&lt;p&gt;The early budget was a pile of RAM. Leave most of an 8 GB machine for the person and the browser. Keep a wake word always on. Borrow one heavy model while a request is in progress, then let it go. One model at a time, because two of them would spend the same memory twice.&lt;/p&gt;

&lt;p&gt;That story is about fitting. The failure I hit was about waiting.&lt;/p&gt;

&lt;p&gt;On 25 October 2026 the dashboard read &lt;strong&gt;13.1 GB free&lt;/strong&gt;, 2.4 GB used, &lt;strong&gt;15.5 GB&lt;/strong&gt; total. The models on disk were &lt;strong&gt;3.5 GB&lt;/strong&gt;: Qwen2.5-3B at 2.0 GB, a 1.5B coder at 1.0 GB, SmolLM2 at 0.3 GB, and the Lessac voice at 0.1 GB. The language model was not even loaded until someone spoke. The listener, which is the process holding the microphone and the speech model, was &lt;strong&gt;1507 MB&lt;/strong&gt;. After I dropped a second language and restarted it, that process was &lt;strong&gt;1331 MB&lt;/strong&gt;, and &lt;strong&gt;13.0 GB&lt;/strong&gt; was still available. The machine had room. The answer was still late.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fast model could not use the sentence
&lt;/h2&gt;

&lt;p&gt;The first voice model was SmolLM2, 360 million parameters. It was quick. “How are you?” came back in &lt;strong&gt;437 ms&lt;/strong&gt;. “What should we do today?” came back in &lt;strong&gt;356 ms&lt;/strong&gt;, as a picnic. A joke took &lt;strong&gt;346 ms&lt;/strong&gt;. A later pass, “Hi, how about you?”, took &lt;strong&gt;857 ms&lt;/strong&gt; to generate and still sounded like a line from a list.&lt;/p&gt;

&lt;p&gt;A model that size can finish a short sentence. Give it “I have two hours free and it is raining” and it does not keep the rain. It picks a pleasant errand and stops. I wrote that down in &lt;a href="//22-the-small-model-was-the-stock-answer.md"&gt;the small model was the stock answer&lt;/a&gt;. Speed was fine. The answer was not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model that could think made the CPU do the work
&lt;/h2&gt;

&lt;p&gt;The voice model is now Qwen2.5-3B-Instruct, 4-bit, 2,104,932,768 bytes, running through llama.cpp on the CPU. There is no discrete GPU on this laptop.&lt;/p&gt;

&lt;p&gt;I sent the sentence the small model had been failing: “I have two hours free and it is raining. What should I do?” The reply used both facts. It suggested reading a book, because it was raining and there were two free hours. That was &lt;strong&gt;39 tokens in 3017 ms&lt;/strong&gt;. About thirteen tokens a second. You feel that gap. The face sits on Thinking the whole time, which at least shows the wait is the model and not a frozen window.&lt;/p&gt;

&lt;p&gt;The same CPU shows up when the assistant writes a page. Qwen2.5-Coder-1.5B produced a small HTML animation in &lt;strong&gt;8220 ms&lt;/strong&gt;, inside a turn of &lt;strong&gt;19233 ms&lt;/strong&gt;. A circle animation took &lt;strong&gt;14347 ms&lt;/strong&gt; to write, and the whole turn was &lt;strong&gt;26338 ms&lt;/strong&gt;. A form from one sentence took &lt;strong&gt;48881 ms&lt;/strong&gt;. None of those runs reported a full memory. They reported a processor chewing through a local model while the person watched.&lt;/p&gt;

&lt;p&gt;Speech itself is cheap when the line is short. “How are you?” was transcribed in &lt;strong&gt;373 ms&lt;/strong&gt;. A short YouTube command was &lt;strong&gt;364 ms&lt;/strong&gt;. The spoken reply from Piper, including playback of “Hi, Savindu,” was &lt;strong&gt;1939 ms&lt;/strong&gt;. The long pause is the language model, after the words are already text.&lt;/p&gt;

&lt;h2&gt;
  
  
  A second language made the same wall taller
&lt;/h2&gt;

&lt;p&gt;I added Sinhala beside English. The speech model had to carry both, and the 3B model had to answer in Sinhala. One question, “ආයුබෝවන්. ඔයා කොහොමද?”, came back in Sinhala in &lt;strong&gt;9564 ms&lt;/strong&gt;. The grammar was rough, and nine seconds is too long for a greeting. Memory was still the same 13 GB free. I took Sinhala out. English speech is the smaller English-only model again. The note on that measurement is &lt;a href="//25-the-slow-reply-was-cpu-time.md"&gt;the slow reply was CPU time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Taking the second language out removes one bill. It does not make the 3B model instant. A question still waits on those tokens. I would rather wait three seconds for an answer that uses the sentence than get a picnic in a third of a second.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am keeping
&lt;/h2&gt;

&lt;p&gt;The 8 GB budget is still the target, because this ThinkPad is luckier than the laptop the project is for. Weights of 3.5 GB and a listener over a gigabyte would sit much closer to the edge on 8 GB, and the rule stays: one heavy model at a time, then it leaves. That rule is about room.&lt;/p&gt;

&lt;p&gt;The rule the CPU added is about the clock. A local assistant feels intelligent when the model is big enough to hold the sentence, and it feels broken when that model takes long enough that you wonder if it heard you. On this machine those two things arrived together. More RAM was already there. It did not move the 3017 ms.&lt;/p&gt;

&lt;p&gt;Next I stay on Qwen2.5-3B for questions and on the small English speech model for the microphone. The budget those numbers still have to fit is &lt;a href="//03-local-ai-on-8gb-ram.md"&gt;an 8GB laptop running YouTube and a local assistant&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>The Slow Reply Was CPU Time</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 11:34:18 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/the-slow-reply-was-cpu-time-4ne0</link>
      <guid>https://dev.to/savinduthathsara/the-slow-reply-was-cpu-time-4ne0</guid>
      <description>&lt;h1&gt;
  
  
  The Slow Reply Was CPU Time
&lt;/h1&gt;

&lt;p&gt;Thirteen gigabytes of memory were still free, and the answer was still slow.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the laptop.&lt;/p&gt;

&lt;p&gt;Sinhala had just been added beside English, and a question took long enough to feel stuck. The check was &lt;code&gt;/proc/meminfo&lt;/code&gt;: &lt;strong&gt;13.0 GB available&lt;/strong&gt; out of 15.5 GB. The listener was &lt;strong&gt;1507 MB&lt;/strong&gt;. The language model was not loaded until someone spoke. So this was not a machine that had run out of memory.&lt;/p&gt;

&lt;p&gt;The time was the models doing work. The bilingual speech model spent &lt;strong&gt;2407 ms&lt;/strong&gt; on a short clip, because it also had to guess the language. A Sinhala reply from Qwen2.5-3B took &lt;strong&gt;9564 ms&lt;/strong&gt;. English is the only speech path again, on the smaller English model. After that restart the listener was &lt;strong&gt;1331 MB&lt;/strong&gt;, and 13.0 GB was still free. The 3B model is still what thinks, so a reply is still a few seconds. It is no longer also paying for a second language. The bilingual note is &lt;a href="//24-english-and-sinhala.md"&gt;English and Sinhala&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>English and Sinhala</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 11:17:06 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/english-and-sinhala-4cdj</link>
      <guid>https://dev.to/savinduthathsara/english-and-sinhala-4cdj</guid>
      <description>&lt;h1&gt;
  
  
  English and Sinhala
&lt;/h1&gt;

&lt;p&gt;The Sinhala voice said "ආයුබෝවන්. මම හර්ත්ලන්." Inference took 112 milliseconds. The greeting itself was 2.04 seconds of audio.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the laptop.&lt;/p&gt;

&lt;p&gt;English was the only filled-in language. Sinhala was an empty row in the same manifest. That row now points at a real voice, &lt;code&gt;si_LK-sinhala-medium&lt;/code&gt;, and both languages share one multilingual speech model. The wake phrase is still "hey Hearthlen". After it, a sentence in Sinhala script is answered in Sinhala and spoken with that voice. English still uses the Lessac voice.&lt;/p&gt;

&lt;p&gt;Asked "ආයුබෝවන්. ඔයා කොහොමද?", Qwen2.5-3B answered in Sinhala script in &lt;strong&gt;9564 ms&lt;/strong&gt;. The sentence is rough. It is Sinhala, which is what the voice speaks. The dashboard shows EN and සිංහල, and the one just heard is the bright label. The window those labels sit on is &lt;a href="//23-the-dashboard.md"&gt;the dashboard&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Dashboard</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 11:08:42 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/the-dashboard-3430</link>
      <guid>https://dev.to/savinduthathsara/the-dashboard-3430</guid>
      <description>&lt;h1&gt;
  
  
  The Dashboard
&lt;/h1&gt;

&lt;p&gt;At 11:07 the Hearthlen window stopped being a text box. The mark was on the left, and the rail next to it said 13.1 GB of memory was free.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the laptop.&lt;/p&gt;

&lt;p&gt;The mark is the same one that sits in the corner while the voice is open. Rings come in when it is listening, the wire sphere turns while Qwen is generating, and the rings go out when it speaks. Under that, a path names the real stages: the microphone, the mel spectrogram, a 96-number wake embedding, the wake head, speech, Qwen 3B, and the voice. Those 96 numbers are the wake head on disk. They are not a store of your documents. The conversation it can recall is the last few turns.&lt;/p&gt;

&lt;p&gt;The numbers are read on the machine. Memory was 13.1 GB free, 2.4 GB used, 15.5 GB total. The model files were 3.5 GB, with 193.9 GB still free on the disk. Qwen2.5-3B was 2.0 GB of that. The listener, the face, the hotkey, and the dashboard were running. The language-model process was not, until the next sentence. The earlier voice is in &lt;a href="//22-the-small-model-was-the-stock-answer.md"&gt;the small model was the stock answer&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Small Model Was the Stock Answer</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 11:03:36 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/the-small-model-was-the-stock-answer-480o</link>
      <guid>https://dev.to/savinduthathsara/the-small-model-was-the-stock-answer-480o</guid>
      <description>&lt;h1&gt;
  
  
  The Small Model Was the Stock Answer
&lt;/h1&gt;

&lt;p&gt;"What should we do today?" came back as "go to the market." The words were generated, and they still sounded like a line that had been saved in advance.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the laptop.&lt;/p&gt;

&lt;p&gt;The voice model was SmolLM2 at 360 million parameters. A model that size can finish a short sentence. It cannot hold the detail you just said and do something with it, so the sentence comes out generic. The voice agent now keeps Qwen2.5-3B-Instruct loaded, 4-bit, 2,104,932,768 bytes. Asked "I have two hours free and it is raining. What should I do?" it answered: "Since it's raining and you have two hours free, why not take this opportunity to read a book?" That was 39 tokens in &lt;strong&gt;3017 ms&lt;/strong&gt;. It used the rain and the two hours. The smaller model never did.&lt;/p&gt;

&lt;p&gt;The face shows Thinking while those tokens are generated. A plain command still goes to the desk. The conversation this replaces is in &lt;a href="//21-the-reply-comes-from-the-model.md"&gt;the reply comes from the model&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Reply Comes From the Model</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:46:08 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/the-reply-comes-from-the-model-2633</link>
      <guid>https://dev.to/savinduthathsara/the-reply-comes-from-the-model-2633</guid>
      <description>&lt;h1&gt;
  
  
  The Reply Comes From the Model
&lt;/h1&gt;

&lt;p&gt;"What should we do today?" The ThinkPad answered, in the model's own words, "i should probably go to the market today." That sentence took 667 milliseconds to generate.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the laptop.&lt;/p&gt;

&lt;p&gt;The greeting used to be a stored line. "How are you?" always came back as the same menu. The voice agent now keeps SmolLM2-360M loaded and sends the latest sentence to it, with the last few turns in front. Speech-to-text on this question was 408 ms, and the whole turn was 3840 ms. The log marks it &lt;code&gt;agent=voice&lt;/code&gt;. An earlier "Hi, how about you?" came back as "hi, heh, I think I'm ready now." in 857 ms.&lt;/p&gt;

&lt;p&gt;A plain request such as "open the browser" still goes to the desk agent, which uses the keyboard and mouse. A sentence that is also a question stays in the conversation. The words show up in the chat while you talk, from &lt;a href="//20-the-words-appear-while-you-talk.md"&gt;the live line&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Words Appear While You Talk</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:37:50 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/the-words-appear-while-you-talk-5a4l</link>
      <guid>https://dev.to/savinduthathsara/the-words-appear-while-you-talk-5a4l</guid>
      <description>&lt;h1&gt;
  
  
  The Words Appear While You Talk
&lt;/h1&gt;

&lt;p&gt;The ThinkPad microphone was already on. A two-second recording peaked at 4976, and the listener's first frames peaked at 2852.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the laptop.&lt;/p&gt;

&lt;p&gt;The card is the Intel HDA device, codec ALC257. The internal mic boost is at 30 dB, the top of that control. What was missing was the picture. The voice session now opens the Hearthlen chat, and while you are still talking the words land in a "You" line and in the box at the bottom. A spoken "how are you" from this desk became &lt;code&gt;caption 'How are you?'&lt;/code&gt; and then &lt;code&gt;heard='How are you?'&lt;/code&gt; in 373 ms. At 10:37 the window showed that line, under "Hi, Savindu.", with the reply beneath it.&lt;/p&gt;

&lt;p&gt;Room noise can make the transcriber repeat one short phrase. A line that does that is thrown away, and a phrase only starts once it is louder than the noise floor measured at startup, which was 833 this time.&lt;/p&gt;

&lt;p&gt;The session those words belong to opens from &lt;a href="//19-win-v-opens-the-voice.md"&gt;Win+V&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Win+V Opens the Voice</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:29:07 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/winv-opens-the-voice-5dlo</link>
      <guid>https://dev.to/savinduthathsara/winv-opens-the-voice-5dlo</guid>
      <description>&lt;h1&gt;
  
  
  Win+V Opens the Voice
&lt;/h1&gt;

&lt;p&gt;Super+V on the ThinkPad, and the voice agent opened in that same second.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the laptop.&lt;/p&gt;

&lt;p&gt;Win+H was already the chat window, from &lt;a href="//13-win-h-opens-the-chat.md"&gt;Win+H opens the chat&lt;/a&gt;. Win+V now asks the listener to start the spoken session, the same one "hey Hearthlen" starts. It says hello and then keeps the microphone. The key went out at &lt;strong&gt;10:28:14&lt;/strong&gt;. The log line is &lt;code&gt;voice: Win+V&lt;/code&gt; at &lt;strong&gt;10:28:14&lt;/strong&gt;. &lt;code&gt;session open&lt;/code&gt; is &lt;strong&gt;10:28:16&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The conversation those keys open is in &lt;a href="//18-a-conversation-then-the-work.md"&gt;a conversation, then the work&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A Conversation, Then the Work</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:23:21 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/a-conversation-then-the-work-2o8g</link>
      <guid>https://dev.to/savinduthathsara/a-conversation-then-the-work-2o8g</guid>
      <description>&lt;h1&gt;
  
  
  A Conversation, Then the Work
&lt;/h1&gt;

&lt;p&gt;The wake word answered once and then went quiet. A person does not talk to a command line.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the ThinkPad.&lt;/p&gt;

&lt;p&gt;After "hey Hearthlen" the microphone stays open. Three agents share the sentence. The voice agent talks, and the small model stays loaded so the next reply does not pay for another startup. The device agent handles the volume, the brightness, files, reminders, and Wi-Fi. The desk agent takes the sentences that start work, create, open, write, and the rest, and it uses the keyboard and mouse on a background thread. The voice says it will do that, and it keeps listening. Eight quiet seconds ends the session.&lt;/p&gt;

&lt;p&gt;The voice agent, already loaded, answered three different sentences on the laptop. "how are you" came back in &lt;strong&gt;437 ms&lt;/strong&gt;. "what should we do today" came back in &lt;strong&gt;356 ms&lt;/strong&gt;. "tell me a short joke" came back in &lt;strong&gt;346 ms&lt;/strong&gt;. A recording of the wake phrase from this desk scored &lt;strong&gt;0.25&lt;/strong&gt;, so that pass never opened the session.&lt;/p&gt;

&lt;p&gt;The previous ear is in &lt;a href="//17-the-wake-word-trained-here.md"&gt;the wake word trained on this Mac&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>The Wake Word Trained on This Mac</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:11:31 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/the-wake-word-trained-on-this-mac-2ch</link>
      <guid>https://dev.to/savinduthathsara/the-wake-word-trained-on-this-mac-2ch</guid>
      <description>&lt;h1&gt;
  
  
  The Wake Word Trained on This Mac
&lt;/h1&gt;

&lt;p&gt;I said “hey Hearthlen” from the next machine. The ThinkPad logged score &lt;strong&gt;0.99&lt;/strong&gt;. The sentence before it, “open the browser”, did not wake it.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the two computers sitting together.&lt;/p&gt;

&lt;p&gt;The earlier listener, in &lt;a href="//16-the-name-it-hears.md"&gt;the name it hears&lt;/a&gt;, transcribed a burst and then guessed. The same phrase came back as Hertzland, Herthlin, and once as something that was not the name at all. There is no published model for this name. openWakeWord already publishes the mel network and the speech-embedding network, and those stay frozen. I trained only the small phrase head, on this Mac, from offline speech, and copied the three files to the ThinkPad. The listener scores each 80 ms of microphone audio on the laptop. It does not download a model when someone says the name.&lt;/p&gt;

&lt;p&gt;The holdout from that training run was positives &lt;strong&gt;0.96&lt;/strong&gt;, negatives &lt;strong&gt;0.04&lt;/strong&gt;, recall &lt;strong&gt;0.91&lt;/strong&gt;, false accepts &lt;strong&gt;0.00&lt;/strong&gt;. The laptop uses threshold &lt;strong&gt;0.97&lt;/strong&gt;. The phrase finished at 10:06:48.494 and the log line is that same second, score &lt;strong&gt;0.98&lt;/strong&gt;. A later pass scored &lt;strong&gt;0.99&lt;/strong&gt;, said hello, and heard the next sentence: &lt;code&gt;Turn the volume up.&lt;/code&gt; Speech-to-text took &lt;strong&gt;367 ms&lt;/strong&gt;. The turn took &lt;strong&gt;1914 ms&lt;/strong&gt;. With the speaker turned down to 46, the same phrase scored &lt;strong&gt;0.91&lt;/strong&gt; and stayed quiet.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>The Name It Hears</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 09:19:52 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/the-name-it-hears-3f28</link>
      <guid>https://dev.to/savinduthathsara/the-name-it-hears-3f28</guid>
      <description>&lt;h1&gt;
  
  
  The Name It Hears
&lt;/h1&gt;

&lt;p&gt;I said “hey Hearthlen” from the next machine. The ThinkPad microphone recorded it, and the wake listener did nothing.&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the two computers sitting together.&lt;/p&gt;

&lt;p&gt;The old listener was PocketSphinx, waiting for “hey hearth” and “hard one”, because that is what an English dictionary makes of a made-up name. On this recording Whisper heard “Hey, Hertzland.” The keyword list, at its most sensitive setting, scored &lt;strong&gt;0&lt;/strong&gt; hits.&lt;/p&gt;

&lt;p&gt;The listener now transcribes a short burst and accepts the name as it actually comes out: hearthlin, herthlin, hertzland. The burst that woke it took &lt;strong&gt;340 ms&lt;/strong&gt;. The log line was &lt;code&gt;wake: hey hearthlen&lt;/code&gt;, one second after the phrase ended, and it gave the greeting.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>He Asked for an Animation and Got a Form</title>
      <dc:creator>Savindu Thathsara</dc:creator>
      <pubDate>Sun, 25 Oct 2026 00:50:46 +0000</pubDate>
      <link>https://dev.to/savinduthathsara/he-asked-for-an-animation-and-got-a-form-2o72</link>
      <guid>https://dev.to/savinduthathsara/he-asked-for-an-animation-and-got-a-form-2o72</guid>
      <description>&lt;h1&gt;
  
  
  He Asked for an Animation and Got a Form
&lt;/h1&gt;

&lt;p&gt;“create html animation” came back as another form, because every HTML sentence was pushed through a form fence, and the animation sentence had been saved as the answer to “what should I type?”&lt;/p&gt;

&lt;p&gt;Savindu Thathsara, &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;savithathsara.me&lt;/a&gt;. This is a Hearthlen note from the ThinkPad.&lt;/p&gt;

&lt;p&gt;The fence is the one in &lt;a href="//14-six-inputs.md"&gt;six inputs means six boxes&lt;/a&gt;. A 360M model, asked for a page, copies the instruction and invents tags. The fence stops that, and it also means the only page it can produce is a form. An animation does not fit in it.&lt;/p&gt;

&lt;p&gt;Two things changed. A sentence that starts a new task is no longer glued onto the previous question. And a page is written by Qwen2.5-Coder 1.5B, on the laptop, then pasted into the editor, saved, and opened. The sentence is the brief. &lt;code&gt;create html animation&lt;/code&gt; became a red square that slides, in &lt;strong&gt;19233 ms&lt;/strong&gt;, of which the coder spent &lt;strong&gt;8220 ms&lt;/strong&gt;. &lt;code&gt;create a circle animation in html&lt;/code&gt; became a red circle that moves, in &lt;strong&gt;26338 ms&lt;/strong&gt;, of which the coder spent &lt;strong&gt;14347 ms&lt;/strong&gt;. Chromium is showing &lt;code&gt;/home/savindu/page-3.html&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Savindu Thathsara builds practical AI and automation in London. This series is the public log of an offline AI operating system he is writing and learning at the same time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://savithathsara.me" rel="noopener noreferrer"&gt;https://savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:savindu@savithathsara.me"&gt;savindu@savithathsara.me&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DEV: &lt;a href="https://dev.to/savinduthathsara"&gt;https://dev.to/savinduthathsara&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
