<?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: Marcin Firmuga</title>
    <description>The latest articles on DEV Community by Marcin Firmuga (@huckler).</description>
    <link>https://dev.to/huckler</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%2F3693207%2F6a4682e6-273e-4a98-9ce7-653391a5abcc.png</url>
      <title>DEV Community: Marcin Firmuga</title>
      <link>https://dev.to/huckler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/huckler"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Sat, 25 Jul 2026 07:00:16 +0000</pubDate>
      <link>https://dev.to/huckler/-37go</link>
      <guid>https://dev.to/huckler/-37go</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/huckler/i-had-a-6533-line-python-response-builder-it-still-worked-that-was-the-problem-34d3" class="crayons-story__hidden-navigation-link"&gt;I Had a 6,533-Line Python Response Builder. It Still Worked. That Was the Problem.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/huckler" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3693207%2F6a4682e6-273e-4a98-9ce7-653391a5abcc.png" alt="huckler profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/huckler" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Marcin Firmuga
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Marcin Firmuga
                
              
              &lt;div id="story-author-preview-content-4227138" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/huckler" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3693207%2F6a4682e6-273e-4a98-9ce7-653391a5abcc.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Marcin Firmuga&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/huckler/i-had-a-6533-line-python-response-builder-it-still-worked-that-was-the-problem-34d3" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/huckler/i-had-a-6533-line-python-response-builder-it-still-worked-that-was-the-problem-34d3" id="article-link-4227138"&gt;
          I Had a 6,533-Line Python Response Builder. It Still Worked. That Was the Problem.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/python"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;python&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/architecture"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;architecture&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/refactoring"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;refactoring&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/huckler/i-had-a-6533-line-python-response-builder-it-still-worked-that-was-the-problem-34d3" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;10&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/huckler/i-had-a-6533-line-python-response-builder-it-still-worked-that-was-the-problem-34d3#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            10 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>I Had a 6,533-Line Python Response Builder. It Still Worked. That Was the Problem.</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Fri, 24 Jul 2026 23:52:39 +0000</pubDate>
      <link>https://dev.to/huckler/i-had-a-6533-line-python-response-builder-it-still-worked-that-was-the-problem-34d3</link>
      <guid>https://dev.to/huckler/i-had-a-6533-line-python-response-builder-it-still-worked-that-was-the-problem-34d3</guid>
      <description>&lt;p&gt;PC Workman has a small offline assistant called &lt;code&gt;hck_GPT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It reads local sensor data, workload history, process information and hardware details. It answers in Polish or English. No account, no cloud, no machine data leaving the PC.&lt;/p&gt;

&lt;p&gt;By v1.8.5, it had &lt;strong&gt;96 intents&lt;/strong&gt;, also had one file called &lt;code&gt;builder.py&lt;/code&gt;.&lt;br&gt;
That file was &lt;strong&gt;6,533 lines long&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And it still worked.&lt;br&gt;
That was the problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs6m7pf356290n3vcd22m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs6m7pf356290n3vcd22m.png" alt=" " width="799" height="332"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The file did not become ridiculous overnight
&lt;/h2&gt;

&lt;p&gt;There was no single bad decision that created the monolith.&lt;br&gt;
It grew ten lines at a time.&lt;/p&gt;

&lt;p&gt;One new intent, one new response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Polish version beside the English one, a helper added near the bottom because I was already in the file.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A tester asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can it explain why my laptop is warm?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I add &lt;code&gt;_resp_temperature()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Someone else asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can it tell me if I can run this game?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I add &lt;code&gt;_resp_game_can_run()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then startup questions.&lt;br&gt;
Then RAM questions.&lt;br&gt;
Then thermal history.&lt;br&gt;
Then upgrade compatibility.&lt;br&gt;
...&lt;/p&gt;

&lt;p&gt;Every commit looked reasonable on its own.&lt;/p&gt;

&lt;p&gt;That is how technical debt usually gets in.&lt;/p&gt;

&lt;p&gt;Not through one obviously stupid decision.&lt;/p&gt;

&lt;p&gt;Through a hundred small decisions that each save ten minutes.&lt;/p&gt;

&lt;p&gt;Eventually &lt;code&gt;ResponseBuilder&lt;/code&gt; had 96 handlers in one class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResponseBuilder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_temperature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_why_slow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_game_can_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_full_specs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;# 92 more
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;File opened slowly enough that my editor paused for a beat.&lt;br&gt;
More importantly, I had stopped wandering through it.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;I opened it only when I already knew exactly what I needed.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I avoided shared helpers because I could not remember what else they touched.&lt;/p&gt;

&lt;p&gt;I postponed cleanup because even a small change meant scrolling past thousands of unrelated lines.&lt;/p&gt;

&lt;p&gt;File was not impossible to understand.&lt;/p&gt;

&lt;p&gt;It was just unpleasant enough that I stopped improving the parts around the task.&lt;/p&gt;

&lt;p&gt;That was worse.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A file you are afraid to open is a file you have already stopped improving.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Why I finally touched it
&lt;/h2&gt;

&lt;p&gt;I build PC Workman at night after working in a plastic-repair shop in Radom, Poland.&lt;/p&gt;

&lt;p&gt;For a long time, that made the project feel private.&lt;/p&gt;

&lt;p&gt;Messy code was my problem.&lt;br&gt;
A slow page was my problem.&lt;/p&gt;

&lt;p&gt;A version string copied into eight files was ugly, but nobody depended on it except me.&lt;/p&gt;

&lt;p&gt;Then PC Workman reached the &lt;a href="https://apps.microsoft.com/detail/9PGW6WS2N50V" rel="noopener noreferrer"&gt;Microsoft Store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nothing changed in the repository that day.&lt;/p&gt;

&lt;p&gt;Same files. Same functions.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;Same 6,533-line builder.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But strangers could now click &lt;strong&gt;Install&lt;/strong&gt; and run it on machines I would never see.&lt;/p&gt;

&lt;p&gt;That changed what I was willing to ignore, project had users.&lt;/p&gt;

&lt;p&gt;A tester offered a Ryzen 9 and RTX 4090 system as a test bench because I did not own hardware like that.&lt;/p&gt;

&lt;p&gt;People started sending screenshots of PC Workman learning their machines.&lt;br&gt;
Someone sent the first meaningful 50 PLN support payment.&lt;br&gt;
These are small numbers by company standards.&lt;/p&gt;

&lt;p&gt;For a solo project built after physical shifts, they changed the weight of the work.&lt;/p&gt;

&lt;p&gt;Code no longer felt like a private mess I could clean “someday.”&lt;/p&gt;

&lt;p&gt;So I opened &lt;code&gt;builder.py&lt;/code&gt; and started cutting.&lt;/p&gt;


&lt;h2&gt;
  
  
  The one rule: do not break the public seam
&lt;/h2&gt;

&lt;p&gt;Rest of the application talked to the response layer through one call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The chat panel used it, proactive monitor used it.&lt;br&gt;
Test suite used it.&lt;/p&gt;

&lt;p&gt;I could have redesigned the whole response API while splitting the file.&lt;br&gt;
I did not.&lt;/p&gt;

&lt;p&gt;I wanted one side of the refactor to stay completely still.&lt;br&gt;
My rule was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Move the implementation. Do not move the door.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That meant keeping:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ResponseBuilder&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build(result, lang)&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_resp_&amp;lt;intent&amp;gt;&lt;/code&gt; handler names;&lt;/li&gt;
&lt;li&gt;alias resolution;&lt;/li&gt;
&lt;li&gt;bilingual output;&lt;/li&gt;
&lt;li&gt;unsupported-intent behavior;&lt;/li&gt;
&lt;li&gt;every existing caller import.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A refactor that changes every caller at the same time is difficult to trust.&lt;/p&gt;

&lt;p&gt;If something breaks, you no longer know whether the problem came from moving code or changing the contract.&lt;/p&gt;

&lt;p&gt;So the contract stayed.&lt;/p&gt;


&lt;h2&gt;
  
  
  The facade stayed. The body moved out.
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ResponseBuilder&lt;/code&gt; became a facade composed from domain mixins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResponseBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;HardwareResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;UpgradeResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ThermalResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;GamingResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SystemResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PerformanceResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InsightsResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;AssistantResponses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Build bilingual responses for every parsed intent.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The word “facade” sounds fancier than the idea, rest of the application still knocks on the same door.&lt;br&gt;
Rooms behind it are just no longer one giant hall.&lt;/p&gt;

&lt;p&gt;Each mixin contains one group of handlers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThermalResponses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_temperature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_fan_speed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_thermal_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Mixins are not separate services.&lt;/strong&gt;&lt;br&gt;
They do not have their own lifecycle,they are slices of one object, separated because the methods change for different reasons.&lt;/p&gt;

&lt;p&gt;That distinction mattered.&lt;/p&gt;

&lt;p&gt;I was not trying to build an architecture diagram impressive enough for LinkedIn.&lt;/p&gt;

&lt;p&gt;I was trying to stop one file from becoming the place where every future feature went to die.&lt;/p&gt;


&lt;h2&gt;
  
  
  The dispatcher did not move
&lt;/h2&gt;

&lt;p&gt;The existing dispatch logic was already useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_INTENT_ALIASES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_resp_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an intent 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;temperature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the builder looks for:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;getattr()&lt;/code&gt; performs that lookup on the final &lt;code&gt;ResponseBuilder&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Python’s method resolution order walks through the mixins and finds the method.&lt;/p&gt;

&lt;p&gt;It does not care whether &lt;code&gt;_resp_temperature()&lt;/code&gt; lives inside the old &lt;code&gt;builder.py&lt;/code&gt; or the new &lt;code&gt;r_thermal.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The dispatch path stayed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parsed intent
    -&amp;gt; alias resolution
    -&amp;gt; "_resp_&amp;lt;intent&amp;gt;"
    -&amp;gt; method lookup
    -&amp;gt; response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Filename was never part of the contract.&lt;/p&gt;

&lt;p&gt;That made the extraction almost invisible from outside the package.&lt;/p&gt;




&lt;h2&gt;
  
  
  I split by subject, not by size
&lt;/h2&gt;

&lt;p&gt;I did not create eight equal files.&lt;br&gt;
Two equally large files can still be two badly organised files.&lt;br&gt;
I grouped handlers by what they answer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Handlers&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_hardware.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;CPU, GPU, RAM, disks, motherboard, full specs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_insights.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;trends, comparisons, session digests, what changed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_performance.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;load, throttling, why the PC is slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_system.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;health, processes, startup, security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_thermal.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;temperatures, fans, voltage baselines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_assistant.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;greetings, help, context recall&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_gaming.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;game compatibility and gaming history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r_upgrade.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;offline hardware compatibility&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two more files carry shared work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;common.py
flows.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;common.py&lt;/code&gt; holds things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bilingual text selection;&lt;/li&gt;
&lt;li&gt;number formatting;&lt;/li&gt;
&lt;li&gt;follow-up hints;&lt;/li&gt;
&lt;li&gt;labels such as &lt;code&gt;+23% above your norm&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;flows.py&lt;/code&gt; holds guided conversations that take more than one message.&lt;br&gt;
The old &lt;code&gt;builder.py&lt;/code&gt; dropped from 6,533 lines to under 600.&lt;/p&gt;

&lt;p&gt;Its job is now boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compose the mixins;&lt;/li&gt;
&lt;li&gt;resolve the intent;&lt;/li&gt;
&lt;li&gt;call the handler;&lt;/li&gt;
&lt;li&gt;return the answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is exactly what I wanted.&lt;/p&gt;


&lt;h2&gt;
  
  
  The smallest module showed the biggest change
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;r_upgrade.py&lt;/code&gt; started with only two handlers.&lt;/p&gt;

&lt;p&gt;It could easily have been pasted into an existing file.&lt;/p&gt;

&lt;p&gt;A year earlier, that is what I would have done.&lt;br&gt;
New feature would have landed wherever the cursor already was.&lt;/p&gt;

&lt;p&gt;This time it received its own module from the first line.&lt;br&gt;
Two handlers, lots of empty room.&lt;/p&gt;

&lt;p&gt;That may sound trivial, but it is the cleanest proof that the refactor changed more than file sizes.&lt;/p&gt;

&lt;p&gt;Next feature had somewhere sensible to live.&lt;/p&gt;


&lt;h2&gt;
  
  
  Mixins solved one problem and introduced another
&lt;/h2&gt;

&lt;p&gt;Mixins were useful here, but they have a sharp edge.&lt;br&gt;
Two mixins can define the same method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThermalResponses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_health_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SystemResponses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_health_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python does not complain.&lt;/p&gt;

&lt;p&gt;One method wins according to inheritance order.&lt;/p&gt;

&lt;p&gt;The other remains in the repository, looks correct during review and never runs.&lt;/p&gt;

&lt;p&gt;That is exactly the kind of bug I do not want in a response system.&lt;/p&gt;

&lt;p&gt;Nothing crashes.&lt;/p&gt;

&lt;p&gt;The answer simply comes from the wrong handler.&lt;/p&gt;

&lt;p&gt;So I added a test that scans every response module and rejects duplicate &lt;code&gt;_resp_*&lt;/code&gt; names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;all_defs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_RESPONSES_GLOB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;all_defs&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;def (_resp_[a-z0-9_]+)\(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;duplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_defs&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;all_defs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duplicates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is not clever, it does not need to be.&lt;br&gt;
Handler naming convention is strict, so a simple structural test is enough.&lt;/p&gt;

&lt;p&gt;Important part is that silent MRO shadowing now turns the build red.&lt;/p&gt;


&lt;h2&gt;
  
  
  I also added a test against my future laziness
&lt;/h2&gt;

&lt;p&gt;Splitting the monolith once was not enough.&lt;br&gt;
Pressure that created it still exists.&lt;/p&gt;

&lt;p&gt;At 11 PM, adding a handler to an existing module will always feel faster than deciding whether the module should split.&lt;br&gt;
A README note would not stop me.&lt;/p&gt;

&lt;p&gt;So every response module now has a line limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_monolith_guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_RESPONSES_GLOB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;line_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertLess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;line_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="mi"&gt;1600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; has &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line_count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; lines - split it &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instead of growing another monolith&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The number &lt;code&gt;1600&lt;/code&gt; is not a universal clean-code law.&lt;br&gt;
A 1,601-line file is not automatically terrible.&lt;/p&gt;

&lt;p&gt;A 300-line file can still be nonsense.&lt;br&gt;
This is a project-specific ratchet.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;No response domain is allowed to become the next 6,533-line dumping ground.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The failure message is deliberately plain.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Architecture policy violation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;split it instead of growing another monolith
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That message is for me six months from now.&lt;/p&gt;

&lt;p&gt;A refactor without a ratchet is just a delay.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before and after
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hck_gpt/
└── responses/
    └── builder.py       # 6,533 lines
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hck_gpt/
└── responses/
    ├── builder.py       # facade + dispatch, under 600 lines
    ├── common.py
    ├── flows.py
    ├── r_assistant.py
    ├── r_gaming.py
    ├── r_hardware.py
    ├── r_insights.py
    ├── r_performance.py
    ├── r_system.py
    ├── r_thermal.py
    └── r_upgrade.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Public call stayed the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maintenance experience did not.&lt;/p&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;thermal responses live with thermal responses;&lt;/li&gt;
&lt;li&gt;hardware work does not require scrolling past greetings;&lt;/li&gt;
&lt;li&gt;duplicate handlers fail CI;&lt;/li&gt;
&lt;li&gt;oversized modules fail CI;&lt;/li&gt;
&lt;li&gt;new domains have an obvious starting point;&lt;/li&gt;
&lt;li&gt;callers remain untouched.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The same release fixed a two-second UI delay
&lt;/h2&gt;

&lt;p&gt;The builder was the biggest refactor in v1.8.5, but not the only one.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;My PC&lt;/strong&gt; page used to take about two seconds to reopen.&lt;/p&gt;

&lt;p&gt;I blamed the charts first.&lt;/p&gt;

&lt;p&gt;Then the amount of hardware data.&lt;/p&gt;

&lt;p&gt;The actual reason was much less glamorous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;two wmic calls on the UI thread
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One fetched the CPU name and one fetched the disk model. Each could wait up to three seconds.&lt;br&gt;
On current Windows systems, &lt;code&gt;wmic&lt;/code&gt; can be painfully slow.&lt;/p&gt;

&lt;p&gt;The page was paying that cost during an interactive action.&lt;br&gt;
&lt;strong&gt;Fix was simple once the cause was visible:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collect stable hardware identity once during startup.&lt;/li&gt;
&lt;li&gt;Reuse the cached identity.&lt;/li&gt;
&lt;li&gt;Build the page once.&lt;/li&gt;
&lt;li&gt;Keep it alive instead of destroying and rebuilding it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The page now reopens in roughly &lt;strong&gt;1–17 ms&lt;/strong&gt;.&lt;br&gt;
Lesson was not “never use &lt;code&gt;wmic&lt;/code&gt;.”&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Stable hardware identity does not belong on the path that must feel instant.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The version number lived in eight places
&lt;/h2&gt;

&lt;p&gt;The app version had another quiet failure, it existed in eight files they had already drifted.&lt;/p&gt;

&lt;p&gt;Title bar could report one version while the single-instance logic searched for a different window title.&lt;/p&gt;

&lt;p&gt;A second launch would then fail to focus the copy already running.&lt;/p&gt;

&lt;p&gt;Nothing dramatic happened.&lt;br&gt;
The app just behaved slightly wrong.&lt;br&gt;
Version now has one source of truth.&lt;/p&gt;

&lt;p&gt;A test scans for hardcoded duplicates and fails if the number starts spreading again.&lt;/p&gt;

&lt;p&gt;This pattern became common across the release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bug
    -&amp;gt; root cause
    -&amp;gt; fix
    -&amp;gt; regression test
    -&amp;gt; build guard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fixing the current problem is useful.&lt;/p&gt;

&lt;p&gt;Making the same class of problem harder to reintroduce is better.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test suite went from 21 to 194
&lt;/h2&gt;

&lt;p&gt;In June, PC Workman had 21 tests.&lt;/p&gt;

&lt;p&gt;By v1.8.5, it had 194.&lt;br&gt;
Number is not the interesting part, what matters is where the tests came from.&lt;/p&gt;

&lt;p&gt;Many were written after failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;intent patterns with no response handler;&lt;/li&gt;
&lt;li&gt;Store installs writing into a read-only path;&lt;/li&gt;
&lt;li&gt;protected Windows processes being treated like normal apps;&lt;/li&gt;
&lt;li&gt;anti-cheat processes missing from safety rules;&lt;/li&gt;
&lt;li&gt;background daemons starting twice;&lt;/li&gt;
&lt;li&gt;learning engines receiving no usable sensor data;&lt;/li&gt;
&lt;li&gt;version strings drifting;&lt;/li&gt;
&lt;li&gt;response modules growing without a boundary;&lt;/li&gt;
&lt;li&gt;duplicate handlers hiding behind mixin order.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the closest a solo project gets to institutional memory.&lt;/p&gt;

&lt;p&gt;There is no team meeting where somebody says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Remember the bug from three months ago?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test says it every time the code changes.&lt;/p&gt;


&lt;h2&gt;
  
  
  What I deliberately did not do
&lt;/h2&gt;
&lt;h3&gt;
  
  
  I did not rename everything
&lt;/h3&gt;

&lt;p&gt;Moving and renaming at the same time makes failures harder to trace.&lt;br&gt;
I moved first. &lt;strong&gt;Names can improve later&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  I did not replace the public API
&lt;/h3&gt;

&lt;p&gt;A new registry or explicit service composition might be cleaner eventually.&lt;/p&gt;

&lt;p&gt;That was not &lt;strong&gt;job of this refactor&lt;/strong&gt;.&lt;br&gt;
Job was to reduce maintenance risk without creating a second project.&lt;/p&gt;
&lt;h3&gt;
  
  
  I did not chase equal file sizes
&lt;/h3&gt;

&lt;p&gt;Line count is a guard, not a design method.&lt;br&gt;
Real boundary is responsibility.&lt;/p&gt;
&lt;h3&gt;
  
  
  I did not pretend mixins are perfect
&lt;/h3&gt;

&lt;p&gt;They preserve shared state and the current public object.&lt;br&gt;
They also make inheritance order matter, that is why the collision test exists.&lt;/p&gt;
&lt;h3&gt;
  
  
  I did not try to remove every piece of technical debt
&lt;/h3&gt;

&lt;p&gt;That would have turned one safe extraction into an endless rewrite.&lt;br&gt;
Codebase only needed to become safer for the next change &lt;strong&gt;&lt;em&gt;and that was enough&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  When this pattern makes sense
&lt;/h2&gt;

&lt;p&gt;A facade plus domain mixins can be a reasonable bridge when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;callers already depend on one stable object;&lt;/li&gt;
&lt;li&gt;many handlers share the same state;&lt;/li&gt;
&lt;li&gt;methods follow a strict naming convention;&lt;/li&gt;
&lt;li&gt;preserving the public surface matters;&lt;/li&gt;
&lt;li&gt;the immediate problem is ownership and navigation;&lt;/li&gt;
&lt;li&gt;tests can guard name collisions and module growth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a poor fit when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;each domain needs separate mutable state;&lt;/li&gt;
&lt;li&gt;components have independent lifecycles;&lt;/li&gt;
&lt;li&gt;dependency boundaries must be explicit;&lt;/li&gt;
&lt;li&gt;method names overlap naturally;&lt;/li&gt;
&lt;li&gt;inheritance order becomes business logic;&lt;/li&gt;
&lt;li&gt;separate services can be introduced without breaking callers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not "the correct Python architecture.", but smallest safe move from one bad state to a better one.&lt;/p&gt;


&lt;h2&gt;
  
  
  What actually changed
&lt;/h2&gt;

&lt;p&gt;From the user’s point of view, almost nothing.&lt;br&gt;
They still ask a question.&lt;br&gt;
Parser still produces an intent, builder still calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;_resp_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same public method still returns the answer.&lt;br&gt;
From my point of view, codebase changed completely.&lt;br&gt;
&lt;strong&gt;File I avoided is gone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The new upgrade feature has its own home, UI no longer waits on slow hardware calls, version number stopped disagreeing with itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the build now refuses several mistakes that used to survive quietly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the part of refactoring people rarely screenshot, Not smaller file. The fear disappearing from the next change.&lt;/p&gt;




&lt;p&gt;PC Workman is free, open-source and offline by design.&lt;/p&gt;

&lt;p&gt;The response-builder split, the architectural guards, the My PC speed-up and the expanded test suite ship in v1.8.5.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;Browse the source on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apps.microsoft.com/detail/9PGW6WS2N50V" rel="noopener noreferrer"&gt;Install PC Workman from the Microsoft Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pcworkman.dev" rel="noopener noreferrer"&gt;Read the project story and technical guides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❤️ &lt;a href="https://buycoffee.to/hcklabs" rel="noopener noreferrer"&gt;If you want to support me, click here :)&lt;/a&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feseuxk8s3rp5ozmhtvxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feseuxk8s3rp5ozmhtvxb.png" alt=" " width="720" height="960"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am Marcin “HCK” Firmuga from Radom, Poland. I repair and weld plastic during the day, then build PC Workman at night. I write about the code that shipped, the assumptions that failed, and the fixes that now have tests behind them.&lt;/p&gt;

</description>
      <category>python</category>
      <category>architecture</category>
      <category>opensource</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>From a Warehouse Floor to the Microsoft Store - PC Workman Marcin Firmuga</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Sun, 19 Jul 2026 13:39:57 +0000</pubDate>
      <link>https://dev.to/huckler/from-a-warehouse-floor-to-the-microsoft-store-pc-workman-marcin-firmuga-8aa</link>
      <guid>https://dev.to/huckler/from-a-warehouse-floor-to-the-microsoft-store-pc-workman-marcin-firmuga-8aa</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://pcworkman.dev/blog/from-a-warehouse-floor-to-the-microsoft-store/" rel="noopener noreferrer"&gt;pcworkman.dev&lt;/a&gt;.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;&lt;u&gt;&lt;a href="https://www.linkedin.com/in/marcinfirmuga/" rel="noopener noreferrer"&gt;Hire me! - LinkedIn :)&lt;/a&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is a temperature a cheap laptop reaches right before it gives up. Mine hits it at 94°C. Fans scream.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For most of last year, that scream was the soundtrack to my nights.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I did not code through those nights out of passion.&lt;br&gt;
I coded because I was scared that if I stopped moving I would vanish,&lt;br&gt;
same quiet way twelve dead projects before this one vanished, and the same quiet way I almost did at twenty-two.&lt;/p&gt;

&lt;p&gt;This morning that fear got the strangest answer I can imagine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PC Workman, the Windows monitor I built on that screaming laptop, alone, broke, between shifts, is live on the Microsoft Store.&lt;/strong&gt;&lt;br&gt;
It is not a ZIP on some forum and it is not a repo you have to clone.&lt;br&gt;
It is a real listing, in the same store as the software I grew up thinking only companies could make.&lt;/p&gt;

&lt;p&gt;Let me tell you how a barcode scanner got there. I will show you the good parts and the desperate parts, and I will show you the actual code, because the code is where both of them ended up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcmrl9p52ym25h3phz9ee.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcmrl9p52ym25h3phz9ee.gif" alt="PC Workman 1.8.0 dashboard, live CPU/GPU/RAM with the offline AI assistant" width="760" height="397"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;PC Workman 1.8.0. Live everything, plus an AI that actually explains it.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The number you never see cross a line
&lt;/h2&gt;

&lt;p&gt;My father died when I was seventeen.&lt;br&gt;
I did not break that week. I broke slowly, over two or three years, and that is the part nobody warns you about. There is no moment. There is no line you catch yourself crossing.&lt;/p&gt;

&lt;p&gt;It works like a power rail sagging. Twelve volts becomes 11.9, then 11.8, and every single reading is still "within spec", so nothing alarms. Then one day you look at the number and it is simply wrong, and you cannot say when that happened. Somewhere around twenty-two, that was me. I gave up on myself quietly, the way almost everyone does it.&lt;/p&gt;

&lt;p&gt;Remember that rail. It comes back later, in code, and I mean that literally.&lt;/p&gt;
&lt;h2&gt;
  
  
  The warehouse
&lt;/h2&gt;

&lt;p&gt;Nine months in a warehouse in the Netherlands. Fifteen kilometres a day on foot, scanning barcodes, for nineteen złoty an hour that turned into about fifteen after deductions.&lt;br&gt;
Call it three and a half euros.&lt;br&gt;
&lt;strong&gt;I did the math on a break once:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;a full nine-hour shift bought roughly one month of the cheapest server hosting I was dreaming about, and I never rented it, because rent for myself came first.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The rhythm was fixed. Shift from morning to evening, dinner from a pan, then six hours at night on a 2014 laptop that thermally throttled if I compiled anything twice in a row.&lt;br&gt;
People ask how long the project took and the honest unit is not months.&lt;br&gt;
It is nights.&lt;/p&gt;

&lt;p&gt;Then, three days before Christmas, the same people who had smiled at me for weeks smiled again and said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"You didn't pass the trial. Tomorrow, goodbye. And out of the apartment."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The 22nd of December. Suitcases stood by the door before I finished understanding the sentence. Two dogs were waiting for me in another country and I had maybe a month of money left.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwwoitaq9j2suv93qxhwj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwwoitaq9j2suv93qxhwj.png" alt="Leaving the Netherlands, 22 December 2025" width="721" height="540"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;22 December. I stood in a corridor and shouted that I wasn't a terrorist, three days before Christmas, in a language that wasn't mine. Long story. Different post.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I did not open a job board that night and I did not write my hundredth identical CV. I opened my editor and started rebuild number four of the monitor. Three weeks later I shipped the first &lt;code&gt;.exe&lt;/code&gt;.&lt;br&gt;
Twelve projects had died before it.&lt;br&gt;
I did not know yet that this was the one that would refuse to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The truest sentence I own from that year: build something, commit something, watch a progress bar move, and feel like you exist. Nobody frames that on a wall. That year it was survival.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  What I actually built
&lt;/h2&gt;

&lt;p&gt;PC Workman answers the question every other monitor dodges:&lt;br&gt;
not &lt;em&gt;whether&lt;/em&gt; your PC is slow, you already know that, but &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You ask it in plain language, through &lt;strong&gt;hck_GPT&lt;/strong&gt;, an assistant that runs entirely on your machine. Under the hood it is a hybrid:&lt;br&gt;
a rule engine with 90 intents and a multi-layer router, plus an optional local model for open questions.&lt;br&gt;
There is no cloud, no API key, and nothing you type ever leaves your computer.&lt;/p&gt;

&lt;p&gt;The routing is unglamorous and that is deliberate.&lt;br&gt;
A message gets tokenized, accent-folded (Polish users type both "wentylatory" and "wentylatory" without diacritics), scored against every intent's phrase list, blended with a small naive-Bayes classifier, and dispatched by name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;why is my pc slow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# ParseResult(intent="why_slow", confidence=0.92, ...)
&lt;/span&gt;
&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_resp_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# bilingual, built from live data
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every handler is a plain method that reads live sensors and real history.&lt;br&gt;
When the data is missing, the assistant says so instead of inventing a number. I wrote that rule into the code review checklist on day one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;an assistant that guesses about your hardware is worse than no assistant.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I could have shipped &lt;code&gt;pip install openai&lt;/code&gt; in an afternoon.&lt;br&gt;
I decided not to, and it was a product decision, not a technical one.&lt;br&gt;
A monitor that reads your machine and then phones a stranger's server to explain it is a contradiction. So the whole intelligence layer runs in the same process that draws the charts, and the privacy page needs one sentence instead of a lawyer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvdutmjmrsv6ii8tf8u6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvdutmjmrsv6ii8tf8u6.gif" alt="hck_GPT, the offline AI assistant answering questions inside PC Workman" width="720" height="376"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;hck_GPT. No internet, no key, nothing sent anywhere. It reads your live machine and answers in plain language.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  A monitor with a memory
&lt;/h2&gt;

&lt;p&gt;Part I actually lose sleep over is memory.&lt;/p&gt;

&lt;p&gt;Every monitor on earth forgets you the second you close it. HWiNFO, Afterburner: open them tomorrow and they will draw your 78°C against the exact same line they draw for every machine that has ever existed.&lt;/p&gt;

&lt;p&gt;The most useful number a monitor can give you is not the temperature.&lt;br&gt;
It is whether &lt;em&gt;this&lt;/em&gt; temperature is normal &lt;em&gt;for you&lt;/em&gt;, on &lt;em&gt;your&lt;/em&gt; machine, doing what you are doing right now.&lt;/p&gt;

&lt;p&gt;So every reading lands in one of five workload buckets:&lt;br&gt;
&lt;strong&gt;&lt;em&gt;idle, light, medium, heavy, gaming&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
Each bucket keeps its own learned normal, folded forward with a Welford accumulator. Three numbers per bucket, updated in constant time, never recomputed from scratch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_welford_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fold one sample into a running accumulator (Welford, 1962).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;mean&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;
    &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;M2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;M2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payoff is a verdict instead of a reading. The same 82°C is fine in the middle of a gaming session and alarming on an idle desktop.&lt;br&gt;
&lt;strong&gt;Same number, opposite meaning, and the difference lives entirely&lt;/strong&gt; in the learned history.&lt;br&gt;
After twelve days on my own machine the idle bucket is calibrated on 613 samples and the gaming bucket is trained on 115, so when something is 14% above &lt;em&gt;my&lt;/em&gt; normal, the app can say exactly that.&lt;/p&gt;
&lt;h2&gt;
  
  
  The oldest math in the project
&lt;/h2&gt;

&lt;p&gt;Voltages get statistics older than my parents. For each rail the analyzer learns a median and a MAD (median absolute deviation), then judges every new sample with a modified z-score.&lt;br&gt;
This is real code from &lt;code&gt;voltage_analyzer.py&lt;/code&gt;, not a sketch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;modified_z&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Modified z-score: M = 0.6745 * (x - median) / MAD.
    Returns 0.0 if MAD is effectively zero (constant signal).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mad&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.6745&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mad&lt;/span&gt;

&lt;span class="nd"&gt;@property&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;normal_band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;The tight &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;expected&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; operating band for this rail.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Z_WATCH&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;_K&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mad&lt;/span&gt;      &lt;span class="c1"&gt;# _K = 1.4826, consistency factor
&lt;/span&gt;    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of that sit Nelson rules from 1984: nine points on the same side of the median, six points trending one direction.&lt;br&gt;
Those rules exist to catch exactly one thing a threshold never will:&lt;br&gt;
the slow sag. A rail that drifts from 12.05 V to 11.88 V over weeks trips no limit, because every individual reading is legal. The pattern is the alarm.&lt;/p&gt;

&lt;p&gt;Now, the rail from earlier. I am the one that sagged for three years inside spec while everyone, me included, swore nothing was wrong.&lt;/p&gt;

&lt;p&gt;I built the alarm I never had. It is statistics from the sixties babysitting a power supply, boring and predictable, and that is exactly why I trust it. Statistics never hallucinate. People do.&lt;/p&gt;

&lt;p&gt;People looked me in the eye at &lt;strong&gt;3.5€ an hour and said&lt;/strong&gt; the rate would improve. It never improved. The math, at least, never lied to me.&lt;/p&gt;
&lt;h2&gt;
  
  
  A year, measured in releases
&lt;/h2&gt;

&lt;p&gt;You never see the grind. You see the version number.&lt;/p&gt;

&lt;p&gt;Here is the receipt. It started as a prototype that could barely draw a graph. Then a first stable &lt;code&gt;.exe&lt;/code&gt;.&lt;br&gt;
Then a SQLite stats engine with minute-to-month aggregation.&lt;br&gt;
Then the hybrid AI, a Startup manager, a Services manager.&lt;br&gt;
Its biggest quality jump the project ever had, and then Smart Learning, the release where the monitor finally got its memory.&lt;/p&gt;

&lt;p&gt;Eleven releases, over eight hundred commits, four complete rebuilds of the interface. Every one of them written after a shift, on the same warm laptop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzeb89am5jk4q78a2u0d7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzeb89am5jk4q78a2u0d7.png" alt="Welding by day, the physical job behind the project" width="520" height="654"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;These days it is a welding gun by day. Hot air, melting plastic back together. The welding taught me the one thing the learning engine needed: you don't get an eye for hot metal from a manual. Cherry red, straw, blue that means you've gone too far. It accumulates. You earn it.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Microsoft said no. Then Microsoft said yes.
&lt;/h2&gt;

&lt;p&gt;Two weeks ago I published a post called &lt;em&gt;"Microsoft said no."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My first &lt;code&gt;.msix&lt;/code&gt; got rejected, and not for the code.&lt;/strong&gt;&lt;br&gt;
The blockers were a blurry tile icon and a privacy-policy link that pointed at my security policy instead.&lt;/p&gt;

&lt;p&gt;A year of voltage-anomaly math and offline AI, and what stopped me at the gate was a fuzzy PNG. The reviewer was right. It stung anyway.&lt;/p&gt;

&lt;p&gt;So I fixed both. I drew a crisp icon, wrote a real privacy policy that lives where a privacy policy should, and folded in thirteen more fixes my testers had found while I waited.&lt;br&gt;
Then I resubmitted and went back to work, because waiting with the app open in another window does not make certification faster.&lt;/p&gt;

&lt;p&gt;This morning the status changed to approved.&lt;br&gt;
A rejection that says "fix these two things and resubmit" was never a no.&lt;br&gt;
It was the Store telling me how close I was.&lt;/p&gt;

&lt;p&gt;The Store also fixes something on your side of the screen.&lt;br&gt;
You no longer have to trust a stranger's ZIP.&lt;/p&gt;

&lt;p&gt;Every build is Sigstore-signed, clean on VirusTotal, and checked by CodeQL on every commit. That paranoia was in the project from the first release. The listing just makes it visible.&lt;/p&gt;
&lt;h2&gt;
  
  
  What the first weeks on the Store taught me
&lt;/h2&gt;

&lt;p&gt;A listing is a promise, and promises get tested fast.&lt;/p&gt;

&lt;p&gt;Within days a tester hit the worst bug of the project's life: &lt;strong&gt;under long, heavy sessions the app could freeze the entire computer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;White screen, dead desktop, restart to recover.&lt;br&gt;
A monitor that can freeze the machine it monitors is not a monitor, so everything else stopped until this was dead.&lt;/p&gt;

&lt;p&gt;The root cause was one missing guard.&lt;br&gt;
My optimizer had a single primitive that suspends idle processes to save resources, and it checked for anti-cheat software but nothing else. Nothing stopped it from suspending &lt;code&gt;dwm.exe&lt;/code&gt;, the process that literally draws the Windows desktop, or from suspending PC Workman itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix went in at the lowest level, so every optimization path got safe at once:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sleep_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# ONE central guard for every process primitive: anti-cheat engines,
&lt;/span&gt;    &lt;span class="c1"&gt;# ~30 OS-critical processes (dwm, explorer, csrss, lsass...),
&lt;/span&gt;    &lt;span class="c1"&gt;# and PC Workman's own pid. No caller can forget to check.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_protected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nf"&gt;is_self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second lesson was cheaper but it changed how I work:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the test suite went from 21 tests to 46 within two weeks of the listing, &amp;gt; and the most valuable ones are the tests that guard against my own &amp;gt; future mistakes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A store listing means strangers update on your word.&lt;br&gt;
The suite is what makes that word worth something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And one more thing nobody tells you:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;the first support message from a person you have never met, about a machine you will never see, feels bigger than the approval email did.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The kid who was afraid of disappearing
&lt;/h2&gt;

&lt;p&gt;For the first months I shipped into an empty room. Thirty views on a post.&lt;br&gt;
Zero stars on the repo.&lt;br&gt;
You write into that silence long enough and you start to wonder whether you are really there at all.&lt;/p&gt;

&lt;p&gt;Then one of my articles reached forty-four thousand people, and I wrote the most honest thing I have ever put online:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;that I keep building because I am terrified of disappearing, and that I &amp;gt; ship code to prove I still exist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I do not have a clean ending for that fear, and anyone who sells you one is lying.&lt;/p&gt;

&lt;p&gt;But I have this. A permanent listing in the Microsoft Store is about the most concrete "I exist" a solo developer can get.&lt;br&gt;
The kid who quietly quit at twenty-two did not stay quit. The rail that sagged inside spec finally got its alarm.&lt;/p&gt;

&lt;p&gt;Twelve projects had to die so this one could stand in a store next to software made by companies with a thousand engineers and a real salary each.&lt;/p&gt;

&lt;p&gt;I built a program that learns for the entire life of the install.&lt;br&gt;
I learn for the life of mine. This grind is a year old, it has not ended, and it is not going to.&lt;/p&gt;

&lt;p&gt;I have finally understood that this is not the tragedy of the story.&lt;br&gt;
It is the proof of it. A finished man has nothing left to recover.&lt;br&gt;
&lt;strong&gt;&lt;u&gt;I get to keep going. That is a pulse.&lt;/u&gt;&lt;/strong&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%2Fpcworkman.dev%2Fassets%2Fimages%2Fmyselfie_dogs.jpg" 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%2Fpcworkman.dev%2Fassets%2Fimages%2Fmyselfie_dogs.jpg" alt="Marcin with two dogs, Kacia and Lusia" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Kacia (11) and Lusia (2). Best teammates for the breaks. Kacia has slept through every release since 1.0. Still here, all three of us.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Thank you.&lt;/strong&gt; To every tester who spent hours breaking things I would never have found alone. To the strangers whose questions turned into real features. To everyone who starred the repo, read a post, or just said "keep going". This one is yours too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PC Workman is &lt;strong&gt;free and open source (MIT)&lt;/strong&gt;. No accounts, no cloud AI, nothing leaves your machine. Physical work by day, code by night, the same rhythm that built every line of it. The next chapter is already loading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Still here. Still shipping.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;PC Workman is free, runs entirely on your machine, and after a year it's on the Microsoft Store.&lt;/strong&gt;&lt;br&gt;
1,100+ downloads · 64 GitHub stars · Sigstore-signed · VirusTotal-clean · open source (MIT).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.microsoft.com/detail/9PGW6WS2N50V" rel="noopener noreferrer"&gt;&lt;strong&gt;Install it from the Microsoft Store&lt;/strong&gt;&lt;/a&gt;: one click, no account, no cloud.&lt;br&gt;
Not on Windows yet? &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;Star the repo&lt;/a&gt; or &lt;a href="https://linktr.ee/marcin_firmuga" rel="noopener noreferrer"&gt;follow the build&lt;/a&gt;. I ship in public, every week.&lt;/p&gt;

&lt;p&gt;And I read every single comment: &lt;strong&gt;if an AI lived inside your PC, what is the first thing you would ask it?&lt;/strong&gt; The best questions become real features. Twenty-eight of them already have.&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>ai</category>
      <category>career</category>
    </item>
    <item>
      <title>The Man Who Got Himself Back - Marcin HCK Firmuga</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Mon, 29 Jun 2026 07:25:48 +0000</pubDate>
      <link>https://dev.to/huckler/the-man-who-got-himself-back-marcin-hck-firmuga-2ch8</link>
      <guid>https://dev.to/huckler/the-man-who-got-himself-back-marcin-hck-firmuga-2ch8</guid>
      <description>&lt;p&gt;&lt;em&gt;The Man Who Got Himself back&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;PC Workman 1.8.0 is the release where my system monitor finally learned to remember your machine.&lt;/strong&gt; It's also the story of the year I spent getting mine back.&lt;br&gt;
&lt;em&gt;&lt;strong&gt;I've stopped being able to tell those two apart.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I had to shout at a man that I'm not a terrorist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;SNF (Stichting Normering Flexwonen)&lt;/strong&gt;&lt;br&gt;
was the only thing that stopped him from putting me on the street that night, out of the apartment the work agency had housed me in for four months. Building was certified. I knew my rights.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;He was gambling that I didn't.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I stood in a corridor somewhere in the Netherlands and screamed the single most absurd sentence of my life, three days before Christmas.&lt;br&gt;
&lt;strong&gt;In a foreign language.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For weeks the people at that job had smiled at me.&lt;br&gt;
Then, wearing the same smile:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You didn't pass the trial. Tomorrow, goodbye and out of the apartment."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The 22nd of December.&lt;br&gt;
My suitcases were by the door before I'd finished understanding the sentence. Two dogs waiting for me in another country. A laptop that climbs to 94°C if I ask it to think too hard. Maybe a month of money left.&lt;/p&gt;

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

&lt;p&gt;I'm telling you this first because that corridor is where this project was made, and four nights ago, at three in the morning, it's still where it's being made.&lt;br&gt;
PC Workman, the thing I shipped this week, was written in conditions like that, and it is still being written in conditions like that.&lt;/p&gt;

&lt;p&gt;So yes, this is a release note. 1.8.0 is out:&lt;br&gt;
the version where my monitor finally remembers your machine instead of meeting it like a stranger every time you open it.&lt;br&gt;
But I'd be lying if I sold it to you as software and stopped there.&lt;/p&gt;

&lt;p&gt;Because the twelve months I spent teaching a program to remember are the same twelve months I spent getting myself back.&lt;br&gt;
And here's about I didn't expect to be able to write down:&lt;br&gt;
&lt;strong&gt;somewhere in that year, I found the guy who went missing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;He'd been in the code the whole time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number you never see cross a line
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;My father died when I was seventeen.&lt;br&gt;
I didn't break that week.&lt;br&gt;
I broke slowly, over the next two or three years, and that's something no one warns you about:&lt;br&gt;
&lt;strong&gt;there's no moment.&lt;/strong&gt; No threshold you catch yourself crossing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's a power rail sagging: 12 volts becomes 11.9, becomes 11.8, and every reading is still "&lt;em&gt;&lt;strong&gt;within spec&lt;/strong&gt;&lt;/em&gt;" so nothing alarms, and then one day you look at the number and it's just wrong, and you have no idea when that happened.&lt;/p&gt;

&lt;p&gt;I went through technical school on fumes. INF.02 on the paper, nothing behind it. And somewhere around 2022, after school handed me the entire weight of being an adult all at once, I gave up on myself. Quietly. The way almost everyone does it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part people will either love or refuse to print:
&lt;/h2&gt;

&lt;p&gt;it was AI that helped me find the exact day I quit.&lt;br&gt;
Bounced between agencies whose names I never learned,&lt;br&gt;
I started talking to a machine the way you'd talk to the one person who never gets tired of you, and it helped me locate the moment, the decision, the sag.&lt;/p&gt;

&lt;p&gt;And the second I could see it, I could refuse it. That's the whole thesis, honestly. You cannot fix a number you never learned to measure.&lt;/p&gt;

&lt;p&gt;So I made a decision that looks stupid typed out and felt like survival at 3 a.m.: I will not let this grind me into one more used-up man it spits out the far end. I'll work while I have strength. I'll learn one thing a day. I'll build out loud, in public, so I can't quietly vanish. And I will not, at thirty, look in a mirror and hate the kid who stopped trying at twenty-two.&lt;/p&gt;

&lt;p&gt;Then I opened my editor.&lt;/p&gt;

&lt;p&gt;A monitor that remembers you&lt;br&gt;
PC Workman tells you why your PC is slow, not just that it is. It learns your machine — your temperatures by workload, your voltage patterns, the games you actually play — and it talks to you through an offline AI assistant I wrote called hck_GPT. 84 intents, no cloud, no API key, all of it running on your own metal.&lt;/p&gt;

&lt;p&gt;There's one-click optimization, ghost-driver detection for hardware you ripped out years ago, an in-game overlay that starts empty and shows only what you choose, and a small antivirus that checks who really signed a process instead of trusting the name.&lt;/p&gt;

&lt;p&gt;The 1.8.0 receipts: 84 intents, 373 known processes, 40+ games it greets by name, 21/21 tests green, ~790 downloads across SourceForge and GitHub, 61 stars — and twelve dead projects buried behind it.&lt;/p&gt;

&lt;p&gt;But the headline of 1.8.0 is the only part I actually lose sleep over. Memory.&lt;/p&gt;

&lt;p&gt;Every monitor on earth forgets you the second you close it.&lt;br&gt;
HWiNFO, Afterburner, open them tomorrow and they'll draw your 78°C against the exact same line they draw for every machine that has ever existed.&lt;br&gt;
I couldn't live with that.&lt;br&gt;
The most useful number a monitor can give you isn't the temperature.&lt;br&gt;
It's whether this temperature is normal for you, and to answer that, the thing has to remember.&lt;/p&gt;

&lt;p&gt;So every reading falls into one of five workload buckets, and each keeps its own learned normal:&lt;br&gt;
&lt;code&gt;def classify(self, cpu_load, gpu_load=0.0):&lt;br&gt;
    """Return the workload bucket for the given CPU / GPU utilisation."""&lt;br&gt;
    if (gpu_load or 0.0) &amp;gt;= 60.0:  return "gaming"&lt;br&gt;
    cl = cpu_load or 0.0&lt;br&gt;
    if cl &amp;lt; 15.0:  return "idle"&lt;br&gt;
    if cl &amp;lt; 40.0:  return "light"&lt;br&gt;
    if cl &amp;lt; 70.0:  return "medium"&lt;br&gt;
    return "heavy"&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;82°C while you game: fine.&lt;br&gt;
82°C sitting idle: something's wrong.&lt;br&gt;
Same number, opposite verdict, judged against your own past instead of a spec line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And it does not forget. I tore out the old 14-day window and rebuilt it as a Welford accumulator:&lt;/strong&gt; three numbers per workload, a running count,&lt;br&gt;
a mean, and a thing called M2 — folded forward, never recomputed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
def _welford_add(acc, x):&lt;br&gt;
    """Fold one sample into a running accumulator (Welford, 1962)."""&lt;br&gt;
    n     = acc["n"] + 1&lt;br&gt;
    delta = x - acc["mean"]&lt;br&gt;
    mean  = acc["mean"] + delta / n&lt;br&gt;
    acc["n"]    = n&lt;br&gt;
    acc["mean"] = mean&lt;br&gt;
    acc["M2"]   = acc["M2"] + delta * (x - mean)&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It keeps learning for the entire life of the install, and the learned shape survives even after the raw data gets pruned at ninety days.&lt;br&gt;
Detail rolls off.&lt;br&gt;
Shape of your machine stays.&lt;br&gt;
That's the whole memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statistics from the 1960s, babysitting your power supply
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Voltages got the oldest math in the project.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Spec says your 12V rail is fine anywhere between 11.4 and 12.6. Technically true, practically uselessm a healthy supply doesn't roam that whole band, but holds tight, around 11.95 to 12.05.&lt;/p&gt;

&lt;p&gt;So instead of the spec, PC Workman learns the median and spread of your rail and runs Nelson rules from 1984 on top of it, hunting the slow sag the threshold will never catch.&lt;/p&gt;

&lt;p&gt;It scores every reading against your own history with a modified z-score, median and MAD, not mean and σ, because one spike drags an average up and lets the next one sail through:&lt;br&gt;
&lt;code&gt;M = 0.6745 × (x − median) / MAD&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A drift to 11.7V is invisible to the spec and screams against your own history. Early warning, months before anything actually dies.&lt;/p&gt;

&lt;p&gt;You already know why I had to build that. I am the rail that sagged for three years inside spec while everyone, me included swore nothing was wrong. I built the alarm I never had.&lt;/p&gt;

&lt;p&gt;Sixty-year-old statistics babysitting a power supply.&lt;br&gt;
Boring, predictable, and that is exactly why I trust them.&lt;br&gt;
Statistics don't hallucinate. People do. People looked me in the eye at 19 PLN an hour and said, "just try harder, the rate will get better."&lt;br&gt;
It never got better. Math, at least, never lied to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Written after the shift
&lt;/h2&gt;

&lt;p&gt;I need you to see where this actually gets made, because it changes how you read everything above.&lt;/p&gt;

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

&lt;p&gt;PC Workman does not get built in a clean bedroom with a mechanical keyboard and a ring light. It gets built after I weld.&lt;br&gt;
Hot air, a gun, melting plastic grates back together in a workshop, and then I go home, open a laptop from 2014, and write a Welford accumulator on it.&lt;/p&gt;

&lt;p&gt;That contrast used to embarrass me.&lt;br&gt;
It doesn't anymore, because the welding taught me the one thing the memory engine needed. You don't get an eye for hot metal from a manual.&lt;br&gt;
It accumulates, cherry red, straw, blue that means you already gone too far.&lt;br&gt;
Nobody hands it to you. You earn it by burning enough of it until the knowledge in your hands is yours and not the chart's.&lt;br&gt;
That's the entire philosophy of the learning engine, and I learned it with a heat gun before I ever wrote it in Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fear changed shape
&lt;/h2&gt;

&lt;p&gt;Here's what I only understood this week, and have never written before.&lt;/p&gt;

&lt;p&gt;For a year the fear was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm scared of disappearing, so I build. Commit something, watch a progress bar move, prove I still exist. That fear is loud but clean.&lt;br&gt;
When you've got nothing, you've got nothing to lose, and that turns out to be its own brutal kind of freedom.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Then something I made hit #1 trending on HackerNoon and held it there for two days.&lt;/strong&gt;&lt;br&gt;
I have a small, real community now, people who spend eight hours stress-testing my releases and then come back.&lt;br&gt;
And the fear quietly mutated into something heavier:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;now I have something I can lose.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;It took me off the board for a week.&lt;br&gt;
I cried for three days. Not from joy.&lt;/strong&gt;&lt;br&gt;
From a flavor of dread I didn't have a word for. It was a fluke.&lt;br&gt;
I'll lose it all. Maybe it only works once. Impostor syndrome, except impostor syndrome while you're broke and welding plastic to eat is a different animal entirely.&lt;br&gt;
It rides shotgun with every single small win, every day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But under the dread was the truest sentence I own, and I'm almost proud of it:&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;I went from trying to gain to having something to protect.&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
The second one is a step higher up the stairs even when he's the one sitting on them, crying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three in the morning
&lt;/h2&gt;

&lt;p&gt;Monday I shipped 1.8.0.&lt;br&gt;
It was supposed to go out four days earlier.&lt;br&gt;
I kept pushing it back because I kept finding &lt;strong&gt;&lt;u&gt;more&lt;/u&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;u&gt;more bugs&lt;/u&gt;&lt;/strong&gt; to kill, &lt;strong&gt;&lt;u&gt;more to test&lt;/u&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;u&gt;more of&lt;/u&gt;&lt;/strong&gt; the machine to &lt;strong&gt;&lt;u&gt;teach&lt;/u&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;u&gt;more reasons&lt;/u&gt;&lt;/strong&gt; not to put my name on something half-true.&lt;br&gt;
In four days I did close to two weeks of work.&lt;/p&gt;

&lt;p&gt;I clicked publish at three in the morning.&lt;br&gt;
Then I lay down to sleep, and from three until twenty past four I stared at the ceiling and asked the only question that ever really comes for me at that hour: &lt;strong&gt;&lt;em&gt;&lt;u&gt;does any of this mean anything.&lt;/u&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I get that question every two to four days. Always at night.&lt;br&gt;
And here's the thing I've learned to trust like a law of physics:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;it lasts about an hour. Sometimes two, sometimes three. And then I beat it, all the way, not halfway. And the motivation comes back whole, like nothing happened.&lt;/p&gt;

&lt;p&gt;You don't argue with weather. You survive the hour, and you wait for the part where time and stubbornness pay you back.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At 4:20 I stopped asking. By nine I was writing this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The man who got himself back
&lt;/h2&gt;

&lt;p&gt;I wanted to title this The Man Who Got Himself Back. In Polish, my language — "Człowiek odzyskał siebie." It's a beautiful title. It's also a lie, and I'd rather hand you the truth, because it's the one thing on this entire page I'm actually sure of.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You don't get yourself back once.&lt;/strong&gt; There's no ceremony,&lt;br&gt;
though one did land in my hands the same Monday I shipped this, a Google one:&lt;br&gt;
&lt;strong&gt;&lt;u&gt;Skills of Tomorrow 3.0 AI, five weeks that felt exactly like the accumulator, not knowledge downloaded, knowledge folded in, slowly, never recomputed.&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But certificate isn't the moment. Moment is smaller, and it repeats.&lt;/strong&gt;&lt;br&gt;
You get yourself back at twenty past four in the morning, when the question comes and you outlast it one more time.&lt;br&gt;
You get yourself back the next night the laptop boots warm and you write one more function instead of closing the lid.&lt;/p&gt;

&lt;p&gt;My monitor learns for the life of the install.&lt;br&gt;
I learn for the life of mine. This grind is twelve months old, it has not ended, and it is not going to, and I've finally understood that this is not the tragedy of the story. It's the proof of it.&lt;br&gt;
A finished man has nothing left to recover.&lt;br&gt;
I get to keep recovering. That's a pulse.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I get myself back. Every morning.&lt;br&gt;
Not yet not today. I'm still here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Find me (and maybe the first coffee?)
&lt;/h2&gt;

&lt;p&gt;PC Workman 1.8.0 is free and open source (MIT), one ZIP, no installer, no account, runs locally on your machine.&lt;/p&gt;

&lt;p&gt;⭐ Star / download: github.com/HuckleR2003/PC_Workman_HCK&lt;br&gt;
Site: pcworkman.dev&lt;br&gt;
Coffee: buycoffee.to/hcklabs&lt;br&gt;
Everything (LinkedIn - X - Dev.to):&lt;br&gt;
linktr.ee/marcin_firmuga&lt;/p&gt;

&lt;p&gt;Polish version: pcworkman.dev/blog/the-man-who-got-himself-back_pl&lt;/p&gt;

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

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I'm Marcin Firmuga,&lt;/strong&gt; solo developer and founder of HCK_Labs.&lt;/p&gt;

&lt;p&gt;I created PC Workman, an open-source, AI-powered PC resource monitor that learns your PC's natural behavior over time, spikes, voltages, temperatures, usage built entirely from scratch on dying hardware during warehouse shifts in the Netherlands.&lt;/p&gt;

&lt;p&gt;Before this:&lt;br&gt;
game translations, PC-technician internships, warehouse operations in multiple countries, and countless failed projects I never finished.&lt;/p&gt;

&lt;p&gt;But this one? This one stuck. Twelve months of code. Four complete UI rebuilds. 26,000 lines deleted, ~50,000 total. 3 a.m. all-nighters. Energy drinks and toast. And my own hck_GPT AI, built over months to give PC Workman a brain and a heart.&lt;/p&gt;

&lt;p&gt;And finally, an app I wouldn't close in five seconds. That's the difference between building and shipping.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Built solo and in public by Marcin "HCK" Firmuga - 22, Radom, Poland. After the welding shift, on a 2014 laptop, in the hour between the night breakdowns. GitHub: HuckleR2003 · pcworkman.dev. Still shipping.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>Your PC Monitor Shows Numbers. It Should Understand Your Machine - Marcin Firmuga</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Tue, 16 Jun 2026 12:38:17 +0000</pubDate>
      <link>https://dev.to/huckler/your-pc-monitor-shows-numbers-it-should-understand-your-machine-marcin-firmuga-4mm2</link>
      <guid>https://dev.to/huckler/your-pc-monitor-shows-numbers-it-should-understand-your-machine-marcin-firmuga-4mm2</guid>
      <description>&lt;p&gt;Your PC monitor shows numbers. It should understand your machine.&lt;/p&gt;

&lt;p&gt;I wrote most of this article in the evening, after a day of welding plastics at a repair shop.&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%2Fr3aj3ju8jwt3a2s1el5t.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%2Fr3aj3ju8jwt3a2s1el5t.png" alt=" " width="605" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's the honest setup. My savings ran out.&lt;/strong&gt;&lt;br&gt;
My IT applications stay silent. So three days ago I started a temporary job that has nothing to do with code, and I write this at night, &lt;strong&gt;&lt;em&gt;the same rhythm this whole project was built in for 11 months.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But here's the part that keeps me going:&lt;/strong&gt;&lt;br&gt;
the thing I'm about to explain isn't a plan or a pitch.&lt;/p&gt;

&lt;p&gt;It's working code in a free, open-source tool you can download right now and read line by line. Industrial-grade statistics, running on your PC, learning your specific machine.&lt;br&gt;
Built by someone who codes between shifts.&lt;/p&gt;

&lt;p&gt;Let me show you why every traditional PC monitor is fundamentally limited  and what learning your specific hardware actually looks like in code.&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%2Fn8t7x77ezzyqhxbpt39b.gif" 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%2Fn8t7x77ezzyqhxbpt39b.gif" alt=" " width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The threshold is dumb by design
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Open any popular system monitor and it does one thing:&lt;/strong&gt;&lt;br&gt;
draws 78°C on a graph. Red when it crosses 80. That's it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It has no idea whether that 78°C is your idle on a hot July afternoon, or gaming on a cooler that's been collecting dust for six months. To the monitor, 78 is just 78.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The threshold is dumb by design.&lt;br&gt;
&lt;strong&gt;That's not an insult but it's its nature.&lt;/strong&gt;&lt;br&gt;
Rule&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"if temp &amp;gt; X, alert"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;has no concept of what it's running on. It doesnt remember yesterday.&lt;br&gt;
It doesn't know your &lt;strong&gt;RTX always holds 71°C in this game&lt;/strong&gt;, and today it s*&lt;em&gt;uddenly hits 77 at the same load in the same room&lt;/em&gt;*.&lt;br&gt;
The threshold only sees a number against a constant somebody hardcoded for every machine in the world at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And here's the most important sentence in this article:&lt;/strong&gt;&lt;br&gt;
your machine isn't in any table.&lt;/p&gt;
&lt;h2&gt;
  
  
  How these tools actually work
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Before anyone says "but I have Afterburner and it's great" — sure, it is.&lt;br&gt;
Let's just look at what it actually does under the hood.&lt;br&gt;
And what the others do, because each one is excellent at one thing and blind in another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;MSI Afterburner / RivaTuner:&lt;/strong&gt;&lt;br&gt;
a hand-drawn fan curve (lookup table) and a fixed clock/voltage offset.&lt;br&gt;
Zero learning. The curve is a table.&lt;br&gt;
"Set and forget" OC doesn't know about silicon aging or ambient temperature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fan Control / Argus Monitor:&lt;/strong&gt;&lt;br&gt;
highly configurable, but still rules and triggers that YOU define.&lt;br&gt;
You are the intelligence. The program just executes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HWiNFO / HWMonitor:&lt;/strong&gt; the gold standard for raw sensor data.&lt;br&gt;
Zero recommendations, zero memory. Pure readout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CCleaner:&lt;/strong&gt; deletes temp files and "cleans the registry".&lt;br&gt;
Registry cleaning is a 2026 myth, Microsoft itself advises against it, performance gain is roughly zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GeForce Experience / Armoury Crate / iCUE:&lt;/strong&gt;&lt;br&gt;
cloud database of GPU+game, presets by hardware category.&lt;br&gt;
A profile for "RTX 4070," not for your specific card or your temperatures. Phones home.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notice the pattern.&lt;/strong&gt;&lt;br&gt;
Every one is a different way to do the same two things:&lt;br&gt;
show data, or execute a rule somebody set in advance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;None of them builds a model of your computer.&lt;/strong&gt;&lt;br&gt;
At best, you are the intelligence, sitting there setting curves by hand.&lt;br&gt;
At worst, the cloud is the intelligence, it knows you have an "RTX 4070" and has no clue your specific unit runs 6 degrees hotter than your neighbor's with the same SKU.&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%2Fcv0bo9muqammixlq085a.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%2Fcv0bo9muqammixlq085a.png" alt=" " width="416" height="322"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Four reasons "general" is weak
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Silicon lottery.&lt;/strong&gt;&lt;br&gt;
Two identical RTX 4070s from the same production line aren't identical.&lt;br&gt;
Different voltage-frequency curves, different leakage, different undervolt headroom. &lt;strong&gt;Gap can reach 50-100 mV&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That forum advice "&lt;em&gt;for a 4070 do -100 mV, works for me&lt;/em&gt;" will crash half the units to a black screen, because half don't have that headroom.&lt;br&gt;
A general profile physically cannot know your silicon.&lt;br&gt;
It saw an averaged card you don't own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aging and drift.&lt;/strong&gt;&lt;br&gt;
Thermal paste pumps out over a year or three, and temperatures climb a few degrees. Fan bearings wear. PSU capacitors age and lose capacitance.&lt;br&gt;
A fixed profile never adapts, because it was written once.&lt;br&gt;
Your "stable" OC from last year throws silent soft-errors today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ambient and context.&lt;/strong&gt;&lt;br&gt;
The same load at 18°C in winter and 28°C in summer produces different core temperatures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"if temp &amp;gt; X"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rule is blind to this. It doesn't know your room, the season, or that you opened a window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Load composition.&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;"Game + Discord + browser + OBS" is a completely different thermal profile than the game alone.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A Blender render (sustained 100% for an hour) behaves differently than a game (bursty spikes) and differently than a crypto miner (pegged full).&lt;br&gt;
General thresholds treat load as if it exists in isolation.&lt;br&gt;
In real life it never does.&lt;/p&gt;
&lt;h2&gt;
  
  
  Voltages. This is where it all comes together.
&lt;/h2&gt;

&lt;p&gt;If you remember one example from this article, remember this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ATX spec for the 12V rail allows ±5%.&lt;/strong&gt; So anything from 11.4V to 12.6V is formally "within norm".&lt;br&gt;
Every classic monitor only alerts you once voltage leaves that band.&lt;/p&gt;

&lt;p&gt;But a healthy PSU doesn't float across that whole range.&lt;br&gt;
A healthy PSU holds your rail much, much tighter, around 11.95-12.05V. That's a real ±0.4%, not ±5%.&lt;/p&gt;

&lt;p&gt;Now: your PSU starts aging.&lt;br&gt;
Under load the rail drops to 11.7V.&lt;br&gt;
Still "&lt;strong&gt;&lt;em&gt;in spec&lt;/em&gt;&lt;/strong&gt;"! The threshold says OK, you're fine.&lt;br&gt;
But those are tired capacitors making themselves known, months, sometimes half a year before the system starts failing under heavier load.&lt;/p&gt;

&lt;p&gt;This is where statistics computed on your history come in, not on a spec sheet.&lt;br&gt;
PC Workman keeps the median and MAD (median absolute deviation) of your own samples and computes a modified Z-score per &lt;strong&gt;Iglewicz&lt;/strong&gt;-&lt;strong&gt;Hoaglin&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;M = 0.6745 × (x − median) / MAD
|M| &amp;gt; 3.5  → anomaly
|M| &amp;gt; 2.5  → warning
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A drop to 11.7V, invisible to the ATX threshold, runs well past 3.5 against your own 11.95-12.05V norm. &lt;strong&gt;&lt;em&gt;Anomaly&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An early warning no threshold on earth catches, because the threshold looks at the manufacturer's spec, not at how this specific PSU behaved over the last few weeks.&lt;/p&gt;

&lt;p&gt;Why median, not mean? Because the mean is a coward.&lt;br&gt;
One voltage spike drags the mean up, widens the band, and the next spike passes without an alarm, the tool anesthetizes itself.&lt;/p&gt;

&lt;p&gt;The median doesn't move after one outlier.&lt;br&gt;
MAD inherits that robustness.&lt;br&gt;
Add four Nelson Rules (single spike, 2-of-3 cluster, nine points on one side, six-point monotonic trend), that's &lt;strong&gt;classic Statistical Process Control&lt;/strong&gt;, the same kind factories have used to watch production lines for decades.&lt;br&gt;
I'm not reinventing the wheel.&lt;br&gt;
I moved proven process control onto your PC's power rail.&lt;/p&gt;

&lt;p&gt;That's the whole thesis in one picture: an absolute spec threshold versus statistical control against your own history.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wait, "AI," meaning what exactly?
&lt;/h2&gt;

&lt;p&gt;I have to say this plainly, or the whole article goes in the trash with the marketing nonsense:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"AI" here does not mean a chatbot bolted onto an old tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's no GPT stapled on that "intelligently analyzes your hardware" and in practice makes things up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Underneath sits real statistics:&lt;/strong&gt; **Welford's **algorithm for online mean and variance (one pass, no keeping the whole history in RAM), median and MAD for voltages, Nelson Rules, process control.&lt;/p&gt;

&lt;p&gt;These are methods from the '60s and '90s, boring, predictable, and that's exactly why I trust them.&lt;br&gt;
Statistics don't hallucinate.&lt;/p&gt;

&lt;p&gt;When someone says "AI in a monitor," 95% of the time it means&lt;br&gt;
"we pasted in an API and now it costs more".&lt;br&gt;
&lt;strong&gt;Here it's the opposite, the model learns locally, on your data, with no account and nothing sent anywhere.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The six lines that start it all
&lt;/h2&gt;

&lt;p&gt;The whole context-aware system begins with one tiny function. This is the actual code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cpu_pct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu_pct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;gpu_pct&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gaming&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cpu_pct&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;idle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cpu_pct&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;light&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cpu_pct&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heavy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Five contexts:&lt;/strong&gt; &lt;em&gt;gaming, idle, light, medium, heavy&lt;/em&gt;.&lt;br&gt;
That's the secret.&lt;/p&gt;

&lt;p&gt;Once the system knows the context, it learns what "normal" means inside it.&lt;br&gt;
Not normal in general.&lt;br&gt;
Normal for your machine, doing what it's doing right now.&lt;br&gt;
Each snapshot lands in one of five buckets, and each bucket keeps its own learned baseline using **Welford's **online algorithm over your last 14 days of history.&lt;/p&gt;

&lt;p&gt;An 80°C threshold for everything is lazy.&lt;br&gt;
72°C while gaming on a mid-tower is fine.&lt;br&gt;
&lt;strong&gt;The same 72°C while idle on a thin laptop means something is wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it actually beats the threshold
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Predictive maintenance&lt;/strong&gt;, the killer feature.&lt;br&gt;
Voltage drift caught by MAD and Nelson Rules means tired capacitors.&lt;br&gt;
A systematic +3-5°C climb over weeks means paste needs replacing, caught before the CPU throttles.&lt;br&gt;
Falling RPM-to-temperature efficiency means dust in the heatsink.&lt;br&gt;
Catching problems before they become problems.&lt;br&gt;
A threshold can't do this by definition, it waits until things are already bad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root-cause throttling&lt;/strong&gt; instead of "CPU hot".&lt;br&gt;
A general tool says: 95°C, a lot.&lt;br&gt;
&lt;strong&gt;The model says:&lt;/strong&gt; 95°C, but only during game+render, and that's +6°C above your 30-day norm for this specific load, most likely dust or paste, here's the trend chart, see for yourself.&lt;br&gt;
The second answer contains a cause.&lt;br&gt;
The first is just a number with an exclamation mark.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anomaly as security.&lt;/strong&gt; A process pretending to be svchost.exe but launched from %TEMP%.&lt;br&gt;
An unusual CPU pattern that looks like a quiet miner.&lt;br&gt;
Pattern-against-your-norm catches things a signature list doesn't know, because you don't need to know the threat's name, you just need to know this machine never behaved like this before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The analogy that closes it
&lt;/h2&gt;

&lt;p&gt;Whoop and Garmin don't tell you&lt;br&gt;
"your resting heart rate is 60, norm is 60-100, you're OK".&lt;br&gt;
They learn your resting HR and HRV, and alert when you drift from your baseline, even if you're still within "population norm".&lt;br&gt;
&lt;strong&gt;That's how they catch something happening a day before you feel it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PC Workman is exactly that, for your computer.&lt;br&gt;
"78°C" without your baseline is like a heart rate of 100 without knowing whether you're looking at a marathon runner after training or someone who just climbed to the second floor out of breath.&lt;br&gt;
&lt;strong&gt;Same number, two completely different worlds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The whole difference is context — and a threshold has none.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honestly: where this has limits
&lt;/h2&gt;

&lt;p&gt;I won't sell you this as magic, because it isn't, and a text pretending its product has no flaws disqualifies itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cold-start.&lt;/strong&gt; Fresh after install,&lt;br&gt;
the model doesn't know your norm yet, it has to gather data for weeks, realistically 6-12 months, to pass through summer and winter, gaming and idle, different loads.&lt;/p&gt;

&lt;p&gt;During that time it's closer to a regular monitor than an intelligent one. That's the price of later talking about your hardware instead of an averaged one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It needs good sensors&lt;/strong&gt;, and Windows can really make you suffer here.&lt;br&gt;
psutil.sensors_temperatures() returns an empty field on Windows, no temperatures, the end, thank you.&lt;br&gt;
Hence the dependency on LibreHardwareMonitor and WMI just to have something to learn from. I know this not from documentation but from tripping over it myself and losing an evening before I understood why the voltage chart was empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It must not bark without reason.&lt;/strong&gt;&lt;br&gt;
One false alarm now and then and you stop trusting the tool, you turn off notifications and that's that.&lt;br&gt;
So 12V spikes during GPU load changes are deliberately suppressed&lt;br&gt;
(they're physically expected, not a failure)&lt;br&gt;
and a pattern that repeats five times stops being treated as an anomaly and becomes your hardware's new norm.&lt;br&gt;
A*&lt;em&gt;nomaly decay.&lt;/em&gt;*&lt;br&gt;
A tool that learns must also know how to retract its own alarm.&lt;/p&gt;

&lt;h2&gt;
  
  
  And one more thing, to be clear:
&lt;/h2&gt;

&lt;p&gt;this is not &lt;strong&gt;anti-HWiNFO&lt;/strong&gt; or &lt;strong&gt;anti-Afterburner&lt;/strong&gt;. Raw sensor data is still the foundation everything stands on. What changes isn't that you read the data, it's what happens to that data next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm telling you this between welding shifts
&lt;/h2&gt;

&lt;p&gt;Your computer has a history. Specific, physical, its own, that one piece of silicon in that one room with that one PSU.&lt;br&gt;
It's time a program remembered it, instead of comparing you to an average you never owned.&lt;/p&gt;

&lt;p&gt;I built this because I got tired of tools that show and never understand. I built it on a laptop that hit 94°C, between warehouse shifts in the Netherlands, then between convenience store shifts in Poland, and now between welding shifts at a repair shop.&lt;/p&gt;

&lt;p&gt;Monday, an article about this project hit #1 Trending on HackerNoon.&lt;br&gt;
&lt;strong&gt;My first thought wasn't "I made it".&lt;br&gt;
It was "what if this is an accident?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fear after success is stranger than fear after failure, with failure you know what to fix, with success you suddenly have something to lose.&lt;/p&gt;

&lt;p&gt;But the code doesn't know I'm scared. It doesn't check trending positions.&lt;br&gt;
It classifies the context and keeps learning. Maybe that's the lesson.&lt;/p&gt;

&lt;p&gt;We stopped needing a tool that shows. We need one that understands,&lt;br&gt;
and does the work for us.&lt;br&gt;
Locally. Quietly.&lt;/p&gt;




&lt;p&gt;This isn't a roadmap, it's working code.&lt;br&gt;
Thermal Baseline Learning and Voltage SPC described above run in&lt;br&gt;
PC Workman v1.7.9 - free, open-source. You can check every line.&lt;/p&gt;

&lt;p&gt;Download or read the code:&lt;br&gt;
&lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;github.com/HuckleR2003/PC_Workman_HCK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full article on the project domain site!: &lt;a href="https://pcworkman.dev" rel="noopener noreferrer"&gt;pcworkman.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything else and coffee! :) : &lt;a href="https://linktr.ee/marcin_firmuga" rel="noopener noreferrer"&gt;linktr.ee/marcin_firmuga&lt;/a&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%2Fovqxebar2788y7fz384t.jpg" 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%2Fovqxebar2788y7fz384t.jpg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;About the Author&lt;br&gt;
I’m Marcin Firmuga. Solo developer and founder of HCK_Labs.&lt;/p&gt;

&lt;p&gt;I created PC Workman, an open-source, AI-powered PC resource monitor who learns, after time, your natural PC behavior (spikes, voltage, temps, usages) built entirely from scratch on dying hardware during warehouse shifts in the Netherlands.&lt;/p&gt;

&lt;p&gt;Before this: game translations, PC technician internships, warehouse operations in multiple countries, and countless failed projects I never finished.&lt;/p&gt;

&lt;p&gt;But this one? This one stuck.&lt;br&gt;
1000+ hours of code. 4 complete UI rebuilds. 16,000 lines deleted.&lt;br&gt;
3 AM all-nighters.Energy drinks and toast.&lt;/p&gt;

&lt;p&gt;And my own hck_GPT AI, building for months to give a PC Workman a brain and heart.&lt;br&gt;
And finally, an app I wouldn’t close in 5 seconds. That’s the difference between building and shipping.&lt;/p&gt;

&lt;p&gt;Marcin Firmuga | 22 | Poland | HCK_Labs Building PC Workman publicly. Physical work by day, code by night.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Marcin Firmuga | 22 | Poland | HCK_Labs&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Building PC Workman publicly. Physical work by day, code by night.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Was Supposed to Fix Bugs. I Accidentally Built Two Features Instead. PC Workman 1.7.8 - Advanced Deep Learning AI, Supply Monitor and Health Keeper.</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Fri, 05 Jun 2026 19:44:00 +0000</pubDate>
      <link>https://dev.to/huckler/i-was-supposed-to-fix-bugs-i-accidentally-built-two-features-instead-pc-workman-178-advanced-a83</link>
      <guid>https://dev.to/huckler/i-was-supposed-to-fix-bugs-i-accidentally-built-two-features-instead-pc-workman-178-advanced-a83</guid>
      <description>&lt;h1&gt;
  
  
  I Was Supposed to Fix Bugs. I Accidentally Built Two Features Instead.
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Friday Shipped &amp;amp; Scarred #11&lt;/strong&gt;, the one where "no new features" lasted about 4 hours.&lt;/p&gt;




&lt;p&gt;The plan after v1.7.7 (which shipped 20+ patches over one week): &lt;strong&gt;maintenance only&lt;/strong&gt;. Fix the tester list. Test things.&lt;br&gt;
&lt;strong&gt;Don't build anything.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I opened Setup &amp;amp; Drivers to verify a fix. My own PC had two GPU entries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RTX&lt;/strong&gt; - the one currently in the machine.&lt;br&gt;
And &lt;strong&gt;GT 1030&lt;/strong&gt; - removed over two years ago.&lt;br&gt;
Driver entries still in the registry, taking up space, doing nothing. Windows keeps dead hardware on life support forever.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I thought: if MY machine has this, everyone's does.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three hours later, Ghost Driver Detection was in the codebase.&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%2F9ocmnikvrodisvp4e388.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%2F9ocmnikvrodisvp4e388.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Ghost Drivers: Why WMI Lies To You
&lt;/h2&gt;

&lt;p&gt;The obvious approach for "which devices are actually connected" is WMI. It's wrong.&lt;/p&gt;

&lt;p&gt;WMI &lt;code&gt;Win32_PnPEntity&lt;/code&gt; returns phantom devices too, that's exactly the problem I was trying to detect. You can't ask the ghost if it's a ghost.&lt;/p&gt;

&lt;p&gt;What actually works: &lt;code&gt;pnputil /enum-devices --connected&lt;/code&gt;.&lt;br&gt;
PnPUtil queries the kernel's live device tree, not the registry cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# core/startup_watcher.py — _get_pnp_connected_names()
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pnputil&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/enum-devices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--connected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/class&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;guid&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;creationflags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATE_NO_WINDOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Parse "Instance ID: ..." blocks - only hardware that's physically here right now
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The detection logic is a set diff:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Registry drivers -&amp;gt; all installed entries for a device class&lt;/li&gt;
&lt;li&gt;Connected (pnputil) -&amp;gt; what's actually plugged in right now&lt;/li&gt;
&lt;li&gt;Gap -&amp;gt; ghost
Any driver entry older than 20 months not in the connected set gets flagged. Red badge. Age info.
&lt;strong&gt;One-click removal via pnputil /remove-device.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The feature shipped fast because the registry-reading infrastructure for the Drivers tab already existed.&lt;/strong&gt;&lt;br&gt;
I just needed the diff logic and a new card in Optimization Center.&lt;/p&gt;
&lt;h3&gt;
  
  
  Background App Hibernation:
&lt;/h3&gt;

&lt;p&gt;Two Modes, Different Tradeoffs&lt;br&gt;
Feature #14 of 16 planned for Optimization Center. Started as a bug investigation into idle process detection, turned into a full feature.&lt;/p&gt;
&lt;h3&gt;
  
  
  Detecting "idle" without false positives
&lt;/h3&gt;

&lt;p&gt;The naive version: flag any process with CPU &amp;lt; 1% for 15 minutes. Problem: that includes background services, compiler daemons, git processes — anything that legitimately idles. The user shouldn't see those.&lt;/p&gt;

&lt;p&gt;The actual filter in app_activity_tracker.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Only surface apps that were ever in the foreground this session.
# If it was never in the foreground, it's a service — skip it.
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;known_fg_pids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;continue&lt;/span&gt;

&lt;span class="c1"&gt;# CPU guard: need 3 consecutive samples all below CPU_IDLE_PCT = 3.0%
# "below threshold" ≠ "not doing background work"
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;CPU_SAMPLES_NEED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# CPU_SAMPLES_NEED = 3
&lt;/span&gt;    &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="n"&gt;cpu_avg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;CPU_SAMPLES_NEED&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;CPU_SAMPLES_NEED&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cpu_avg&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;CPU_IDLE_PCT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The foreground window tracking uses&lt;br&gt;
&lt;strong&gt;GetForegroundWindow and GetWindowThreadProcessId via ctypes&lt;/strong&gt;, polled every 15 seconds. No external deps, just pure Windows API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@staticmethod&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_foreground_pid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;hwnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;windll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetForegroundWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;pid&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;c_ulong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;windll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GetWindowThreadProcessId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hwnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;byref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;two&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt; &lt;span class="n"&gt;behaviors&lt;/span&gt;
&lt;span class="n"&gt;LOW&lt;/span&gt; &lt;span class="n"&gt;PRIORITY&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nc"&gt;SetPriorityClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDLE_PRIORITY_CLASS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt; &lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;IDLE_PRIORITY_CLASS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x00000040&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_set_priority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority_class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;windll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OpenProcess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROCESS_SET_INFORMATION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;windll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SetPriorityClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority_class&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;windll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloseHandle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;still&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Gets&lt;/span&gt; &lt;span class="n"&gt;CPU&lt;/span&gt; &lt;span class="n"&gt;scheduling&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="n"&gt;everything&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;idle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Safe&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;apps&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;might&lt;/span&gt; &lt;span class="n"&gt;need&lt;/span&gt; &lt;span class="n"&gt;soon&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;Discord&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Spotify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;FREEZE&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;suspend&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt; &lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="n"&gt;NtSuspendProcess&lt;/span&gt; &lt;span class="n"&gt;internally&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;behavior&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;freeze&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;suspend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# NtSuspendProcess under the hood
&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;_set_priority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDLE_PRIORITY_CLASS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero CPU usage. Stays in RAM. Instant proc.resume() on wake. Good for things like updater processes that sit there all day doing nothing.&lt;/p&gt;

&lt;p&gt;Turbo integration&lt;br&gt;
The behaviors persist to hibernation_prefs.json per exe name. When TURBO mode activates (the existing power plan + service stop system in v1.7.7), hibernation behaviors apply automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# optimization_services.py — _tpp_run()
&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_pp_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_TPP&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;turbo_guid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_TPP&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;hibm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;COMPONENTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;core.hibernation_manager&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hibm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;hibm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply_turbo_behaviors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# applies all configured per-exe behaviors
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And reverses on Turbo deactivate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_tpp_restore&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_pp_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original_guid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_TPP&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;hibm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;COMPONENTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;core.hibernation_manager&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hibm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;hibm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;restore_turbo_apps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# wakes everything that was frozen
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Protected list of 30+ system process names (svchost.exe, MsMpEng.exe, dwm.exe, etc.) that never appear as hibernation candidates regardless of CPU or idle time.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Parser Bug That Corrupted Polish Words
&lt;/h2&gt;

&lt;p&gt;parser.py had an accent normalization step — a mapping of incomplete Polish fragments to their full forms, for users who don't type diacritics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;_ACCENT_MAP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatur&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatura&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# fix: "jak jest temperatur" → "temperatura"
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wydajnosc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wydajność&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pamieci&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pamięci&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_normalize_accents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accented&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ACCENT_MAP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accented&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# ← THE BUG
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatur&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;substring&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatura&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;When&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatura cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt; &lt;span class="n"&gt;matched&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;fragment&lt;/span&gt; &lt;span class="n"&gt;inside&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatura&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperaturaa&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;broke&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatura cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;routing&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;hw_cpu&lt;/span&gt; &lt;span class="n"&gt;instead&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="n"&gt;because&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;multi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperatura cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;longer&lt;/span&gt; &lt;span class="n"&gt;matched&lt;/span&gt; &lt;span class="n"&gt;anything&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;vocabulary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fix: word-boundary matching.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_normalize_accents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accented&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ACCENT_MAP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accented&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;\b only matches "temperatur" as a** standalone word*&lt;em&gt;. "temperatura" **passes through untouched.&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;This was caught during the 20-question intent routing test I ran post-audit.&lt;br&gt;
"temperatura cpu" was scoring hw_cpu with 33% confidence.&lt;br&gt;
Traced it to "temperaturaa cpu" matching nothing.&lt;/p&gt;

&lt;p&gt;The Cache That Was Rebuilding on Every Message&lt;br&gt;
Same file. Different problem. The folded pattern cache (used for accent-insensitive matching) was being built inside parse():&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# OLD — runs on every single message
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;folded_patterns_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_ascii_fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;INTENT_PATTERNS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;# ... scoring ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;INTENT_PATTERNS has 82 intents, some with 30+ patterns each. Every user message rebuilt this entire dict from scratch. O(n×m) per call.&lt;/p&gt;

&lt;p&gt;Fix: lazy class-level cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# NEW - built once, reused forever
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntentParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_folded_cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_folded_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_folded_cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;IntentParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_folded_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_ascii_fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;INTENT_PATTERNS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_folded_cache&lt;/span&gt;
&lt;span class="n"&gt;INTENT_PATTERNS&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time.&lt;/span&gt; &lt;span class="n"&gt;There&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s no reason to rebuild it on message #47.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;82/82 - What Full Intent Coverage Actually Means&lt;br&gt;
The hck_GPT AI engine routes messages using a hybrid system:&lt;br&gt;
keyword scoring and Naive Bayes blend TO confidence score&lt;br&gt;
and rule engine if ≥ 0.65, Ollama LLM if below.&lt;/p&gt;

&lt;p&gt;Each intent has two config entries in hybrid_engine.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;_CONTEXT_WINDOWS&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt; &lt;span class="n"&gt;far&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;AI&lt;/span&gt; &lt;span class="n"&gt;looks&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;_CONTEXT_WINDOWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hw_cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# last 5 minutes — live snapshot
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# last 10 minutes
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temp_comparison&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# last 7 days — trend comparison
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weekly_trends&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;10080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;session_digest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mi"&gt;480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# 8-hour session summary
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fan_speed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ... 82 total
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;_INTENT_HINTS&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt; &lt;span class="n"&gt;Ollama&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;told&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;focus&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;_INTENT_HINTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User is asking about system temperatures - be specific: CPU, GPU, and threshold warnings.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temp_comparison&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User asks if PC is running hotter than usual - compare current temps to 7-day and 30-day historical averages.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fan_speed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User is asking about fan RPM - show all fan sensors, current RPM, and if any fans are stalled.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ram_flush&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User wants to free up RAM - explain what&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s safe to close, give current top RAM consumers with MB values.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ... 82 total
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before this week: 34/82 had context windows. 54/82 had hints. Every unregistered intent fell through to a 30-minute default window and empty guidance.&lt;/p&gt;

&lt;p&gt;Now all 82 have both. A query about "temperatur cpu" gets a 10-minute window (relevant recent data) and a hint telling the LLM exactly what to check.&lt;br&gt;
A trend query like "is my cpu hot more than average" (temp_comparison) gets 7 days of data and the right comparison guidance.&lt;/p&gt;

&lt;p&gt;The before/after on intent detection after fixing the parser&lt;br&gt;
bug and filling the maps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Query   Before  After   Context
temperatur cpu  hw_cpu (broken) temperature ✓ 10m
is my pc more warm than normal? hw_all RULE 5m  temp_comparison ✓ 10080m
make roast about my pc  unknown fun_roast ✓   30m
morning brief   unknown morning_brief ✓   10080m
is my cpu overclocked?  hw_cpu  overclock_check ✓ 5m
Test suite after all changes: 21/21.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hck_GPT Panel Startup Bug&lt;br&gt;
One-liner symptoms: panel appears at the very top of the window on fresh launch. Toggle Max View Mode once and it snaps to the correct bottom position.&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%2F3wkisp7poikz2cf5b8bu.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%2F3wkisp7poikz2cf5b8bu.png" alt=" " width="730" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Root cause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collapsed_h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The animation runs 350ms after panel creation. It reads parent.winfo_height() to compute y = parent_h - current_h.&lt;/p&gt;

&lt;p&gt;But 350ms isn't enough on the first launch - the window hasn't been laid out yet, so winfo_height() returns 0.&lt;br&gt;
&lt;strong&gt;Then y = 0 - 34 = -34, clamped to 0. Panel at the top.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Max View Mode triggered a geometry change, which forced a re-layout, which gave correct winfo_height().&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;on_end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;parent_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;winfo_height&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent_h&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Window not rendered yet — retry in 80ms
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;on_end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="c1"&gt;# ... normal animation
&lt;/span&gt;&lt;span class="n"&gt;Polls&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;arbitrary&lt;/span&gt; &lt;span class="n"&gt;sleeps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;shot&lt;/span&gt; &lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;guess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The Numbers
&lt;/h1&gt;

&lt;p&gt;2 unplanned features shipped (Ghost Drivers, Background App Hibernation)&lt;br&gt;
15/16 Optimization Center features live&lt;br&gt;
82/82 intents with context windows + LLM hints (was 34/54)&lt;br&gt;
14   vocabulary patterns fixed or added&lt;br&gt;
1   parser bug causing word corruption&lt;br&gt;
1   startup positioning bug in hck_GPT panel&lt;br&gt;
21/21 automated tests passing&lt;br&gt;
I was supposed to fix bugs. I fixed the bugs. I also shipped two features. I have no explanation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Stack &amp;amp; Links
&lt;/h1&gt;

&lt;p&gt;PC Workman is a real-time Windows system monitor with embedded AI assistant (hck_GPT). Open source, Python 3.9+ / Tkinter, Windows 10+.&lt;/p&gt;

&lt;p&gt;GitHub: github.com/HuckleR2003/PC_Workman_HCK&lt;br&gt;
Medium (narrative version): &lt;a href="https://medium.com/@MarcinFirmuga/i-was-supposed-to-fix-bugs-i-accidentally-built-a-ghost-driver-detector-instead-pc-workman-1-7-8-395c7b927f8f" rel="noopener noreferrer"&gt;link&lt;/a&gt;&lt;br&gt;
Support: &lt;a href="https://buycoffee.to/hcklabs" rel="noopener noreferrer"&gt;Coffee&lt;/a&gt; or &lt;a href="https://github.com/sponsors/HuckleR2003" rel="noopener noreferrer"&gt;Github&lt;/a&gt; :)&lt;br&gt;
Marcin Firmuga - HCK_Labs - solo dev, Poland.&lt;br&gt;
11 months. Still shipping.&lt;/p&gt;

&lt;h1&gt;
  
  
  About the Author
&lt;/h1&gt;

&lt;p&gt;I’m &lt;a href="https://linktr.ee/marcin_firmuga" rel="noopener noreferrer"&gt;Marcin Firmuga&lt;/a&gt;. Solo developer and founder of HCK_Labs.&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%2Ffhgwy1d2htmfiykxdkn2.jpg" 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%2Ffhgwy1d2htmfiykxdkn2.jpg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;PC Workman&lt;/a&gt;, an open-source, AI-powered PC resource monitor who learns, after time, your natural PC behavior (spikes, voltage, temps, usages) built entirely from scratch on dying hardware during warehouse shifts in the Netherlands.&lt;/p&gt;

&lt;p&gt;Before this: game translations, PC technician internships, warehouse operations in multiple countries, and countless failed projects I never finished.&lt;/p&gt;

&lt;p&gt;But this one? This one stuck.&lt;br&gt;
1000+ hours of code. 4 complete UI rebuilds. 16,000 lines deleted.&lt;br&gt;
3 AM all-nighters.Energy drinks and toast.&lt;/p&gt;

&lt;p&gt;And my own &lt;a href="https://github.com/HuckleR2003/hck-GPT" rel="noopener noreferrer"&gt;hck_GPT&lt;/a&gt; AI, building for months to give a PC Workman a brain and heart.&lt;br&gt;
And finally, an app I wouldn’t close in 5 seconds. That’s the difference between building and shipping.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>I Built an AI-Powered PC Monitor in Python. 28 Strangers Shaped Its Brain. PC Workman 1.7.6</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Thu, 28 May 2026 20:47:16 +0000</pubDate>
      <link>https://dev.to/huckler/i-built-an-ai-powered-pc-monitor-in-python-28-strangers-shaped-its-brain-pc-workman-176-l4d</link>
      <guid>https://dev.to/huckler/i-built-an-ai-powered-pc-monitor-in-python-28-strangers-shaped-its-brain-pc-workman-176-l4d</guid>
      <description>&lt;p&gt;I built an AI-powered PC monitor in Python. 28 strangers shaped its brain.&lt;br&gt;
This article is about PC Workman 1.7.6.&lt;br&gt;
But it's also about what indie dev actually looks like, between retail shifts, late night compiler sessions, and debugging Polish character encoding bugs at 4 AM.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where it started
&lt;/h2&gt;

&lt;p&gt;PC Workman has created, when I live and work in Nederlands by Agency.&lt;br&gt;
Then 5 months later, I come back to Poland and trying to get a place for me.&lt;br&gt;
For 3 weeks I working by International Trucker.&lt;br&gt;
Then I got my little stop from coding, but after visits Slovakia and Czechy I have seen I carry a... 900% OVER MASS THAN LIMIT.&lt;br&gt;
I don't get anything, I just see that before next trip to France.&lt;br&gt;
Next&lt;br&gt;
I was working as a cashier. Coming home after 8-hour shifts and sitting down to code.&lt;/p&gt;

&lt;p&gt;Not because I had energy. Because I couldn't stop.&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%2Fdp7st51hkpczdwsd24yn.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%2Fdp7st51hkpczdwsd24yn.png" alt=" " width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PC Workman started from one problem: my PC would slow down and I had no idea why. Task Manager said "CPU: 87%." But which process? Since when? How long? Nothing.&lt;/p&gt;

&lt;p&gt;Every monitoring tool was either outdated, required installing 3 extra libraries, or looked like it was designed in 2009 and nobody touched the code since.&lt;/p&gt;

&lt;p&gt;So I thought: I'll build my own.&lt;/p&gt;

&lt;p&gt;Classic mistake. Best decision I ever made.&lt;/p&gt;
&lt;h2&gt;
  
  
  10 months, 96 files, 48,000 lines
&lt;/h2&gt;

&lt;p&gt;Current state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Python files:     96
Total lines:      48,081
Response builder: 255,065 chars (yes, one file)
Process library:  241 entries
AI intents:       82
Response handlers: 65
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F3u0wcbv3t46r62yufjj6.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%2F3u0wcbv3t46r62yufjj6.png" alt=" " width="800" height="662"&gt;&lt;/a&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%2Fa4eqjdl2d3vxqn9w4ynn.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%2Fa4eqjdl2d3vxqn9w4ynn.png" alt=" " width="707" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of these numbers are what I'm most proud of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: AI that understands "how much RAM is Chrome eating"
&lt;/h2&gt;

&lt;p&gt;The most technically interesting part of PC Workman is hck_GPT — an AI assistant built directly into the app.&lt;/p&gt;

&lt;p&gt;No external API. Doesn't send your data anywhere. Works locally through a hybrid engine: if the intent gets recognized by the 82-intent parser, it responds deterministically from real data. If not, it delegates to a local Ollama LLM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user input
    → IntentParser (vocab match + ML classifier)
    → HybridEngine (rule dispatch vs LLM fallback)
    → ResponseBuilder (65 handlers, real sensor data)
    → bilingual response (PL/EN auto-detected)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;82 intents cover everything from "why is CPU high" to "can I run Cyberpunk" to "what's eating my battery." Each intent has dozens of patterns — because users ask the same thing 15 different ways.&lt;/p&gt;

&lt;p&gt;The bilingual helper looks almost embarrassingly simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;en&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;pl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind that sits 854 lines of vocabulary patterns in two languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: The Polish ł that broke routing
&lt;/h2&gt;

&lt;p&gt;This is one of my favorite bugs because it was so non-obvious.&lt;/p&gt;

&lt;p&gt;The parser normalizes text before matching — strips diacritics so "dlaczego" (why) with or without accents hits the same intent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_ascii_fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;unicodedata&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;unicodedata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NFD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;unicodedata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NFD normalization decomposes "ą" into "a" + combining ogonek, then the filter removes combining characters. Works great for ą, ę, ó, ź, ż, ń.&lt;/p&gt;

&lt;p&gt;But not for ł.&lt;/p&gt;

&lt;p&gt;ł (U+0142) isn't "l" with a combining stroke. It's a separate character that NFD doesn't decompose at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user types:    "jak dlugo wytrzyma bateria"   (plain l)
vocab pattern: "jak długo wytrzyma bateria"   (ł stays as ł after fold)

fold("długo") → "długo"   &amp;lt;- ł preserved
fold("dlugo") → "dlugo"   &amp;lt;- l preserved

"długo" ≠ "dlugo"  -&amp;gt; NO MATCH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Flulfct91l5w4owounvje.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%2Flulfct91l5w4owounvje.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The battery_estimate intent was returning conf=0.00 on a perfect question.&lt;/p&gt;

&lt;p&gt;Fix: explicit ASCII fallback patterns for every intent containing ł:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# vocabulary.py - battery_estimate patterns
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jak dlugo wytrzyma bateria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# ASCII fallback
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jak długo wytrzyma bateria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# canonical Polish
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;how long will battery last&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# English
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the type of bug you only find when building an app in two languages simultaneously and one of them has characters that don't behave the way you think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: 28 strangers designed 6 new features
&lt;/h2&gt;

&lt;p&gt;Few weeks ago I posted a simple question on GitHub Discussions and LinkedIn:&lt;/p&gt;

&lt;p&gt;"What would you ask an AI that lives inside your system monitor?"&lt;/p&gt;

&lt;p&gt;28 answers. From GitHub, LinkedIn DMs, comments.&lt;/p&gt;

&lt;p&gt;Every answer became a real function in the response builder.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Intent&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;game_can_run&lt;/td&gt;
&lt;td&gt;Checks if your PC can handle a game (20-game DB with RAM/VRAM/disk requirements)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;battery_estimate&lt;/td&gt;
&lt;td&gt;psutil.sensors_battery() + drain rate based on activity type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;upgrade_feasibility&lt;/td&gt;
&lt;td&gt;WMI slot count + current sticks + free slots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;top_resource_hog&lt;/td&gt;
&lt;td&gt;TOP 5 processes by RSS memory + disk I/O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gaming_ram_usage&lt;/td&gt;
&lt;td&gt;Live game process RAM + 7-day comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;daily_ram_usage&lt;/td&gt;
&lt;td&gt;7-day trend + verdict: very high / high / moderate / low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When you ask hck_GPT "can I run Cyberpunk" it checks your psutil RAM, WMI VRAM, free disk space and responds with specific numbers. No hallucination. No "usually..." No guessing.&lt;/p&gt;

&lt;p&gt;The no-data fallback is deliberate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_no_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;what_missing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PREFIX&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; Not enough data for a reliable answer.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;d rather tell you honestly than guess.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I don't have data, I say so. AI that guesses is worse than AI that stays quiet.&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%2F5tapihaxlygcvcs1k1pf.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%2F5tapihaxlygcvcs1k1pf.png" alt=" " width="414" height="836"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: DeepMonitor - from ugly table to real tool
&lt;/h2&gt;

&lt;p&gt;For a long time the hardware view in PC Workman was weak. Inline min/max values with no alignment, dark uneven colors, no structure.&lt;/p&gt;

&lt;p&gt;Rewrote it from scratch on ttk.Treeview with 4 fixed columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;Sensor                    | Value     | Min       | Max
----------------------------------------------------------
&lt;/span&gt;  CPU
    [Temperatures]
      Package             | 52.1°C    | 44.0°C    | 52.1°C
      Core #0             | 49.3°C    | 45.1°C    | 51.8°C
    [Utilization]
      Processor           | 13.7%     |  0.0%     | 23.6%
    [Clocks]
      Current             | 3.990 GHz |           | 4.011 GHz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each category has its own background tint. Temperatures go from white to amber at 70°C to red at 83°C. Utilization hits red at 88%.&lt;/p&gt;

&lt;p&gt;Action bar: Save Data (exports .txt/.csv), Pause (freezes the view, button turns amber), Reset (clears session min/max).&lt;/p&gt;

&lt;p&gt;Same psutil and hardware_sensors feed hck_GPT. When DeepMonitor shows a red CPU temp line, the proactive monitor probably already sent an alert through hck_GPT a few minutes earlier. Two views, one data source.&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%2F38rclec1na4nql3xlulq.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%2F38rclec1na4nql3xlulq.png" alt=" " width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 5: Proactive monitor - AI that doesn't wait for your question
&lt;/h2&gt;

&lt;p&gt;One of my favorite modules. Runs in background and starts conversations on its own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;THROTTLE_RATIO&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.60&lt;/span&gt;   &lt;span class="c1"&gt;# below 60% of max freq = throttled
&lt;/span&gt;&lt;span class="n"&gt;CPU_SPIKE_PCT&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;   &lt;span class="c1"&gt;# single process &amp;gt;30% = spike alert
&lt;/span&gt;&lt;span class="n"&gt;SESSION_BUDGET&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;      &lt;span class="c1"&gt;# max 3 unsolicited alerts per 30 min
&lt;/span&gt;&lt;span class="n"&gt;SESSION_WINDOW_S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1800&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SESSION_BUDGET isn't random — based on CHI 2025 research on proactive AI assistants and when proactivity becomes annoying.&lt;/p&gt;

&lt;p&gt;Throttling alert:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hck_GPT: CPU power limit hit (58% of max). Heat is usually the cause. Type 'temperature'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GPU temperature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hck_GPT: GPU temperature spike to 89°C. Check cooling or lower graphics settings.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One alert. Specific reason. Specific next action. Not "your computer may be experiencing reduced performance."&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 6: Language sync — one hour debugging for one line
&lt;/h2&gt;

&lt;p&gt;For 10 months I built an app for Polish users entirely in English. That was a mistake I finally fixed.&lt;/p&gt;

&lt;p&gt;But the Settings language toggle didn't sync with hck_GPT. Click "PL" — interface changes, hck_GPT keeps responding in English.&lt;/p&gt;

&lt;p&gt;The fix was clean: utils/i18n.py has a callback system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# panel.py __init__:
&lt;/span&gt;&lt;span class="nf"&gt;_i18n_register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_on_i18n_lang_changed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_on_i18n_lang_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;new_lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_i18n_get_lang&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ui_lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_lang&lt;/span&gt;
    &lt;span class="n"&gt;proactive_monitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_language&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_refresh_welcome_for_lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After switching to PL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hck_GPT: Witaj z powrotem — PC Workman gotowy do działania.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One callback registration. One hour understanding why the widget wasn't refreshing at the right moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbers that surprised me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;28,000 LinkedIn views on the "building what 28 people asked for" post&lt;/li&gt;
&lt;li&gt;27,500 views on "most developers never ship an .exe"&lt;/li&gt;
&lt;li&gt;1,135 em-dashes found and replaced in one maintenance session across 58 files&lt;/li&gt;
&lt;li&gt;241 processes in the knowledge base&lt;/li&gt;
&lt;li&gt;82 intents in the parser, each with dozens of PL+EN patterns&lt;/li&gt;
&lt;li&gt;0 external APIs — everything local
Most surprising: the two most viral posts weren't about the most technically interesting things. They were about truths every developer recognizes but rarely says out loud.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Security module — offline, no signatures, no cloud. Pattern detection on data PC Workman already collects.&lt;/p&gt;

&lt;p&gt;svch0st.exe pretending to be svchost.exe? Flagged.&lt;br&gt;
Crypto miner with abnormal CPU pattern 24/7? Flagged.&lt;br&gt;
New high-privilege process that wasn't there yesterday? Flagged.&lt;/p&gt;

&lt;p&gt;Your antivirus knows about threats from around the world. PC Workman knows what's normal for YOUR specific machine.&lt;/p&gt;

&lt;p&gt;And Microsoft Store submission. I've been saying this since v1.6.3. This time I mean it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Current stats:&lt;/strong&gt; 56 GitHub stars, 270+ downloads, 270+ commits, 82 AI intents, 48,081 lines, 10 months, one €1.50 coffee donation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;github.com/HuckleR2003/PC_Workman_HCK&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;All links:&lt;/strong&gt; &lt;a href="https://linktr.ee/marcin_firmuga" rel="noopener noreferrer"&gt;linktr.ee/marcin_firmuga&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have a question you'd ask an AI inside your system monitor — drop it in the comments. Every one becomes a real feature.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Marcin Firmuga | 22 | Poland | HCK_Labs&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Building PC Workman and GuideAI publicly. 10 months. 4 rebuilds. Still shipping.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;I’m Marcin Firmuga. Solo developer and founder of HCK_Labs.&lt;/p&gt;

&lt;p&gt;I created PC Workman, an open-source, AI-powered PC resource monitor who learns, after time, your natural PC behavior (spikes, voltage, temps, usages) built entirely from scratch on dying hardware during warehouse shifts in the Netherlands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before this:&lt;/strong&gt; game translations, PC technician internships, warehouse operations in multiple countries, and countless failed projects I never finished.&lt;/p&gt;

&lt;p&gt;But this one? This one stuck.&lt;br&gt;
1000+ hours of code. 4 complete UI rebuilds. 16,000 lines deleted.&lt;br&gt;
3 AM all-nighters.Energy drinks and toast.&lt;/p&gt;

&lt;p&gt;And my own hck_GPT AI, building for months to give a PC Workman a brain and heart.&lt;br&gt;
And finally, an app I wouldn’t close in 5 seconds. That’s the difference between building and shipping.&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%2Fz587dot6kwux3j5oveem.jpg" 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%2Fz587dot6kwux3j5oveem.jpg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PC_Workman is the result.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I Taught My Offline AI to Remember, Watch, and Warn, Without Any Cloud (Part 2)</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Tue, 12 May 2026 15:17:33 +0000</pubDate>
      <link>https://dev.to/huckler/how-i-taught-my-offline-ai-to-remember-watch-and-warn-without-any-cloud-part-2-5hib</link>
      <guid>https://dev.to/huckler/how-i-taught-my-offline-ai-to-remember-watch-and-warn-without-any-cloud-part-2-5hib</guid>
      <description>&lt;p&gt;Part 1 covered how hck_GPT routes messages through 9 layers and decides between rules and a local LLM. If you missed it:&lt;br&gt;
&lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523"&gt;Part 1 - Intent Scoring, Hybrid Routing, Temperature per Intent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That was the brain. This is the memory and the instincts.&lt;/p&gt;

&lt;p&gt;Part 1's AI was reactive. You ask, it answers. Close the app, everything is gone. No history. No learning. No initiative.&lt;/p&gt;

&lt;p&gt;That's not how a PC companion should work. If I've been running PC Workman for two weeks, it should know that my CPU averages 28% and today's 67% is unusual. It should notice that Chrome has been eating 2GB RAM for an hour and mention it before I ask. It should remember my GPU model without me telling it twice.&lt;/p&gt;

&lt;p&gt;So I built three systems that Part 1 didn't have: a persistent knowledge base that survives restarts, a metrics store that snapshots hardware data every 5 minutes into SQLite, and a proactive monitor that watches your system and pushes alerts without being asked.&lt;/p&gt;

&lt;p&gt;All offline. All local. Your data never leaves your machine.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. The Knowledge Base, AI That Remembers Across Restarts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 1 had session memory,&lt;/strong&gt;&lt;br&gt;
a Python dict that dies when the app closes. Useful for&lt;br&gt;
"we talked about RAM 3 messages ago" but useless for&lt;br&gt;
"your GPU is an RTX 3060 with 6GB VRAM"&lt;br&gt;
which shouldn't need re-scanning every launch.&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%2Fon6z1mao8ansltjvmi6i.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%2Fon6z1mao8ansltjvmi6i.png" alt=" " width="594" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four tables, each with a different job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;EXISTS&lt;/span&gt; &lt;span class="nf"&gt;hardware_profile &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;     &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;PRIMARY&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;   &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="n"&gt;REAL&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;EXISTS&lt;/span&gt; &lt;span class="nf"&gt;usage_patterns &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;metric&lt;/span&gt;  &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;PRIMARY&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;   &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="n"&gt;REAL&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;EXISTS&lt;/span&gt; &lt;span class="nf"&gt;user_facts &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;        &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;PRIMARY&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;      &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt;     &lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;DEFAULT&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;detected&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="n"&gt;REAL&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;DEFAULT&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;REAL&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;EXISTS&lt;/span&gt; &lt;span class="nf"&gt;conversation_log &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;         &lt;span class="n"&gt;INTEGER&lt;/span&gt; &lt;span class="n"&gt;PRIMARY&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;AUTOINCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;session_id&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;    &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timestamp&lt;/span&gt;  &lt;span class="n"&gt;REAL&lt;/span&gt;    &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt;       &lt;span class="n"&gt;TEXT&lt;/span&gt;    &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;    &lt;span class="n"&gt;TEXT&lt;/span&gt;    &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;hardware_profile&lt;/strong&gt; stores things that rarely change:&lt;br&gt;
CPU model, GPU name, VRAM, motherboard, RAM speed, OS version.&lt;/p&gt;

&lt;p&gt;Scanned once via psutil + WMI, then cached.&lt;br&gt;
The &lt;code&gt;hardware_is_fresh()&lt;/code&gt; method checks if the last scan was within 24 hours - if yes, skip the scan.&lt;br&gt;
No wasted resources on startup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;usage_patterns&lt;/strong&gt; stores things that change slowly:&lt;br&gt;
average CPU load, peak hours, top apps, detected use-case&lt;br&gt;
("gaming" vs "development" vs "office").&lt;br&gt;
Updated periodically from the stats engine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;user_facts&lt;/strong&gt; stores things the AI inferred or the user stated:&lt;br&gt;
preferred language, PC usage type, whether they play games.&lt;br&gt;
Each fact has a confidence score — detected facts start at 1.0, inferred facts can be lower.&lt;br&gt;
This is how hck_GPT knows to greet you in Polish without asking every session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;conversation_log&lt;/strong&gt; keeps the last 500 messages across sessions&lt;br&gt;
(pruned monthly). Not for replaying conversations, for pattern detection. "User asks about temperature every Monday" is a signal.&lt;/p&gt;

&lt;p&gt;The knowledge base builds a context summary for every AI response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_knowledge_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;hw&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_all_hardware&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;facts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_all_facts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hardware:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_HW_LABELS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User facts:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())[:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(knowledge base empty)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gets injected into every Ollama prompt. The LLM doesn't ask "what GPU do you have?", it already knows.&lt;br&gt;
From the first message of every session.&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%2F6rldniwf64djsajtylxn.gif" 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%2F6rldniwf64djsajtylxn.gif" alt=" " width="720" height="376"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Metrics Store, 90 Days of Hardware History in SQLite
&lt;/h2&gt;

&lt;p&gt;Session memory remembers what happened in the last 30 minutes.&lt;br&gt;
The knowledge base remembers your hardware profile.&lt;br&gt;
But what about "was my CPU hotter yesterday than today?"&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%2Flunbge1svzvs8q73jxg2.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%2Flunbge1svzvs8q73jxg2.png" alt=" " width="799" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Metrics Store answers that. Every 5 minutes, a background thread snapshots 20+ sensor values into SQLite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;SNAPSHOT_INTERVAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;   &lt;span class="c1"&gt;# 5 minutes between snapshots
&lt;/span&gt;&lt;span class="n"&gt;RETENTION_DAYS&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;    &lt;span class="c1"&gt;# auto-prune after 90 days
&lt;/span&gt;
&lt;span class="n"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;EXISTS&lt;/span&gt; &lt;span class="nf"&gt;deepmonitor_snapshots &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;            &lt;span class="n"&gt;INTEGER&lt;/span&gt; &lt;span class="n"&gt;PRIMARY&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;AUTOINCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ts&lt;/span&gt;            &lt;span class="n"&gt;REAL&lt;/span&gt;    &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date_str&lt;/span&gt;      &lt;span class="n"&gt;TEXT&lt;/span&gt;    &lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cpu_load&lt;/span&gt;      &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cpu_temp&lt;/span&gt;      &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cpu_mhz&lt;/span&gt;       &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cpu_power&lt;/span&gt;     &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gpu_temp&lt;/span&gt;      &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gpu_load&lt;/span&gt;      &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gpu_vram_pct&lt;/span&gt;  &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gpu_power&lt;/span&gt;     &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ram_pct&lt;/span&gt;       &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;swap_pct&lt;/span&gt;      &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;mb_temp_sys&lt;/span&gt;   &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;mb_volt_12v&lt;/span&gt;   &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;mb_volt_5v&lt;/span&gt;    &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;mb_volt_33v&lt;/span&gt;   &lt;span class="n"&gt;REAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;disk_json&lt;/span&gt;     &lt;span class="n"&gt;TEXT&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This table shares the same &lt;code&gt;hck_stats.db&lt;/code&gt; file as the main stats engine — one database, WAL mode, concurrent reads and writes without locks.&lt;/p&gt;

&lt;p&gt;The writer loop staggers its first write by 60 seconds so the UI finishes loading first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_writer_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_stop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# let UI boot
&lt;/span&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_stop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_set&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_save_snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_prune_old_rows&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;writer error: %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_stop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SNAPSHOT_INTERVAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Auto-prune runs after every snapshot — rows older than 90 days get deleted. Database stays small (~5-10 MB per month).&lt;/p&gt;

&lt;p&gt;The critical part is what happens on startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_load_historical_baselines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;since&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        SELECT
          AVG(CASE WHEN cpu_load &amp;gt;= 0 THEN cpu_load END) AS cpu_av,
          AVG(CASE WHEN ram_pct  &amp;gt;= 0 THEN ram_pct  END) AS ram_av,
          MIN(CASE WHEN cpu_load &amp;gt;= 0 THEN cpu_load END) AS cpu_lo,
          MAX(CASE WHEN cpu_load &amp;gt;= 0 THEN cpu_load END) AS cpu_hi,
          COUNT(*) AS n
        FROM deepmonitor_snapshots WHERE ts &amp;gt;= ?
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;since&lt;/span&gt;&lt;span class="p"&gt;,)).&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;live_sensors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_hist_cpu_avg_7d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu_av&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_hist_ram_avg_7d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ram_av&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On app boot, the store loads 7-day min/max/avg baselines into live memory. From the very first message, hck_GPT can say "your CPU is at 67% — but your 7-day average is 28%, something is off." Not because it guessed. Because it has 2,016 data points from the last week (288 snapshots/day × 7 days).&lt;/p&gt;

&lt;p&gt;Without this, the AI would need to run for hours before it could make any comparison. With it, historical context is available from second one.&lt;/p&gt;

&lt;p&gt;The public API is simple — two methods cover 90% of use cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metrics_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# raw snapshots
&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metrics_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;daily_summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# per-day aggregates
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. The Proactive Monitor, AI That Speaks First
&lt;/h2&gt;

&lt;p&gt;This is the part that makes people say "wait, it does WHAT?"&lt;/p&gt;

&lt;p&gt;Most AI assistants wait for input. You type, they respond. Passive.&lt;/p&gt;

&lt;p&gt;hck_GPT's Proactive Monitor is a daemon thread that runs every 45 seconds, checks system state, and pushes alerts to the chat panel without anyone asking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CPU_HIGH_PCT&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;85.0&lt;/span&gt;
&lt;span class="n"&gt;CPU_CRIT_PCT&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;95.0&lt;/span&gt;
&lt;span class="n"&gt;RAM_HIGH_PCT&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;88.0&lt;/span&gt;
&lt;span class="n"&gt;RAM_CRIT_PCT&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;93.0&lt;/span&gt;
&lt;span class="n"&gt;DISK_LOW_GB&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;
&lt;span class="n"&gt;THROTTLE_RATIO&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.60&lt;/span&gt;
&lt;span class="n"&gt;CHECK_INTERVAL_S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;
&lt;span class="n"&gt;MIN_GAP_SAME_S&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;   &lt;span class="c1"&gt;# don't repeat same alert for 5 min
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seven conditions monitored:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU sustained high&lt;/strong&gt;, not a spike, sustained.&lt;br&gt;
Two consecutive checks above 85% before alerting.&lt;br&gt;
One check could be a game loading.&lt;br&gt;
Two means something is wrong.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU critical&lt;/strong&gt; - above 95%. Immediate alert.&lt;br&gt;
No waiting for second check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RAM high&lt;/strong&gt; - above 88%. Suggests checking what's eating memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RAM critical&lt;/strong&gt; - above 93%. Pagefile is getting hit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU throttling&lt;/strong&gt; - current frequency divided by max frequency below 60%. Your CPU is being thermally limited.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Disk nearly full&lt;/strong&gt; - any partition below 4 GB free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Long session&lt;/strong&gt; - PC running for many hours. Gentle reminder.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every alert has a bilingual message pool, Polish and English versions with slight variations so the same alert doesn't read identically twice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;_MSGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu_high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hck_GPT: ⚠ CPU sustained at {val}%. Type &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;top processes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; to see who&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s responsible.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hck_GPT: CPU {val}% — something&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s eating it. Type &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;top&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; to find out what.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hck_GPT: Heads up — CPU at {val}%. Expected, or something sneaky in the background?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hck_GPT: ⚠ CPU na {val}% od dłuższego czasu. Wpisz &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;top procesy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; żeby zobaczyć winowajcę.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hck_GPT: CPU {val}% — coś go zjada. Jeśli to nie Ty, to kto? Wpisz &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;top&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The anti-spam logic is critical. Without it, a sustained CPU spike would flood the chat with warnings every 45 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIN_GAP_SAME_S&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;  &lt;span class="c1"&gt;# 5 minutes between same alert type
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_should_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_last_push&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MIN_GAP_SAME_S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_last_push&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The push mechanism uses callbacks — the UI registers a function, the monitor calls it from the background thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;proactive_monitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;root.after(0, ...)&lt;/code&gt; schedules the message on tkinter's main thread. Background thread never touches the GUI directly. No race conditions. No crashes.&lt;/p&gt;

&lt;p&gt;There's also a silent banner callback for non-intrusive status updates — "All quiet" vs "CPU 87% SPIKE | 2 alerts" in the hck_GPT status bar.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Bilingual Vocabulary — 854 Lines, Zero Translation API
&lt;/h2&gt;

&lt;p&gt;Part 1 mentioned that Polish and English patterns are "defined separately." Here's what that actually looks like at scale.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vocabulary.py&lt;/code&gt; is 854 lines. 25+ intents. Each intent has a list of trigger patterns in both languages, mixed together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INTENT_PATTERNS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hw_cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;# Polish tokens
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;procesor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rdzeń&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rdzenie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;taktowanie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# English tokens
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;processor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cores&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;boost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# Polish multi-word (high bonus)
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jaki procesor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jaki mam procesor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ile rdzeni&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;co mam za procesor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;powiedz mi o procesorze&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# English multi-word
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;which processor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tell me about my cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu details&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No translation step.&lt;br&gt;
No language detection preprocessing.&lt;br&gt;
Both languages live in the same list.&lt;br&gt;
The intent parser scores them all the same way — exact match, prefix match, typo tolerance. If someone types "jaki mam procesor" they get the same intent (&lt;code&gt;hw_cpu&lt;/code&gt;) with the same confidence as "what cpu do I have."&lt;/p&gt;

&lt;p&gt;The scoring comment at the top of the file explains the math:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Pattern scoring (in parser.py):
#   - Multi-word phrases:  len(words) * 1.5  (biggest bonus)
#   - Exact single token:  1.0
#   - Partial prefix:      0.4
#   - Normalised:          min(1.0, score / 3.0)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding more multi-word phrases to an intent raises its confidence, making it more likely to hit the 0.60 threshold for the rule engine.&lt;br&gt;
Ambiguous queries stay below threshold and go to Ollama.&lt;br&gt;
The vocabulary file IS the tuning knob, no hyperparameters to optimize, just patterns to add.&lt;/p&gt;

&lt;p&gt;This week I added 12 new intents based on questions from LinkedIn followers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;battery_drain&lt;/code&gt; - "Which process is draining my battery?"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;session_compare&lt;/code&gt; - "Was it better yesterday?"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pc_changes&lt;/code&gt; - "What changed since yesterday?"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;startup_safety&lt;/code&gt; - "Is it safe to disable this?"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_cache&lt;/code&gt; - "Is my browser slow because of caching?"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;swap_analysis&lt;/code&gt; - "Which processes are using swap?"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;network_usage&lt;/code&gt; - "Which process is using my network?"
Each one: 10-20 patterns, Polish + English, with bilingual response handlers reading live data from psutil and the metrics store.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Part 1 + Part 2 Give You Together
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Part 1&lt;/th&gt;
&lt;th&gt;Part 2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input processing&lt;/td&gt;
&lt;td&gt;Intent parser, confidence scoring&lt;/td&gt;
&lt;td&gt;Bilingual vocabulary (854 lines)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision&lt;/td&gt;
&lt;td&gt;9-layer routing, hybrid engine&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response&lt;/td&gt;
&lt;td&gt;Rule engine + Ollama, temperature per intent&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short-term memory&lt;/td&gt;
&lt;td&gt;Session dict, trend tracking&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-term memory&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;User Knowledge Base (SQLite, AppData)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Historical data&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Metrics Store (snapshots q5min, 90-day retention)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proactive behavior&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Daemon monitor (7 conditions, anti-spam, bilingual alerts)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup context&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;7-day baselines loaded on boot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Part 1 built a brain that responds. Part 2 gave it memory that persists, data that accumulates, and instincts that act without being asked.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Still Missing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cross-session conversation context.&lt;/strong&gt;&lt;br&gt;
The knowledge base stores hardware profiles and usage patterns, but conversation topics don't persist. If you asked about RAM yesterday, today's session doesn't know.&lt;br&gt;
The conversation_log table has the data — the response builder just doesn't query it yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Predictive alerts.&lt;/strong&gt; The proactive monitor reacts to current state.&lt;br&gt;
It doesn't predict. "Your RAM tends to spike around 9 PM on weekdays" is possible with the metrics store data - the SQL is straightforward, the pattern detection isn't built yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automatic vocabulary expansion.&lt;/strong&gt; Every unrecognized query requires manual pattern addition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A feedback loop that logs low-confidence queries and suggests new patterns would cut maintenance time significantly.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Offline-First Philosophy
&lt;/h2&gt;

&lt;p&gt;Every feature in this article stores data locally. SQLite in AppData. Snapshots in the shared stats database.&lt;br&gt;
Alerts computed from psutil readings. Nothing is sent anywhere.&lt;/p&gt;

&lt;p&gt;**This isn't a limitation - it's a design choice.&lt;br&gt;
**When your app monitors CPU temperatures, reads Windows registry, scans running processes, and tracks usage patterns over 90 days, the data is sensitive by definition.&lt;br&gt;
Sending it to a cloud API for every interaction isn't just slow. It's a trust problem.&lt;/p&gt;

&lt;p&gt;The optional Ollama integration (coming before v2.0) will give users a choice: stay fully offline with the Core AI, or enable a local LLM for smarter conversations.&lt;br&gt;
The key word is "local." Even the LLM runs on your hardware.&lt;/p&gt;

&lt;p&gt;Your data. Your machine. Your choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Project
&lt;/h2&gt;

&lt;p&gt;PC Workman is open source. MIT licensed.&lt;br&gt;
&lt;strong&gt;The .exe doesn't require Python.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Download: &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK/releases" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt;&lt;br&gt;
Part 1: &lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523"&gt;How I Built an Offline AI Assistant in Python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All my links: &lt;a href="https://linktr.ee/marcin_firmuga" rel="noopener noreferrer"&gt;linktr.ee/marcin_firmuga&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently doing Google's AI certification (Umiejętności Jutra 3.0 through SGH).&lt;br&gt;
Curious how it'll change the way I think about this engine.&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%2F6im1p54s0eckow9ev075.jpg" 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%2F6im1p54s0eckow9ev075.jpg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Marcin Firmuga | Python Developer | HCK_Labs&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Building PC Workman publicly between retail shifts. 800+ hours, 28 GitHub stars, and an AI that now remembers what it told you last week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Real guide from my 10 months of work PC Workman
(Open Source, fully build in public (fails, tiny wins)</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Mon, 04 May 2026 06:44:25 +0000</pubDate>
      <link>https://dev.to/huckler/real-guide-from-my-10-months-of-work-pc-workman-open-source-fully-build-in-public-fails-tiny-6k1</link>
      <guid>https://dev.to/huckler/real-guide-from-my-10-months-of-work-pc-workman-open-source-fully-build-in-public-fails-tiny-6k1</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523" class="crayons-story__hidden-navigation-link"&gt;How I Built an Offline AI Assistant in Python - No OpenAI, No LangChain, No Dependencies&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;A 5-step decision chain for two languages&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/huckler" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3693207%2F6a4682e6-273e-4a98-9ce7-653391a5abcc.png" alt="huckler profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/huckler" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Marcin Firmuga
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Marcin Firmuga
                
              
              &lt;div id="story-author-preview-content-3604170" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/huckler" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3693207%2F6a4682e6-273e-4a98-9ce7-653391a5abcc.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Marcin Firmuga&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 3&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523" id="article-link-3604170"&gt;
          How I Built an Offline AI Assistant in Python - No OpenAI, No LangChain, No Dependencies
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/python"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;python&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;63&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              4&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>buildinpublic</category>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>How I Built an Offline AI Assistant in Python - No OpenAI, No LangChain, No Dependencies</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Sun, 03 May 2026 13:45:33 +0000</pubDate>
      <link>https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523</link>
      <guid>https://dev.to/huckler/how-i-built-an-offline-ai-assistant-in-python-no-openai-no-langchain-no-dependencies-4523</guid>
      <description>&lt;p&gt;Every tutorial about building an AI assistant starts the same way:&lt;br&gt;
&lt;code&gt;pip install openai&lt;/code&gt;. Get an API key. Send everything to GPT. Done.&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%2Fzhygehs3k9e4wkcyz279.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%2Fzhygehs3k9e4wkcyz279.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your assistant costs money per message, dies without internet, and you have zero control over what happens between the question and the answer.&lt;/p&gt;

&lt;p&gt;I needed something different.&lt;/p&gt;

&lt;p&gt;PC Workman is an open-source system monitor that runs on people's PCs. Some of those PCs are behind firewalls.&lt;br&gt;
Some users don't want their system data leaving their machine.&lt;/p&gt;

&lt;p&gt;So I built hck_GPT... a hybrid AI assistant that works fully offline,&lt;br&gt;
handles Polish and English without a language model, routes messages through a 5-step decision chain, blends keyword scoring with&lt;br&gt;
ML confidence, remembers what it said 3 messages ago, and optionally talks to a local LLM (Ollama) when it's available.&lt;/p&gt;

&lt;p&gt;No cloud. No API key. No &lt;code&gt;pip install&lt;/code&gt; magic.&lt;br&gt;
Here's how it works. All of it.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Intent Scoring - One Algorithm for Two Languages, Zero NLP Libraries
&lt;/h2&gt;

&lt;p&gt;The first problem: how do you figure out what someone is asking without shipping a 500MB NLP model?&lt;/p&gt;

&lt;p&gt;Most intent parsers use spaCy, NLTK, or a transformer. I used string matching. But not the dumb kind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_score_intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;full_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Multi-word phrase -&amp;gt; bonus proportional to word count
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;full_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;   &lt;span class="c1"&gt;# "why is ram so high" = 5 x 1.5
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;                          &lt;span class="c1"&gt;# exact match
&lt;/span&gt;            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
            &lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;                          &lt;span class="c1"&gt;# prefix match ("perfor" -&amp;gt; "performance")
&lt;/span&gt;            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_edit_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
            &lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;                          &lt;span class="c1"&gt;# typo tolerance: 1-char edit distance
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three levels of matching in a single loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exact match&lt;/strong&gt; gives 1.0 - "cpu" in tokens, done.&lt;br&gt;
&lt;strong&gt;Prefix match&lt;/strong&gt; gives 0.4 - "perfor" matches "performance".&lt;br&gt;
This is how the parser handles both languages without a language detector.&lt;br&gt;
Polish and English vocabulary patterns are defined separately, but the scoring algorithm is identical.&lt;br&gt;
&lt;strong&gt;Typo tolerance&lt;/strong&gt; gives 0.6 - Levenshtein distance of 1 catches "temperture" → "temperature" without a spell checker.&lt;/p&gt;

&lt;p&gt;Multi-word phrases get bonus scoring proportional to word count. "what changed in performance" (5 words x 1.5 = 7.5 pts) beats a standalone "performance" (1 pt).&lt;br&gt;
More specific queries earn higher confidence.&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%2F9fxmgk7ro83i18yglobk.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%2F9fxmgk7ro83i18yglobk.png" alt=" " width="800" height="871"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The edit distance function has an early-exit: if the length difference between two strings is more than 2, skip the computation entirely.&lt;br&gt;
This matters because this runs on every message in a GUI thread.&lt;br&gt;
Blocking for 200ms on a distance calculation would feel like lag.&lt;/p&gt;

&lt;p&gt;Zero dependencies. Works in both languages. Runs in under 1ms.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Hybrid Confidence - When to Trust ML, When to Trust Keywords
&lt;/h2&gt;

&lt;p&gt;If you have a keyword scorer AND an ML classifier, you need to decide who wins. Most systems pick one. I blend them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_blend_with_ml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kw_intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kw_conf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ml_intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ml_conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ml_classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ml_conf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# ML very confident — trust it outright
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ml_intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ml_conf&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ml_conf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ml_intent&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;kw_intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Agreement -&amp;gt; amplify the signal
&lt;/span&gt;            &lt;span class="n"&gt;blended&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.65&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ml_conf&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;kw_conf&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ml_intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blended&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Disagreement → pick the stronger weighted signal
&lt;/span&gt;            &lt;span class="n"&gt;ml_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.65&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ml_conf&lt;/span&gt;
            &lt;span class="n"&gt;kw_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;kw_conf&lt;/span&gt;
            &lt;span class="n"&gt;winner&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ml_intent&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ml_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;kw_score&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;kw_intent&lt;/span&gt;
            &lt;span class="n"&gt;conf&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ml_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kw_score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ml_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kw_score&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;

    &lt;span class="c1"&gt;# ML not confident enough - fall back to pure keyword scoring
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kw_intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kw_conf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three trust zones instead of one threshold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Above 0.70&lt;/strong&gt; - ML is confident. Trust it. Keywords don't get a vote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Between 0.35 and 0.69&lt;/strong&gt;, the interesting zone. If both models agree on the intent, the blended confidence goes up (agreement, amplified signal). If they disagree, the loser still gets 15% of the vote.&lt;br&gt;
That 15% matters it prevents the winner from being overconfident on ambiguous inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Below 0.35&lt;/strong&gt; - ML doesn't know. Pure keyword scoring takes over.&lt;/p&gt;

&lt;p&gt;The 0.65/0.35 weight split is intentional.&lt;br&gt;
ML gets more weight because when it's right, it understands full semantics. Keywords only match surface patterns.&lt;br&gt;
But keywords are more reliable on short, domain-specific inputs like&lt;br&gt;
"cpu" or "mb" where ML tends to underperform.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. The Routing Decision - 5 Steps from Message to Answer
&lt;/h2&gt;

&lt;p&gt;This is the core of the whole engine. Every message follows the same path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;RULE_THRESHOLD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.60&lt;/span&gt;   &lt;span class="c1"&gt;# above -&amp;gt; deterministic rule engine
&lt;/span&gt;&lt;span class="n"&gt;LOW_THRESHOLD&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;   &lt;span class="c1"&gt;# below -&amp;gt; not worth even trying
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ParseResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidence&lt;/span&gt;
    &lt;span class="n"&gt;intent&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 1: Open-ended queries -&amp;gt; LLM first
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small_talk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_available&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_query_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# graceful degradation
&lt;/span&gt;
    &lt;span class="c1"&gt;# Step 2: High confidence -&amp;gt; deterministic, instant answer
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;RULE_THRESHOLD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 3: Medium confidence -&amp;gt; try LLM for smarter answer
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_check_available&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;llm_resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_query_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;llm_resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;llm_resp&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 4: LLM unavailable → rule engine best-effort
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;LOW_THRESHOLD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 5: Nothing works → caller handles it
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No single point of failure. Every step has a fallback.&lt;/p&gt;

&lt;p&gt;Type "cpu" → keyword confidence is 0.95 → Step 2 handles it instantly. Rule engine. Deterministic. No LLM involved.&lt;/p&gt;

&lt;p&gt;Type "why is my computer acting weird today" → keyword confidence is 0.30 → Step 2 skips → Step 3 sends it to Ollama with full system context → if Ollama is down, Step 4 gives a best-effort rule response.&lt;/p&gt;

&lt;p&gt;Type "how are you" → intent is "small_talk" → Step 1 sends it straight to LLM → if unavailable, rule engine returns a canned friendly response.&lt;/p&gt;

&lt;p&gt;I didn't want Ollama for everything, it's slow (2-5 seconds).&lt;br&gt;
I didn't want if/else for everything, it can't handle questions&lt;br&gt;
I didn't anticipate.&lt;br&gt;
So I gave every message a confidence score and&lt;br&gt;
let the score decide which engine handles it.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Intent-Aware Temperature - The Surgeon vs The Friend
&lt;/h2&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%2Fytgdjpbcczx8fr5i9omq.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%2Fytgdjpbcczx8fr5i9omq.png" alt=" " width="612" height="750"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every AI tutorial I've seen uses one temperature setting. Global. Static.&lt;br&gt;
Same creativity level whether you're asking about CPU specs or saying hello.&lt;/p&gt;

&lt;p&gt;I use 20 different temperatures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;_INTENT_TEMPERATURE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# Factual / diagnostic - precision over creativity
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hw_cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# wrong MHz is bad advice
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hw_gpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;throttle_check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stats&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;disk_health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ram_why_high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;0.40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;why_slow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="mf"&gt;0.45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;# Optimization - some creativity welcome
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;performance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;optimization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;0.55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speed_up_pc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;health_check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;0.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;# Conversational - warmth and personality
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;small_talk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;0.80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# "how are you" deserves a human answer
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;about_program&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;0.65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;help&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;           &lt;span class="mf"&gt;0.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_INTENT_TEMPERATURE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEMPERATURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# default 0.72
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"What CPU do I have?" -&amp;gt; 0.35. I want a surgeon.&lt;br&gt;
The answer is a fact: Intel Core i7-12700H, 14 cores, 4.7 GHz boost.&lt;br&gt;
There is exactly one correct answer.&lt;br&gt;
Creativity here means wrong numbers.&lt;/p&gt;

&lt;p&gt;"How are you?" -&amp;gt; 0.80. I want a friend.&lt;br&gt;
Warmth, personality, maybe a joke.&lt;/p&gt;

&lt;p&gt;"Why is my PC slow?" -&amp;gt; 0.45. Somewhere between.&lt;br&gt;
The diagnostic needs to be accurate, but the explanation should be readable, not a data dump.&lt;/p&gt;

&lt;p&gt;One line of code.&lt;br&gt;
Massive difference in response quality.&lt;br&gt;
Probably the highest value-per-line-of-code in the entire engine.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Fallback Chain with Availability Cache
&lt;/h2&gt;

&lt;p&gt;Ollama runs locally but it's not always there.&lt;br&gt;
&lt;strong&gt;Maybe **the user didn't install it.&lt;br&gt;
**Maybe **the model is loading. Maybe it crashed.&lt;br&gt;
**Your assistant can't hang for 30 seconds waiting to find out.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AVAILABILITY_TTL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;   &lt;span class="c1"&gt;# re-check Ollama every 5 minutes
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Respect the cool-down from previous failures
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_temp_unavail_until&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# Cache: don't ping /api/tags on every message
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_available&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_available_checked_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AVAILABILITY_TTL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_available&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_available_checked_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_available&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_pick_best_model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# llama3.2 &amp;gt; mistral &amp;gt; phi3 &amp;gt; gemma &amp;gt; first available
&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_available&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_query_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_temp_unavail_until&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;   &lt;span class="c1"&gt;# crash -&amp;gt; 60s cool-down
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_temp_unavail_until&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;   &lt;span class="c1"&gt;# empty -&amp;gt; model loading, 30s
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_format_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two levels of cool-down. Empty response (model loading) -&amp;gt;** 30 seconds*&lt;em&gt;. Exception (crash, timeout) -&amp;gt;&lt;/em&gt;* 60 seconds*&lt;em&gt;.&lt;br&gt;
Full availability re-check -&amp;gt; **every 5 minutes&lt;/em&gt;*.&lt;/p&gt;

&lt;p&gt;The user never waits for a ping. If Ollama was unavailable 10 seconds ago, the engine routes to rules immediately.&lt;br&gt;
Answer in milliseconds instead of a spinner.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;_pick_best_model()&lt;/code&gt; runs once on availability check:&lt;br&gt;
llama3.2 &amp;gt; mistral &amp;gt; phi3 &amp;gt; gemma &amp;gt; whatever is installed.&lt;br&gt;
If you have multiple models, hck_GPT picks the best one automatically.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Session Memory - AI That Remembers What It Said 3 Messages Ago
&lt;/h2&gt;

&lt;p&gt;Most chatbot tutorials treat every message as independent.&lt;br&gt;
User asks about RAM. Gets an answer.&lt;br&gt;
User asks about system health. Gets a generic response that doesn't mention the RAM issue from 30 seconds ago.&lt;br&gt;
hck_GPT remembers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# When answering a RAM question - save the data:
&lt;/span&gt;&lt;span class="n"&gt;session_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record_response_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hw_ram&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_gb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;speed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="mi"&gt;3200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;typical_avg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;# Later, in a different handler (health_check) - reference it:
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resp_health_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ram_sess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hw_ram&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ram_sess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_gb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ram&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  (Your &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ram_sess&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_gb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; GB RAM we discussed earlier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; - now at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ram&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%, that&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s worth watching)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No SQLite. No JSON file. Just a dict:&lt;br&gt;
&lt;code&gt;{intent: {key: val, recorded_at: timestamp}}&lt;/code&gt;.&lt;br&gt;
Lives in RAM for the session. When the app closes, it's gone.&lt;br&gt;
That's intentional, session memory shouldn't outlive the session.&lt;/p&gt;

&lt;p&gt;There's also trend tracking fed by snapshots every 30 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_trend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_cpu_trend&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ram_trend&lt;/span&gt;
    &lt;span class="n"&gt;readings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# circular buffer of last 8 readings
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;mid&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;first_avg&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readings&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;
    &lt;span class="n"&gt;second_avg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;delta&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;second_avg&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;first_avg&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rising&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;falling&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Split the buffer in half. Compare averages. Rising, falling, or stable. This lets hck_GPT say "your CPU has been climbing for the last few minutes" instead of just showing the current number.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. System Prompt with Live PC Context — Facts, Not Vibes
&lt;/h2&gt;

&lt;p&gt;When a message reaches Ollama, the LLM doesn't guess about your system.&lt;br&gt;
It gets injected context built from real data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;== Live System State ==
CPU: 67%  @ 3840 MHz / max 4800 MHz
RAM: 71%  (11.4/16.0 GB used,  4.6 GB free)
Disk C: 48.3 GB free / 476.0 GB total

== Today's Averages ==
CPU avg: 34.2%  peak: 89.0%
RAM avg: 68.1%

== Top Processes (by CPU) ==
  chrome.exe       CPU 18.4%  RAM 892 MB
  code.exe         CPU 12.1%  RAM 441 MB
  python.exe       CPU  3.2%  RAM 156 MB

== Hardware Profile ==
CPU: Intel Core i7-12700H  (14 cores, boost 4.7 GHz)
GPU: NVIDIA GeForce RTX 3060  VRAM: 6 GB
RAM: 16.0 GB @ 3200 MHz

== Today vs Typical ==
CPU today 34% vs typical 28%  /\ (+6%)
RAM today 71% vs typical 51%  /\ (+20%)

== Learned Usage Patterns ==
Typical CPU avg (7-day baseline): 28%
Heaviest app this week: chrome.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each section comes from a different module. psutil for live data.&lt;br&gt;
SQLite for historical averages. WMI for hardware profile.&lt;br&gt;
The Stats Engine for 7-day baselines.&lt;/p&gt;

&lt;p&gt;The "Today vs Typical" section is the difference between an assistant that says "CPU 67%" and one that says "CPU 67% — but your normal is 28%, something is off." Context, not just data. That's the whole philosophy in two lines of a prompt.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Costs vs The OpenAI Approach
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;hck_GPT (this approach)&lt;/th&gt;
&lt;th&gt;pip install openai&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;zero (beyond psutil)&lt;/td&gt;
&lt;td&gt;openai, tiktoken, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model size&lt;/td&gt;
&lt;td&gt;zero (rule engine is pure Python)&lt;/td&gt;
&lt;td&gt;N/A (cloud)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API costs&lt;/td&gt;
&lt;td&gt;zero&lt;/td&gt;
&lt;td&gt;$0.002-0.06 per message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;&amp;lt;1ms rules, 2-5s Ollama&lt;/td&gt;
&lt;td&gt;500-2000ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet&lt;/td&gt;
&lt;td&gt;not required&lt;/td&gt;
&lt;td&gt;required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy&lt;/td&gt;
&lt;td&gt;data stays local&lt;/td&gt;
&lt;td&gt;sent to OpenAI servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;td&gt;~5MB&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;The intent vocabulary is hand-built.&lt;br&gt;
~200 patterns across 25 intents.&lt;br&gt;
Every time a user asks something I didn't anticipate,&lt;br&gt;
I add patterns manually. This doesn't scale past maybe 50 intents.&lt;br&gt;
A lightweight local classifier (even scikit-learn with TF-IDF) would handle the long tail better.&lt;/p&gt;

&lt;p&gt;The confidence thresholds (0.60, 0.35, 0.20) were tuned by testing, not by math. They work for my use case but they're not optimal.&lt;br&gt;
A proper evaluation dataset would help.&lt;/p&gt;

&lt;p&gt;Session memory is per-session only. The user knowledge base (SQLite in AppData) stores hardware profiles and usage patterns, but conversation context doesn't persist across restarts yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I'm Writing This
&lt;/h2&gt;

&lt;p&gt;Every "build an AI assistant" tutorial I found in 2026...&lt;br&gt;
starts with &lt;code&gt;pip install langchain&lt;/code&gt; or &lt;code&gt;pip install openai&lt;/code&gt;.&lt;br&gt;
Cloud API. Token costs. Internet required.&lt;br&gt;
That's fine for some use cases.&lt;/p&gt;

&lt;p&gt;But if you're building a desktop app that runs on someone else's machine, behind their firewall, on their data, you need a different approach.&lt;br&gt;
&lt;strong&gt;This is that approach:&lt;/strong&gt; a hybrid engine that's fast when it can be, smart when it needs to be, and never crashes because a server is down.&lt;/p&gt;

&lt;p&gt;PC Workman is open source, MIT licensed.&lt;br&gt;
The full AI engine is in &lt;code&gt;hck_gpt/&lt;/code&gt;- intent parser, hybrid engine, response builder, session memory, context builder.&lt;br&gt;
Read it, fork it, build something better.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;Download the .exe (no Python needed): &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK/releases" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read the source: &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;github.com/HuckleR2003/PC_Workman_HCK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All my links: &lt;a href="https://linktr.ee/marcin_firmuga" rel="noopener noreferrer"&gt;linktr.ee/marcin_firmuga&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you build something with a similar approach,&lt;br&gt;
or if you'd do it completely differently.&lt;br&gt;
I want to hear about it!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Marcin Firmuga, solo developer and founder of HCK_Labs.&lt;br&gt;
Building PC Workman publicly between retail shifts.&lt;br&gt;
**800+ hours, 25 GitHub stars&lt;/em&gt;&lt;em&gt;, and one offline AI engine that grew 9 layers when I wasn't looking.&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%2Fgs21l05msxy81qadrdpy.jpg" 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%2Fgs21l05msxy81qadrdpy.jpg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow the build: &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://linkedin.com/in/marcinfirmuga" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://x.com/hck_lab" rel="noopener noreferrer"&gt;X&lt;/a&gt; · &lt;a href="https://medium.com/@marcinfirmuga" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why I Sign Every .exe With Sigstore - PC Workman v1.7.2 Release, Security-First Open Source</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Tue, 28 Apr 2026 21:43:04 +0000</pubDate>
      <link>https://dev.to/huckler/why-i-sign-every-exe-with-sigstore-pc-workman-v172-release-security-first-open-source-4pfh</link>
      <guid>https://dev.to/huckler/why-i-sign-every-exe-with-sigstore-pc-workman-v172-release-security-first-open-source-4pfh</guid>
      <description>&lt;p&gt;Someone tried to scare me with a security audit. It backfired.&lt;/p&gt;

&lt;p&gt;A few days ago, a stranger on the internet found PC Workman — my open-source system monitor — downloaded the .exe, and before running it, did what any sane person should do in 2026: they ran a full security audit.&lt;/p&gt;

&lt;p&gt;Not a quick VirusTotal check. A proper audit. They used Claude to analyze the codebase, the build pipeline, the permissions model, the network behavior, everything.&lt;/p&gt;

&lt;p&gt;Then they sent me the results. I think they expected me to panic.&lt;br&gt;
Instead I replied: "Can I see the full report?"&lt;/p&gt;

&lt;p&gt;They shared it. The audit confirmed what I already knew — clean code, no telemetry, no hidden network calls, no suspicious behavior. They ended up becoming a tester.&lt;/p&gt;

&lt;p&gt;This is the story of PC Workman v1.7.2, the biggest release in the project's history, and why security isn't something I added after the fact. It's baked into how I build.&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%2Ffxe5438ks20gtwxur8c9.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%2Ffxe5438ks20gtwxur8c9.png" alt=" " width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Nobody Trusts .exe Files Anymore (And Why They Shouldn't)
&lt;/h2&gt;

&lt;p&gt;Let's be honest. Downloading a random .exe from GitHub in 2026 is a trust exercise most people fail. And they're right to fail it.&lt;/p&gt;

&lt;p&gt;Open-source doesn't mean safe. It means auditable. The code being public is step one. But if you're shipping executables, you need to prove that the .exe you're distributing was actually built from that public code, wasn't tampered with, and doesn't phone home.&lt;/p&gt;

&lt;p&gt;Most solo developers skip this entirely. They push a PyInstaller build to releases, write "trust me bro" in the README, and wonder why downloads stay low.&lt;/p&gt;

&lt;p&gt;I decided early on that if PC Workman was going to ask for system-level access — reading CPU temperatures, monitoring processes, scanning Windows registry — then security couldn't be an afterthought.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Security Actually Looks Like in PC Workman
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Sigstore Digital Signatures
&lt;/h3&gt;

&lt;p&gt;Every release gets signed with Sigstore. This is the same signing infrastructure used by Kubernetes, npm, and PyPI. It creates a cryptographic proof that ties the executable to my GitHub identity and logs it in a public transparency ledger.&lt;/p&gt;

&lt;p&gt;Anyone can verify it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sigstore verify github PC_Workman_HCK_1.7.2.exe &lt;span class="nt"&gt;--bundle&lt;/span&gt; sigstore.bundle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the signature doesn't match, the file was tampered with. Don't run it.&lt;/p&gt;

&lt;h3&gt;
  
  
  VirusTotal — 70+ Engines, Every Release
&lt;/h3&gt;

&lt;p&gt;Before any .exe goes public, it gets uploaded to VirusTotal and scanned against 70+ antivirus engines. Current result for v1.7.2: 0 detections.&lt;/p&gt;

&lt;p&gt;You don't have to take my word for it. Go to virustotal.com, upload the file yourself, and check.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub CodeQL — Automated on Every Commit
&lt;/h3&gt;

&lt;p&gt;CodeQL runs on every push to main. It scans for common Python vulnerability patterns: injection attacks, path traversal, insecure deserialization, hardcoded secrets. If something triggers, it blocks the commit.&lt;/p&gt;

&lt;p&gt;This isn't something I run occasionally. It runs on every single commit, automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  SECURITY.md — 445 Lines of Policy
&lt;/h3&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%2Fcktsczcu1xphrnkd8ny5.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%2Fcktsczcu1xphrnkd8ny5.png" alt=" " width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most GitHub repos either don't have a security policy, or they have a template that says "email me." PC Workman's SECURITY.md is 445 lines covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supported versions and update timeline&lt;/li&gt;
&lt;li&gt;How to report vulnerabilities (private GitHub reporting + email)&lt;/li&gt;
&lt;li&gt;Response timeline (24h acknowledgment, 72h validation, 7 days for critical fixes)&lt;/li&gt;
&lt;li&gt;CVSS severity classification&lt;/li&gt;
&lt;li&gt;Dependency management process&lt;/li&gt;
&lt;li&gt;Detailed verification instructions for every release&lt;/li&gt;
&lt;li&gt;FAQ addressing trust questions directly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It exists because if you're asking users to run your code with admin privileges, you owe them a complete answer to "why should I trust this?"&lt;/p&gt;

&lt;h3&gt;
  
  
  What PC Workman Does NOT Do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No telemetry. Zero. Nothing phones home.&lt;/li&gt;
&lt;li&gt;No analytics. No tracking. No user profiling.&lt;/li&gt;
&lt;li&gt;No cloud dependency. Core monitoring is 100% offline.&lt;/li&gt;
&lt;li&gt;No data leaves your machine unless you explicitly use the optional AI features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The network section of the audit came back clean because there's nothing to find.&lt;/p&gt;




&lt;h2&gt;
  
  
  v1.7.2 — What Actually Changed
&lt;/h2&gt;

&lt;p&gt;Now for the release itself. The last downloadable .exe was v1.6.8 from March. That was a monitoring tool that collected data and showed it to you.&lt;/p&gt;

&lt;p&gt;v1.7.2 is a different animal. It acts on what it finds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid AI Engine (Complete hck_GPT Rewrite)
&lt;/h3&gt;

&lt;p&gt;The AI layer went from a single &lt;code&gt;chat_handler.py&lt;/code&gt; file to a modular engine with 5 subpackages: &lt;code&gt;engine/&lt;/code&gt;, &lt;code&gt;intents/&lt;/code&gt;, &lt;code&gt;memory/&lt;/code&gt;, &lt;code&gt;context/&lt;/code&gt;, &lt;code&gt;responses/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The routing logic is simple: known intents (stats, alerts, temperature, processes) hit the rule engine first. Fast, predictable, zero external dependency. Open-ended questions ("why is my PC slow right now?") get forwarded to Ollama — a local LLM that runs on your machine. No cloud API. No API key. No tokens.&lt;/p&gt;

&lt;p&gt;If Ollama isn't installed, the engine falls back gracefully. No crashes, no error messages about missing services. It just uses what it has.&lt;/p&gt;

&lt;p&gt;Every response is bilingual. Polish or English, auto-detected per message. The parser uses ASCII-fold dual scoring to handle Polish diacritics without breaking intent matching.&lt;/p&gt;

&lt;p&gt;There's also a proactive monitor running as a background daemon. It watches for sustained CPU pressure (&amp;gt;80% for 30 seconds), RAM warnings (&amp;gt;85%), throttling, low disk space, and long session uptime. When something triggers, it pushes an alert to the chat panel. You don't have to ask. It tells you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Startup Manager
&lt;/h3&gt;

&lt;p&gt;Full page that reads from three Windows registry hives (&lt;code&gt;HKCU&lt;/code&gt;, &lt;code&gt;HKLM&lt;/code&gt;, &lt;code&gt;WOW6432Node&lt;/code&gt;). No admin rights needed for reading. Knowledge base of 30 common programs with impact ratings (High/Medium/Low). Three panels: programs to optimize, programs safe to disable, and the full list.&lt;/p&gt;

&lt;p&gt;Disable means real &lt;code&gt;winreg.DeleteValue()&lt;/code&gt; — but only after a confirmation dialog. Nothing gets removed silently. User choices persist to JSON between sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Services Manager
&lt;/h3&gt;

&lt;p&gt;Catalogue of 40+ Windows services sorted into four categories: Essential (locked, can't be touched), Recommended, Optional, and Likely Unnecessary. Each row shows current status, startup type, and action buttons (Stop/Start/Restart).&lt;/p&gt;

&lt;p&gt;The interesting part is the TURBO Mode integration. You select which non-essential services should auto-stop when TURBO activates. When TURBO deactivates, they restore to their previous state. Selections persist between sessions. All changes get logged.&lt;/p&gt;

&lt;p&gt;Admin detection is built in — if you're not elevated, the manager shows a warning banner instead of pretending the buttons work and failing silently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimization Hub
&lt;/h3&gt;

&lt;p&gt;The old single "Optimization &amp;amp; Services" button in My PC Central got replaced with a 3-zone interactive Canvas widget. Left zone: Optimization Center. Top-right: Startup Manager with live registry entry count. Bottom-right: Services Manager with running service count. Hover brightens the active zone. Metrics update from a background daemon thread.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everything Else
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;First Setup &amp;amp; Drivers page with arc gauge health score computed from driver ages and startup count. Reads directly from Windows registry. No internet, no third-party API.&lt;/li&gt;
&lt;li&gt;Dashboard nav buttons fully redesigned — dark gradients, bordeaux brackets, 7 vector icons drawn on Canvas (zero image files).&lt;/li&gt;
&lt;li&gt;Inter font via GDI32 with Segoe UI fallback.&lt;/li&gt;
&lt;li&gt;HCK_Labs and Guide pages redesigned as full blog layouts.&lt;/li&gt;
&lt;li&gt;Efficiency tab fixes: correct physical core count, per-core session stats, side-by-side TOP CPU/RAM consumers.&lt;/li&gt;
&lt;li&gt;4 new &lt;code&gt;query_api&lt;/code&gt; methods: temperature history, temperature summary, top processes lifetime, weekly comparison with trend detection.&lt;/li&gt;
&lt;li&gt;hck_GPT language bug fixed, temperature fallback fixed, unconditional TURBO tip removed.&lt;/li&gt;
&lt;li&gt;Complete .exe packaging rewrite: 25+ hidden imports, settings directory bundled, proper output naming.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version:&lt;/strong&gt; 1.7.2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commits since last .exe:&lt;/strong&gt; ~60&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New modules:&lt;/strong&gt; 8&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub stars:&lt;/strong&gt; 25&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Downloads:&lt;/strong&gt; ~100+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hours logged:&lt;/strong&gt; 800+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VirusTotal:&lt;/strong&gt; 0/70 detections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sigstore:&lt;/strong&gt; Signed and verified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CodeQL:&lt;/strong&gt; Active on every commit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SECURITY.md:&lt;/strong&gt; 445 lines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telemetry:&lt;/strong&gt; None. Zero. Nothing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmxw07emn1wzrqmtj17a.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%2Ftmxw07emn1wzrqmtj17a.png" alt=" " width="799" height="399"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Ship .exe Files (And Why More Developers Should)
&lt;/h2&gt;

&lt;p&gt;Most open-source projects live and die on GitHub. The README says "clone the repo, install dependencies, run startup.py." That's fine for developers. For everyone else, the project doesn't exist.&lt;/p&gt;

&lt;p&gt;Shipping an executable is harder. You deal with PyInstaller nightmares (8 hours debugging hidden imports for v1.6.8), false positive antivirus detections, signing infrastructure, and the constant question of "how do I prove this is safe?"&lt;/p&gt;

&lt;p&gt;But it's also where the real feedback comes from. Source code users are patient. They expect rough edges. .exe users click the button and expect it to work. That's the standard worth building toward.&lt;/p&gt;

&lt;p&gt;v1.7.2 is the second .exe I've ever shipped. The first was v1.6.8 in March — a monitoring tool with placeholder buttons and a neon green Turbo Boost card. The app barely resembles that version now.&lt;/p&gt;

&lt;p&gt;If you want to try it, the .exe is on GitHub Releases. If you want to audit it first, the source is right there. If you want to verify the signature, the instructions are in SECURITY.md. If you find something wrong, the reporting process is documented.&lt;/p&gt;

&lt;p&gt;That's how it should work.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;v1.7.3 through v1.7.8 will build out the TURBO suite: suspending inactive background processes, auto power plan switching, CPU core unparking, and full integration testing.&lt;/p&gt;

&lt;p&gt;v2.0 targets Microsoft Store publishing and Ollama as a first-class local AI option.&lt;/p&gt;

&lt;p&gt;Next week I start Umiejętności Jutra 3.0 — Google's AI certification program through SGH. First structured learning since I finished technikum. Curious how it'll shape the roadmap.&lt;/p&gt;

&lt;p&gt;PC Workman is open source, MIT licensed. 800+ hours of solo development between retail shifts. Still shipping. Still signing. Still scanning.&lt;/p&gt;

&lt;p&gt;Star the repo: &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;github.com/HuckleR2003/PC_Workman_HCK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All my links: &lt;a href="https://linktr.ee/marcin_firmuga" rel="noopener noreferrer"&gt;linktr.ee/marcin_firmuga&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Marcin Firmuga, solo developer and founder of HCK_Labs. Building PC Workman publicly, honestly, between Żabka shifts. Follow the build: &lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://linkedin.com/in/marcinfirmuga" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://x.com/hck_lab" rel="noopener noreferrer"&gt;X/Twitter&lt;/a&gt; · &lt;a href="https://medium.com/@MarcinFirmuga" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Wednesday Code Autopsy #4: The Canvas Arc Nobody Uses - PC Workman</title>
      <dc:creator>Marcin Firmuga</dc:creator>
      <pubDate>Thu, 16 Apr 2026 17:50:16 +0000</pubDate>
      <link>https://dev.to/huckler/wednesday-code-autopsy-4-the-canvas-arc-nobody-uses-pc-workman-oob</link>
      <guid>https://dev.to/huckler/wednesday-code-autopsy-4-the-canvas-arc-nobody-uses-pc-workman-oob</guid>
      <description>&lt;p&gt;Needed circular progress gauge. Googled "Python circular progress bar." Every answer: &lt;code&gt;pip install [library]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Drew mine with pure tkinter Canvas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero dependencies&lt;/li&gt;
&lt;li&gt;Two parameters: &lt;code&gt;style="arc"&lt;/code&gt;, &lt;code&gt;extent=-270&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Professional look&lt;/li&gt;
&lt;li&gt;20 lines of code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;secret:&lt;/strong&gt; tkinter has THREE arc styles. 99% of devs only use one.&lt;/p&gt;




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

&lt;p&gt;I needed a circular progress gauge for PC Workman's "First Setup &amp;amp; Drivers" page.&lt;/p&gt;

&lt;p&gt;Something clean. Professional. The kind you see in system health dashboards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First instinct:&lt;/strong&gt; Google.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Search:&lt;/strong&gt; "Python circular progress bar"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;matplotlib circular progress tutorial&lt;/li&gt;
&lt;li&gt;PIL + pillow gauge example&lt;/li&gt;
&lt;li&gt;PyQt QProgressBar subclass&lt;/li&gt;
&lt;li&gt;Custom tkinter widget library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every answer started the same: &lt;code&gt;pip install [library]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;PC Workman is already PyQt6 + tkinter + psutil + SQLite. Adding matplotlib for one gauge? Overkill.&lt;/p&gt;

&lt;p&gt;There had to be a better way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Discovery
&lt;/h2&gt;

&lt;p&gt;Opened the &lt;a href="https://docs.python.org/3/library/tkinter.html#canvas-objects" rel="noopener noreferrer"&gt;tkinter Canvas docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Not Stack Overflow. Not a tutorial. The &lt;strong&gt;actual documentation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Found &lt;code&gt;create_arc()&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;style:&lt;/strong&gt; One of 'pieslice' (default), 'chord', or &lt;strong&gt;'arc'&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;style="arc"&lt;/strong&gt; — draws just the arc itself. No fill. No center lines.&lt;/p&gt;

&lt;p&gt;This was it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_draw_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Background arc (full 270° track)
&lt;/span&gt;    &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#1f2937&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Progress arc (proportional to score)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_score_color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;extent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;[10-second PC Health gauge animation]&lt;/p&gt;

&lt;p&gt;Clean. Professional. Zero dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Geometry
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;create_arc()&lt;/code&gt; takes a &lt;strong&gt;bounding box&lt;/strong&gt;, not center + radius:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
&lt;span class="c1"&gt;#                 └─────┬─────┘
#                 rectangle containing circle
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a perfect circle at (60, 60) with radius 50:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
&lt;span class="c1"&gt;#                 60-50, 60-50, 60+50, 60+50
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fbeolvjqnssprhnyrv369.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%2Fbeolvjqnssprhnyrv369.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Angles
&lt;/h3&gt;

&lt;p&gt;tkinter measures angles from &lt;strong&gt;East (3 o'clock) = 0°&lt;/strong&gt;, counterclockwise:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;th&gt;Degrees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;East&lt;/td&gt;
&lt;td&gt;0°&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;North&lt;/td&gt;
&lt;td&gt;90°&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;West&lt;/td&gt;
&lt;td&gt;180°&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;South&lt;/td&gt;
&lt;td&gt;270°&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Trick:&lt;/strong&gt; Negative &lt;code&gt;extent&lt;/code&gt; goes &lt;strong&gt;clockwise&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For a speedometer (7:30 to 4:30 position):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# 225° = bottom-left (7:30)
&lt;/span&gt;&lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt;  &lt;span class="c1"&gt;# -270° clockwise = wraps to bottom-right (4:30)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect 270° gauge.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Secret Third Style
&lt;/h3&gt;

&lt;p&gt;Most devs know two Canvas arc styles:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Style&lt;/th&gt;
&lt;th&gt;What It Draws&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"pieslice"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filled wedge from center (default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"chord"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Arc + straight line connecting ends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;"arc"&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Just the arc curve&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Almost nobody uses &lt;code&gt;style="arc"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's your circular progress bar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#10b981&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7-pixel green arc. No fill. No custom drawing.&lt;br&gt;
&lt;strong&gt;style="arc"&lt;/strong&gt; has been in tkinter since Python 1.x. 99% of developers have never touched it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Production Implementation
&lt;/h2&gt;

&lt;p&gt;The two-line example is simplified. Here's what ships in PC Workman:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_draw_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;92&lt;/span&gt;
    &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;

    &lt;span class="c1"&gt;# Layer 1: Outer glow (wider, darker)
&lt;/span&gt;    &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#1a2035&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Layer 2: Track (gray path)
&lt;/span&gt;    &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#1f2937&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Layer 3: Progress (colored, proportional)
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_score_color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;extent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Score text
&lt;/span&gt;        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                          &lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Consolas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#6b7280&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Consolas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Three layers on same Canvas:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Outer glow&lt;/strong&gt; — 10px dark, 4px larger radius (depth)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track&lt;/strong&gt; — 7px gray, full 270° (background)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progress&lt;/strong&gt; — 7px colored, proportional (gauge)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No masking. No blending. Just stacking arcs.&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%2F1ftdl9caznp8z2j9dayf.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%2F1ftdl9caznp8z2j9dayf.png" alt=" " width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Math
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;extent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Calculation&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;-int(270 * 1.0)&lt;/td&gt;
&lt;td&gt;-270 (full)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;-int(270 * 0.75)&lt;/td&gt;
&lt;td&gt;-202 (¾)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;-int(270 * 0.5)&lt;/td&gt;
&lt;td&gt;-135 (½)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-int(270 * 0.0)&lt;/td&gt;
&lt;td&gt;0 (empty)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;int()&lt;/code&gt; is critical.&lt;/strong&gt; tkinter won't accept float extents — it'll silently fail and draw nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Color Grading
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_score_color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#10b981&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Green
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#fbbf24&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Amber
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#ef4444&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;      &lt;span class="c1"&gt;# Red
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_score_grade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EXCELLENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GOOD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAIR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POOR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three thresholds. Same color in arc, number, and label.&lt;/p&gt;

&lt;p&gt;No color library. Just hex values.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scanning State
&lt;/h2&gt;

&lt;p&gt;Gauge drawn twice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;On load&lt;/strong&gt; — gray track only (&lt;code&gt;score=None&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After scan&lt;/strong&gt; — colored progress (&lt;code&gt;score=0-100&lt;/code&gt;)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Initial
&lt;/span&gt;&lt;span class="nf"&gt;_draw_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;health_canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# After scan thread
&lt;/span&gt;&lt;span class="nf"&gt;_draw_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;health_canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;calculated_score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;if score is not None&lt;/code&gt; prevents empty arc or crash.&lt;/p&gt;

&lt;p&gt;While scanning (registry check, driver status, updates), gauge waits as clean gray circle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Copyable Minimal Example
&lt;/h2&gt;

&lt;p&gt;Want this in your project? Here's the stripped version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tkinter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tk&lt;/span&gt;

&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Tk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#0a0e14&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;draw_gauge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Gray track
&lt;/span&gt;    &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#1f2937&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Colored progress
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;extent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;270&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#10b981&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Text
&lt;/span&gt;        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                          &lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Consolas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nf"&gt;draw_gauge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mainloop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;20 lines. Zero dependencies. Production-ready.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;This gauge powers health check in &lt;strong&gt;PC Workman&lt;/strong&gt; (110+ downloads, 23 GitHub stars).&lt;br&gt;
First thing users see in "First Setup &amp;amp; Drivers."&lt;/p&gt;

&lt;p&gt;Makes the section feel premium — smooth, clean, not default tkinter.&lt;br&gt;
All because I read Canvas docs instead of installing matplotlib.&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%2Fdzxq20tj4msgw37vn2cf.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%2Fdzxq20tj4msgw37vn2cf.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Most developers solve problems by adding dependencies.&lt;br&gt;
Need progress bar? Install library.&lt;br&gt;&lt;br&gt;
Need chart? Install library.&lt;br&gt;&lt;br&gt;
Need widget? Install library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nothing wrong with libraries. Good ones save time.&lt;br&gt;
&lt;strong&gt;But sometimes the best solution is in stdlib docs.&lt;/strong&gt;&lt;br&gt;
In a parameter you've never used.&lt;br&gt;
On a page you've never read.&lt;br&gt;
&lt;strong&gt;style="arc"&lt;/strong&gt; has existed since Python 1.x.&lt;br&gt;
99% of developers never touched it.&lt;br&gt;
I found it in 5 minutes of reading docs instead of Googling "how to."&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;PC Workman v1.7.x builds toward &lt;strong&gt;TURBO Mode&lt;/strong&gt;. Windows optimization tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU unparking&lt;/li&gt;
&lt;li&gt;RAM flushing&lt;/li&gt;
&lt;li&gt;Service management&lt;/li&gt;
&lt;li&gt;Power plan switching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"First Setup &amp;amp; Drivers" scans system, gives health score before TURBO touches anything.&lt;/p&gt;

&lt;p&gt;This gauge is part of that foundation.&lt;/p&gt;

&lt;p&gt;v1.7.2 ships next week.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What's your "I can't believe this is possible with just X" moment?&lt;/strong&gt;&lt;br&gt;
Time you almost installed library, then realized solution was in docs?&lt;br&gt;
Drop it below &lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PC Workman:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK#readme" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HuckleR2003/PC_Workman_HCK/releases/latest" rel="noopener noreferrer"&gt;Download&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Follow the build:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;X: &lt;a href="https://twitter.com/hck_lab" rel="noopener noreferrer"&gt;@hck_lab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://linkedin.com/in/marcinfirmuga" rel="noopener noreferrer"&gt;Marcin Firmuga&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;All links: &lt;a href="https://linktr.ee/hck_labs" rel="noopener noreferrer"&gt;linktr.ee/hck_labs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Wednesday Code Autopsy continues next week.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Building PC Workman in public. One arc at a time.&lt;/p&gt;

</description>
      <category>python</category>
      <category>buildinpublic</category>
      <category>opensource</category>
      <category>github</category>
    </item>
  </channel>
</rss>
