<?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: Breno Gomes Cardoso</title>
    <description>The latest articles on DEV Community by Breno Gomes Cardoso (@breno-cardoso).</description>
    <link>https://dev.to/breno-cardoso</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F99mvlsfu5tfj9m7ku25d.png</url>
      <title>DEV Community: Breno Gomes Cardoso</title>
      <link>https://dev.to/breno-cardoso</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/breno-cardoso"/>
    <language>en</language>
    <item>
      <title>I don't listen to meetings anymore. My sloth does.</title>
      <dc:creator>Breno Gomes Cardoso</dc:creator>
      <pubDate>Mon, 26 Oct 2026 04:29:03 +0000</pubDate>
      <link>https://dev.to/breno-cardoso/i-dont-listen-to-meetings-anymore-my-sloth-does-39fg</link>
      <guid>https://dev.to/breno-cardoso/i-dont-listen-to-meetings-anymore-my-sloth-does-39fg</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Taking notes in a meeting is expensive. While you're writing down what someone just said, you're already missing what they're saying now, so you end up doing two things badly. And most transcription and note-taking tools send the audio to someone else's server. In a lot of workplaces, mine included, that alone rules them out.&lt;/p&gt;

&lt;p&gt;Durmain fixes that for me. It's a sloth that sleeps in the corner of the screen and listens to the call locally. When the call ends, it writes the minutes: a summary, the decisions, the tasks and who they belong to, and a score for how much the whole thing could have been an email.&lt;/p&gt;

&lt;p&gt;And if I'm feeling too lazy to pay attention at all, that's fine too. The sloth wakes up and starts taking notes whenever someone says my name, so I know when I'm being pulled in.&lt;/p&gt;

&lt;p&gt;Everything runs on my laptop. No audio and no text ever leave it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/1hUOONgVPXY" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The whole video was recorded with Wi-Fi off. The voice is a friend reading a fake meeting about a barbecue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/breno-concrete" rel="noopener noreferrer"&gt;
        breno-concrete
      &lt;/a&gt; / &lt;a href="https://github.com/breno-concrete/durmain" rel="noopener noreferrer"&gt;
        durmain
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A sloth that sleeps in the corner of your screen during calls and wakes up when someone says your name. 100% local: faster-whisper + Ollama.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/breno-concrete/durmain/docs/sloth_sleeping.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fbreno-concrete%2Fdurmain%2FHEAD%2Fdocs%2Fsloth_sleeping.png" width="160" alt="Durmain sleeping"&gt;&lt;/a&gt;
  &amp;nbsp;&amp;nbsp;&amp;nbsp;
  &lt;a rel="noopener noreferrer" href="https://github.com/breno-concrete/durmain/docs/sloth_writing.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fbreno-concrete%2Fdurmain%2FHEAD%2Fdocs%2Fsloth_writing.png" width="160" alt="Durmain taking notes"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Durmain&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  A sloth that sleeps in the corner of your screen during calls and lectures,&lt;br&gt;
  wakes up when someone says your name, and writes the minutes when it's over.&lt;br&gt;
  &lt;b&gt;Everything runs on your machine. No audio or text ever leaves it.&lt;/b&gt;
&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Some meetings only need you for the thirty seconds when someone asks you something. The rest of the time you're half listening, and that's exactly when your name gets called.&lt;/p&gt;

&lt;p&gt;Durmain listens to your computer's audio, transcribes it locally, and stays asleep until your name comes up. Then it wakes up, shows what was just said, and starts taking notes. When the call ends, a local LLM turns the transcript into minutes: a summary, decisions, tasks, every time you were mentioned, and an honest score for "this could have been an email".&lt;/p&gt;

&lt;p&gt;Meeting audio is other people's voices and other people's words. It shouldn't go to a third-party…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/breno-concrete/durmain" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The open-source AI here is Whisper (open weights, through faster-whisper) for speech-to-text and Qwen2.5 7B (open weights, Apache 2.0) running locally through Ollama for the minutes.&lt;/p&gt;

&lt;p&gt;The pipeline is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;system audio ─► 5 s blocks ─► faster-whisper + VAD ─► transcript
                                      │                    │
                                      ▼                    ▼ when the call ends
                              name detector ─► sloth   Ollama (qwen2.5:7b) ─► minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capture:&lt;/strong&gt; &lt;code&gt;pyaudiowpatch&lt;/code&gt; records what the PC is playing (WASAPI loopback), in 5 second blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transcription:&lt;/strong&gt; &lt;code&gt;faster-whisper&lt;/code&gt;, model &lt;code&gt;small&lt;/code&gt;, on CPU with &lt;code&gt;int8&lt;/code&gt;. It runs on its own thread, with a queue between recording and transcribing, so recording never waits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name detection:&lt;/strong&gt; &lt;code&gt;rapidfuzz&lt;/code&gt;, word by word, because Whisper almost never writes my name the same way twice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sloth:&lt;/strong&gt; a borderless &lt;code&gt;tkinter&lt;/code&gt; window, always on top, with 20 animation frames.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minutes:&lt;/strong&gt; Ollama running &lt;code&gt;qwen2.5:7b&lt;/code&gt;, only after the call ends. Never at the same time as the transcription.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the plan. Here's what actually happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Whisper makes things up when nobody is talking
&lt;/h3&gt;

&lt;p&gt;The first time I paused a video, the transcript said "Legendas pela comunidade Amara.org" ("Subtitles by the Amara.org community"). Whisper learned from subtitled videos, so silence turns into subtitle credits. &lt;code&gt;vad_filter=True&lt;/code&gt; wasn't enough on its own. I also drop segments with low confidence and filter a short list of known phantom phrases. After that: zero invented sentences during silence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ctrl+C stopped working
&lt;/h3&gt;

&lt;p&gt;WASAPI loopback doesn't deliver any audio while nothing is playing. So &lt;code&gt;stream.read()&lt;/code&gt; just sits there, blocked inside C code, and Python can't handle Ctrl+C until it returns. I moved the read to another thread. Ctrl+C worked, but closing the stream with that thread still stuck in &lt;code&gt;read()&lt;/code&gt; gave me a segmentation fault. The fix was callback mode: PortAudio calls my function when there's audio, and nobody is ever stuck waiting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Whisper can't spell my name
&lt;/h3&gt;

&lt;p&gt;In my first scripted test, Whisper wrote "Brenna", "Brena", "Bruno" and "branco". The fuzzy match was fine. It just never got the right word.&lt;/p&gt;

&lt;p&gt;Lowering the similarity threshold from 85 to 80 would catch "Bruno". But then every real Bruno in the meeting would wake the sloth, and my test script had Bruno and Brenda in it on purpose. Instead, I passed my name to Whisper as a &lt;code&gt;hotword&lt;/code&gt;, which makes it more likely to pick that word when the audio is ambiguous.&lt;/p&gt;

&lt;p&gt;Same recording, 20 mentions of my name and 6 decoy sentences: &lt;strong&gt;15/20 became 16/20, still with 0 false alarms.&lt;/strong&gt; It fixed the misspellings without turning the real Bruno into Breno.&lt;/p&gt;

&lt;h3&gt;
  
  
  The model copied my example
&lt;/h3&gt;

&lt;p&gt;The prompt for the minutes took more rounds than any piece of code. A 7B model takes everything literally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I put an example task in the prompt. The model listed that exact sentence as something that was said in the meeting.&lt;/li&gt;
&lt;li&gt;I wrote "if the score is below 5, write 'not applicable'". It gave a 10/10 and wrote "not applicable".&lt;/li&gt;
&lt;li&gt;I added a list of phrases that usually mean a task. It started marking everything as a task, including a compliment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What worked: a template with no real-looking examples, no conditional rules, quotes copied from a single line of the transcript, and one rule I like a lot: &lt;strong&gt;when in doubt, don't list it.&lt;/strong&gt; A missing item is better than an invented one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The model thought I was talking
&lt;/h3&gt;

&lt;p&gt;The early minutes said things like "Breno mentioned that...". But loopback only captures what comes out of the speakers, not my microphone. Every word in the transcript is someone else's. That limitation became a rule in the prompt: the user only listens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't ask the LLM what code can do
&lt;/h3&gt;

&lt;p&gt;I asked the model to list every time my name was mentioned. It found 6 out of 14. The name detector already had all 14, so now that section is built by code and the LLM never touches it. Use the LLM only where you actually need one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The context window that cuts silently
&lt;/h3&gt;

&lt;p&gt;A 20-minute lecture turned into 5,091 tokens. That's more than Ollama's default context window, and when that happens it doesn't throw an error. It just reads the beginning. Setting &lt;code&gt;num_ctx&lt;/code&gt; to 16384 fixed it, but I only found out because I printed the token count.&lt;/p&gt;

&lt;h3&gt;
  
  
  The GPU crash
&lt;/h3&gt;

&lt;p&gt;Once, right after a session, Ollama failed to load the model on my GPU with a CUDA error. Since the transcript is written to disk line by line during the call, nothing was lost. I ran the minutes script again and it worked.&lt;/p&gt;

&lt;p&gt;This is what the CPU looks like during a live session. Every spike is one 5 second block going through Whisper:&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%2Fqc960861wsmugh8xpexu.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%2Fqc960861wsmugh8xpexu.png" alt="CPU usage during transcription" width="618" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Meeting audio is other people's voices. They agreed to join a meeting, not to have their voice sent to a server I don't control. With open models running locally, that question doesn't even come up.&lt;/p&gt;

&lt;p&gt;It also means it works offline (the demo was recorded with Wi-Fi off), it costs nothing per minute, and switching to another model is changing one string.&lt;/p&gt;

&lt;p&gt;To be honest about the trade-off: a big closed model would probably do a better job on the minutes. In my test it would likely have caught the task Whisper half cut off, and it wouldn't file a decision as a task. That's what I give up. What I get is that nothing leaves my laptop, and I can read every line of what the tool does with the data. For meetings, I'll take that trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built this with an AI coding assistant acting as a mentor: it explained concepts and reviewed my code, and wrote some of the glue code (the Ollama call, the overlay) so I could make the deadline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;This week I used it on a 20-minute public lecture and on a test call with a friend. Writing those minutes by hand would take me 15 minutes; Durmain did it in under a minute.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What&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;Name detection, live call&lt;/td&gt;
&lt;td&gt;8/10 mentions, 0 false alarms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Name detection, scripted recording&lt;/td&gt;
&lt;td&gt;16/20, 0 false alarms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alert latency&lt;/td&gt;
&lt;td&gt;2.5 s on average (worst case ~7 s)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;8/10 decisions and tasks captured, 0 invented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20-minute lecture&lt;/td&gt;
&lt;td&gt;5,091 tokens, minutes in ~36 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silence&lt;/td&gt;
&lt;td&gt;0 invented sentences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resources&lt;/td&gt;
&lt;td&gt;583 MB of RAM, CPU spikes to ~40-50% for 1-2 s per block&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It's not perfect. Blocks don't overlap, so a word spoken right at the edge of a block can get cut, and that caused most of the missed mentions. The 7B model sometimes puts things in the wrong section. Those are the next things I'd fix.&lt;/p&gt;

&lt;p&gt;But for the meetings where I only need to hear my name, the sloth is already doing the listening.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>python</category>
    </item>
  </channel>
</rss>
