<?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: Kayato123</title>
    <description>The latest articles on DEV Community by Kayato123 (@kayato123_fca8d3c04a54849).</description>
    <link>https://dev.to/kayato123_fca8d3c04a54849</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%2F4227008%2F7ad8b604-8982-4b19-9a2e-5459cc1fe1ad.png</url>
      <title>DEV Community: Kayato123</title>
      <link>https://dev.to/kayato123_fca8d3c04a54849</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kayato123_fca8d3c04a54849"/>
    <language>en</language>
    <item>
      <title>Check this out</title>
      <dc:creator>Kayato123</dc:creator>
      <pubDate>Wed, 04 Nov 2026 18:49:22 +0000</pubDate>
      <link>https://dev.to/kayato123_fca8d3c04a54849/check-this-out-1a0g</link>
      <guid>https://dev.to/kayato123_fca8d3c04a54849/check-this-out-1a0g</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kayato123_fca8d3c04a54849/how-i-built-a-local-ai-assistant-that-admits-when-it-didnt-actually-do-the-thing-25bh" class="crayons-story__hidden-navigation-link"&gt;How I built a local AI assistant that admits when it didn't actually do the thing&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="/kayato123_fca8d3c04a54849" 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%2F4227008%2F7ad8b604-8982-4b19-9a2e-5459cc1fe1ad.png" alt="kayato123_fca8d3c04a54849 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kayato123_fca8d3c04a54849" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Kayato123
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Kayato123
                
                
              
              &lt;div id="story-author-preview-content-4977232" 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="/kayato123_fca8d3c04a54849" 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%2F4227008%2F7ad8b604-8982-4b19-9a2e-5459cc1fe1ad.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Kayato123&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/kayato123_fca8d3c04a54849/how-i-built-a-local-ai-assistant-that-admits-when-it-didnt-actually-do-the-thing-25bh" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 4&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/kayato123_fca8d3c04a54849/how-i-built-a-local-ai-assistant-that-admits-when-it-didnt-actually-do-the-thing-25bh" id="article-link-4977232"&gt;
          How I built a local AI assistant that admits when it didn't actually do the thing
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&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/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/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&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/kayato123_fca8d3c04a54849/how-i-built-a-local-ai-assistant-that-admits-when-it-didnt-actually-do-the-thing-25bh" 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/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/kayato123_fca8d3c04a54849/how-i-built-a-local-ai-assistant-that-admits-when-it-didnt-actually-do-the-thing-25bh#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;
            6 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

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

&lt;/div&gt;


</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>How I built a local AI assistant that admits when it didn't actually do the thing</title>
      <dc:creator>Kayato123</dc:creator>
      <pubDate>Wed, 04 Nov 2026 18:48:39 +0000</pubDate>
      <link>https://dev.to/kayato123_fca8d3c04a54849/how-i-built-a-local-ai-assistant-that-admits-when-it-didnt-actually-do-the-thing-25bh</link>
      <guid>https://dev.to/kayato123_fca8d3c04a54849/how-i-built-a-local-ai-assistant-that-admits-when-it-didnt-actually-do-the-thing-25bh</guid>
      <description>&lt;h1&gt;
  
  
  How I built a local AI assistant that admits when it didn't actually do the thing
&lt;/h1&gt;

&lt;p&gt;The sentence that started this project was five words long:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I've sent the email."&lt;br&gt;
It hadn't. Nothing had run. There was no email tool call in that turn, no SMTP connection, no record of anything. Just a small local model, a confident tone, and a sentence that was completely false.&lt;br&gt;
If you've wired a 7B model up to function calling, you've probably met the same failure. It's not a crash. It's not an exception in your logs. It's worse: &lt;strong&gt;it's a fluent, well-formed paragraph that silently disagrees with reality.&lt;/strong&gt; Your UI shows a checkmark, the user moves on with their day, and the thing never happened.&lt;br&gt;
This is the story of the fix in my open-source project, &lt;a href="https://github.com/Quasynvo/Quasnooze" rel="noopener noreferrer"&gt;Quasnooze&lt;/a&gt;, and the one design decision I'd defend hardest if you asked me why it's built the way it is.&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem: hallucination isn't just wrong facts, it's wrong &lt;em&gt;actions&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Most discussion of hallucination is about knowledge. The model says the library was released in 2015 when it was 2017. Annoying, but visible — the user can catch it.&lt;br&gt;
Agentic hallucination is different in kind. When a model has tools, it doesn't just describe the world, it &lt;em&gt;narrates its own effects on the world&lt;/em&gt;. And small models are especially prone to narrating effects that didn't happen, because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The training signal rewards helpful-sounding completions. "I've sent it" is a more satisfying answer than "I can't confirm that."&lt;/li&gt;
&lt;li&gt;A tool call can fail, get denied, time out, or never be emitted at all — but the model's next token prediction doesn't care about any of that.&lt;/li&gt;
&lt;li&gt;The failure is &lt;strong&gt;invisible to the developer&lt;/strong&gt; unless you deliberately check for it. The HTTP response was 200. The text streamed fine. The turn "succeeded."
My first attempt was the obvious one: prompt engineering. A system prompt with strong instructions — never claim an action you didn't take, only refer to tool output, don't invent contact details. I wrote it carefully. I iterated on it.
It mostly worked.
&lt;strong&gt;That's what made it dangerous.&lt;/strong&gt; A 90%-effective prompt doesn't fail randomly, it fails &lt;em&gt;confidently&lt;/em&gt; — and it fails exactly on the turns where the model feels most helpful, which are the turns where you're least likely to double-check. Worse, a stronger model doesn't fix it, it just produces a more convincing paragraph. The lie gets better grammar.
Prompting, in other words, was asking the same component that made the error to be the component that catches it.
## The fix: audit the reply, don't trust it
The insight I built around is small but it changes the architecture:
The model's reply is &lt;strong&gt;not output&lt;/strong&gt;. It's a &lt;strong&gt;claim&lt;/strong&gt;, and claims can be checked against evidence.
At the end of every turn, Quasnooze has two things the model doesn't fully control:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The tool trace&lt;/strong&gt; — which tools actually ran, whether they returned &lt;code&gt;ok&lt;/code&gt;, whether the user &lt;em&gt;denied&lt;/em&gt; them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The memory facts&lt;/strong&gt; — what's genuinely in the store, not what the model wishes were there.
So instead of trusting the prose, the app compares the prose to the evidence. &lt;code&gt;src/guard.js&lt;/code&gt; is a pure function that takes the reply, the trace, the memory facts, the user's text and the tool output, and returns a list of flags.
Here's the actual API — this runs standalone, no server, no model:
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;auditReply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderGuardNote&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/guard.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;auditReply&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Done — I've sent the email to priya@example.com.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;                       &lt;span class="c1"&gt;// nothing actually ran this turn&lt;/span&gt;
  &lt;span class="na"&gt;memoryFacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;userText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email priya about the launch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;renderGuardNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real output from that snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"action-without-evidence"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"the reply says &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;i've sent&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; but no tool ran that could have done it"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"invented-email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"an address appears that was never given to me: priya@example.com"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the note the user actually sees:&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="p"&gt;---&lt;/span&gt;
🛡️ &lt;span class="gs"&gt;**Code check:**&lt;/span&gt; the reply above needs a second look.
  • the reply says "i've sent" but no tool ran that could have done it
  • an address appears that was never given to me: priya@example.com
&lt;span class="ge"&gt;_Quasnooze checks claims against what actually ran — this one did not line up._&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The detail that matters most: it never rewrites the model
&lt;/h3&gt;

&lt;p&gt;The tempting version of this feature silently corrects the text, or regenerates the response, or quietly drops the offending sentence. I deliberately didn't do any of that, for a reason I now feel strongly about:&lt;br&gt;
&lt;strong&gt;A silent correction is just a tidier way of lying about what happened.&lt;/strong&gt;&lt;br&gt;
If the code edits the model's words, the user cannot tell whether the assistant genuinely succeeded or whether a regex papered over a failure. So the guard appends a visible note and never touches the model's text. The transparency &lt;em&gt;is&lt;/em&gt; the product. A flag is a nudge, not an alarm — the styling is deliberately calm, because false positives are real and I don't want to train people to panic.&lt;/p&gt;
&lt;h2&gt;
  
  
  The other half: approval is a separate code path
&lt;/h2&gt;

&lt;p&gt;The same principle — &lt;em&gt;never let one layer quietly speak for another&lt;/em&gt; — shaped the permission system.&lt;br&gt;
When a tool is sensitive, the model can't approve it. Neither can a spoken "yes." Neither can an animation. Approval is a distinct path from the visual state machine, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;visualizer can display five states&lt;/strong&gt; (idle, listening, thinking, speaking, interrupted) and has no ability to authorize anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action previews are display-only metadata.&lt;/strong&gt; They're sanitized and redacted with a fixed set of reason codes, they're ephemeral, and they are never the object that permits execution. That separation is enforced by the shape of the code, not by good intentions.&lt;/li&gt;
&lt;li&gt;A denied tool in the trace is itself evidence: if you denied a permission prompt and the reply still claims success, the guard says so, explicitly, in the note.
That last one is my favourite small detail in the codebase. A denial is a fact about the turn, and the audit treats it as one.
## Stack and setup, honestly
Quasnooze is &lt;strong&gt;Node.js 22 or newer&lt;/strong&gt;, with &lt;strong&gt;no required runtime dependencies and no framework&lt;/strong&gt;. The reasoning runs locally through &lt;strong&gt;Ollama&lt;/strong&gt;; optional cloud providers, browser speech and messaging channels each have their own explicit data boundary, and they're off unless you turn them on. It's MIT licensed.
Three commands:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Quasynvo/Quasnooze.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Quasnooze
npm run setup   &lt;span class="c"&gt;# configure model, workspace, access key, optional channels&lt;/span&gt;
npm run doctor  &lt;span class="c"&gt;# check what's actually working, including what isn't&lt;/span&gt;
npm run brain   &lt;span class="c"&gt;# verify your model is reachable&lt;/span&gt;
npm start       &lt;span class="c"&gt;# panel on http://localhost:7777 by default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;npm run doctor&lt;/code&gt; deserves a mention: it only probes loopback origins, and it will happily tell you that a feature is &lt;em&gt;not&lt;/em&gt; ready rather than pretend. It's the most-used script in the repo for a reason — most "it doesn't work" issues are configuration, not code.&lt;br&gt;
If you want the voice visuals in your own project, the renderer is a plain ES module with no build step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createVisualizer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/visualizer.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createVisualizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;voiceCanvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Drive this from real application state, not from a decorative timer.&lt;/span&gt;
&lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;thinking&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's unfinished (please read this part too)
&lt;/h2&gt;

&lt;p&gt;I'd rather undersell this than have you find the gaps yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Windows voice host is a preview.&lt;/strong&gt; Physical microphone behaviour, wake-word detection and startup handling still need real-hardware acceptance testing. It's the least proven part of the project.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;native API exposes amplitude, not FFT&lt;/strong&gt;, so the "speaking" visual in native mode is decorative rather than a true output spectrum. The code distinguishes live FFT, native scalar level, synthetic demo data and state-only motion, and never dresses one up as another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval is serviceable, not good.&lt;/strong&gt; It works; don't expect a research-grade RAG stack.&lt;/li&gt;
&lt;li&gt;There are &lt;strong&gt;54 test files&lt;/strong&gt; run with &lt;code&gt;node --test&lt;/code&gt;, and not one of them can tell you whether a microphone works.&lt;/li&gt;
&lt;li&gt;The guard's verb lists are &lt;strong&gt;regexes&lt;/strong&gt;. They will produce false positives eventually. That's the part I most want help with.
## Try it, and tell me where it's wrong
Repo: &lt;strong&gt;&lt;a href="https://github.com/Quasynvo/Quasnooze" rel="noopener noreferrer"&gt;github.com/Quasynvo/Quasnooze&lt;/a&gt;&lt;/strong&gt;
If the audit idea is interesting to you, a ⭐ genuinely helps the project get seen — but what helps &lt;em&gt;me&lt;/em&gt; far more is this:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Break the guard.&lt;/strong&gt; Find a reply that asserts an action with no evidence and slips past &lt;code&gt;auditReply&lt;/code&gt;. Those cases are worth more than stars, and I'll credit them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tell me if post-hoc auditing is the wrong layer.&lt;/strong&gt; My instinct is that checking after generation is the only place you &lt;em&gt;can&lt;/em&gt; check, because it's the only place the claim exists. But if you've solved this inside the tool-calling schema, or with a real claim-verification eval set, I want to read how.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open an issue for anything misconfigured&lt;/strong&gt; rather than filing it as "broken" — &lt;code&gt;npm run doctor&lt;/code&gt; usually points at the culprit.
PRs are welcome; there's a &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; and the test suite is plain &lt;code&gt;node --test&lt;/code&gt; with no global install needed.
And if you take one thing from this post without ever cloning the repo: &lt;strong&gt;don't ask the component that lied to catch the lie.&lt;/strong&gt; Give your assistant something it doesn't control to check itself against.
---
&lt;em&gt;If you build something similar — or you've got a better answer for the guard's regex problem — I'd love to hear it in the comments.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
