<?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: J3ffJessie</title>
    <description>The latest articles on DEV Community by J3ffJessie (@j3ffjessie).</description>
    <link>https://dev.to/j3ffjessie</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F129185%2F37c19477-2e89-4eb2-ba88-1c4dbb0f747d.jpeg</url>
      <title>DEV Community: J3ffJessie</title>
      <link>https://dev.to/j3ffjessie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/j3ffjessie"/>
    <language>en</language>
    <item>
      <title>Torc Bot 3: Torclation Services</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Fri, 27 Feb 2026 20:28:52 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/torc-bot-3-torclation-services-3m8k</link>
      <guid>https://dev.to/j3ffjessie/torc-bot-3-torclation-services-3m8k</guid>
      <description>&lt;h2&gt;
  
  
  Why build it?
&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%2Fylu9nujc010fxzkff12h.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%2Fylu9nujc010fxzkff12h.png" alt="Animated Gathering of people of a community" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So within the Torc community, we have a global user base with a very large contingent in LATAM. For a lot of our events there is a specific Espanol version of the stream and there are other times that there are specific events that are only for Spanish speaking members. For those of us in the community that aren't fortunate enough to speak spanish this means we miss out on those events. So about a month ago, during one of our dual events it was brought up that users would love to participate in the Spanish speaking event if they could get translation of what was being said so they could participate in the chat.  I took this as priority immediately because I want the community to have access to everything possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to start
&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%2F38kxkl4k52dsuohuw8ze.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%2F38kxkl4k52dsuohuw8ze.png" alt="Developer looking lost with both hands up sort of asking what now" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I honestly had no idea where to even start with this feature. I went to the Discord documentation to check through what exactly was available and did some searching online to familiarize myself with how Discord audio works. Apparently Discord sends audio in Opus codec format. So I started looking at options to utilize Opus codec and what I could do with it. Now I am no audiophile so when I started reading about audio formats and encoding and decoding and all that I admittedly was in over my head.  &lt;/p&gt;

&lt;p&gt;A few searches later for different existing discord bots that mess with audio I found documentation that mentioned Opusscript decoder to be able to decode the audio file to a PCM format so it could be used for my purpose of sending off to AI model for translation.  I started by adding in the simple commands to start/stop the translation functionality and verified that everything fired properly without creating new issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Flow
&lt;/h2&gt;

&lt;p&gt;For everything to work properly, when the user runs the command /translate start within a voice channel, the bot joins the audio call to start listening.  The flow follows the following pattern&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Discord voice channel
        │
        ▼
  voiceService.js        — Opus audio capture + per-frame decoding
        │
        ▼
transcriptionService.js  — PCM → WAV → Whisper (Groq API)
        │
        ▼
 translationService.js   — Translated English text (Groq API / LLaMA)
        │
        ▼
  streamingService.js    — WebSocket broadcast
        │
        ▼
   captions.html         — Live captions displayed in browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The details
&lt;/h2&gt;

&lt;p&gt;So I shared on X, this was the most interesting feature that I have added so far to the bot, what I really meant was that this was the most difficult and draining feature to add as well as interesting.  So, lets get into the details of it and explain what is happening behind the scenes of the operation.&lt;/p&gt;




&lt;h3&gt;
  
  
  sessionService
&lt;/h3&gt;

&lt;p&gt;When the user runs the /translate start command, the bot checks that the user is in a voice channel first... and if they aren't it informs the user to join a voice channel. This error handling was added to avoid accidental triggers in non voice channels when attempting to use other commands or just accidental usage.  A session is created via the sessionService which generates a unique random token that is tied to the discord community server (guild ID) adn stores a set of connected WebSocket clients.&lt;/p&gt;

&lt;p&gt;Once this is done, it calls to voiceService to have the bot join the voice channel as a listener and calls to the captureAudio function that starts capturing the spoken audio.&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;async&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;guildId&lt;/span&gt;&lt;span class="p"&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;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;joinVoiceChannel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;guildId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;guild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;adapterCreator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;guild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;voiceAdapterCreator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;selfDeaf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;selfMute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connections&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;span class="nx"&gt;guildId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;connection&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;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&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;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Brief delay avoids the corrupted first Opus frame Discord sends&lt;/span&gt;
      &lt;span class="c1"&gt;// when a user's encoder initializes.&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guildId&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;guildId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&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;One key in this function is the setTimeout to delay capture of Audio. One of the most infuriating things I kept running into was that there were corrupt Opus frames. Originally I was using the Opus dependency and due to being on a newer version of Node and also newer version of discordjs package, their were issues where when a corrupt frame was found it would stop the audio capture completely which meant users saw nothing in the captions page.  Obviously this is a waste of time because it needs to handle corrupted frames without ending the service.&lt;/p&gt;

&lt;p&gt;So I did some searching and AI assistance to find out that opusscript works best with Node 20 and did the switch around and still had corrupt frame issues but only right at the beginnning of the audio capture. So I wrote up a timeout with a delay and no longer received a corrupt frame immediately on audio capture. Using OpusScript I am able to chunk the audio together in small batches and maintain consistent capturing while sending the audio off to be translated without losing much of the audio being captured at all.&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;async&lt;/span&gt; &lt;span class="nf"&gt;captureAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;guildId&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="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeCaptures&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="nx"&gt;userId&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeCaptures&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;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&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;opusStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EndBehaviorType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AfterSilence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;audioBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hitMaxDuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpusScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;48000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OpusScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AUDIO&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;pcmChunks&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;settled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;settle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;settled&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="nx"&gt;settled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&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;maxTimer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;hitMaxDuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;opusStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="nf"&gt;settle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;MAX_CAPTURE_MS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;opusStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&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;packet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pcm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;pcmChunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;audioBytes&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Corrupted Opus frame — skip this frame, keep going&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;opusStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;end&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxTimer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;settle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;opusStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxTimer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;settle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;opusStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxTimer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;settle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Capture error for user &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&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="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Release the lock immediately — the next utterance can start capturing&lt;/span&gt;
      &lt;span class="c1"&gt;// without waiting for the Whisper + translation API calls to finish.&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeCaptures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// User is still speaking — re-subscribe right away before yielding to&lt;/span&gt;
      &lt;span class="c1"&gt;// the event loop so we don't miss audio between chunks.&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hitMaxDuration&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guildId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;guildId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&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="nx"&gt;opusStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Hand off to background processing — does not block the next capture.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;48000&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;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioBytes&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;minBytes&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;pcmChunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcmChunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;guildId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Process error for user &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&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;h3&gt;
  
  
  We have audio, now what?
&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%2Fpn477bzdph9jynajwj9y.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%2Fpn477bzdph9jynajwj9y.png" alt="Person listening to audio on headphones while sitting down" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OpusScript takes the audio from Discord and decodes it into a temporary PCM file which is then converted into a WAV file that becomes the transcript to be used for translation by Groq llama-3.1b model. In easy speak, we are taking speech, converting it to text, then translating the text and passing it to the UI for consumption.  The intricate part of it all was figuring out the chunks so that when we capture audio and begin the process of sending that opus coded file for translation, we immediately catch the next spoken word so that we don't miss out on any of the spoken words. It isn't perfect by any means, but overall with the limitations of server response and timing it does as well as I believe it can be done at the moment without hosting the translation locally to cut out some of the latency.&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;async&lt;/span&gt; &lt;span class="nf"&gt;convertPcmToWav&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcmFile&lt;/span&gt;&lt;span class="p"&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;wavFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pcmFile&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pcm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.wav&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pcmFile&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;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FileWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wavFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;sampleRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;bitDepth&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="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;finish&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wavFile&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&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="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid file path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transcriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;whisper-large-v3-turbo&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;llama-3.1-8b-instant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;temperature&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="c1"&gt;// 🔥 important for consistency&lt;/span&gt;
      &lt;span class="na"&gt;messages&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You are a translation engine. Translate ALL input text to English. Return ONLY the translated text. Do not explain. Do not add commentary.&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="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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;h3&gt;
  
  
  Translation meets the UI
&lt;/h3&gt;

&lt;p&gt;Early in the process, when the user summons the bot to do translation there is a captions url that is generated. This URL points the user to the browser to a simple HTML page that gets the translated text passed in to display to the user.&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%2Fodwhx4v6cham62d3zal2.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%2Fodwhx4v6cham62d3zal2.png" alt="Screen capture of the captions page where translations are displayed to the user" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows the user to have both the Discord stream pulled up and also the translation in the browser so they can see both at the same time and respond in the chat and participate.  The initial design of the caption page was as simple as possible and I plan to throw a fresh paint of coat on that in the near future to make it more visually appealing, but for the initial release my major focus was on performance and getting things to work and work decently enough to be useful for users.  I believe that I am as close to live translation as I can get without hosting the models locally and cutting out server calls. &lt;/p&gt;

&lt;h2&gt;
  
  
  Iteration....? Future Additions
&lt;/h2&gt;

&lt;p&gt;Future adjustments will be made as feedback comes in and more uses are done live to see more and more results.  This will result in prompt changes, timing changes to see if adjusting the amount of audio captured before sending for translation will help or if smaller chunks are better than pushing for longer periods of audio to try and eliminate splitting sentences and things with translations.&lt;/p&gt;

&lt;p&gt;Overall, the learning on this was great and the end result although not fully noticed yet is that I have created something for the community at large that can be utilized by other discord servers if they choose and offer this ability within their servers for their users.  I am thoroughly enjoying doing things that help the community overall and make the Torc discord an inclusive place where we support people from all areas and try to offer the ability for everyone to join and participate as much as possible.&lt;/p&gt;

&lt;p&gt;Plans are in process of adding multi-server support so that the bot can run independently in mutlitple servers with config handled by server admins on what features do what. This is the next big push for the bot as I want to have it available for other communities that may have a need for translation of their events and what not.&lt;/p&gt;

&lt;p&gt;Disclaimer: Images people or persons are generated using ChatGPT while snippets of code and webpages are not. Writing has been done with the assistance of AI to attempt at maintaining readability of technical descriptions.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>community</category>
      <category>showdev</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Torc Bot 2: The Refactor</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Mon, 23 Feb 2026 18:55:04 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/torc-bot-2-the-refactor-2f34</link>
      <guid>https://dev.to/j3ffjessie/torc-bot-2-the-refactor-2f34</guid>
      <description>&lt;h2&gt;
  
  
  Refactoring is important, but also difficult
&lt;/h2&gt;

&lt;p&gt;You ever create something with the best intentions of it being to standard and end up just winging it after you get started? Yeah, I did that with Torc Bot, the discord bot I created for the Torc.dev community. Originally slotted for just a summarization bot to help the community catch up with chats turned into a randomized grouping of features all jumbled into a 2k line single file bot.  Originally I built out the summarization to use Groq AI llama model just to pull the last 100 messages from a channel and pass them to the AI model for summarization.  Worked pretty well and was useful.&lt;/p&gt;

&lt;p&gt;Then came requests to add a weekly server summary so we could see what was discussed across all channels, then reminder functionality and some internal tools to help the Torc team.  What started out as a simple single file discord bot started to morph into a giant mess of commands and services functions and utility functions that was getting hard to maintain and even harder to add new features to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazfav9lpzg8idao3hzz7.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%2Fazfav9lpzg8idao3hzz7.png" alt="Stressed Developer Looking Through Code" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can't I just do this thing?
&lt;/h2&gt;

&lt;p&gt;This became evident when I went to add a new feature to have translation services for some of our streamed events in the discord community. As Torc is a global team and we have multiple languages and our live events usually have a Spanish speaking alternative for our LATAM community. These are awesome events and sometimes the LATAM side gets different events than our regular english speaking side and if you don't speak Spanish those events may not make a lot of sense.  So I set out like the good little botman that I am to add the ability to have live translation to the discord bot. That is when I realized that I should have done things correctly from the start.&lt;/p&gt;

&lt;p&gt;I was attempting to add in multiple commands, utilities and services to this discord bot that would all be living inside an already jam packed file and things were getting lost easily.  If I had an issue with something not working properly, it was a seek and find to try and track down where the function was that controlled that logic and ensuring that the dependencies were all loaded correctly and it was maddening, like &lt;strong&gt;Why can't I just do this thing?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Refactor
&lt;/h2&gt;

&lt;p&gt;Now I won't lie to you and say I spent many nights working the refactor of this discord bot. I took a couple days to sort out the basic project layout with file structure, and then tossed it over to Claude to handle moving functionality and code into specific files for utility functions and services as well as commands.  Once Claude was done migrating and setting things up, I spent a couple days going through each new file created to ensure commands were correct and referencing the right environment variables for both local hosting and live server hosting. What would have taken me probably a month of going line by line to sort through everything into the correct files and make sure that cross functionality was working only took Claude like 45 minutes total with a few re-prompts for clarification.&lt;/p&gt;

&lt;p&gt;The leg work of just verifying files was a lot easier utilizing AI in this fashion. I knew that all the commands worked, and that everything that was currently implemented was functional on the server hosted version (outside of coffee pairing... stupid bot).  So passing off just the reorganization of files to AI was the easiest decision to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the result
&lt;/h2&gt;

&lt;p&gt;The end goal was a user friendly code base that was easy to navigate, edit and add new features to.  Overall I feel like that has been accomplished by doing this refactor of everything.  I now have a code base that someone can fork and run their own discord bot for their own server or whatever without needing to decipher hieroglyphics or hunt through numerous files trying to diagnose any issues that they may have during setup or development.&lt;/p&gt;

&lt;p&gt;The bot went from a 2k+ line index.js file to that file being 154 lines in total currently.  Obviously there are more files, but overall the structure is easier to understand given the standard file structure.&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%2Favsg1be0kz4g6l2uu5r4.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%2Favsg1be0kz4g6l2uu5r4.png" alt="Project File Structure in VS Code" width="474" height="715"&gt;&lt;/a&gt;&lt;br&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%2Fw7nnrim8l6kz1lv6e4ow.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%2Fw7nnrim8l6kz1lv6e4ow.png" alt="Project File Structure in VS Code" width="476" height="878"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully going forward I have an easier time adding in new features and diagnosing issues when there are changes to the Discord API or way of doing things and it makes it easier to add the fixes without hunting for hours and hating myself for past decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why am I writing about this?
&lt;/h2&gt;

&lt;p&gt;To provide the learned lesson to any other developer starting a new project to encourage you, even if the project seems like it will be something small and you don't think you will be iterating on it. Make sure that you set up your project structure according to the normal standars for a project that scales to avoid the headache that I had. Although not critical as this was just a discord bot, the extra work to refactor and verify could have taken a lot longer to get done. This would have meant new features and requests would have had a longer ramp up time to be introduced. Versus if I had just done it correctly from the start we may be further ahead than we are now.&lt;/p&gt;

&lt;p&gt;Disclaimer: First image was generated using AI ChatGPT other images and all writing was done without AI assistance.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a Multifunctional Discord Bot: A Comprehensive Technical Deep Dive</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Mon, 12 Jan 2026 18:19:14 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/building-a-multifunctional-discord-bot-a-comprehensive-technical-deep-dive-3kf6</link>
      <guid>https://dev.to/j3ffjessie/building-a-multifunctional-discord-bot-a-comprehensive-technical-deep-dive-3kf6</guid>
      <description>&lt;p&gt;Discord has become the go-to platform for running communities, whether you’re organizing a gaming guild, a dev collective, or a professional network. It has plenty of built-in tools, but sometimes you just want to build the thing that matches how your community actually works.&lt;/p&gt;

&lt;p&gt;This post walks through the architecture and implementation of the Torc Discord bot that does a little of everything, channel and server summaries, coffee chat pairings, a reminder system, and event integration. Along the way, it highlights patterns like rate limiting, concurrency safety, async scheduling, and resilient error handling. Note that code blocks are not the full complete functions or code blocks, that was done intentionally as then this post would be like 10 pages long. I mainly wanted to give an overview of the configuration and layout versus direct copy pasta of the entire bot file. Hopefully that doesn't detract you from reading. &lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;The bot is built on &lt;code&gt;discord.js&lt;/code&gt;, the go to library for working with the Discord API from Node.js. It integrates with a few external services to extend Discord’s capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Groq API&lt;/strong&gt; for fast, low-latency LLM-powered conversation summarization using the Llama 3.1 8B model (I'm cheap)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Luma API&lt;/strong&gt; for fetching and listing upcoming events
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mee6 API&lt;/strong&gt; (optional) for gamification data such as member levels
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;node-cron&lt;/strong&gt; for running scheduled tasks on a fixed timetable
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Commands follow a message driven design and support both modern slash commands and older prefix-based commands. This keeps the bot compatible with existing usage while taking advantage of newer Discord interaction patterns. There are also a couple automated cron jobs that run as well that are not using message driven design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conversation Summarization
&lt;/h2&gt;

&lt;p&gt;The original reason I started building this bot, was because Taylor mentioned that he couldn't keep up with the chat and if he could get a summary that was easy to read and quick it would help. So I started working on putting that together and the rest just sort of snowballed. Also, to note that I don't believe Taylor has ever used the summarize command since it has been built. ROFL!!! &lt;/p&gt;

&lt;p&gt;For channel summaries, the bot grabs the latest 100 messages in the channel where the command is entered and sends them to Groq’s &lt;code&gt;llama-3.1-8b-instant&lt;/code&gt; model to produce a concise recap:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;summarizeMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;groq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;messages&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a friendly Discord conversation analyzer...&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="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Please provide a detailed summary...:\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llama-3.1-8b-instant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&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="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error in summarization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;Key design choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system prompt asks for friendly, bulleted output without getting overly rigid or over-categorized.
&lt;/li&gt;
&lt;li&gt;A temperature of &lt;code&gt;0.7&lt;/code&gt; balances consistency with natural variation in phrasing.
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Long responses are chunked into ~1900-character segments to stay under Discord’s message limits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Could the prompt be better? Probably. I haven't given it much work since  I was able to get a result that I was comfortable with. I am open to criticism or input though.&lt;/p&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server-Wide Weekly Digests
&lt;/h2&gt;

&lt;p&gt;This functionality was more of a necessity than a community ask. It gives a quick way on Monday for any user to check what happened the previous week and have some context on conversations that may come up in the chat again. A cron job runs every Monday at 10:00 UTC and kicks off a server-wide digest:&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="nx"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 10 * * 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;gatherServerConversationsAndSummarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Post to designated channel...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server summarization works similarly to the channel summarization. It grabs the last 100 messages from all accessible channels and chunks them together for processing and passes that off for summarization. The server summarization prompt is more structured and explicitly asks the model to pull out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facts and announcements
&lt;/li&gt;
&lt;li&gt;Decisions and conclusions
&lt;/li&gt;
&lt;li&gt;Ongoing discussions
&lt;/li&gt;
&lt;li&gt;Action items and follow-ups
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To keep things honest, the prompt also includes strict rules such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only summarizing what is actually present in the messages
&lt;/li&gt;
&lt;li&gt;Not inferring motivation, intent, or outcomes
&lt;/li&gt;
&lt;li&gt;Not inventing decisions, action items, or conclusions
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That keeps the digest grounded in real conversation rather than guesses.&lt;/p&gt;




&lt;h2&gt;
  
  
  Coffee Chat Pairings
&lt;/h2&gt;

&lt;p&gt;Probably the functionality I am most proud of. Most people are familiar with coffee chats. Quick little 15 minute conversations to get to know someone else and network and just have conversation. Well, what is one of the most important parts of a community? You guessed it!!! We want our members to know each other and have a strong network. It has been said by Taylor and a few others, but we want Torc especially the Discord community to feel like home. Where you can be yourself and share your wins and struggles without feeling like you will be judged, instead being understood and supported.  So since I know full well that reaching out to a stranger to ask about doing a coffee chat is sort of awkward, I put together the functionality that pairs people together to have coffee chats in hopes that it gives a little nudge that makes doing the coffee chats less awkward and gets people more comfortable in reaching out to others.&lt;/p&gt;




&lt;p&gt;The “coffee chat” system is designed to regularly pair up members who have a specific role, without constantly repeating the same matches. It can optionally factor in Mee6 leveling data to encourage pairings across different engagement levels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pairing With Cooldowns
&lt;/h3&gt;

&lt;p&gt;The core pairing function shuffles the member list and then tries to find a partner that satisfies the cooldown and fairness rules:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pairUpWithCooldown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cooldownMs&lt;/span&gt;&lt;span class="p"&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;shuffled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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;pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;partnerIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// 1) Try to find a partner that was not paired recently&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;wasRecentlyPaired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cooldownMs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;partnerIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&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="c1"&gt;// 2) If none found, prefer the partner with the fewest prior pairings&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;partnerIndex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&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;span class="c1"&gt;// Fallback logic to find least-matched partner...&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;partnerIndex&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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="nx"&gt;pairs&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 pairing logic favors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partners who have not been matched recently (respecting a cooldown window).
&lt;/li&gt;
&lt;li&gt;Partners with fewer historical pairings together to increase network diversity.
&lt;/li&gt;
&lt;li&gt;Pairs whose last meetup was the longest time ago when there is a tie.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the experience fresh, even in smaller communities where the pool of members is limited.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing History and Avoiding Races
&lt;/h3&gt;

&lt;p&gt;Pairing history is stored in a JSON file with per-user records, for example:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_id&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;history&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="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;partnerId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;other_user_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1704067200000&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 bot includes migration logic so older data formats can be upgraded automatically, which avoids breaking existing deployments when the schema changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reminder System
&lt;/h2&gt;

&lt;p&gt;The reminder feature was requested and probably could be better than it is, but I honestly prioritized other features over it as we have way too many ways to set reminders in places. This feature show how to manage long-running tasks safely, with persistent state, time parsing, and basic concurrency control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexible Time Parsing
&lt;/h3&gt;

&lt;p&gt;Users can set reminders with flexible time strings like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;!remindme 2 weeks Take out the trash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!remindme 1 month 3 days Project deadline&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!remindme 5h30m Call the dentist&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A regex-based parser walks the string, extracts units, and converts everything to milliseconds: (No, I did not write my own regex. Thank you chat gippity)&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&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;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?:\.\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)?)\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;mo&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;nths&lt;/span&gt;&lt;span class="se"&gt;?)?&lt;/span&gt;&lt;span class="sr"&gt;|w&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;eeks&lt;/span&gt;&lt;span class="se"&gt;?)?&lt;/span&gt;&lt;span class="sr"&gt;|d&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ays&lt;/span&gt;&lt;span class="se"&gt;?)?&lt;/span&gt;&lt;span class="sr"&gt;|h&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ours&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;|rs&lt;/span&gt;&lt;span class="se"&gt;?)?&lt;/span&gt;&lt;span class="sr"&gt;|m&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;in&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ute&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;s&lt;/span&gt;&lt;span class="se"&gt;?)?&lt;/span&gt;&lt;span class="sr"&gt;|s&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ec&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;ond&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;s&lt;/span&gt;&lt;span class="se"&gt;?)?)&lt;/span&gt;&lt;span class="sr"&gt;/gi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ... parse and accumulate&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Math&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="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;h3&gt;
  
  
  File Locking for Persistence
&lt;/h3&gt;

&lt;p&gt;Reminders are stored as JSON on disk. Because multiple commands can be processed at the same time, the bot uses a simple file-based lock to avoid two processes reading and writing the file simultaneously:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;acquireRemindersLock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delayMs&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="k"&gt;try&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;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;REMINDER_LOCK_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fd&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="o"&gt;=&amp;gt;&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="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;REMINDER_LOCK_FILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EEXIST&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;REMINDER_LOCK_FILE&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;ageMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mtimeMs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ageMs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;REMINDER_LOCK_FILE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delayMs&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could not acquire reminders lock&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a lock file is older than a threshold, it is treated as stale and removed, which helps the system recover from crashes without manual intervention.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduling and Cancellation
&lt;/h3&gt;

&lt;p&gt;Once a reminder is stored, it is scheduled via &lt;code&gt;setTimeout&lt;/code&gt;, and the timeout IDs are tracked so they can be cancelled later:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;scheduleReminder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reminder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scheduledTimeouts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reminder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scheduledTimeouts&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="nx"&gt;reminder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;scheduledTimeouts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reminder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&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;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;sendReminder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reminder&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;scheduledTimeouts&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;span class="nx"&gt;reminder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&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 a user cancels a reminder, the bot clears the timeout and removes it from the map, preventing duplicate or stale notifications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Event Management
&lt;/h2&gt;

&lt;p&gt;Torc does a lot of events, both in person and virtual. Expected when the team has like 3 individual shows and also the community specific events. Previously it was connected to Guild and pulled events utilizing their API, however the team shifted to using Luma so users can subscribe the  calendar and get notifications instead of having to do per event subscription.&lt;/p&gt;

&lt;p&gt;For events, the bot connects to Luma (once someone gets me the correct API Key) and pulls in upcoming calendar entries, then sends them to the user through a DM with rich embeds that include titles, times, images, and links:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchUpcomingEvents&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://public-api.luma.com/v1/calendar/list-events&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="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-luma-api-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LUMA_API_KEY&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTime&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;Sorting by &lt;code&gt;startTime&lt;/code&gt; ensures events are displayed in chronological order, which makes it easy for members to see what is coming up next.&lt;/p&gt;




&lt;h2&gt;
  
  
  Advanced Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Rate Limiting
&lt;/h3&gt;

&lt;p&gt;To respect Discord’s rate limits, the bot spaces out outgoing messages with a simple delay helper:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for &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;chunk&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&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;This pattern keeps the bot responsive while reducing the chance of hitting hard limits during bursts of activity. (There are no bursts&lt;/p&gt;

&lt;h3&gt;
  
  
  Safe Member Fetching
&lt;/h3&gt;

&lt;p&gt;Member fetches can be slow or hang in large guilds, so the bot wraps &lt;code&gt;guild.members.fetch()&lt;/code&gt; in a timeout using &lt;code&gt;Promise.race&lt;/code&gt;:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchGuildMembersWithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10000&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;guild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GuildMembersFetchTimeout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&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;If the fetch takes too long, the bot fails fast, logs the error, and can fall back to a safer behavior instead of blocking everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Logging and Admin Alerts
&lt;/h3&gt;

&lt;p&gt;All major operations use a shared error logger that prints to stderr and pings an admin account without throwing additional errors on failure:&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notifyAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - `&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}${(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Intentionally ignore to avoid cascading failures&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;This gives me visibility into production issues while keeping the bot running even when notifications fail. Could I possibly use something awesome like Sentry for this? Possibly, but I am just a poor boy and honestly don't want anyone scolding my little bot unless it's me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deduplicating Message Events
&lt;/h3&gt;

&lt;p&gt;Because certain events can fire more than once for the same message, the bot uses a short-lived &lt;code&gt;Set&lt;/code&gt; to deduplicate processing:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processedMessageIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;processedMessageIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;processedMessageIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;processedMessageIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents double-counting messages in summaries, stats, or other handlers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configuration and Deployment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Environment Configuration
&lt;/h3&gt;

&lt;p&gt;The bot is configured through environment variables, keeping secrets and settings out of the codebase (like a good dev is supposed to do right?):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DISCORD_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_bot_token
&lt;span class="nv"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_client_id
&lt;span class="nv"&gt;GROQ_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_groq_key
&lt;span class="nv"&gt;LUMA_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_luma_key
&lt;span class="nv"&gt;GUILD_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_main_guild
&lt;span class="nv"&gt;ADMIN_USER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_admin_id
&lt;span class="nv"&gt;COFFEE_ROLE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"coffee chat"&lt;/span&gt;
&lt;span class="nv"&gt;COFFEE_CRON_SCHEDULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0 9 * * 1"&lt;/span&gt;
&lt;span class="nv"&gt;COFFEE_PAIRING_COOLDOWN_DAYS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30
&lt;span class="nv"&gt;COFFEE_MIN_MEE6_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="nv"&gt;COFFEE_FETCH_MEMBERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="nv"&gt;COFFEE_FETCH_TIMEOUT_MS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it straightforward to run the same code across staging and production with different credentials and schedules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Health Checks and Hosting
&lt;/h3&gt;

&lt;p&gt;A tiny HTTP server on port &lt;code&gt;3000&lt;/code&gt; exposes a health endpoint:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Discord summarizer bot is running.&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;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="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="s2"&gt;`HTTP server listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;This is handy for containerized deployments, load balancers, or platform health checks.&lt;/p&gt;

&lt;h3&gt;
  
  
  State and Scaling
&lt;/h3&gt;

&lt;p&gt;By default, the bot uses the local filesystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;reminders.json&lt;/code&gt; for scheduled reminders
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;coffee_pairs.json&lt;/code&gt; for pairing history
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;locations.log&lt;/code&gt; for optional location tracking
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For production, especially across multiple instances, a real database such as PostgreSQL or MongoDB is a better fit for consistency and durability.&lt;/p&gt;

&lt;p&gt;Items on my watch list as the community grows and if &lt;strong&gt;&lt;em&gt;major if&lt;/em&gt;&lt;/strong&gt; the usage increases substantially: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Message handling can benefit from more robust deduplication or a message queue for very high volumes.
&lt;/li&gt;
&lt;li&gt;Reminder scheduling may require an external job queue (for example, Bull or Bee-Queue) for thousands of timers. (highly doubt this will ever be necessary but have explored the options) &lt;/li&gt;
&lt;li&gt;Coffee pairings currently run in roughly O(n²) due to cooldown checks, so if we get quite a large group of people volunteering to participate I might need more efficient data structures.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This bot (my baby) is a product of and for the community. I have been using it as a way to stay fresh in my non ServiceNow development and keeping familiar with more modern JavaScript as well as playing with AI and ways it can be used.  It has been great seeing it be used and benefit the community. I hope that continues and I can add even more features to it that benefit the community. I have a couple ideas that are already out there and just being reviewed before they are potentially implemented.&lt;/p&gt;

&lt;p&gt;This bot pulls together several patterns in one place: external API integrations, smart scheduling, careful file operations, timeouts, and defensive error handling. The same ideas apply well beyond Discord, from other chat platforms to background services and workflow engines.&lt;/p&gt;

&lt;p&gt;If you are planning your own Discord bot, this architecture gives you a solid starting point. Focus on reliability and observability first, then layer on features like summaries, pairings, reminders, and events as your community grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you built Discord bots before?&lt;/strong&gt; Share your experiences in the comments – especially any patterns that worked well (or failed in interesting ways).&lt;/p&gt;

&lt;p&gt;If you are looking for a community of like minded individuals we have something for everyone in our Discord, feel free to join in the fun &lt;a href="https://discord.com/invite/E3NXKRjErh" rel="noopener noreferrer"&gt;Torc Discord&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>architecture</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Mon, 12 Jan 2026 14:37:06 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/-gd0</link>
      <guid>https://dev.to/j3ffjessie/-gd0</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/yoditdevn8n/how-not-to-self-reject-before-you-even-try-7ka" class="crayons-story__hidden-navigation-link"&gt;How Not to Self-Reject Before You Even Try&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="/yoditdevn8n" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3453564%2Fad38afe7-f20e-4010-bb40-47efaeafb8be.jpg" alt="yoditdevn8n profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/yoditdevn8n" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Yodit Weldegeorgise
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Yodit Weldegeorgise
                
              
              &lt;div id="story-author-preview-content-3165669" 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="/yoditdevn8n" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3453564%2Fad38afe7-f20e-4010-bb40-47efaeafb8be.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Yodit Weldegeorgise&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/yoditdevn8n/how-not-to-self-reject-before-you-even-try-7ka" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jan 12&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/yoditdevn8n/how-not-to-self-reject-before-you-even-try-7ka" id="article-link-3165669"&gt;
          How Not to Self-Reject Before You Even Try
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/career"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;career&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mentalhealth"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mentalhealth&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/motivation"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;motivation&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/yoditdevn8n/how-not-to-self-reject-before-you-even-try-7ka" 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;11&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/yoditdevn8n/how-not-to-self-reject-before-you-even-try-7ka#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; 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;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

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

&lt;/div&gt;




</description>
      <category>career</category>
      <category>mentalhealth</category>
      <category>motivation</category>
    </item>
    <item>
      <title>2025 Retrospective</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Fri, 02 Jan 2026 17:46:41 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/2025-retrospective-4i84</link>
      <guid>https://dev.to/j3ffjessie/2025-retrospective-4i84</guid>
      <description>&lt;h2&gt;
  
  
  2025 Retrospective
&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%2Ff271b67u9e9cxrptu3i4.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%2Ff271b67u9e9cxrptu3i4.png" alt="2025 Wrapped" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2025 has come and gone and this is the first year I have actually sat down and done somewhat of a review of the year. I feel like the year went so quickly and at the same time it seems like the beginning of it was so long ago. Below are the highlights of 2025 and where I want to lean going into 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highlights
&lt;/h2&gt;

&lt;p&gt;Major highlights for 2025, I was a Torc Ambassador and part of one of the most amazing communities in tech. Seriously, the amount of people that are in this community sharing and helping each other is amazing and I honestly would be a lot worse for wear had I not found this community. Being an ambassador and sharing the message and meeting new people was a major highlight of 2025.&lt;/p&gt;

&lt;p&gt;My favorite thing I built in 2025 was the Torc community Discord bot. Its small and isn’t world changing technology, but it has an entire communities input into it. We probably could have easily installed one of the regular bots and just used whatever it comes with but this one had some extra love put into it. It started with Taylor mentioning he needed a summary of what happens in the Discord because it was hard for him to keep up. I dug into building a basic bot and then integrated AI tooling so that it could take the messages and summarize them so that anyone could call the bot and get a quick summary of the conversation and be caught up on the happenings. This then expanded into a weekly roll up of the entire server to capture the week that was of conversations. Set that up on CRON so it was automated to run and just happens. Also built in a reminder function so that users could set up reminders if they wanted to. There are some helpful commands for the Torc team internal so they can utilize the bot for gathering information that assists with events and other things like that. The latest addition is the one I am really proud of and can’t wait for it to be in the normal rotation. Since this is a community of like minded people and lets face it, most of us are introverted and shy. I added in coffee chat pairing functionality that pairs up members of the community to get together and have a coffee chat. However long the people want, it doesn’t even force it, just a quick little pairing and sends a DM to the pairs letting them know they were paired up and to reach out. Takes some of the leg work out of it and hopefully will lead to more networking and community building.&lt;/p&gt;

&lt;p&gt;I helped co-organize a virtual ServiceNow conference, nullEDGE in October and oh my that was huge. What started as an idea thrown out by Jace became a whole major conference in a matter of months. Working with Jace and the others while putting together the website for it was a major accomplishment. Working full time and doing this as a side hustle to get things organized and presented in a way that was easy to navigate was a challenge that forced me to remember web development outside of ServiceNow which was definitely fun. We had over 1K registered attendees for the conference and it went amazing. Met amazing people within the ServiceNow ecosystem and now we are planning more events in 2026 which has me stoked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lean into 2026
&lt;/h2&gt;

&lt;p&gt;What am I looking for in 2026? More community focused content and building in public. I really let myself down in 2025 that I did not do more building in public and sharing stuff. I had wanted that to be a thing that I pushed for and I just never sat down and actually did it. I am planning on changing that and hopefully will be able to stick to it this year. I am going to take a more focused approach and slow down a bit so that I can actually put together a plan and follow that. I need to be more intentional with things and follow a laid out plan so that I don’t get sidetracked and forget things.&lt;/p&gt;

&lt;p&gt;Work focus, trying to do anything and everything for my project that helps us succeed as a team. We have been going strong for roughly 4 years and have slowed a bit with less customization to our project as we lean more into setting things up for the future so its easier to maintain things. We are looking into migrating to a more integrated service portal and that requires a lot of documentation and building out POCs so this year is looking up for quite a bit of work that we will be hustling to get through. I have an amazing team that I work with and have the best lead supporting me every single day. I wouldn’t have made it this far without Cielo being there allowing me to fail and learn and grow. She has been amazing at guiding me in the right direction while also allowing me to provide my input to guide areas of the project as well. Truly blessed to have her on my team and making things super easy for me.&lt;/p&gt;

&lt;p&gt;2026 is shaping up to be an amazing year as long as I focus and continue being there when it counts. Happy New Year and hope that at the end of the year I can return and summarize things again with even more successes.&lt;/p&gt;

</description>
      <category>community</category>
    </item>
    <item>
      <title>Why Community Helps</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Mon, 10 Mar 2025 13:03:05 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/why-community-helps-ji6</link>
      <guid>https://dev.to/j3ffjessie/why-community-helps-ji6</guid>
      <description>&lt;h2&gt;
  
  
  Torc is home, but what does that mean?
&lt;/h2&gt;

&lt;p&gt;Well, for those that are looking for work, it's a talent delivery and engagement platform. However, if you look a little bit under the hood you find that it’s a community of likeminded people all involved in or building towards a career in tech. No this isn't a bootcamp group, although we know communities for that. So why Torc? Well, regular events on the latest trends and topics in tech are freely available. Resume reviews, LinkedIn profile reviews, interview help as well as any other random &lt;em&gt;help me&lt;/em&gt; you can think of in tech, we can do that. The bread and butter is the Torc.dev profile on the platform itself. This provides you the opportunity to see the jobs that are readily available that match your skills that you put in your profile. &lt;/p&gt;

&lt;h2&gt;
  
  
  Torc Profile
&lt;/h2&gt;

&lt;p&gt;Easy sign up, which will be easier than ever as the next version of the site finishes up. You add your skills and experience and boom the magic of industry leading AI kicks into gear matching your skills with jobs that are available for placement on the Torc platform.  Torc even goes a step further than that and they provide assessments based on the skills that you added to your profile so that you can take the assessments (don't cheat they can see that tab switching) and this provides them with evidence of your skills. You apply to a position or say you are interested? The next step kicks in where a real person looks over your profile and assessments (if you completed them, not mandatory, but helpful) and verifies you match up with what the job is needing.  Sound easy, because it truly is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where is the community aspect?
&lt;/h2&gt;

&lt;p&gt;Now we get to the party, and that my friends is the Torc Discord. This is where you find all the like minded people I wrote about at the beginning. We got Seniors, Middle, Junior and every other level you can think of in tech across the spectrum all in one location. Want to hang out with SAP people? We got that! You wanna hang out with some .Net developers? We got that too!! &lt;br&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%2Faey000bysn6lati1cdku.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%2Faey000bysn6lati1cdku.png" alt="DJ Khalid Another One Meme" width="569" height="570"&gt;&lt;/a&gt;&lt;br&gt;
Running joke in the Discord because they just keep coming. Key thing here is.... oh yeah did I mention we also aren't strictly English language events? I didn't mention that? Man, well we also have events hosted in Spanish as well. We have channels for Spanish and Portugese so you don't have to only have English speaking events if you don't want to. Tooling is being built for the community routinely to assist the community as well as provide insight to the community. Guides on setting up your LinkedIn, Resume Templates as well as all the regular events that are put on through the week. We also definitely have fun and routinely chat about daily life and checking in with each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cal.torc.dev" rel="noopener noreferrer"&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%2Fm1tenrtnjqwc66aqjts8.jpeg" alt="Event Calendar" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should I join?
&lt;/h2&gt;

&lt;p&gt;Why wouldn't you? Honestly, with the market the way it is right now its hard to get those opportunities and you don't feel like things are working and you are wanting help but don't want to look desperate on LinkedIn asking for help with things. Join us, we care not only about you getting the job, promotion, opportunity but we care about you as a person and want you to succeed in whatever you choose to do. Torc is home, we want you to feel that way when you are on the platform and in the community. Connect with people, meet at events and know that you have a full community behind you ready to help whenever you need it. We will also make fun of each other because that is what home is, a place you can be comfortable and be the real you. So what are you waiting for? Join the platform, jump in the Discord and say Jeff sent you in the Discord and I will promise to reply with a cool Meme or Gif to greet you. &lt;/p&gt;

&lt;p&gt;To quote my friend and one of the community team at Torc Jason Torres&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%2Fx3yxqtrj3nyh229z23mu.jpeg" 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%2Fx3yxqtrj3nyh229z23mu.jpeg" alt="Tweet from Jason Torres" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just click the image below and Welcome Home.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bit.ly/43aLiNM" rel="noopener noreferrer"&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%2Fj7t4ym290r54yzy551nk.png" alt="Torc Company Logo" width="246" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Moderating tags on Dev</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Sat, 24 Sep 2022 22:00:34 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/moderating-tags-on-dev-23oo</link>
      <guid>https://dev.to/j3ffjessie/moderating-tags-on-dev-23oo</guid>
      <description>&lt;h2&gt;
  
  
  Hello There
&lt;/h2&gt;

&lt;p&gt;I have recently seen quite a few posts being published here on Dev that are asking for more moderation of posts and/or better moderation within certain tags on Dev. As one of many tag moderators that helps out here at Dev I felt like maybe I should write something to let everyone know how tag moderation happens here on Dev and what we as tag moderators actually do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is tag moderation?
&lt;/h2&gt;

&lt;p&gt;Well, tags on Dev are all of the #'s included on a post within the header of each respective post, like #discuss is included on this article at the top under the title area. There have been and continue to be efforts made to find moderators for every tag that is on Dev, although some are still without. Essentially, tag moderation is a way to control the feeds by ensuring that articles are using the correct tags for the feeds that they are posting in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do Tag mods do?
&lt;/h2&gt;

&lt;p&gt;"Tag mods work with each other and DEV staff to ensure that content on the site is tagged appropriately, while also politely educating DEV users on how to follow tag guidelines." This is directly from the Tag Moderation Guide that can be found here on Dev &lt;a href="https://dev.to/tag-moderation"&gt;Tag Moderation Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What does the process look like for tag moderators?  Well, each tag mod is different in how they handle moderation for each of the tags that they have volunteered to moderate.  My process is fairly simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the mod center&lt;/li&gt;
&lt;li&gt;Choose one the tags that I am a moderator for&lt;/li&gt;
&lt;li&gt;Read through the articles including that respective tag&lt;/li&gt;
&lt;li&gt;Read over the tag submission guidelines that are included for each tag.&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%2Fc20ooycd191ofep1pfq6.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%2Fc20ooycd191ofep1pfq6.png" alt="Submission Guidelines Example" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally after reading through the guidelines I will go back to the post and re-read through the article to determine if it really fits the guidelines to use the included tag, or, if it would be a better fit a different tag.  I will then either remove the misused tag or add a proposed tag that fits better for that post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does my feed contain articles that don't belong?
&lt;/h2&gt;

&lt;p&gt;Well, tag moderators are volunteers that have been vetted to help out the Dev Team.  We aren't on the staff, nor do we recieve anything super awesome for doing it.  We work our normal jobs, enjoy retirement or just do whatever. Moderating tags on Dev is an extra little duty we volunteered for.  So with that, it means that someone isn't glued to the tag moderation 24/7 so it takes a little bit.  We wish that we could be super human and moderate the feeds as quick as the Flash, but it's not really practical.  We do our best, and continue to meet up weekly to come up with better approaches to accomplishing our task of making Dev better.  You can control your feed as a user by controlling how much of each tag shows up in your home feed, all you need to do is adjust the weights inside the followed tags section of your dashboard.&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%2Fkd7oafx0zgijb4c00ohm.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%2Fkd7oafx0zgijb4c00ohm.png" alt="Tag Dashboard" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Common question, "Can I put negative weights to a tag?" Yes you can.  It will help decrease the likelihood of that tag showing up in your feed.  It isn't perfect, but it helps tremendously.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the biggest issue with tag moderation?
&lt;/h2&gt;

&lt;p&gt;Honestly, in my experience the largest issue faced by tag moderators is the misuse of tags on published articles.  As authors, including tags that don't fit your post clogs up other users feeds with articles that have nothing to do with that particular tag.  As authors, reading the submission guidelines is a huge help to ensuring that you include only the tags that your post fits into. This goes a long way in ensuring Dev feeds only contain articles that actually belong there.&lt;/p&gt;

&lt;h2&gt;
  
  
  But I want my post on the main feed!!!
&lt;/h2&gt;

&lt;p&gt;Believe me, we all want our post to show up on the main feed right at the top.  Write a thorough article on a topic that garners enough attention and it will. However, using tags that influence the main feed just to get there without fitting the guidelines will almost always end with your post having that tag removed if the post doesn't warrant using that tag. Habitual mis-use of a tag will usually result in a moderator flagging your account to the admin team to investigate. &lt;/p&gt;

&lt;p&gt;As moderators and trusted users, we also have the ability to set your article as either high quality (meaning it is amazing material that needs to be seen) or low quality (meaning that the quality of the content is not that great and doesn't need to be shown very often), this influences the main feed and how often your article shows up in feeds. &lt;/p&gt;

&lt;h2&gt;
  
  
  What should I do as an author?
&lt;/h2&gt;

&lt;p&gt;All authors can be of the most help by reading through the tag submission guidelines.  Most authors write articles in a a few set tags that fit their niche. This makes it even easier, you just read through and make sure you understand the submission guidelines for those tags that you use regularly.  If you are really feeling love for your particular niche or tag, reach out to the Dev Team and inquire about becoming a tag moderator for that tag and join the team helping to keep the feeds cleaned up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We try our best, in our own time to clean up the feeds as best as we can.  Ideas that help that are always welcomed and are talked about weekly to see if they could be truly beneficial.  I completely understand the feeling of reading through an article in a particular feed and wondering why it is there and why there are so many spam posts and wondering why nothing is being done.  Trust me, we are working on it as quick as we can, but we aren't perfect and we have outside commitments that limit our time moderating the tags.  &lt;/p&gt;

&lt;h2&gt;
  
  
  You used #discuss so where is the discussion?
&lt;/h2&gt;

&lt;p&gt;Well, shout in the comments and share your ideas on what can be done better, if you want to moderate a particular tag, or on the slight chance; show the tag moderators some love by letting us know that our work is appreciated.  I know I appreciate the work done by the moderators and the Dev Team continuously trying to make Dev and Forem overall a more inclusive and organized space for people to share their writing.&lt;/p&gt;

</description>
      <category>moderation</category>
    </item>
    <item>
      <title>Abandoning Social Media and the mental health affects</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Thu, 03 Jun 2021 03:42:42 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/abandoning-social-media-and-the-mental-health-affects-1k3g</link>
      <guid>https://dev.to/j3ffjessie/abandoning-social-media-and-the-mental-health-affects-1k3g</guid>
      <description>&lt;h1&gt;
  
  
  Abandoning Social Media
&lt;/h1&gt;

&lt;p&gt;So, I will start with saying that abandoning social media isn't a call to action or anything.  I don't hate social media, or anyone that utilizes it.  I had to take a break from social media due to the severe anxiety and stress it was causing me.  I will explain a little more and the benefits I have seen after just a week of limiting my social media interaction.&lt;/p&gt;

&lt;p&gt;So, a little over a week ago I hit a very low point of stress and depression in regards to my developer journey and figuring out how to get noticed and have a chance at getting a job in the industry.  I usually find solace in going on social media, checking the latest Instagram posts, seeing what is trending on Twitter and the like. However, lately as I have really dug deep into trying to build myself up and put myself out there to get hired, I have noticed that a lot of seriously messed up stuff has been going down with multiple companies and how they handle employees and offers made to possible employees.  I don't know if it was algorithms or what but it was all I was seeing.&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%2Ff9emsxyjzlym4876baon.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%2Ff9emsxyjzlym4876baon.jpg" alt="negative emotions" width="626" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Negative mindset breeds Negative Results
&lt;/h2&gt;

&lt;p&gt;Now, I won't put all of the blame on social media for my deepened state of negativity.  I am in the process of dealing with (have been for the past two months) a pinched nerve in my neck that causes extreme discomfort and pain.  With the current work that I do it only increases the issue but until I can get into the doctor and remedy it I have tried handling it as best as possible.  However, the negativity I have seen on social media on top of my own personal issues has really driven the wedge in my performance. I found myself becoming distant from friends online and groups that I would code with.  I started having very little interest in projects that were exciting to me before.  I felt like if these people I see on Twitter are getting let go or can't get a job; then what chance do I have? &lt;/p&gt;

&lt;h2&gt;
  
  
  Put In The Work
&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%2Fi4r335fwqc539wxp83hz.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%2Fi4r335fwqc539wxp83hz.jpg" alt="pushing a boulder uphill" width="626" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I took the advice of some mentors and kind people that reached out offering to help me prep myself and get myself ready for moving into Tech.  I started applying to places and built up my Resume.  I started interacting more with other developers and especially developers from the companies I wanted to work for.  After a month of applying and having multiple first round phone call interviews, all I have to show for that effort is frustration and serious doubts I have that &lt;strong&gt;IT&lt;/strong&gt; factor that will help get me hired.  With zero feedback from any phone interview, over thirty no responses at all and quite a few direct emails to the person posting the job listing with no reply; where did I end up?&lt;br&gt;
I started noticing that more and more companies were pulling offers back from possible employees after they had put in notice for their previous company.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mental Destruction
&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%2Fs.yimg.com%2Fny%2Fapi%2Fres%2F1.2%2FOBqCrbIsZBFsiijb8SjfZA--%2FYXBwaWQ9aGlnaGxhbmRlcjt3PTk2MDtjZj13ZWJw%2Fhttps%3A%2F%2Fs.yimg.com%2Fcd%2Fresizer%2F2.0%2Foriginal%2F_dqmT57upudDm8-thHe0pbhccGg" 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%2Fs.yimg.com%2Fny%2Fapi%2Fres%2F1.2%2FOBqCrbIsZBFsiijb8SjfZA--%2FYXBwaWQ9aGlnaGxhbmRlcjt3PTk2MDtjZj13ZWJw%2Fhttps%3A%2F%2Fs.yimg.com%2Fcd%2Fresizer%2F2.0%2Foriginal%2F_dqmT57upudDm8-thHe0pbhccGg" alt="mental breakdown" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My mindset went full on negativity.  I honestly started hating development.  I didn't want to code, I didn't want to build anything at all.  I deleted Twitter and Instagram from my phone and didn't log onto my computer at home.  I didn't look at code for over a week and just went to work at my normal job and come home and relaxed and spent more time with the family.  After over a week of this, what have I gained?  First, I have gained a relief from my head being a cesspool of negativity.  I slowly eased my way back into posting in my Slack channels and my Discord groups.  I started dabbling with some of my code, still not really excited to get to it right now but I have put major efforts into learning more and reading instead of coding non-stop. I know that this is probably a &lt;em&gt;normal&lt;/em&gt; thing that happens to everyone.  That will probably be one of the first few comments, if there are any on this post.  However, lets really dive into that thought.  If this is &lt;em&gt;normal&lt;/em&gt;, why haven't we fixed it?  There is absolutely no reason that it should be this difficult for someone to get a job in this industry.  There are countless positions out there with thousands of companies.  I will paraphrase what someone else told me about the industry, companies all want senior developers, but won't invest the time into developing great junior developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next?
&lt;/h2&gt;

&lt;p&gt;Honestly, I have no idea.  I know that I love development and I really enjoy coding and building things.  I have so much fun working with others and developing different applications and websites.  However, I can say that for the foreseeable future, social media will be an afterthought for me.  I want to invest more time and effort into my own learning and building new and exciting things that I enjoy.  One day maybe I will be a fit for a company willing to give me a chance to prove that I can fit their open role if they will just invest and give me a chance.  Until then, I don't feel it to be mentally healthy for me to continue applying and interviewing with multiple companies and putting so much effort into reaching out when I either get no response back or get nothing in return after interviews.&lt;/p&gt;

&lt;h1&gt;
  
  
  Normal Does Not Make It Right
&lt;/h1&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%2Fz424muncvuz0d1k9x6vb.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%2Fz424muncvuz0d1k9x6vb.png" alt="fix the system" width="290" height="192"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;We need to take a serious look at the hiring process collectively and find a fix that treats everyone respectfully and provides a healthy hiring environment.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>junior</category>
      <category>health</category>
      <category>hiring</category>
    </item>
    <item>
      <title>How do Family and Friends help shape our Habits?</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Thu, 18 Feb 2021 18:45:49 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/how-do-family-and-friends-help-shape-our-habits-d9a</link>
      <guid>https://dev.to/j3ffjessie/how-do-family-and-friends-help-shape-our-habits-d9a</guid>
      <description>&lt;h1&gt;
  
  
  How do our Family and Friends influence our Habits?
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;'A Genius is not born, but is educated and trained'&lt;br&gt;
-Lazslo Polgar&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lazslo believed in this so much he would prove it with his children.  He and his wife had three daughters: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Susan, Sofia, and Judit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their childhood was other than ordinary by any of our ideas.  They were surrounded by nothing but Chess.  From books, continuous playing, and tournaments.  The children didn't feel like their obsession with chess was out of the norm.  As we will see,k whatever habits are normal in our culture are among the most attractive behaviors we will ever find.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Seductive Pull of Social Norms
&lt;/h2&gt;

&lt;p&gt;Humans are herd animals; we want to fit in and to be accepted.  We also want to earn the respect and approval of our peers.  This is why we are so keen on telling others about our successes and showing things off on social media all the time.  We are seeking approval from others on our accomplishments.  It is essential to our survival for the most part.  Our ancestry lived in tribes for a reason; if you were to be kicked out of the tribe it could be a death sentence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The lone wolf dies, but the pack survives&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As Charles Darwin noted,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;'In the long history of humankind, those who learned to collaborate and improvise most efficiently have prevailed.'&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is why you will hear and see the most successful people talk about how their successes are the result of teamwork.  Building great teams and working with other great people.  Those that learn to collaborate with others and improvise in situations are the ones that prevail.  How does that help us as developers?  Well, it means that we are immediately set up for success for the most part.  Development is a collaborative environment for the most part.  You have designers, clients, and back-end developers along with front-end developers.  All of these people are collaborating to make an idea or vision come to life.  If you can collaborate and improvise things on the fly during this process you have a stronger chance of succeeding.  That is why you will always see people suggesting that you pair code or go to meet-ups when you are learning and building your portfolio.  Being around others and sharing ideas and getting ideas from others is how we all succeed.  This isn't an individual field, you have to be able to work with others, and do it fairly well to have a chance at succeeding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habits of Children
&lt;/h2&gt;

&lt;p&gt;We don't choose our habits as children, we often tend to imitate the habits of those that are around us. Getting dirty fixing the car like Dad or putting on makeup like our Mom.  We often follow the habits of our culture without even thinking about it.  This can influence us even as we grow into adulthood with our attitudes and how we handle certain situations or handle environments. I never realized it until I became a Dad that I imitate the habits of my Dad when dealing with my kids and handling behavior from them.  It's just what I was raised in and it shaped my experience of what a father is supposed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Group Influence
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;'The customs and practices of life in society sweep us along'&lt;br&gt;
-Michel de Montaigne&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most of the time going along with the group doesn't even feel like a burden.  This is because habits that help us fit in are very attractive to us.  We tend to imitate the habits of three particular groups.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Close&lt;/li&gt;
&lt;li&gt;The Many&lt;/li&gt;
&lt;li&gt;The Powerful&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Imitating the Close
&lt;/h2&gt;

&lt;p&gt;As you might imagine, imitating the close relates to the people that are around us most often.  We pick up habits from how our parents interact with each other, how our coworkers structure their work to get results.  When your close friend tries something new, you try it as well.  If your significant other has a habit of checking the thermostat before bed each night, you start to check the thermostat before bed as well because you have picked up the habit from your significant other.  The closer you are to someone, the more likely you are to pick up some of their habits and imitate them.&lt;/p&gt;

&lt;p&gt;One of the most effective things you can do to build better habits is to join a group where your desired habit is their normal behavior.  This is the number one reason that code communities are so amazing.  You want to be a developer, your desired habit is to create things using code or designing. You join a code community group, whether it is on Slack, Discord, or other social media and your desired habit is normal in those groups because everyone in that group shares a common interest.  This propels your new desired habit to the top of your list because you now belong to a group where that habit is normal.  You also have &lt;em&gt;close&lt;/em&gt; people with habits to imitate.  Someone in the group is always posting code snippets of little things they are doing to create projects, so you start to do little code snippets.  It fosters your desired habit and makes you feel accepted in the group which makes your habit even more attractive. Make your group choices even easier by following a simple two-step thought process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Join a group where your habit is the normal behavior&lt;/li&gt;
&lt;li&gt;Join a group where you already have something else in common with the group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For myself, I have a couple of groups for this, I am part of &lt;a href="https://vetswhocode.io/" rel="noopener noreferrer"&gt;VetsWhoCode&lt;/a&gt; which is where I learned the majority of my coding from.  I went through the CoHort with other Veterans and the entire group consists of Veterans from all walks of life.  This fosters my desired habit of being a developer because I interact daily with other developers that are also Veterans and they understand certain personality traits that I have and I can relate to a lot of what they are experiencing.  I also have a second group &lt;a href="https://twitter.com/coder_dads?s=20" rel="noopener noreferrer"&gt;CoderDads&lt;/a&gt; which is great because it is a completely different feel than the VetsWhoCode group.  I joined this group because it fosters Fatherhood more than coding and gives me other Dads to relate to in the aspect of being a father and trying to join the tech field as a career.&lt;/p&gt;

&lt;p&gt;There is nothing that sustains our motivation more than belonging.  Our new journey to form a new habit is now a shared journey with others.  Instead of &lt;em&gt;I am a Developer&lt;/em&gt; or &lt;em&gt;I Write Code&lt;/em&gt; it now becomes &lt;em&gt;We are Developers&lt;/em&gt; and &lt;em&gt;We Write Code&lt;/em&gt;.  Having this shared identity reinforces our own identity, we have the support and know that we are not alone on the journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imitating the Many
&lt;/h2&gt;

&lt;p&gt;Whenever we are unsure how to act, we look to the group to guide our behavior.  This is in all aspects of our lives if you think about it.  We check reviews on Amazon for products or check Yelp for reviews of restaurants and foodservice places.  We want to imitate the &lt;em&gt;best&lt;/em&gt; buying or eating habits.  This is usually a good strategy.  This is a lot of evidence that shows there is safety in numbers.  However, there can be a downside to this following.  The normal behavior of the group often overpowers the desired behavior of the individual.  A good example of this is the argument of why Developers use GitHub vs GitLab for their code repositories.  This question popped up on my Masstodon feed the other day as to why developers use one or the other.  The answers were all fairly similar and showed a very good look into the group imitation.  A large portion of the answers simply stated the reason they use GitHub over GitLab is mainly that everyone else the person interacts with uses it.  There were a few that had specific reasons for using one or the other, but the majority of people used one or the other because of the people that they interact with myself included.  &lt;/p&gt;

&lt;p&gt;The reward for being accepted is often greater than the reward for being right.  This is why in large group arguments or debates we as individuals will choose to side with the group that is winning the argument or has a larger majority of the group.  When we are accepted we feel better than if we had supported the other side of the argument and been right versus being wrong and being accepted.  This ties into a lot of happenings in the world today, but I won't go into those types of arguments in a post like this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;'Most Days, we would rather be wrong with the crowd than be right on our own' - James Clear&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Imitating the Powerful
&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%2Fdf9r9th9twzdg628grek.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%2Fdf9r9th9twzdg628grek.png" alt="More Power" width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We all want power, prestige, and status.  Try to deny it, but deep down it is what drives us forward to succeed and accomplish our dreams.  We want awards and to be acknowledged and praised.  Historically, people with great power have had access to more resources, they worry less about survival and they are more attractive partners to others.  We are drawn to behaviors that earn us respect and the approval and admiration of our peers.  We spend so much effort to fit in, that once we do, we have to try and find ways to stand out.  We spend the longest time pushing and doing our best to get accepted into a group.  You build tons of projects to finally get that dream job at a company, and once you are there you realize that you are just one of the developers.  Now you have to work even harder to make yourself stand out as one of the top developers or the subject matter expert on a certain aspect of the codebase and what not.  It is a continuous process that we go through.  &lt;/p&gt;

&lt;p&gt;We attempt to copy the habits of successful people because we want to be successful.  This is evident when you see a lot of companies spring up after one success story for a certain thing.  One person makes it big by making decorated tumblers and all of a sudden thousands of people storm Shopify and Etsy to build out their decorated tumbler store.  Not knocking it at all, just the first example that came to mind because I was just looking at different tumblers myself.  Many of our habits are imitations of people that we admire.  We imitate people that we &lt;em&gt;envy&lt;/em&gt;. This is one of the things that as junior developers we have to be wary of.  You want to have a person that you admire and look up to.  That helps drive you to continue working and build amazing things and to help build an inclusive and safe community.  However, you also have to realize that as a junior developer you aren't going to be the best at everything, and comparing yourself to someone more experienced is not the healthiest for trying to make this a successful journey.  Realize that you have just started on this journey and that you will eventually get to that point but &lt;em&gt;Do Not&lt;/em&gt; compare yourself to senior developers.  They were where we were once too, they have spent years learning things that we are just now getting the taste of working with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imitation is the Greatest Form of Flattery
&lt;/h2&gt;

&lt;p&gt;For those Senior Developers and creators, please accept the imitation for what it is on most levels.  You are being admired by others that hold you to a high standard and feel you are their guiding light.  Be inclusive and accepting of others wanting to learn from you.  I'm not saying mentor everyone that reaches out to you but interact and give guidance to other developers that are interacting with you.  This fosters their creativity which drives changes in the industry and things to be created that we don't think are possible now.  Fostering a safe and inclusive creative community can only drive us further into the future and bring the best out of everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Up Next
&lt;/h2&gt;

&lt;p&gt;In the next article, we will dive into how to find and fix the cause of our bad habits.  This will give us a better understanding of what is limiting us from realizing our full potential and keeping us from excelling at our new habits.  As always I appreciate you reading this article, sharing, and interacting with me.  Connect with me on &lt;a href="https://twitter.com/j3ffjessie" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>developer</category>
      <category>javascript</category>
      <category>habits</category>
    </item>
    <item>
      <title>How to Build Good Habits and Excel as a Junior Developer Part 7</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Sun, 31 Jan 2021 14:37:00 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-8-4jfc</link>
      <guid>https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-8-4jfc</guid>
      <description>&lt;h1&gt;
  
  
  Simply Irresistible
&lt;/h1&gt;

&lt;p&gt;We as humans are prone to fall for exaggerated versions of reality. &lt;a href="https://www.imdb.com/title/tt1677720/" rel="noopener noreferrer"&gt;Ready Player One&lt;/a&gt; is a film that portrays this very well with a few extenuating circumstances added in.  We have gotten good at pushing our buttons.  Food is the best example to use for this.  We crave all the sugary and salty foods instead of healthy foods.  Most people will not stick to any keto diets or vegetarian diets because some of the foods in those diets lack the salty sweetness of the foods that they were previously eating.  We will also choose to overeat because those foods are available.  Don't need the extra cookie, but hey it's here so why not.  This behavior is counter to our original wiring of hunting for our survival food.  Foods that are high in dynamic contrast keep the experience interesting which encourages us to eat more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Irresistible Habits
&lt;/h2&gt;

&lt;p&gt;To increase the odds that a behavior will occur we need to make it attractive.  Now we learn how to make them &lt;em&gt;Irresistible&lt;/em&gt;.  It is &lt;em&gt;&lt;em&gt;not&lt;/em&gt;&lt;/em&gt; possible to turn every single habit into a super-powerful stimulus, but we can make any of our habits more enticing.  To do so, we have to understand what a craving is and how it works.  The first stop is a biological signature that all habits share =&amp;gt; &lt;strong&gt;The Dopamine Spike&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dopamine Spike
&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%2Fmiro.medium.com%2Fmax%2F700%2F0%2AjKu1MAaSWGWlXch9" 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%2Fmiro.medium.com%2Fmax%2F700%2F0%2AjKu1MAaSWGWlXch9" alt="The Dopamine Spike" width="700" height="1117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To put Dopamine into perspective of how vital it is, in 1954 neuroscientists James Olds and Peter Milner implanted electrodes into the brains of rats.  Using those electrodes, there were able to block the release of dopamine to the brain.  The tested rats lost all will to live.  Without Dopamine you will still enjoy things, you just won't desire to do them or want whatever it is.&lt;/p&gt;

&lt;p&gt;Our habits are a dopamine-driven feedback loop.  Every behavior that is highly habit-forming ie:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;taking drugs&lt;/li&gt;
&lt;li&gt;eating junk food&lt;/li&gt;
&lt;li&gt;playing video games&lt;/li&gt;
&lt;li&gt;browsing social media&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;these habits are all associated with high levels of dopamine.  Dopamine plays a very central role in many of our neurological processes,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;motivation&lt;/li&gt;
&lt;li&gt;learning &amp;amp; memory&lt;/li&gt;
&lt;li&gt;punishment &amp;amp; aversion&lt;/li&gt;
&lt;li&gt;voluntary movement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For habits, the big thing to know is, Dopamine is released not only when you &lt;em&gt;experience&lt;/em&gt; pleasure, but also when you &lt;em&gt;anticipate&lt;/em&gt; it.  The anticipation of getting a reward, &lt;em&gt;&lt;em&gt;not&lt;/em&gt;&lt;/em&gt; actually getting the reward that gets us to take action. These insights show the importance of the 2nd Law of Behavior Change.  We make our habits attractive because the anticipation of the reward motivates us to act in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Temptation Bundling
&lt;/h2&gt;

&lt;p&gt;Temptation bundling works by linking an action you &lt;em&gt;want&lt;/em&gt; to do, with an action that you &lt;em&gt;need&lt;/em&gt; to do.  You are more likely to find a behavior attractive if you get to do one of your favorite things at the same time.  I &lt;em&gt;need&lt;/em&gt; to finish painting the living room, I &lt;em&gt;want&lt;/em&gt; to listen to the new Nickelback album (kidding...nobody listens to Nickelback). So you bundle that together and only listen to the new album while you are painting the living room.&lt;/p&gt;

&lt;p&gt;Temptation bundling is one easy way to apply a psychological theory known as &lt;a href="https://link.springer.com/referenceworkentry/10.1007%2F978-1-4419-1698-3_1165" rel="noopener noreferrer"&gt;Premack's Principle&lt;/a&gt; this principle states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More probable behaviors will reinforce less probable behaviors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we can go another step further and combine Temptation Bundling with &lt;a href="https://dev.to/vetswhocode/how-to-build-good-habits-and-excel-as-a-junior-developer-part-4-make-it-obvious-3fh5"&gt;Habit Stacking&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After I [current habit], I will [habit I need].&lt;/p&gt;

&lt;p&gt;After [habit I need], I will [habit I want].&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Eventually, with enough iterations you will look forward to the new habit you &lt;em&gt;need&lt;/em&gt; because you will get to do the habit that you &lt;em&gt;want&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Up Next
&lt;/h2&gt;

&lt;p&gt;So far this has been a very internal and solo adventure, so in the next article, we will go over the role that your family and friends can play to help you along the route of forming your new habits.  Thanks again to all of you that read my articles, please don't hesitate to comment or connect to me through social media, I am &lt;a class="mentioned-user" href="https://dev.to/j3ffjessie"&gt;@j3ffjessie&lt;/a&gt; on Twitter. &lt;/p&gt;

</description>
      <category>junior</category>
      <category>javascript</category>
      <category>programmer</category>
      <category>habits</category>
    </item>
    <item>
      <title>How to Build Good Habits and Excel as a Junior Developer Part 6</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Thu, 14 Jan 2021 17:24:42 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-6-2206</link>
      <guid>https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-6-2206</guid>
      <description>&lt;h1&gt;
  
  
  Environment and Self Control
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Let’s Kick Our Bad Habits
&lt;/h2&gt;

&lt;p&gt;In the last article, we went through how changing our environment will help us build better habits by eliminating the cues for our negative habits.  Just reading through you start to think, well how hard could that be.  Maybe you made some minor changes to your environment and implemented some of the tips, just to find out that it wasn't as easy as you thought it would be.  You are probably sitting there saying, I lack the self-control to make these changes, or maybe you don't believe that changing the environment you are in can affect your habits all that much.  I want to lead this article with a perfect example of how the environment can change your habits.&lt;/p&gt;

&lt;p&gt;The best way that I can relate to this is to take you into a small part of Military History.  We are going to go back to around 1971 and the Vietnam War.  That year two Congressmen went and visited soldiers that were stationed in Vietnam.  Surprisingly they found out that roughly 15 percent of the soldiers there were addicted to heroin.  Further research would find that around 35 percent of soldiers stationed there had tried heroin while being there, while 20 percent of them were fully addicted.  A very severe problem.  Typical response from the Government and most people's first thoughts would be that there needs to be a major overhaul to the area, start putting people into rehabilitation programs, and get them clean.&lt;/p&gt;

&lt;p&gt;However, Lee Robins, who was one of the researchers in charge of working through this issue came up with a finding that pretty much upended all beliefs about addiction.  Robins was able to find that once these same heroin-addicted soldiers returned home, only around 5 percent of them relapsed within a year of being home; and just 12 percent of the returning soldiers relapsed within 3 years.  In more stark terms, roughly 9 out of 10 returning soldiers eliminated their addiction.  What was the major change? &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No immediate access to the stress cue for their bad habit&lt;/li&gt;
&lt;li&gt;Not surrounded by others who contributed to their bad habit&lt;/li&gt;
&lt;li&gt;Back in a stable environment where they were happier and no longer needed the heroin to get by&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Now, you might say that they must have had tremendous self-control to resist the urge to relapse.  However, contrary to popular belief people who appear to have tons of self-control are not that different from those of us that are struggling.  &lt;em&gt;Disciplined&lt;/em&gt; people are better at structuring their lives in a way that &lt;em&gt;does not&lt;/em&gt; require a lot of willpower and self-control.  They spend less time in tempting situations.&lt;/p&gt;

&lt;p&gt;If you read Self-help books about success, you will find a common trend.  Perseverance, grit, and willpower are essential to success.  To improve these qualities you don't just wish you were a more disciplined person; you have to create a more disciplined environment.&lt;/p&gt;

&lt;p&gt;Our bad habits are &lt;a href="https://en.wikipedia.org/wiki/Autocatalysis" rel="noopener noreferrer"&gt;Autocatalytic&lt;/a&gt;, meaning that the process feeds itself to continue ie...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Feel bad -&amp;gt; eat junk food -&amp;gt; Feel worse for eating junk food -&amp;gt; eat more junk food.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Watching TV or your phone all day makes you feel sluggish -&amp;gt; you watch even more because you don't have the energy to do anything else -&amp;gt; feel horrible about watching nothing but tv or your phone.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;This is referred to as &lt;em&gt;cue-induced wanting&lt;/em&gt; where an external trigger causes us to compulsively crave to repeat a bad habit.  You begin to notice something, and then you want it.  It happens all the time and we don't even notice it.  BLUF(bottom line upfront), you can break a habit, but your highly unlikely to forget it.&lt;/p&gt;

&lt;p&gt;The most reliable way to cut our bad habits is to break them off at the source.  To do that, we have to reduce exposure to the cue that causes it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can't seem to get work done? Leave your phone in another room.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A big one for us junior developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Continually feel like you aren't enough or not good enough? Stop following social media accounts that trigger your jealousy or envy.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;If you have read any of the other articles you can see that this process is the inversion of the 1st Law of Behavior Change.  Instead of &lt;em&gt;making it obvious&lt;/em&gt;, we want to make our bad habits &lt;em&gt;invisible&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Self-control is a short term strategy, not a long term solution.  We can usually resist temptation once or twice, but eventually, we cave.  The secret is to make the cues of our good habits obvious and the cues for our bad habits invisible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Up Next
&lt;/h2&gt;

&lt;p&gt;Next, we will go into the 2nd Law of Behavior Change: &lt;em&gt;Make it Attractive&lt;/em&gt; and start with learning how to make the cues for our wanted good habits irresistible.  Thanks again for all the likes and shares along with the feedback.&lt;/p&gt;

</description>
      <category>junior</category>
      <category>javascript</category>
      <category>programmer</category>
      <category>habits</category>
    </item>
    <item>
      <title>How to Build Good Habits and Excel as a Junior Developer Part 5 : Environment Over Motivation</title>
      <dc:creator>J3ffJessie</dc:creator>
      <pubDate>Thu, 31 Dec 2020 19:16:52 +0000</pubDate>
      <link>https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-5-environment-over-motivation-2ojj</link>
      <guid>https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-5-environment-over-motivation-2ojj</guid>
      <description>&lt;h1&gt;
  
  
  Why Motivation Lacks Importance
&lt;/h1&gt;

&lt;p&gt;We have gone over different strategies to implement new habits for ourselves. We started with identifying our mission statement. &lt;a href="https://dev.to/vetswhocode/how-to-build-good-habits-and-excel-as-a-junior-developer-17h5"&gt;Who Do I Want To Be&lt;/a&gt;, then moved into figuring out what our current habits are using a &lt;a href="https://dev.to/vetswhocode/how-to-build-good-habits-and-excel-as-a-junior-developer-part-3-awareness-3hcn"&gt;Habit Scorecard&lt;/a&gt;, we also learned about making &lt;a href="https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-4-make-it-obvious-3fh5"&gt;Implementation Statements&lt;/a&gt;. Last we learned about the &lt;a href="https://www.britannica.com/biography/Denis-Diderot" rel="noopener noreferrer"&gt;Diderot Effect&lt;/a&gt; and how habit stacking relates to building upon current habits to implement our new habits by &lt;a href="https://dev.to/j3ffjessie/how-to-build-good-habits-and-excel-as-a-junior-developer-part-4-make-it-obvious-3fh5"&gt;Making It Obvious&lt;/a&gt;.  Now we are going to learn about how our Motivation to create our new habits is &lt;strong&gt;not&lt;/strong&gt; as important as the environment in which we are in trying to create these new habits.&lt;/p&gt;

&lt;p&gt;Numerous studies have proven that we as humans don't base our decisions on certain things such as food purchases and product purchases based on what the item is, but more on &lt;strong&gt;where&lt;/strong&gt; the item is located.  Putting bottled water stations closer to checkout instead of soda stations will ultimately lead to more bottled water sales due to the location of the water compared to the checkout. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Environment is the invisible hand that shapes human behavior. -James Clear (Atomic Habits).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This has also been studied psychologically. In 1936, psychologist Kurt Lewin wrote a simple equation that correlates how Behavior is a function of the Person in their Environment&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;B = &lt;em&gt;f&lt;/em&gt; (P,E)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every single organism on the planet has its methods for sensing and understanding the world. In humans, we are directed by our sensory nervous system.  We use sight, sound, smell, touch, and taste.  The most powerful of all human sensory abilities is &lt;strong&gt;vision&lt;/strong&gt;.  We have roughly eleven million receptors in our body, with ten million of those are dedicated to our vision.  With this information, we can ultimately believe that if we implement changes in what we &lt;em&gt;see&lt;/em&gt; then we can impact what we &lt;em&gt;do&lt;/em&gt;.  So with that information, we can now move into building our new habits by designing our new environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design your Environment For Success
&lt;/h2&gt;

&lt;p&gt;Every habit is initiated by a &lt;strong&gt;cue&lt;/strong&gt; and we are most likely to notice cues that stand out (&lt;strong&gt;Obvious&lt;/strong&gt;).  Our environments, however, often make it ever so easy to &lt;em&gt;not&lt;/em&gt; do certain actions because there is no obvious cue to trigger the behavior.  When our cues are hidden or too subtle, they are easy to ignore.  By comparison, creating obvious visual cues will draw your attention toward the desired habit.  So, how do we design our environment to help make cues for our new wanted habits more obvious?&lt;/p&gt;

&lt;p&gt;If you want to make a habit a big part of your life, make the cue for that habit a big part of your environment.  Want to code more, place your laptop next to your favorite chair.  You have to make sure that the best choice is the most obvious choice you can make.  If the cue is right in front of you it is easier to make that choice and implement the new good habit.&lt;/p&gt;

&lt;p&gt;Environment design is powerful not only because it affects how we engage with the world, but because we rarely do it.  Most of us live in a world that someone else created for us.  We live in a dorm room with pre-populated furniture and setup.  We live in a house where our design choice is provided by the builder and how they implemented certain features (not always the case if you built your own house).  Ultimately, we can alter the spaces that we live and work in to increase our exposure to positive cues, and reduce our exposure to negative ones.  Designing your environment allows you to take back control and become the architect of your life.  &lt;em&gt;Be the Designer of your world and not merely the consumer of it.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context Is Cue
&lt;/h2&gt;

&lt;p&gt;Starting cues can be very specific, and over time those habits become associated not with a single trigger but with the entire context surrounding the behavior.  Most people are social drinkers, only drinking when surrounded by friends and music or a party environment.  We mentally assign our habits to the locations in which they occur; at home, at the office, or in the gym. Every location develops a connection to certain habits and routines.  You interact a certain way with objects in your home and at your office, due to the location, those objects are in.  Our behavior is not defined by the objects in our environment but our relationship to them.  If we begin to think of our environment &lt;em&gt;not&lt;/em&gt; as filled with things or objects, but more as a place filled with relationships and how we interact with the spaces around us we begin to move forward.&lt;/p&gt;

&lt;p&gt;For one person, sitting on the couch is the place where they read every night for an hour, for another person the couch is where they watch television and eat dinner after work.  Every environment can have different cues and different habits for different people, that is what makes our environment so powerful.  We can tailor it to our needs and make our environment work &lt;strong&gt;for&lt;/strong&gt; us instead of against us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick a New Environment
&lt;/h2&gt;

&lt;p&gt;The power of context reveals an important strategy: habits can be easier to change in a new environment.  If we escape the triggers and cues that keep us repeating our current habits and choose a new environment, we can create a new routine and build new habits attached to the new location.  It is &lt;em&gt;much&lt;/em&gt; easier to associate a new habit with a new context than to build a new habit on top of one filled with competing cues.  When we step out of our normal environment, we leave our environmental biases in those locations.&lt;/p&gt;

&lt;p&gt;If you are like me, you really can't afford to move to a new location completely just to start building new habits.  So what do we do?  Well, you can easily redefine or rearrange your current setup.  Create separate spaces for work and entertainment things.  An easy Mantra pushed in the book is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One Space, one use&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I currently have my downstairs office room set up as my desktop and my wife and I's work station.  The only thing that gets done there is work-related.  If I want to browse the internet for fun or watch videos, I move from my office to the garage or another room in the house.  I have to do this or my office will be associated with random fun work on my phone or tablet instead of me coding or working.  Make sure that you remove distractions when possible.  Turn phones on Do Not Disturb (DND) or turn them off completely if you can.  This will help avoid social media FOMO and allow you to focus.&lt;/p&gt;

&lt;p&gt;If you can manage to stick with this strategy, with each context associated with a particular habit and way of thinking, your habits will begin to thrive under these predictable circumstances.  The focus will become automatic, relaxation will be easier when you leave your work environment finished with your work to a dedicated relaxation zone.  Sleep will be much easier to obtain when you associate the only thing that happens in bed is sleep and not browsing your phone or watching television.  If we want behaviors that are predictable and stable, we need an environment that is stable and predictable as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Up Next
&lt;/h2&gt;

&lt;p&gt;Up next we will go into managing our self-control and the struggles we face while trying to implement new habits given the steps we have taken thus far.  As always, I appreciate every single person who reads these articles and interacts by commenting or inquiring about more information.  Thank you so much for your engagement and time.&lt;/p&gt;

</description>
      <category>junior</category>
      <category>javascript</category>
      <category>programmer</category>
      <category>habits</category>
    </item>
  </channel>
</rss>
