<?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>Forem: fern_d3v</title>
    <description>The latest articles on Forem by fern_d3v (@fern_d3v).</description>
    <link>https://forem.com/fern_d3v</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%2F3327450%2F49f8e837-0b2b-4395-91c2-044b5a8fc81b.png</url>
      <title>Forem: fern_d3v</title>
      <link>https://forem.com/fern_d3v</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fern_d3v"/>
    <language>en</language>
    <item>
      <title>soft_reset episode2</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Wed, 11 Feb 2026 23:03:42 +0000</pubDate>
      <link>https://forem.com/fern_d3v/burnout-rust-and-the-feruchemy-problem-52f4</link>
      <guid>https://forem.com/fern_d3v/burnout-rust-and-the-feruchemy-problem-52f4</guid>
      <description>&lt;h2&gt;
  
  
  Burnout, Rust, and the Feruchemy Problem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Burnout is weird. You know you need rest, but rest feels impossible when your brain won't stop running.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This week, I stopped pretending productivity was the cure. I let myself just exist. Morning coffee with my cat watching birds, bonding with a borrowed cat, falling down a TUI rabbit hole (shoutout to &lt;a href="https://github.com/bugzmanov/bookokrat" rel="noopener noreferrer"&gt;bookokrat&lt;/a&gt; and &lt;a href="https://github.com/Jaxx497/NoctaVox" rel="noopener noreferrer"&gt;noctavox&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The thing that clicked: I've been thinking about Mistborn, and Feruchemy a lot lately. You can only tap what you've actually stored. You can't pull the rest you never gave yourself. Burnout isn't a motivation problem; it's an empty metalmind.&lt;/p&gt;

&lt;p&gt;So I'm making changes. Going all-in on Rust. Swapping GUIs for CLI's. Being intentional instead of just busy. And I'm trying to remember; &lt;em&gt;Sometimes the real win is just making space to exist.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What does rest actually look like for you&lt;/p&gt;

&lt;p&gt;&lt;em&gt;check out the full podcast &lt;a href="https://open.spotify.com/episode/0mRrzBJB8WAneheKPwMofd?si=WbQs7K82TASnebERr2Q79Q" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt; &lt;br&gt;
&lt;em&gt;cover image by &lt;a href="https://larasarmiento.artstation.com/projects/6bZwE5" rel="noopener noreferrer"&gt;Laura Samiento&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>learning</category>
      <category>burnout</category>
      <category>podcast</category>
      <category>rust</category>
    </item>
    <item>
      <title>burnout in learning</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Tue, 27 Jan 2026 20:41:59 +0000</pubDate>
      <link>https://forem.com/fern_d3v/burnout-in-learning-4fb6</link>
      <guid>https://forem.com/fern_d3v/burnout-in-learning-4fb6</guid>
      <description>&lt;h2&gt;
  
  
  the weight of burnout
&lt;/h2&gt;

&lt;p&gt;life hits everyone differently. no two people share the exact same struggles, and no one person can claim to have greater struggles than another. burnout is one of those struggles that varies per individual. and the age-old question is, "how do i avoid burnout?"&lt;/p&gt;

&lt;p&gt;i don't have those answers, unfortunately. burnout is one of my biggest struggles. has been for as long as i can remember. back when i was in film school it seemed easier to counter burnout as it approached, but the older i got, the lower my threshold for burnout became. this time, i got about 6 months before the burnout really took its toll. &lt;/p&gt;

&lt;h2&gt;
  
  
  i am not the oprah of solutions
&lt;/h2&gt;

&lt;p&gt;while developers are, at their core, problem solvers. and there are a million and one videos and articles on how to avoid burnout. none offered long term applicable solutions to me. set alarms to remind yourself so you don't go a day without it does not work mid-burnout (having adhd doesn't help honestly). set a schedule, these are my absolute enemy. &lt;/p&gt;

&lt;p&gt;i cannot get locked into a schedule that would dictate my though process. i'm just a lil weirdo who needs to be able to do things on their time or nothing will happen. &lt;/p&gt;

&lt;h2&gt;
  
  
  wrap it up, friend
&lt;/h2&gt;

&lt;p&gt;i apologize if you came into this tiny article hoping for a solution to burnout. solutions evade me like fish covered in oil in a stream. i would be forever grateful to anyone who feels a kinship to this issue, and has found a way to combat, or minimize their burnout.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>learning</category>
      <category>burnout</category>
    </item>
    <item>
      <title>interpreter? hmm...</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Fri, 31 Oct 2025 16:45:13 +0000</pubDate>
      <link>https://forem.com/fern_d3v/interpreter-hmm-m3g</link>
      <guid>https://forem.com/fern_d3v/interpreter-hmm-m3g</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;new project&lt;/strong&gt;: nekkoscript
&lt;/h2&gt;

&lt;p&gt;I have decided that for my next personal project, I am going to learn how to make my own lil language that I'm calling nekkoscript. Originally, this was going to be interpreted into JavaScript, but after doing some research, I think I want to go with Typescript instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;but why?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Why not? I have absolutely no clue what I am doing or even how to write my own language, just like my previous project &lt;a href="https://github.com/fern-d3v/devKataCLI" rel="noopener noreferrer"&gt;devKataCLI&lt;/a&gt;. I find that if I go in completely blind and learn as I go, that success is far more likely. There is an internal drive to learn that pushes me daily, and that feral goblin is ravenous for knowledge. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;typescript?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The decision to switch from JavaScript to TypeScript was pretty simple to me. I really admire how TypeScript functions and how strict it is with types. I find it forces me to write cleaner code and need to be more present than when I write JavaScript (that is probably just a me problem, but I'm trying to work with my weaknesses here).&lt;/p&gt;

&lt;h3&gt;
  
  
  we have one yes, but what about &lt;strong&gt;second language?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I was told as a kid, "go big or go home". Well... I am at home already so, I guess I gotta go big. After I finish nekkoscript, I want to work on my own fully compiled programming language. For this one, I will probably lean on Rust (it fascinates me).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;is that all?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For now? Yes. These are some really big goals I have set for myself and I am ecstatic to work on them! Currently, I am following this &lt;a href="https://youtube.com/playlist?list=PL_2VhOvlMk4UHGqYCLWc6GO8FaPl8fQTh&amp;amp;si=rBoC-H1crT4DDLwB" rel="noopener noreferrer"&gt;tutorial series on youtube&lt;/a&gt; on making a TypeScript Interpreter. I highly recommend check it out if this topic has piqued your own lil learning goblin. &lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;nikko the nekko header. wip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>typescript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building Better Dev Habits with devKataCLI: A Terminal-Based Practice Routin</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Mon, 06 Oct 2025 05:37:48 +0000</pubDate>
      <link>https://forem.com/fern_d3v/building-better-dev-habits-with-devkatacli-a-terminal-based-practice-routin-4ojc</link>
      <guid>https://forem.com/fern_d3v/building-better-dev-habits-with-devkatacli-a-terminal-based-practice-routin-4ojc</guid>
      <description>&lt;h2&gt;
  
  
  Building Better Dev Habits with devKataCLI: A Terminal-Based Practice Routine
&lt;/h2&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;The Problem: My ADHD brain can't stick to morning dev routines. I know I should practice coding daily, but consistency is hard when you're tired from your day job and need structure.&lt;/p&gt;

&lt;p&gt;The Solution: I built devKataCLI - a terminal-based tool that guides you through daily dev warmup routines. It's like having a personal trainer for your coding habits, but in your terminal.&lt;/p&gt;

&lt;p&gt;How It Works: Three progressive kata levels:&lt;br&gt;
•  miniKata (10-15 min): Posture check, daily goals, read a tech article, review a GitHub repo&lt;br&gt;
•  namiKata (15-30 min): Everything above + hydration check, review yesterday's code, typing practice&lt;br&gt;
•  devKata (30-45 min): Everything above + stretches, coding challenge, coding sandbox&lt;/p&gt;

&lt;p&gt;The Tech: Built with Node.js, @clack/prompts for beautiful CLI interactions, integrated with &lt;a href="http://dev.to/"&gt;Dev.to&lt;/a&gt; and GitHub APIs, git commit reviews, and detailed session logging.&lt;/p&gt;

&lt;p&gt;Why It Matters: Start small, build progressively, and trick your brain into consistent practice. The CLI handles the planning - you just show up and code.&lt;/p&gt;

&lt;p&gt;Try it: npm install -g devkatacli or npx devkatacli start&lt;/p&gt;

&lt;p&gt;Full article dives into the technical challenges, architecture decisions, API integrations without axios (learned the hard way!), and how progressive habits actually work. Plus my journey from "I should practice more" to actually doing it every morning.&lt;/p&gt;
&lt;h2&gt;
  
  
  How devKataCLI Works
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The User Experience
&lt;/h3&gt;

&lt;p&gt;Let me walk you through what a typical morning looks like with devKata. You wake up, grab your coffee (or tea, no judgment), and instead of staring blankly at your IDE wondering where to start, you simply open your terminal and type:&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;$ &lt;/span&gt;devkata start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And boom, you're greeted with this beautiful ASCII art banner that I spent way too much time on (but it looks sick, so worth it):&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%2F3yna0p6ajxf1cdalpymo.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%2F3yna0p6ajxf1cdalpymo.png" alt="devKataCLI opening prompt" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CLI then asks you which kata you want to run. Let's say you're feeling ambitious and choose the full devKata:&lt;/p&gt;

&lt;p&gt;Then it walks you through each task, one at a time. First up? Posture check. Because let's be real, we all sit like shrimp at our desks.&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%2Fyh40khlrq5lvooo2d7tf.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%2Fyh40khlrq5lvooo2d7tf.png" alt="Posture Check" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, you set your daily goals. This is where the magic happens - you're being intentional about your day before the chaos starts:&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%2Fyniz0kjkzdebgzqlbvan.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%2Fyniz0kjkzdebgzqlbvan.png" alt="Daily Goals" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then it gets really cool - the CLI searches &lt;a href="http://dev.to/"&gt;Dev.to&lt;/a&gt; for a random article based on tags you provide:&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%2Fifj2yldoenyiiguqfxb5.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%2Fifj2yldoenyiiguqfxb5.png" alt="Tech Article" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pattern continues, you get to choose a subject to search GitHub for and it will fetch a random repository for you to review:&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%2Faf7s96renzkuti1cn2ds.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%2Faf7s96renzkuti1cn2ds.png" alt="Random Repo Review" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole experience feels like having a personal trainer for your dev skills, but without the yelling.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's Inside Each Kata?
&lt;/h3&gt;

&lt;p&gt;miniKata (10-15 minutes)&lt;br&gt;
Your morning warmup starts with a posture check (because we all sit like shrimp). Set three daily goals to stay focused on what matters. Then the CLI searches &lt;a href="http://dev.to/"&gt;Dev.to&lt;/a&gt; for a random tech article based on your tags and finds a highly-starred GitHub repo to review. First API integration = lots of mistakes, but it works! Fair warning: no language filter yet, so you might get an article in Portuguese.&lt;/p&gt;

&lt;p&gt;namiKata (15-30 minutes)&lt;br&gt;
Builds on miniKata by adding: hydration check, communications review, and the big one - reviewing yesterday's git commits. This habit keeps your GitHub graph green and helps you pick up where you left off. Ends with typing practice on MonkeyType because keyboard speed matters when you're in flow state.&lt;/p&gt;

&lt;p&gt;devKata (30-45 minutes)&lt;br&gt;
The final boss. Adds stretches (stay limber!), a coding challenge (CodeWars or LeetCode - your choice), and the coding sandbox. The sandbox is a persistent file in ~/.config/devKata/ that opens in your IDE. It's your blank canvas - practice algorithms, debug that annoying bug, or slowly build a side project. Whatever you write stays there for tomorrow. Future plan: make it a git repo so every sandbox session builds that commit streak.&lt;/p&gt;

&lt;p&gt;The progression is intentional: miniKata teaches basics, namiKata adds real dev workflow, devKata makes you actually code. Start small, build up, stay consistent.&lt;/p&gt;
&lt;h2&gt;
  
  
  Technical Deep Dive
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;I wrote this in JavaScript utilizing Node.js because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;This is a CLI and I don't know any other languages to build one in (yet!)&lt;/li&gt;
&lt;li&gt;I needed something familiar for building my first real application&lt;/li&gt;
&lt;li&gt;Node gives me access to its vast library of packages&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The core dependencies I chose were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/natemoo-re/clack" rel="noopener noreferrer"&gt;&lt;strong&gt;@clack/prompts&lt;/strong&gt;&lt;/a&gt; - This library is &lt;em&gt;chef's kiss&lt;/em&gt;. It provides beautiful, interactive CLI prompts that make the whole experience feel polished. I chose it over Inquirer because the API is cleaner and the prompts look gorgeous right out of the box.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/alexeyraspopov/picocolors" rel="noopener noreferrer"&gt;&lt;strong&gt;picocolors&lt;/strong&gt;&lt;/a&gt; - The fastest terminal styling library. I went with the Dracula color scheme because purple and cyan just hit different.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tj/commander.js" rel="noopener noreferrer"&gt;&lt;strong&gt;commander&lt;/strong&gt;&lt;/a&gt; - For command parsing and routing. Super straightforward for defining &lt;code&gt;devkata new&lt;/code&gt; and &lt;code&gt;devkata start&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;

&lt;p&gt;The project is structured like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;devKataCLI/
├── src/
│   ├── index.js              # Entry point &amp;amp; command routing
│   ├── commands/
│   │   ├── new.js           # Kata creation workflow
│   │   └── start.js         # Kata execution engine
│   └── utils/
│       ├── storage.js       # File system operations
│       ├── handlers.js      # Task-specific handlers
│       ├── apiHelpers.js    # API integrations
│       ├── systemHelpers.js # System operations (git, browser)
│       ├── logger.js        # Session logging
│       └── helpers.js       # General utilities
└── package.json

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flow is pretty straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User runs &lt;code&gt;devkata new&lt;/code&gt; or &lt;code&gt;devkata start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commander&lt;/strong&gt; routes to the appropriate command file&lt;/li&gt;
&lt;li&gt;Command files use &lt;strong&gt;@clack/prompts&lt;/strong&gt; for user interaction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage utils&lt;/strong&gt; handle reading/writing to &lt;code&gt;~/.config/devKata/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handlers&lt;/strong&gt; execute specific tasks (posture check, code review, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logger&lt;/strong&gt; tracks sessions and progress&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything is saved to &lt;code&gt;~/.config/devKata/&lt;/code&gt; which includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kata.json&lt;/code&gt; - Your saved kata configurations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;config.json&lt;/code&gt; - Git repos and sandbox languages&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;logs/&lt;/code&gt; - Daily session logs with metrics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;coding-sandbox.*&lt;/code&gt; - Your practice files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Features I'm Proud Of
&lt;/h3&gt;

&lt;h3&gt;
  
  
  1. Interactive Configuration
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;devkata new&lt;/code&gt; command is where users build their kata. I'm really proud of how this turned out because it guides you through the entire setup without feeling overwhelming:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;newCmd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;intro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dracula&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;special&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create a new devKata routine&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;kataType&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;select&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dracula&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;What type of kata would you like to create?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;options&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;miniKata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;miniKata (10-15 minutes)&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;namiKata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;namiKata (15-30 minutes)&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devKata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devKata (30-45 minutes)&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDefaults&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;select&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dracula&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;How would you like to configure this kata?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;options&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;value&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="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dracula&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;special&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Use default kata&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;value&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;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dracula&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create custom kata&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="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// ... rest of the setup flow&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I implemented a &lt;strong&gt;progressive default system&lt;/strong&gt; where each kata type builds on the previous one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildKata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&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;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="c1"&gt;// Always start with miniKata&lt;/span&gt;
    &lt;span class="nx"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_KATAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;miniKata&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Add namiKata tasks if selected&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;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;namiKata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devKata&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;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_KATAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namiKata&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Add devKata tasks if selected&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;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devKata&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;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_KATAS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;devKata&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;tasks&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 means if you choose devKata, you automatically get all the miniKata and namiKata tasks too. It's progressive!&lt;/p&gt;

&lt;h3&gt;
  
  
  2. API Integrations
&lt;/h3&gt;

&lt;p&gt;This was my first time working with APIs, and honestly, I made it way harder on myself than it needed to be. I didn't use axios or any fancy HTTP library - just raw Node.js &lt;code&gt;https&lt;/code&gt; module because I wanted to understand how HTTP requests actually work.&lt;/p&gt;

&lt;p&gt;Here's my custom HTTPS wrapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;httpsGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeout&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="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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;timeout&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User-Agent&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;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36&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;Accept&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;application/json&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;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&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;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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;data&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="nx"&gt;response&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;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;chunk&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;data&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="nx"&gt;response&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;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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&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;statusCode&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="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="s2"&gt;`HTTP &lt;/span&gt;&lt;span class="p"&gt;${&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;statusCode&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="k"&gt;return&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;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&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;parsed&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="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="s1"&gt;Failed to parse JSON response&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="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;request&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="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="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="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;The &lt;strong&gt;User-Agent&lt;/strong&gt; header was crucial - without it, some APIs were blocking my requests thinking I was a bot (which, fair).&lt;/p&gt;

&lt;p&gt;For &lt;a href="http://dev.to/"&gt;Dev.to&lt;/a&gt; articles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchDevToArticles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tags&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;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;tags&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="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tags&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://dev.to/api/articles?tag=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;per_page=100`&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;articles&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;httpsGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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="na"&gt;success&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="na"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;articles&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="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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;success&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;articles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="na"&gt;count&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="na"&gt;error&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for GitHub repos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchGitHubRepos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&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;let&lt;/span&gt; &lt;span class="nx"&gt;searchQuery&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;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="nx"&gt;searchQuery&lt;/span&gt; &lt;span class="o"&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;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; stars:&amp;gt;1000`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;searchQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`language:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; stars:&amp;gt;1000`&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://api.github.com/search/repositories?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;sort=stars&amp;amp;order=desc&amp;amp;per_page=100`&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="nf"&gt;httpsGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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="na"&gt;success&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="na"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;:&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;items&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&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;items&lt;/span&gt; &lt;span class="p"&gt;?&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;items&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="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;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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;success&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;repos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="na"&gt;count&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="na"&gt;error&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added the &lt;code&gt;stars:&amp;gt;1000&lt;/code&gt; filter to ensure we're only surfacing quality repos, not random experiments.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Git Integration
&lt;/h3&gt;

&lt;p&gt;This feature is probably my favorite because it actually makes you look at your code from yesterday. The implementation uses Node's &lt;code&gt;child_process&lt;/code&gt; to run git commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getGitCommits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repoPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;since&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yesterday&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalizedPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repoPath&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;untilDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;since&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yesterday&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;today&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;now&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;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`cd &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedPath&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; git --no-pager log --since=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;since&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; --until=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;untilDate&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; --oneline`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt; &lt;span class="p"&gt;}&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;execAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&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;commits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stdout&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="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;line&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;success&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="nx"&gt;commits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;commits&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;repoPath&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;success&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;commits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="na"&gt;count&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="na"&gt;error&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key here is &lt;code&gt;git --no-pager&lt;/code&gt; - without that flag, git tries to open a pager and the command hangs. Learned that one the hard way.&lt;/p&gt;

&lt;p&gt;You can even view the full diff of a commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCommitDiff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repoPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commitHash&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;normalizedPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repoPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Validate commit hash (should be alphanumeric)&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="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-f0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+$/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commitHash&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="s1"&gt;Invalid commit hash&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;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`cd &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedPath&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; git --no-pager show &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;commitHash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; --color=always`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt; &lt;span class="p"&gt;}&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;execAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maxBuffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;success&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="na"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;commitHash&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;success&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;diff&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="na"&gt;error&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--color=always&lt;/code&gt; flag preserves git's beautiful diff coloring in the terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Progress Tracking &amp;amp; Logging
&lt;/h3&gt;

&lt;p&gt;Every session is logged with detailed metrics. This was important to me because I wanted to be able to look back and see my consistency over time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createSessionObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kataType&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;generateUUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;kataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;kataType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;startTime&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;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;endTime&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="na"&gt;totalDuration&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="na"&gt;status&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="na"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
        &lt;span class="na"&gt;summary&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;Each task gets its own log entry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createTaskLogEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="na"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notes&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logs are saved as JSON files in &lt;code&gt;~/.config/devKata/logs/&lt;/code&gt; with filenames like &lt;code&gt;kataLog_2025-10-06.json&lt;/code&gt;. This makes it easy to parse and potentially build analytics or visualizations later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interesting Technical Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Challenge 1: Building Without External HTTP Libraries
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; I wanted to keep dependencies minimal, but I also needed to fetch data from &lt;a href="http://dev.to/"&gt;Dev.to&lt;/a&gt; and GitHub APIs. Most tutorials say "just use axios" but I wanted to actually understand HTTP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Approach:&lt;/strong&gt; I dove into Node's built-in &lt;code&gt;https&lt;/code&gt; module documentation. It's... not the friendliest API. Everything is event-based and you have to manually handle response chunks, timeouts, errors, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; I built a Promise wrapper around &lt;code&gt;https.get()&lt;/code&gt; that handles all the edge cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;httpsGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeout&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="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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;timeout&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User-Agent&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;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)&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;Accept&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;application/json&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;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&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;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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;data&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="nx"&gt;response&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;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;chunk&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;data&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="nx"&gt;response&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;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="k"&gt;try&lt;/span&gt; &lt;span class="p"&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="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="s1"&gt;Failed to parse JSON&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="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;request&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;timeout&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="nx"&gt;request&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;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="s1"&gt;Request timeout&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;request&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What I Learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;User-Agent&lt;/code&gt; header is &lt;em&gt;crucial&lt;/em&gt; - without it, you're getting blocked&lt;/li&gt;
&lt;li&gt;Always set timeouts or your CLI will hang indefinitely&lt;/li&gt;
&lt;li&gt;JSON parsing can fail, always wrap in try-catch&lt;/li&gt;
&lt;li&gt;Event-driven code is harder to reason about than Promises&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Would I use axios next time? Probably, but I'm glad I learned the hard way first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge 2: Task Handler Routing System
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; Each task type needs different behavior. Posture checks show tips, code reviews open git diffs, articles search APIs, etc. How do I route tasks to the right handler without a massive if-else chain?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Approach:&lt;/strong&gt; I initially had a giant switch statement in &lt;code&gt;start.js&lt;/code&gt; that was getting unmanageable. I needed something more extensible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; I created a handler system where each task type has its own function in &lt;code&gt;handlers.js&lt;/code&gt;, and the router uses keyword matching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;taskResult&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;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Route to appropriate handler based on task description&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posture&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;taskResult&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;handlePostureCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;goal&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;taskResult&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;handleSetDailyGoals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&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;taskResult&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;handleReadTechArticle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;repo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;github&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;taskResult&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;handleRandomRepoReview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;review&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yesterday&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;taskResult&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;handleReviewYesterdaysCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typing&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;taskResult&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;handleTypingPractice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;challenge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;codewars&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;taskResult&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;handleDailyCodingChallenge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sandbox&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;taskResult&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;handleCodingSandbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Fallback for custom tasks&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;confirmed&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;confirm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dracula&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`complete &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&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="nx"&gt;taskResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;confirmed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cancelled&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;details&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;Each handler returns a consistent result shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cancelled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Task-specific data for logging&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What I Learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistency in return values makes everything easier downstream&lt;/li&gt;
&lt;li&gt;Keyword matching is flexible for custom tasks&lt;/li&gt;
&lt;li&gt;Having a fallback handler is crucial for extensibility&lt;/li&gt;
&lt;li&gt;This pattern makes testing individual handlers way easier&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Challenge 3: Session Logging Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; I wanted rich session logs that track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What tasks were completed&lt;/li&gt;
&lt;li&gt;How long each took&lt;/li&gt;
&lt;li&gt;What the user actually did (which article, which repo, etc.)&lt;/li&gt;
&lt;li&gt;Session status (mastered, partial, abandoned)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But I also needed this to be non-blocking and not ruin the UX if logging fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Approach:&lt;/strong&gt; I designed a hierarchical logging structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.config/devKata/logs/
  └── kataLog_2025-10-06.json
      ├── date
      ├── appVersion
      └── sessions[]
          ├── sessionId
          ├── kataType
          ├── startTime
          ├── endTime
          ├── tasks[]
          │   ├── taskId
          │   ├── description
          │   ├── status (mastered/deferred/abandoned)
          │   ├── duration
          │   └── details{}
          └── summary{}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; I created a logging system that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates a session object at the start&lt;/li&gt;
&lt;li&gt;Appends task entries as they complete&lt;/li&gt;
&lt;li&gt;Calculates summary stats at the end&lt;/li&gt;
&lt;li&gt;Saves to a daily log file
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Complete the session after all tasks&lt;/span&gt;
&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endTime&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="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalDuration&lt;/span&gt; &lt;span class="o"&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;floor&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;Date&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;session&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="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Calculate summary&lt;/span&gt;
&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;totalTasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&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="na"&gt;mastered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mastered&lt;/span&gt;&lt;span class="dl"&gt;"&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="na"&gt;deferred&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deferred&lt;/span&gt;&lt;span class="dl"&gt;"&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="na"&gt;abandoned&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;// Determine session status&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;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mastered&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalTasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mastered&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;partial&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="c1"&gt;// Save the session to log&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;appendSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What I Learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ISO timestamps are your friend&lt;/li&gt;
&lt;li&gt;Calculating metrics at save-time is easier than computing on-read&lt;/li&gt;
&lt;li&gt;Daily log files keep things organized&lt;/li&gt;
&lt;li&gt;Having detailed logs opens up future analytics possibilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The logging system also captures task-specific details. For example, when you read an article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;confirmed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cancelled&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;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tagArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;article&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="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&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;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&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;This means I can later analyze things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What topics am I reading about most?&lt;/li&gt;
&lt;li&gt;Which repos did I review?&lt;/li&gt;
&lt;li&gt;What's my completion rate over time?&lt;/li&gt;
&lt;li&gt;How long do different tasks actually take me?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Challenge 4: Cross-Platform System Integration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; I needed to open browsers, editors, and directories from the CLI. But &lt;code&gt;open&lt;/code&gt; on macOS, &lt;code&gt;start&lt;/code&gt; on Windows, and &lt;code&gt;xdg-open&lt;/code&gt; on Linux are all different commands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Approach:&lt;/strong&gt; I initially hardcoded &lt;code&gt;open&lt;/code&gt; because I develop on macOS. Then I realized this would break for anyone not on Mac (oops).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; Platform detection with fallbacks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;openRepoInIDE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repoPath&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;normalizedPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repoPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Try VS Code first (cross-platform)&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="nf"&gt;execAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`code &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedPath&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Opened in VS Code&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;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Fallback to macOS 'open' command&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="nf"&gt;execAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`open &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizedPath&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Opened repository&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;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Last fallback: manual instruction&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;success&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Navigate to: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;normalizedPath&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="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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to open repository&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;p&gt;&lt;strong&gt;What I Learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always test on multiple platforms (or get friends to test for you)&lt;/li&gt;
&lt;li&gt;Graceful fallbacks &amp;gt; breaking the entire app&lt;/li&gt;
&lt;li&gt;User instructions are better than silent failures&lt;/li&gt;
&lt;li&gt;The VS Code CLI (&lt;code&gt;code&lt;/code&gt;) is surprisingly well-supported&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Distribution Strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Making It Easy to Install
&lt;/h3&gt;

&lt;p&gt;One of my goals with devKataCLI was to make it as frictionless as possible to get started. Nobody wants to clone a repo, run &lt;code&gt;npm install&lt;/code&gt;, and figure out linking just to try a CLI tool. So I focused on multiple distribution methods:&lt;/p&gt;

&lt;h3&gt;
  
  
  npm Global Package
&lt;/h3&gt;

&lt;p&gt;This was the easiest to set up. In my &lt;code&gt;package.json&lt;/code&gt;, I defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"devkatacli"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"devkata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/index.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;bin&lt;/code&gt; field tells npm to create a symlink to &lt;code&gt;src/index.js&lt;/code&gt; when someone installs globally. The shebang at the top of that file (&lt;code&gt;#!/usr/bin/env node&lt;/code&gt;) makes it executable.&lt;/p&gt;

&lt;p&gt;Publishing was as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm login
npm publish

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now anyone can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; devkatacli
devkata &lt;span class="nt"&gt;--help&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Homebrew Tap
&lt;/h3&gt;

&lt;p&gt;This was more involved but &lt;em&gt;so&lt;/em&gt; worth it for macOS users. Homebrew is the de facto package manager for Mac, and having a formula makes installation brain-dead simple.&lt;/p&gt;

&lt;p&gt;I created a tap (a third-party Homebrew repository) at &lt;code&gt;fern-d3v/homebrew-devkatacli&lt;/code&gt; and “wrote” (borrowed from the internet) a formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Devkatacli&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Formula&lt;/span&gt;
  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Master dev habits, one kata at a time"&lt;/span&gt;
  &lt;span class="n"&gt;homepage&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;https://github.com/fern-d3v/devKataCLI&amp;gt;"&lt;/span&gt;
  &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;https://registry.npmjs.org/devkatacli/-/devkatacli-1.0.0.tgz&amp;gt;"&lt;/span&gt;
  &lt;span class="n"&gt;sha256&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_SHA_HERE"&lt;/span&gt;
  &lt;span class="n"&gt;license&lt;/span&gt; &lt;span class="s2"&gt;"MIT"&lt;/span&gt;

  &lt;span class="n"&gt;depends_on&lt;/span&gt; &lt;span class="s2"&gt;"node"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;install&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"install"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"-g"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--prefix=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"devkatacli@&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install_symlink&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;libexec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/devkata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--help"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now users can:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap fern-d3v/devkatacli
brew &lt;span class="nb"&gt;install &lt;/span&gt;devkatacli

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voilà, they're kata masters!&lt;/p&gt;

&lt;h3&gt;
  
  
  npx for Zero Install
&lt;/h3&gt;

&lt;p&gt;This is my favorite because there's literally zero setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx devkatacli start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It downloads and runs the CLI on the fly. Perfect for people who want to try it before committing to an install.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Offer Multiple Options?
&lt;/h3&gt;

&lt;p&gt;Because developers have preferences! Some people love Homebrew, some prefer npm, some just want to try things without installing. By supporting all three, I'm removing friction and letting people use the tool however they're comfortable.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Technical Learnings
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CLI Development is a Different Beast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I learned that building a CLI is fundamentally different from building a web app. There's no DOM, no hot reload, no browser DevTools. When something breaks, you're debugging with &lt;code&gt;console.log&lt;/code&gt; like it's 2010 (and honestly? It's kinda refreshing).&lt;/p&gt;

&lt;p&gt;The interactive prompt libraries like @clack/prompts are game-changers. They handle all the terminal manipulation, cursor positioning, and input parsing so you can focus on the UX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;APIs Are Both Simpler and Harder Than I Thought&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Simple because: most REST APIs are just HTTP GET requests that return JSON.&lt;/p&gt;

&lt;p&gt;Harder because: handling timeouts, retries, rate limits, parsing errors, network issues, API changes, etc. All the edge cases you don't think about until they break your CLI at 2 AM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File System Operations Require Paranoia&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always assume:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file doesn't exist&lt;/li&gt;
&lt;li&gt;The directory isn't writable&lt;/li&gt;
&lt;li&gt;The JSON is corrupted&lt;/li&gt;
&lt;li&gt;The user will Ctrl+C at the worst possible moment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Defensive programming isn't optional in CLI tools. Wrap everything in try-catch, validate all paths, use atomic writes, and always have fallbacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ES Modules in Node Are Great (Once You Figure Them Out)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;"type": "module"&lt;/code&gt; in package.json unlocks modern JavaScript in Node. But there are gotchas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need &lt;code&gt;.js&lt;/code&gt; extensions in imports (annoying but whatever)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__dirname&lt;/code&gt; doesn't exist (use &lt;code&gt;path.dirname(fileURLToPath(import.meta.url))&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Some old packages don't support ESM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Worth it though. Async/await everywhere, clean imports, no more webpack for CLI tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product Learnings
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Default Templates Are Essential&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Originally I was going to make users build their katas from scratch. Then I tested with a friend (me) who said "I have no idea what tasks to add, just give me something that works."&lt;/p&gt;

&lt;p&gt;That's when I added the default kata templates. Now 95% of users just choose the defaults and start immediately. The option to customize is there, but most people just want to get going.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progressive Complexity Actually Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The miniKata → namiKata → devKata progression wasn't just a cool naming scheme. It genuinely helps people build the habit gradually. Start with 10 minutes, then 15, then 30+. By the time you're doing full devKatas, it doesn't feel overwhelming because you've been building up to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feedback Loops Matter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every completed task shows a success message. Every kata completion gets a cute "see you tomorrow &amp;lt;3" outro. These tiny dopamine hits make the routine feel rewarding, not like a chore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation Is a Feature&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I spent a lot of time on the README, writing clear installation instructions, and creating a CONTRIBUTING guide. That documentation has driven more engagement than anything else. Good docs = people actually using your tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Source Learnings
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Choosing MIT License Was Liberating&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I went with MIT because I want people to use this, fork it, remix it, whatever. No restrictions, just build cool stuff. It's freeing to not worry about license compatibility issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue Templates Help Everyone&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When someone reports a bug, the issue template guides them to include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node version&lt;/li&gt;
&lt;li&gt;OS&lt;/li&gt;
&lt;li&gt;Steps to reproduce&lt;/li&gt;
&lt;li&gt;Error messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This saves SO much back-and-forth in comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Being Vulnerable Is Okay&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is my first real open source project. My code isn't perfect. There are probably bugs I don't know about. And that's okay! Putting it out there, flaws and all, has been incredibly educational. People are mostly supportive and helpful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results and Feedback
&lt;/h2&gt;

&lt;h3&gt;
  
  
  My Own Usage
&lt;/h3&gt;

&lt;p&gt;I've been using devKataCLI almost every morning for the last week. The biggest change? I actually &lt;em&gt;start&lt;/em&gt; coding sessions now. Before, I'd sit at my desk, scroll Twitter for 30 minutes, maybe check emails, and suddenly it's 10 AM and I haven't written a line of code.&lt;/p&gt;

&lt;p&gt;Now I run &lt;code&gt;devkata start&lt;/code&gt;, and within 15-30 minutes I'm warmed up, I've seen what I did yesterday, I've learned something new, and my brain is in "coding mode." The routine tricks my ADHD brain into focusing.&lt;/p&gt;

&lt;p&gt;The daily goals feature is surprisingly powerful. Just writing down three things makes me aware of what actually matters that day. I still get distracted, but I catch myself faster because I know what I'm supposed to be doing.&lt;/p&gt;

&lt;p&gt;The coding sandbox has become my favorite part. It's just a blank file that persists every day. I've been using it to practice algorithms, work through LeetCode problems slowly, and even prototype features for other projects. It's my scratch space, and it's always there waiting for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Future Plans
&lt;/h3&gt;

&lt;p&gt;I have a lot of ideas for where to take devKataCLI. Here's what's on the roadmap:&lt;/p&gt;

&lt;h3&gt;
  
  
  Near-Term (Next 1-3 Months)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🔧 Better Error Handling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More graceful failures when APIs are down&lt;/li&gt;
&lt;li&gt;Offline mode that works without internet&lt;/li&gt;
&lt;li&gt;Better validation for git repositories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📊 Progress Analytics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Weekly summary of kata completions&lt;/li&gt;
&lt;li&gt;Streak tracking (don't break the chain!)&lt;/li&gt;
&lt;li&gt;Visual progress charts (open to suggestions!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🎨 Customization Options&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom color themes (not everyone loves Dracula purple)&lt;/li&gt;
&lt;li&gt;Configurable task durations&lt;/li&gt;
&lt;li&gt;Ability to reorder tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🌐 More API Integrations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hacker News top stories&lt;/li&gt;
&lt;li&gt;Reddit programming threads&lt;/li&gt;
&lt;li&gt;Stack Overflow questions&lt;/li&gt;
&lt;li&gt;YouTube coding tutorials&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mid-Term (3-6 Months)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🧩 Plugin System&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let community members create custom tasks&lt;/li&gt;
&lt;li&gt;Plugin marketplace (npm packages with naming convention &lt;code&gt;devkata-plugin-*&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Easy plugin installation via CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🤝 Integration with External Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Todoist/Notion for daily goals&lt;/li&gt;
&lt;li&gt;Wakatime for coding metrics&lt;/li&gt;
&lt;li&gt;Slack/Discord notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📱 Mobile Companion App?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maybe a simple mobile app that syncs with the CLI&lt;/li&gt;
&lt;li&gt;Push notifications for kata reminders&lt;/li&gt;
&lt;li&gt;View your stats on the go&lt;/li&gt;
&lt;li&gt;(This is ambitious and I don't know React Native, so... TBD)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Long-Term (6+ Months)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🏆 Gamification&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Achievement system (badges, levels)&lt;/li&gt;
&lt;li&gt;Challenges (complete 30 devKatas in a row)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;👥 Team/Collaborative Features&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shared katas for dev teams&lt;/li&gt;
&lt;li&gt;Group challenges&lt;/li&gt;
&lt;li&gt;Team leaderboards&lt;/li&gt;
&lt;li&gt;Morning standup integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Community Ideas I'm Considering
&lt;/h3&gt;

&lt;p&gt;People have suggested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pomodoro timer integration&lt;/strong&gt; - Start a kata, get Pomodoro breaks built in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Music/playlist integration&lt;/strong&gt; - Open Spotify playlists for focus&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Habit tracking integration&lt;/strong&gt; - Sync with Habitica or similar&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How You Can Help
&lt;/h3&gt;

&lt;p&gt;The roadmap is flexible! If you have ideas, open an issue on GitHub. If you want to build something, PRs are always welcome. Even just using the tool and reporting bugs helps immensely.&lt;/p&gt;

&lt;p&gt;I'm also considering creating a Discord community for devKata users to share their routines, tips, and custom tasks. Would people be interested in that? Let me know!&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Via npm:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; devkatacli
devkata new
devkata start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Via Homebrew:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap fern-d3v/devkatacli
brew &lt;span class="nb"&gt;install &lt;/span&gt;devkatacli
devkata new
devkata start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Or try without installing:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx devkatacli start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Getting Involved
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;⭐ GitHub:&lt;/strong&gt; &lt;a href="https://github.com/fern-d3v/devKataCLI" rel="noopener noreferrer"&gt;https://github.com/fern-d3v/devKataCLI&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Star the repo if you find it useful!&lt;/li&gt;
&lt;li&gt;Open issues for bugs or feature requests&lt;/li&gt;
&lt;li&gt;Submit PRs (check &lt;a href="http://contributing.md/" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; first)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📦 npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/devkatacli" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/devkatacli&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download stats help me understand usage&lt;/li&gt;
&lt;li&gt;Leave feedback in the npm comments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;☕ Support:&lt;/strong&gt; &lt;a href="https://ko-fi.com/fernd3v" rel="noopener noreferrer"&gt;https://ko-fi.com/fernd3v&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buy me a coffee if you want to support development&lt;/li&gt;
&lt;li&gt;All donations go toward making this tool better&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Building devKataCLI has been one of the most rewarding projects I've worked on. Not because it's technically complex (it's not), but because it solves a real problem I had.&lt;/p&gt;

&lt;p&gt;The core insight is simple: &lt;strong&gt;consistency beats intensity&lt;/strong&gt;. Doing a 15-minute kata every morning is infinitely better than planning an ambitious 4-hour study session that never happens. By making the routine frictionless, progressive, and actually enjoyable, devKataCLI helps bridge the gap between intention and action.&lt;/p&gt;

&lt;p&gt;I'm still learning as I go. The code isn't perfect. There are features I want to add and bugs I need to fix. But it's out there, people are using it, and it's helping them build better habits. That's pretty cool.&lt;/p&gt;

&lt;p&gt;If you struggle with consistency, give devKataCLI a try. Start with a miniKata. Just 10-15 minutes. See if it clicks. Maybe it'll work for you like it worked for me.&lt;/p&gt;

&lt;p&gt;And if you're thinking about building a CLI tool yourself? Do it. The world needs more terminal-based utilities. Plus, it's incredibly fun to build something you use every single day.&lt;/p&gt;

&lt;p&gt;Now if you'll excuse me, I have tomorrow's devKata to prepare for.&lt;/p&gt;

&lt;p&gt;⛩️&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔗 &lt;a href="https://github.com/fern-d3v/devKataCLI" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://www.npmjs.com/package/devkatacli" rel="noopener noreferrer"&gt;npm Package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;☕ &lt;a href="https://ko-fi.com/fernd3v" rel="noopener noreferrer"&gt;Support on Ko-fi&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;What are your daily dev habits? How do you stay consistent with practice? Let me know in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>javascript</category>
      <category>node</category>
      <category>learning</category>
    </item>
    <item>
      <title>Return;</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Sun, 21 Sep 2025 08:05:22 +0000</pubDate>
      <link>https://forem.com/fern_d3v/return-l27</link>
      <guid>https://forem.com/fern_d3v/return-l27</guid>
      <description>&lt;h2&gt;
  
  
  When things change
&lt;/h2&gt;

&lt;p&gt;I had to take a small break from writing my weekly blog. I don't know about many of you, but I am a creature of habit, and if that habit is broken or interrupted at all everything goes down the drain. I had gotten a job after taking a couple months to myself, and severely underestimated the toll of working full time again and studying full time webdev / maintaining a weekly custom blog.&lt;/p&gt;

&lt;p&gt;While that was a really cool project, and I will probably go back to it at some point. I think from here out, I am just going to be publishing my articles here. My original goal was to catalogue my learning journey and if I feel too overwhelmed to do everything that went into maintaining my blog, then I'm just not going to write the post or upload it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Looking to the future
&lt;/h2&gt;

&lt;p&gt;While I may have taken a break from writing a weekly blog, I did not take a break from learning and building. I have made a couple fun little CLI tools for learning purposes and am actively working on my first actual CLI app that I will personally be using and hope others find use in it as well (more on that very very soon, probably monday).&lt;/p&gt;

&lt;p&gt;I am still not even halfway through my full stack dev path, but I can tell you this right now, I think I want to make CLI tools for devs to use. My biggest thing in life has been that I enjoy being of assistance to others. And in this field, what better way to do that than to work on dev tools?&lt;/p&gt;

&lt;p&gt;I recently read &lt;a href="https://dev.to/dayvster/dev-culture-is-dying-the-curious-developer-is-gone-lkn"&gt;this article&lt;/a&gt; about how developers don't make things anymore for the joy of learning something new. That really struck a cord with me. I used to be a video editor and one of my favorite things to do in my downtime was to tinker with weird things or to learn a new method for doing something to grow my abilities. I feel my natural desire to assist, coupled with my love of tinkering and learning will lend itself well regardless of what I end up doing as a dev.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Return;</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Sun, 21 Sep 2025 08:05:22 +0000</pubDate>
      <link>https://forem.com/fern_d3v/return-57mn</link>
      <guid>https://forem.com/fern_d3v/return-57mn</guid>
      <description>&lt;h2&gt;
  
  
  When things change
&lt;/h2&gt;

&lt;p&gt;I had to take a small break from writing my weekly blog. I don't know about many of you, but I am a creature of habit, and if that habit is broken or interrupted at all everything goes down the drain. I had gotten a job after taking a couple months to myself, and severely underestimated the toll of working full time again and studying full time webdev / maintaining a weekly custom blog.&lt;/p&gt;

&lt;p&gt;While that was a really cool project, and I will probably go back to it at some point. I think from here out, I am just going to be publishing my articles here. My original goal was to catalogue my learning journey and if I feel too overwhelmed to do everything that went into maintaining my blog, then I'm just not going to write the post or upload it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Looking to the future
&lt;/h2&gt;

&lt;p&gt;While I may have taken a break from writing a weekly blog, I did not take a break from learning and building. I have made a couple fun little CLI tools for learning purposes and am actively working on my first actual CLI app that I will personally be using and hope others find use in it as well (more on that very very soon, probably monday).&lt;/p&gt;

&lt;p&gt;I am still not even halfway through my full stack dev path, but I can tell you this right now, I think I want to make CLI tools for devs to use. My biggest thing in life has been that I enjoy being of assistance to others. And in this field, what better way to do that than to work on dev tools?&lt;/p&gt;

&lt;p&gt;I recently read &lt;a href="https://dev.to/dayvster/dev-culture-is-dying-the-curious-developer-is-gone-lkn"&gt;this article&lt;/a&gt; about how developers don't make things anymore for the joy of learning something new. That really struck a cord with me. I used to be a video editor and one of my favorite things to do in my downtime was to tinker with weird things or to learn a new method for doing something to grow my abilities. I feel my natural desire to assist, coupled with my love of tinkering and learning will lend itself well regardless of what I end up doing as a dev.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>🧠 Getting Git: A Friendly Intro to Git, GitHub, and GitHub Pages</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Sat, 02 Aug 2025 22:04:18 +0000</pubDate>
      <link>https://forem.com/fern_d3v/getting-git-a-friendly-intro-to-git-github-and-github-pages-4jjm</link>
      <guid>https://forem.com/fern_d3v/getting-git-a-friendly-intro-to-git-github-and-github-pages-4jjm</guid>
      <description>&lt;p&gt;Version control felt like wizardry when I first started coding. Cryptic commands, weird workflows, and a whole lot of mystery.&lt;/p&gt;

&lt;p&gt;But once I got it, I realized: Git is one of the most powerful tools in your developer toolbox.&lt;/p&gt;

&lt;p&gt;In this blog post, I guide you through setting up Git and GitHub step-by-step, with real terminal commands and tips for beginners:&lt;/p&gt;

&lt;p&gt;💻 In this post you'll learn:&lt;/p&gt;

&lt;p&gt;What version control actually means&lt;/p&gt;

&lt;p&gt;How to initialize a local Git repo from your terminal&lt;/p&gt;

&lt;p&gt;How to connect it to GitHub&lt;/p&gt;

&lt;p&gt;How to publish your own website for free using GitHub Pages&lt;/p&gt;

&lt;p&gt;No fluff, just a beginner-friendly walkthrough written by someone who recently went through it too.&lt;/p&gt;

&lt;p&gt;If you're building your first portfolio, starting dev school, or just need a refresher, this one's for you.&lt;/p&gt;

&lt;p&gt;👉 Read the full post here:&lt;br&gt;
🌐 &lt;a href="https://fern-d3v.github.io/console-log/posts/commandLine.html" rel="noopener noreferrer"&gt;console.git(versionControl)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know what helped (or confused you), I’d love to improve it for future devs just starting out!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>github</category>
    </item>
    <item>
      <title>Visual Studio Code for Beginners!</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Sat, 26 Jul 2025 23:22:52 +0000</pubDate>
      <link>https://forem.com/fern_d3v/visual-studio-code-for-beginners-dg8</link>
      <guid>https://forem.com/fern_d3v/visual-studio-code-for-beginners-dg8</guid>
      <description>&lt;h2&gt;
  
  
  open source-ish...
&lt;/h2&gt;

&lt;p&gt;One of the most important decisions you will make in the early days of aspiring to become a full-stack dev is which &lt;strong&gt;IDE&lt;/strong&gt; (integrated development environment) you will choose. Now, technically it is &lt;em&gt;way more important&lt;/em&gt; to find good instruction, but, finding an IDE that has a large community and is widely used is indispensable. Having support in the droves of millions for whenever you have questions gives a peace of mind that I didn't know I needed with this decision.&lt;/p&gt;

&lt;p&gt;Originally, I wanted to use &lt;strong&gt;WebStorm&lt;/strong&gt; by JetBrains. An IDE made for JavaScript and TypeScript (but can be used for HTML, CSS, and many others). I have a fondness for JetBrains. Their font "&lt;em&gt;JetBrains Mono&lt;/em&gt;" is what this site runs on and I really like the sleek, simple layout of their software. But I was reminded gently by a co-learner over on Codecademy that having the things mentioned above are really more important than what an IDE looks and feels like. Especially if you are just starting out like I am and don't have the first idea what these things really can do.&lt;/p&gt;

&lt;p&gt;So we start with &lt;strong&gt;Visual Studio Code&lt;/strong&gt;, made by &lt;em&gt;Microsoft&lt;/em&gt;. It is an IDE that feels open source at first look. It has what seems like an endless chasm of plugins and themes to dive into. In this post, we will go over basic install and setup of VS Code as well as some of the plugins that I use daily that make life easier and some that are just fun little QoL things.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you, like me, had a hard time choosing an IDE at first, then keep reading! I'm sure by the end of this you will either be excited to install VS Code, or even more confused like I was on my first VS Code walkthrough.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you enjoyed what I have written so far and want to read more, head on over to &lt;a href="https://fern-d3v.github.io/console-log/posts/visualStudioCode.html" rel="noopener noreferrer"&gt;console.log&lt;/a&gt; for the full post!&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;br&gt;
-fern_d3v&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>learning</category>
      <category>codenewbie</category>
      <category>software</category>
    </item>
    <item>
      <title>learning through repetition</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Sun, 20 Jul 2025 00:08:11 +0000</pubDate>
      <link>https://forem.com/fern_d3v/consolereference-learning-through-repetition-2jh1</link>
      <guid>https://forem.com/fern_d3v/consolereference-learning-through-repetition-2jh1</guid>
      <description>&lt;p&gt;I made a reference site to use for development so I can quickly reference things I need in the future. So far I have made pages for HTML and CSS. I struggled with setting up tables in HTML and had a hard refresher in CSS syntax and proper management, but this project helped immensely.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Strap in, grab a caffeinated drink (don't lie, you were looking for yours just like I am mine), and get ready for a beginners guide to how to make your own quick reference site.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Want to know more?
&lt;/h3&gt;

&lt;p&gt;Check out the full story on my blog at &lt;a href="https://fern-d3v.github.io/console-log/posts/cheatsheet.html" rel="noopener noreferrer"&gt;console.log&lt;/a&gt; where I dive deeper into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a reference site&lt;/li&gt;
&lt;li&gt;Why I am making one &lt;/li&gt;
&lt;li&gt;A soft outline of how you can make one too!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! If you’re on your own learning journey, I’d love to hear from you.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>codecademy</category>
      <category>blog</category>
    </item>
    <item>
      <title>Meet BMO: My Pixel Coding Companion</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Thu, 17 Jul 2025 02:35:42 +0000</pubDate>
      <link>https://forem.com/fern_d3v/meet-bmo-my-pixel-coding-companion-4n11</link>
      <guid>https://forem.com/fern_d3v/meet-bmo-my-pixel-coding-companion-4n11</guid>
      <description>&lt;p&gt;This is BMO.&lt;br&gt;&lt;br&gt;
He reviews every commit.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;With zero mercy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5c981z91w4ednf9gjwx.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%2Fm5c981z91w4ednf9gjwx.png" alt="this is bmo!" width="800" height="999"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I made this pixel art of my cat as a little mascot for my dev journey.&lt;br&gt;&lt;br&gt;
Pixelated, focused, and probably judging my syntax.&lt;/p&gt;

&lt;p&gt;Right now, I'm learning JavaScript and building out my personal projects, starting small, but trying to stay consistent.&lt;/p&gt;

&lt;p&gt;If you're also starting out or building in public, drop a link to your work below! Let’s connect.&lt;/p&gt;




&lt;p&gt;&lt;code&gt;#devcat #pixelart #beginnerdev #buildinpublic&lt;/code&gt;&lt;/p&gt;

</description>
      <category>devcat</category>
      <category>pixelart</category>
      <category>beginnerdev</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Why I Chose Codecademy to Learn Full-Stack Web Development</title>
      <dc:creator>fern_d3v</dc:creator>
      <pubDate>Sat, 12 Jul 2025 23:23:39 +0000</pubDate>
      <link>https://forem.com/fern_d3v/why-i-chose-codecademy-to-learn-full-stack-web-development-4ade</link>
      <guid>https://forem.com/fern_d3v/why-i-chose-codecademy-to-learn-full-stack-web-development-4ade</guid>
      <description>&lt;p&gt;When I started learning web development, I was overwhelmed by scattered tutorials and random YouTube videos. I needed more than information—I needed &lt;strong&gt;structure&lt;/strong&gt; and a clear roadmap to guide me.&lt;/p&gt;

&lt;p&gt;That’s why I chose &lt;strong&gt;Codecademy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Their Full-Stack Web Development path breaks down complex topics like HTML, JavaScript, React, Node.js, and deployment into bite-sized lessons with instant feedback. The browser-based IDE means no setup hassles, just focused learning and progress.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“It’s just code, feedback, and progress—one lesson at a time.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While freeCodeCamp offers deep, free content, I needed a more linear, guided experience to keep momentum and motivation early on. Codecademy’s platform gave me that — helping me build confidence and consistency.&lt;/p&gt;




&lt;h3&gt;
  
  
  Want to know more?
&lt;/h3&gt;

&lt;p&gt;Check out the full story on my blog at &lt;a href="https://fern-d3v.github.io/console-log/posts/post4.html" rel="noopener noreferrer"&gt;console.log&lt;/a&gt; where I dive deeper into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How I saved money on Codecademy Pro
&lt;/li&gt;
&lt;li&gt;Why I set a tough 3-month goal
&lt;/li&gt;
&lt;li&gt;What’s next after finishing the full-stack path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! If you’re on your own learning journey, I’d love to hear from you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;— &amp;lt;/fern&amp;gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>codecademy</category>
      <category>blog</category>
    </item>
  </channel>
</rss>
