<?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>Stormkit Community</title>
    <description>The most recent home feed on Stormkit Community.</description>
    <link>https://stormkit.forem.com</link>
    <atom:link rel="self" type="application/rss+xml" href="https://stormkit.forem.com/feed"/>
    <language>en</language>
    <item>
      <title>COSS Weekly: OpenClaw competitor NanoClaw Raises $12M, Dust Raises $40M, Sonar Acquires Gitar, and more</title>
      <dc:creator>Sabir Ibrahim</dc:creator>
      <pubDate>Mon, 25 May 2026 17:30:00 +0000</pubDate>
      <link>https://stormkit.forem.com/sabirchinstrap/coss-weekly-openclaw-competitor-nanoclaw-raises-12m-dust-raises-40m-sonar-acquires-gitar-and-345a</link>
      <guid>https://stormkit.forem.com/sabirchinstrap/coss-weekly-openclaw-competitor-nanoclaw-raises-12m-dust-raises-40m-sonar-acquires-gitar-and-345a</guid>
      <description>&lt;p&gt;This week in COSS: NanoCo, the company behind the OpenClaw competitor NanoClaw, turned down a $20M buyout offer and raised a $12M seed round; Dust raised a $40M Series B for its multiplayer AI platform; Sonar acquired Gitar to expand its code verification platform; Mistral AI acquired Emmi AI in an industrial push; and Deno Land continued its challenge of Oracle's JavaScript trademark. &lt;/p&gt;

&lt;p&gt;We also feature the following companies in Cossmology: Blindside Networks, Confluent, Dria, EvoMap, NanoCo, Omi, OpenSRE, Parrot Security, Vates, and Workbrew.&lt;/p&gt;

&lt;h2&gt;
  
  
  COSS Headlines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.theregister.com/software/2025/02/05/oracle-lays-mines-in-javascript-trademark-battle/303348" rel="noopener noreferrer"&gt;Oracle lays mines in JavaScript trademark battle&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/deno" rel="noopener noreferrer"&gt;Deno&lt;/a&gt;&lt;br&gt;
&lt;em&gt;OSS News &amp;amp; Views · The Register&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://blog.zulip.com/2026/05/15/announcing-zulip-foundation/" rel="noopener noreferrer"&gt;Announcing the Zulip Foundation&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/zulip" rel="noopener noreferrer"&gt;Zulip&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Announcement · Zulip Blog&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.reuters.com/business/autos-transportation/mistral-ai-buys-austrian-physics-ai-startup-industrial-push-2026-05-19/" rel="noopener noreferrer"&gt;Mistral AI buys Austrian physics AI startup in industrial push&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/mistral-ai" rel="noopener noreferrer"&gt;Mistral AI&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Announcement · Reuters&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.forbes.com/sites/gabrielalinzainescu/2026/05/17/what-marketers-can-learn-from-a-small-ai-startup-that-said-no-to-elon/" rel="noopener noreferrer"&gt;What Marketers Can Learn From A small AI Startup That Said No To Elon&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/black-forest-labs" rel="noopener noreferrer"&gt;Black Forest Labs&lt;/a&gt;&lt;br&gt;
&lt;em&gt;OSS News &amp;amp; Views · Forbes&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://venturebeat.com/technology/aws-nabs-white-hot-gen-ai-media-creation-startup-fal-becoming-its-preferred-cloud-provider" rel="noopener noreferrer"&gt;AWS nabs white hot gen AI media creation startup fal, becoming its preferred cloud provider&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/fal-ai" rel="noopener noreferrer"&gt;FAL.AI&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Announcement · VentureBeat&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://techcrunch.com/2026/05/20/nanoclaw-creator-turns-down-20m-buyout-offer-raises-12m-seed-instead/" rel="noopener noreferrer"&gt;NanoClaw creator turns down $20M buyout offer, raises $12M seed instead&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/nanoclaw" rel="noopener noreferrer"&gt;NanoCo&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Funding · TechCrunch&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://fortune.com/2026/05/20/exclusive-first-claw-company-to-raise-funding-nanoco-nanoclaw-cohen-brothers/" rel="noopener noreferrer"&gt;Meet the brothers who turned a homegrown AI agent into a $12 million bet on the future of work — in six weeks&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/nanoclaw" rel="noopener noreferrer"&gt;NanoCo&lt;/a&gt;&lt;br&gt;
&lt;em&gt;OSS News &amp;amp; Views · Fortune&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.sonarsource.com/company/press-releases/sonar-acquires-gitar/" rel="noopener noreferrer"&gt;Sonar Acquires Gitar, Expanding Code Verification Platform to Include AI Code Review&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/sonarsource" rel="noopener noreferrer"&gt;SonarSource&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Announcement · Sonar Newsroom&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dust.tt/blog/series-b-multiplayer-ai" rel="noopener noreferrer"&gt;Dust raises $40M Series B to scale multiplayer AI for human-agent collaboration&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/dust" rel="noopener noreferrer"&gt;Dust&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Funding · Dust Blog&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.theregister.com/devops/2026/05/15/git-is-unprepared-for-the-ai-coding-tsunami/5241480" rel="noopener noreferrer"&gt;Git is unprepared for the AI coding tsunami&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Companies mentioned:&lt;/strong&gt; &lt;a href="https://cossmology.com/organizations/gitbutler" rel="noopener noreferrer"&gt;GitButler&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Media Mention · The Register&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cossmology.com/headlines" rel="noopener noreferrer"&gt;More COSS Headlines →&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Featured COSS Companies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/parrot-security" rel="noopener noreferrer"&gt;Parrot Security&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Debian-based Linux distro for cybersecurity&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/blindside-networks" rel="noopener noreferrer"&gt;Blindside Networks&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Open-source virtual classroom hosting&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/vates" rel="noopener noreferrer"&gt;Vates&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Open source virtualization platform&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/nanoclaw" rel="noopener noreferrer"&gt;NanoCo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Creators of OpenClaw alternative NanoClaw&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/confluent" rel="noopener noreferrer"&gt;Confluent&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Cloud-native data streaming platform&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/evomap" rel="noopener noreferrer"&gt;EvoMap&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;AI agent self-evolution infrastructure&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/workbrew" rel="noopener noreferrer"&gt;Workbrew&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Enterprise Homebrew management platform&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/dria" rel="noopener noreferrer"&gt;Dria&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Decentralized AI inference network&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/omi" rel="noopener noreferrer"&gt;Omi&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Open-source AI wearable for memory&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://cossmology.com/organizations/opensre" rel="noopener noreferrer"&gt;OpenSRE&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Open-source AI SRE agent framework&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cossmology.com/organizations" rel="noopener noreferrer"&gt;More COSS Companies →&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>coss</category>
      <category>weekly</category>
    </item>
    <item>
      <title>Building Cursor for Community: A Buildathon Built on Time Pressure</title>
      <dc:creator>Valery Odinga</dc:creator>
      <pubDate>Mon, 25 May 2026 17:26:08 +0000</pubDate>
      <link>https://stormkit.forem.com/odingaval/building-cursor-for-community-a-buildathon-built-on-time-pressure-12ih</link>
      <guid>https://stormkit.forem.com/odingaval/building-cursor-for-community-a-buildathon-built-on-time-pressure-12ih</guid>
      <description>&lt;p&gt;Over the weekend, I attended an event hosted by &lt;strong&gt;Cursor Kenya&lt;/strong&gt;, bringing together developers, builders, and tech enthusiasts to explore modern AI-assisted development workflows and collaboration tools.&lt;/p&gt;

&lt;p&gt;The sessions focused on how developers can build faster using AI, improve productivity, and rethink how software is developed in collaborative environments. We also got introduced to tools like &lt;strong&gt;Sentry&lt;/strong&gt; for monitoring and debugging applications, received credits to experiment with, and later moved into a &lt;strong&gt;buildathon&lt;/strong&gt;challenge.&lt;/p&gt;

&lt;p&gt;What followed was not just a coding exercise, but a very tight constraint problem: we had &lt;strong&gt;one hour to build a working prototype&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That constraint became the foundation of everything we built.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Reality of Hackathons and Time Constraints
&lt;/h2&gt;

&lt;p&gt;Anyone who has participated in hackathons or coding competitions knows that time is the most limiting resource.&lt;/p&gt;

&lt;p&gt;In theory, teams are supposed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;brainstorm ideas,&lt;/li&gt;
&lt;li&gt;design a solution,&lt;/li&gt;
&lt;li&gt;divide tasks,&lt;/li&gt;
&lt;li&gt;build a working prototype,&lt;/li&gt;
&lt;li&gt;and prepare a demo all within a few hours or days.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality, most of the time disappears into coordination.&lt;/p&gt;

&lt;p&gt;Even simple things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who is working on what?&lt;/li&gt;
&lt;li&gt;Has this feature been pushed?&lt;/li&gt;
&lt;li&gt;Can someone review this?&lt;/li&gt;
&lt;li&gt;Where is the latest version?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…become friction points.&lt;/p&gt;

&lt;p&gt;And in fast-paced environments like hackathons, bootcamps, or team coding sessions, that friction slows everything down.&lt;/p&gt;

&lt;p&gt;During the buildathon, that limitation was very visible because the time window was extremely small, just &lt;strong&gt;60 minutes&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the Idea Started
&lt;/h2&gt;

&lt;p&gt;The idea for &lt;strong&gt;Cursor for Communities&lt;/strong&gt; did not start as a product idea. It started as a response to the constraint.&lt;/p&gt;

&lt;p&gt;We quickly realized that if time is the biggest limitation, then anything that adds delay to collaboration becomes a problem.&lt;/p&gt;

&lt;p&gt;Most developer workflows rely heavily on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pushing code to GitHub,&lt;/li&gt;
&lt;li&gt;waiting for updates,&lt;/li&gt;
&lt;li&gt;reviewing changes after commits,&lt;/li&gt;
&lt;li&gt;and communicating separately through chat tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That works in normal development cycles, but not in time-bound environments.&lt;/p&gt;

&lt;p&gt;So instead of trying to optimize existing workflows, we asked a different question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if collaboration happened in real time, inside the coding environment itself?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question became the foundation of the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Cursor for Community
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cursor for Community&lt;/strong&gt; was designed as a collaboration platform for hackathons, bootcamps, and any environment where multiple developers build together under time pressure.&lt;/p&gt;

&lt;p&gt;The main goal was simple: reduce the delay between writing code and collaborating on it.&lt;/p&gt;

&lt;p&gt;Instead of waiting for commits or pull requests, developers could work in a shared space where progress is visible instantly.&lt;/p&gt;

&lt;p&gt;The system focused on three core ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;real-time visibility,&lt;/li&gt;
&lt;li&gt;faster feedback loops,&lt;/li&gt;
&lt;li&gt;and reduced coordination overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allowed teams to stay focused on building rather than managing workflow transitions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-Time Code Tracking
&lt;/h2&gt;

&lt;p&gt;One of the core features was &lt;strong&gt;live code tracking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of waiting for someone to push changes to GitHub, team members could join a shared workspace and see updates as they happened.&lt;/p&gt;

&lt;p&gt;This changed the collaboration model from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“push → wait → review”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“write → see → react”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This small shift significantly reduces the lag between development and feedback, especially in time-constrained environments like hackathons.&lt;/p&gt;

&lt;p&gt;It also makes it easier for teammates to stay aligned without constant status updates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Team Chat for Fast Coordination
&lt;/h2&gt;

&lt;p&gt;To support collaboration, we added a &lt;strong&gt;team chat system&lt;/strong&gt; inside the platform.&lt;/p&gt;

&lt;p&gt;The goal was not to replace existing communication tools, but to keep communication close to the code.&lt;/p&gt;

&lt;p&gt;Instead of switching between messaging apps and code editors, teams could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ask questions,&lt;/li&gt;
&lt;li&gt;coordinate tasks,&lt;/li&gt;
&lt;li&gt;and resolve blockers quickly in the same environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This reduced context switching, which is often one of the biggest productivity killers in fast-paced development.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI Agent Chat for Development Support
&lt;/h2&gt;

&lt;p&gt;We also integrated an &lt;strong&gt;AI agent chat&lt;/strong&gt; directly into the workspace.&lt;/p&gt;

&lt;p&gt;This allowed developers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ask coding questions,&lt;/li&gt;
&lt;li&gt;debug issues faster,&lt;/li&gt;
&lt;li&gt;get explanations,&lt;/li&gt;
&lt;li&gt;and receive suggestions while building.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than leaving the environment to search for answers, teams could interact with an AI assistant in real time while coding.&lt;/p&gt;

&lt;p&gt;This was especially useful during the buildathon, where every minute mattered and blocking issues needed immediate resolution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mentor Mode for Guided Collaboration
&lt;/h2&gt;

&lt;p&gt;Another important feature was &lt;strong&gt;mentor integration&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Mentors could join the workspace directly, observe what teams were building, and provide guidance in real time.&lt;/p&gt;

&lt;p&gt;This made mentorship more interactive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;debugging could happen live,&lt;/li&gt;
&lt;li&gt;architectural suggestions could be given immediately,&lt;/li&gt;
&lt;li&gt;and teams could get feedback without breaking their flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of mentorship happening in scheduled check-ins, it became part of the development process itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools, Support, and Buildathon Environment
&lt;/h2&gt;

&lt;p&gt;During the event, we also got exposure to observability and debugging tools like Sentry, along with credits that helped teams experiment quickly.&lt;/p&gt;

&lt;p&gt;The environment encouraged rapid prototyping,not polished production systems, but functional ideas built under pressure.&lt;/p&gt;

&lt;p&gt;That setup aligned perfectly with the challenge: build something useful in a very short time window.&lt;/p&gt;




&lt;h2&gt;
  
  
  Outcome and Ranking
&lt;/h2&gt;

&lt;p&gt;By the end of the buildathon, our project ranked &lt;strong&gt;3rd overall&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But more importantly, we managed to turn a constraint into a product idea and build a working prototype within the limited time.&lt;/p&gt;




&lt;p&gt;The one-hour constraint was not just part of the challenge it shaped the direction of the idea itself.&lt;/p&gt;

&lt;p&gt;It highlighted how much of development time is often lost not in writing code, but in coordinating work between people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cursor for Communities&lt;/strong&gt; emerged from that realization: that collaboration tools matter just as much as coding tools, especially when time is limited.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>community</category>
      <category>productivity</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Why MLFQ Was Way Ahead of Its Time</title>
      <dc:creator>N Satyadev</dc:creator>
      <pubDate>Mon, 25 May 2026 17:21:27 +0000</pubDate>
      <link>https://stormkit.forem.com/n_satyadev_dd94f2ee2957ba/why-mlfq-was-way-ahead-of-its-time-44o7</link>
      <guid>https://stormkit.forem.com/n_satyadev_dd94f2ee2957ba/why-mlfq-was-way-ahead-of-its-time-44o7</guid>
      <description>&lt;p&gt;Enough with the unga bunga puny algorithms.. did you know there exists an&lt;br&gt;
scheduling algorithm that literally paved way for modern technology? and no it is not yet another FCFS where people just throw jobs in array order and call it a day without even bothering to sort... &lt;br&gt;
What I am referring to is MLFQ (Multi Level Feedback Queue). Now a FCFS is fine.. it's like &lt;code&gt;print("hello world")&lt;/code&gt; of OS scheduling but clearly we don't wanna &lt;em&gt;"hello"&lt;/em&gt; the world forever.. there are in fact unhealthy amount of reasons why MLFQ is considered one of the greatest algorithms.. it outperforms every previous algorithm to exist.. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FCFS&lt;/strong&gt;: just runs in arrival order &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SRTF&lt;/strong&gt;: very dangerous as it is prone to starvation (gfg link to starvation article) &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RR&lt;/strong&gt;: well... RR is just RR.. Equality is overrated in 2026 anyway, so we don't really care about it much.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all valid reasons but there's another massive reason that is common to all.. if you notice any algorithm before MLFQ demands a prerequisite number i.e. it's burst time... sure RR does not require it, but RR believes in equal quantum time... which honestly works but MLFQ is RR on steroids which is much better.&lt;/p&gt;

&lt;p&gt;RR operates on a single queue. Job runs for certain quantum time then next one runs and so on until there's no active process left..&lt;/p&gt;

&lt;p&gt;That clearly takes care of the scheduling but do you see why it is not so efficient? Imagine yourself in a supermarket, all you want are some&lt;br&gt;
hot cheetos.. but grandma amy, Infront of you is buying half the store cuz she got 27 coupons. Now you gotta wait for 30 whole mins just to get your cheetos.. the point is, that is pretty inefficient. Not that it won't get the job done but why wait so long for something so insignificant? that is whole point of MLFQ..&lt;/p&gt;

&lt;p&gt;In this blog/article/my rant from now we're gonna get into deep dive discussion on MLFQ including a working C code walk through.&lt;/p&gt;

&lt;p&gt;Now comes the juicy part.. the actual C code on how to go about it..&lt;/p&gt;

&lt;h3&gt;
  
  
  IMPLEMENTATION
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Stage 1: The Structure
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Job Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;struct Job {&lt;br&gt;
    int arrival_time;&lt;br&gt;
    int cpu_burst;&lt;br&gt;
    int start;&lt;br&gt;
    int end;&lt;br&gt;
    int turnaround;&lt;br&gt;
    int response;&lt;br&gt;
    int remaining_time;&lt;br&gt;
    bool inQueue;&lt;br&gt;
    int serial;&lt;br&gt;
    int alloted_time;&lt;br&gt;
    int alloted_left;&lt;br&gt;
};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;struct Node {&lt;br&gt;
    int data;&lt;br&gt;
    struct Node *next;&lt;br&gt;
};&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 2: The Implementation
&lt;/h3&gt;

&lt;p&gt;So, the structure we go ahead from now is list the rule and I show&lt;br&gt;
how I implemented it in code&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 1&lt;/strong&gt;:  If a process has a &lt;strong&gt;higher priority&lt;/strong&gt; (higher queue), it runs first. If the priorities are equal, the process runs in round-robin fashion.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (head != NULL) {&lt;br&gt;
    currentNode = head;&lt;br&gt;
    activeHead = &amp;amp;head;&lt;br&gt;
    activeTail = &amp;amp;tail;&lt;br&gt;
} else if (head2 != NULL) {&lt;br&gt;
    currentNode = head2;&lt;br&gt;
    activeHead = &amp;amp;head2;&lt;br&gt;
    activeTail = &amp;amp;tail2;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The above has some terms like activeHead and activeTail which you can ignore for now as they are a very special segment which i will discuss later but here what's important is the RULE that is applies... at present the rule says highest priority runs and lower one doesnt... here let say there are only 2 queues.. so we check if &lt;strong&gt;head&lt;/strong&gt; which is the root of that queue(a linked list) is empty or not.. if it is then clearly no jobs are running on high priority so we go for second queue which is head2 in this case.. so now head2 is checked and jobs in there are ran.&lt;br&gt;
But what about next part which is if same priority then jobs run in RR fashion? the next piece of code does exactly that.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(*activeHead) = currentNode-&amp;gt;next;&lt;br&gt;
currentNode-&amp;gt;next = NULL;&lt;br&gt;
(*activeTail)-&amp;gt;next = currentNode;&lt;br&gt;
(*activeTail) = currentNode;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here activeHead indicates which head is active btw(wow! totally genius). all RR does is get the first job and attach it at the back after quantum time.. that way rotation happens and fairness is imposed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 2&lt;/strong&gt;: If a process exhausts its allocated time slice in a higher priority queue, it is demoted to a lower priority queue.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;else if (job-&amp;gt;alloted_left &amp;lt;= 0) {&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now if a job has alot of processing to do it will clearly take alot of time just like grandma amy and we all hate waiting.. hence MLFQ _gracefully _handles the situation by introducing concept of alloted time as mentioned earlier.&lt;/p&gt;

&lt;p&gt;First we check "did the job use all of it's alloted time?" if yes then it has to go to counter two which only works after counter 1(queue1) is empty hence maintaining priority.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (currentNode == head) {&lt;br&gt;
        temp = head;&lt;br&gt;
        head = head-&amp;gt;next;&lt;br&gt;
        temp-&amp;gt;next = NULL;&lt;br&gt;
        if (tail2 == NULL)&lt;br&gt;
            head2 = tail2 = currentNode;&lt;br&gt;
        else {&lt;br&gt;
            tail2-&amp;gt;next = temp; &lt;br&gt;
            tail2 = temp;&lt;br&gt;
            temp = NULL;&lt;br&gt;
        }&lt;br&gt;
   }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;then for our code we must check whether 2nd queue is empty or it already got someone else waiting.. if it's empty we just do &lt;code&gt;head2 = tail2 = currentNode;&lt;/code&gt; which says hey, since there's no job in this queue point the head and tail of this to &lt;em&gt;currentNode&lt;/em&gt; which is well.. the current node. But if it is not empty then we make the poor guy to go back to waiting by appending to end which we can see with this piece of code &lt;/p&gt;

&lt;p&gt;&lt;code&gt;tail2-&amp;gt;next = temp; &lt;br&gt;
tail2 = temp;&lt;br&gt;
temp = NULL;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;finally after we shift lower priority queue we would again want it to get it's alloted time as punishing the job forever just because it takes alot of time isn't fair.. so we do something like &lt;code&gt;job-&amp;gt;alloted_left = job-&amp;gt;alloted_time;&lt;/code&gt; which resets the alloted timer and the job again get back to action (in lower priority)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 3&lt;/strong&gt;: After a fixed reset interval, all processes are boosted back to the highest priority queue.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (reset_timer == 0) {&lt;br&gt;
    clearQueue(&amp;amp;head, &amp;amp;tail, &amp;amp;head2, &amp;amp;tail2, reset);&lt;br&gt;
    enqueueReset(jobs, &amp;amp;head, &amp;amp;tail, len);&lt;br&gt;
    reset_timer = reset;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Reset timer is another feature which makes MLFQ OP.. it not only treats the poor(you with hot cheetos) fairly but also the wealthy(grandma amy.. technically). It introduces reset which is a timer when it resets the whole system. By reset i mean taking all the jobs back to higher priority so that all get equal chance again avoiding starvation again.&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%2Fd7098ywnokohy4dwzzmf.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%2Fd7098ywnokohy4dwzzmf.png" alt=" " width="800" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shows a clear queue function which is an approach that i used for reset. basically this is divided in 3 parts.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (*head2 == NULL) return;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;if 2nd queue is empty.. well just return as no need to reset since whole point of reset is get all stuff from queue2 to queue1.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (*head == NULL) {&lt;br&gt;
    *head = *head2;&lt;br&gt;
    *tail = *tail2;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If head itself is null then head2(head of 2nd queue) is only active.. so we just map the 1st queue to 2nd and that's.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;else {&lt;br&gt;
    (*tail)-&amp;gt;next = *head2;&lt;br&gt;
    *tail = *tail2;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally if head2 is not null and head is also not null then just make the tail(last node of 1st queue) point to head2(first node of queue2) and make the tail of Q1 same as Q2.. Viola.. Now we have a single Q1 which has all current jobs.&lt;/p&gt;

&lt;p&gt;Now we also need to insert new jobs available as we cannot leave any job unattended hence following can be done.&lt;/p&gt;

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

&lt;p&gt;What the code does here is parse the entire array containing jobs, check whether it is still in queue and has not ended yet which indicates job is not finished yet. if found we make a new node out of it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if(!(*head)) {&lt;br&gt;
    *head = *tail = newNode;&lt;br&gt;
} else {&lt;br&gt;
    (*tail)-&amp;gt;next = newNode;&lt;br&gt;
    *tail = newNode;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then we check if head empty? if yes then there no active jobs and this new one is the highest priority if not then we just append the new job at tail of **FIRST **Queue not 2nd because new jobs are always assigned highest priority.&lt;/p&gt;

&lt;p&gt;Now the an interesting approach here is use of &lt;strong&gt;double pointers&lt;/strong&gt; a double pointer is as name suggests pointer to a pointer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;struct Node **activeHead, **activeTail;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What this does is declare a variable that points to something that is pointing to something else.. like &lt;strong&gt;activeHead -&amp;gt; head -&amp;gt; Node&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;essentially is like a of a train. Hypothetically let say there are only 3 compartments in a train. The engine which drives everything is a actual Node. 2nd compartment is connected to engine and 3rd is connected to 2nd.. similarly head -&amp;gt; Node and activeHead -&amp;gt; head.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now how does this help in this scenario?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;MLFQ is not restricted to only 2 Queues but more than 2 which makes it even more efficient. This double pointer helps avoid a huge if else statement by using activeHead, we write the scheduling logic once. We point activeHead to whichever queue has jobs, and the code treats it the same way whether it’s Queue 1, Queue 2, or Queue 10. It’s polymorphism for C programmers.&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%2Fr85nix0iodvpfaoayark.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%2Fr85nix0iodvpfaoayark.png" alt=" " width="749" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;If you see it can get pretty ugly real fast. For more Queue's the if else string gets extended further which makes the code complete trash and stinky. &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%2Fzpak9blgghnnci1sl92i.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%2Fzpak9blgghnnci1sl92i.png" alt=" " width="379" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it leads us back to the snippet shared in the very first rule. This way we set the activeHead and activeTail by checking whether head is empty or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;And that pretty much wraps up my implementation of MLFQ. What initially looked like “just another scheduling algorithm” ended up being one of the most interesting systems I’ve implemented so far. &lt;br&gt;
Anyways if you actually read till here, congratulations. You survived queues, starvation, double pointers and my terrible supermarket analogies.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>architecture</category>
      <category>showdev</category>
    </item>
    <item>
      <title>8 Vite Config Options Every Developer Should Know (Vite 8)</title>
      <dc:creator>Erik Hanchett</dc:creator>
      <pubDate>Mon, 25 May 2026 17:14:13 +0000</pubDate>
      <link>https://stormkit.forem.com/erikch/8-vite-config-options-every-developer-should-know-vite-8-22im</link>
      <guid>https://stormkit.forem.com/erikch/8-vite-config-options-every-developer-should-know-vite-8-22im</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Last week I was at &lt;a href="https://vueconf.us/" rel="noopener noreferrer"&gt;Vueconf US&lt;/a&gt;. It's one of my favorite conferences and I try to go every year. This year Evan You gave a talk on the future of Vue and tooling. Halfway through he started talking about Vite and some of the new features of Vite 8 that just came out. I was amazed at how far Vite has come and the millions of downloads a month it's getting. What I found especially interesting was how few people really knew about these features. Evan asked the audience by a show of hands who had tried out &lt;a href="https://vite.dev/blog/announcing-vite8" rel="noopener noreferrer"&gt;Vite 8&lt;/a&gt;, and only a few people raised their hands! So when I got home I decided to write this blog post and create a video on some configurations you must try out with Vite, including some new features that just came out with Vite 8.&lt;/p&gt;

&lt;p&gt;If you haven't heard yet, Vite 8 shipped in March 2026 with the most significant architectural change since Vite 2. One of the most significant is the Rust-based bundler called Rolldown that delivers &lt;a href="https://vite.dev/blog/announcing-vite8" rel="noopener noreferrer"&gt;10-30x faster builds&lt;/a&gt;. If you've been using Vite with zero config, that's fine. The defaults are great. However, there are a handful of options that, once you know them, you'll reach for in every project.&lt;/p&gt;

&lt;p&gt;This post covers 8 config options that you should know. Two are new in Vite 8, and six have been around but you probably have not heard of them. All of them go in your &lt;code&gt;vite.config.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I put this post together using &lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;Kiro&lt;/a&gt;, an AI-powered IDE. The &lt;code&gt;forwardConsole&lt;/code&gt; option in section 1 is something Kiro benefits from directly. &lt;/p&gt;

&lt;p&gt;I also made a video covering all of these with a live demo. Check it out if you prefer watching over reading:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/WbIz38_54KM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 20.19+ or 22.12+ (required by Vite 8)&lt;/li&gt;
&lt;li&gt;A Vite project (any framework)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To upgrade to Vite 8:&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;vite@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. server.forwardConsole
&lt;/h3&gt;

&lt;p&gt;New in Vite 8. When you enable this, browser console errors and warnings show up in your Vite terminal instead of only in DevTools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;forwardConsole&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's useful when you're working with AI coding agents that can't see the browser, or when you just want to keep your eyes on the terminal instead of switching to DevTools. Vite auto-enables it when it detects an AI coding agent via &lt;a href="https://www.npmjs.com/package/@vercel/detect-agent" rel="noopener noreferrer"&gt;&lt;code&gt;@vercel/detect-agent&lt;/code&gt;&lt;/a&gt;. Otherwise it defaults to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can get more granular with it too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;forwardConsole&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;unhandledErrors&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;logLevels&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;warn&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;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output includes source-mapped stack traces, so you see the original TypeScript line numbers, not the compiled output.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. resolve.tsconfigPaths
&lt;/h3&gt;

&lt;p&gt;Also new in Vite 8. Before this you had to install the &lt;code&gt;vite-tsconfig-paths&lt;/code&gt; plugin to use TypeScript path aliases. Now it's built in and works in both the dev server and build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;tsconfigPaths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One setup mistake I see a lot: make sure &lt;code&gt;paths&lt;/code&gt; is inside &lt;code&gt;compilerOptions&lt;/code&gt;, not at the top level of the JSON. Easy to get wrong when editing by hand:&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;wrong&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;top&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;level,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ignored&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Vite&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;"files"&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;"paths"&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;"@/*"&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="s2"&gt;"./src/*"&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;"references"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.app.json"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;correct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paths&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;inside&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;compilerOptions&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;"files"&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;"references"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.app.json"&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;"compilerOptions"&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;"paths"&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;"@/*"&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="s2"&gt;"./src/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@components/*"&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="s2"&gt;"./src/components/*"&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="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;There's a small performance cost, so it's opt-in rather than the default. The &lt;a href="https://www.typescriptlang.org/tsconfig/#paths" rel="noopener noreferrer"&gt;TypeScript team also notes&lt;/a&gt; that &lt;code&gt;paths&lt;/code&gt; is intended to inform TypeScript about mappings handled by other tools, not to change emit behavior. Still, I think it's well worth trying out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;resolve.alias vs resolve.tsconfigPaths: which should you use?&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;resolve.alias&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;resolve.tsconfigPaths&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Config location&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vite.config.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with plain JS&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single source of truth&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires Vite 8&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ (built-in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance cost&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Small&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use &lt;code&gt;tsconfigPaths&lt;/code&gt; if you want one place to define aliases and you're already on TypeScript. Use &lt;code&gt;alias&lt;/code&gt; for plain JS projects, monorepos, or when you want aliases independent of TypeScript's config.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. server.proxy
&lt;/h3&gt;

&lt;p&gt;I don't see a lot of developers using this one. The proxy isn't really about fixing CORS. It's about making your dev environment behave like production.&lt;/p&gt;

&lt;p&gt;In production, your frontend and API are usually on the same domain. They might have the same origin, so CORS is not needed. For example, in dev, your frontend may be on &lt;code&gt;localhost:5173&lt;/code&gt; and your backend on &lt;code&gt;localhost:8080&lt;/code&gt;. If you have different ports, and different origins, tne you'll get a CORS error. The proxy closes helps fix this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;proxy&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;/api&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;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;changeOrigin&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;rewrite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;api/&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="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;Any request to &lt;code&gt;/api/*&lt;/code&gt; gets forwarded to &lt;code&gt;http://localhost:8080/*&lt;/code&gt;. The browser only ever sees &lt;code&gt;localhost:5173&lt;/code&gt;, so no cross-origin request and no CORS error.&lt;/p&gt;

&lt;p&gt;A few other reasons to reach for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Working against a teammate's service or a third-party API that hasn't added &lt;code&gt;localhost&lt;/code&gt; to their CORS config? You can't change their server, but you can proxy through Vite.&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;Access-Control-Allow-Origin: localhost:5173&lt;/code&gt; to your backend is a dev concern leaking into prod config. The proxy keeps that out entirely.&lt;/li&gt;
&lt;li&gt;You can inject auth headers for external services in the proxy &lt;code&gt;configure&lt;/code&gt; callback, keeping them out of the browser bundle. This is dev-only though. For production, handle auth server-side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;changeOrigin: true&lt;/code&gt; makes the request appear to come from the target host, which some backends require. &lt;code&gt;rewrite&lt;/code&gt; strips the &lt;code&gt;/api&lt;/code&gt; prefix before forwarding.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. server.hmr.overlay
&lt;/h3&gt;

&lt;p&gt;By default, Vite shows a full-screen red overlay when there's a server error. Runtime errors, HMR failures, and transform errors all trigger it. If you find it disruptive while editing, you can turn it off.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;hmr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;overlay&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="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;Errors still appear in the terminal and browser console. Turn it off when you're doing UI-heavy work and the overlay keeps blocking the component you're editing. I've been turning the overlay off a lot when I work. It's been so much nicer. Leave it on if you like the overlay.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. resolve.alias
&lt;/h3&gt;

&lt;p&gt;While I prefer the &lt;code&gt;tsconfigpaths&lt;/code&gt;, sometimes you have to use &lt;code&gt;resolve.alias&lt;/code&gt; instead. It is the explicit way to set up import shortcuts without touching tsconfig at all. It's great for JS projects, monorepos, or when you want aliases that aren't tied to TypeScript's path resolution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&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;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&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;@components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/components&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;@utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/utils&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;path.resolve&lt;/code&gt; (or &lt;code&gt;fileURLToPath&lt;/code&gt; with ESM) to get a proper absolute path. Passing a bare string like &lt;code&gt;'/src'&lt;/code&gt; resolves to the filesystem root on most systems, not your project root.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. server.open
&lt;/h3&gt;

&lt;p&gt;I've been really liking this option. Yes it's small but once you turn it on, you'll never turn it off (at least most of the time). Set &lt;code&gt;server.open: true&lt;/code&gt; and Vite opens your browser automatically when the dev server starts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also pass a path string to land on a specific route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard&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;Pairs well with conditional config (see the Bonus section) so you can set &lt;code&gt;open&lt;/code&gt; only when running &lt;code&gt;vite dev&lt;/code&gt;, not during build.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. build.sourcemap
&lt;/h3&gt;

&lt;p&gt;By default, Vite doesn't generate sourcemaps for production builds, so errors in production point at minified output. Turn this on and stack traces point at your actual source files. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FYI: Source maps are turned on for dev builds, so don't accidentaly turn this on by accident and leak your source code in production!&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npm run build&lt;/code&gt; then &lt;code&gt;npm run preview&lt;/code&gt; (preview runs &lt;code&gt;vite preview&lt;/code&gt;). Open DevTools, go to Sources, and you'll see your actual &lt;code&gt;.vue&lt;/code&gt; and &lt;code&gt;.ts&lt;/code&gt; files. Click any line in a stack trace and it jumps to the original source. This is perfect for debugging and adding in break points.&lt;/p&gt;

&lt;p&gt;Three modes are available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// separate .map files alongside the bundle&lt;/span&gt;
  &lt;span class="nx"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// sourcemap embedded directly in the JS file&lt;/span&gt;
  &lt;span class="nx"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// .map files generated, no reference in the bundle&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;'hidden'&lt;/code&gt; is useful if you're uploading sourcemaps to an error monitoring service like &lt;a href="https://docs.sentry.io/platforms/javascript/sourcemaps/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;. They can decode your stack traces server-side without the browser ever loading the maps. One thing to know: &lt;code&gt;'hidden'&lt;/code&gt; only removes the &lt;code&gt;//# sourceMappingURL=&lt;/code&gt; comment from the bundle. The &lt;code&gt;.map&lt;/code&gt; files are still generated and will be deployed alongside your JS unless you explicitly exclude them. If you want them truly private, add a step to strip &lt;code&gt;*.map&lt;/code&gt; files before uploading. Otherwise your source maps might leak to production!&lt;/p&gt;




&lt;h3&gt;
  
  
  8. envPrefix
&lt;/h3&gt;

&lt;p&gt;Occasionally I look for this one, it's useful when I'm migrating code and the prefixs are different. By default, Vite only exposes env variables prefixed with &lt;code&gt;VITE_&lt;/code&gt; to your client code. Everything else in your &lt;code&gt;.env&lt;/code&gt; file stays server-side. &lt;code&gt;envPrefix&lt;/code&gt; lets you change that prefix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;envPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUBLIC_&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;With this set, your &lt;code&gt;.env&lt;/code&gt; file might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;PUBLIC_API_URL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com&lt;/span&gt;
&lt;span class="py"&gt;PUBLIC_APP_NAME&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;My App&lt;/span&gt;
&lt;span class="py"&gt;SECRET_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;supersecret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in your components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUBLIC_API_URL&lt;/span&gt;   &lt;span class="c1"&gt;// "https://api.example.com"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUBLIC_APP_NAME&lt;/span&gt;  &lt;span class="c1"&gt;// "My App"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SECRET_DB_PASSWORD&lt;/span&gt; &lt;span class="c1"&gt;// undefined, never sent to the browser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only variables matching your prefix make it into the bundle. Everything else is stripped at build time, even if it's in the same &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;If you're migrating from Create React App (&lt;code&gt;REACT_APP_&lt;/code&gt;) or Next.js (&lt;code&gt;NEXT_PUBLIC_&lt;/code&gt;), you can match your existing naming convention instead of renaming every variable. You can also pass an array to expose multiple prefixes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;envPrefix&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;PUBLIC_&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;APP_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Bonus: conditional config and define
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;This bonus is more for the advanced users out there! If you are let me know in the comments!&lt;/em&gt; You can pass a function to &lt;code&gt;defineConfig&lt;/code&gt; instead of an object. It receives &lt;code&gt;command&lt;/code&gt; (&lt;code&gt;'serve'&lt;/code&gt; or &lt;code&gt;'build'&lt;/code&gt;) and &lt;code&gt;mode&lt;/code&gt; (&lt;code&gt;'development'&lt;/code&gt; or &lt;code&gt;'production'&lt;/code&gt;), so you can change config based on context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&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="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serve&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;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&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;code&gt;define&lt;/code&gt; bakes global constants into the build at compile time. Values are inlined directly into the output, so there's no runtime cost:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;__APP_VERSION__&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;__BUILD_DATE__&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add type declarations to &lt;code&gt;vite-env.d.ts&lt;/code&gt; so TypeScript knows about them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__APP_VERSION__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__BUILD_DATE__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cleanup
&lt;/h2&gt;

&lt;p&gt;Most of these are config-only changes. A few touch other files: &lt;code&gt;tsconfigPaths&lt;/code&gt; requires &lt;code&gt;paths&lt;/code&gt; in your &lt;code&gt;tsconfig.json&lt;/code&gt;, &lt;code&gt;envPrefix&lt;/code&gt; pairs with a &lt;code&gt;.env&lt;/code&gt; file, and &lt;code&gt;define&lt;/code&gt; needs type declarations in &lt;code&gt;vite-env.d.ts&lt;/code&gt;. To revert any option, remove it from &lt;code&gt;vite.config.ts&lt;/code&gt; and Vite falls back to its defaults.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why aren't my TypeScript path aliases working in Vite?&lt;/strong&gt;&lt;br&gt;
Make sure &lt;code&gt;paths&lt;/code&gt; is inside &lt;code&gt;compilerOptions&lt;/code&gt; in your &lt;code&gt;tsconfig.json&lt;/code&gt;, not at the top level. Vite 8's built-in &lt;code&gt;resolve.tsconfigPaths: true&lt;/code&gt; reads from &lt;code&gt;compilerOptions.paths&lt;/code&gt; only. A top-level &lt;code&gt;paths&lt;/code&gt; key is silently ignored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between resolve.alias and resolve.tsconfigPaths in Vite?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;resolve.alias&lt;/code&gt; is defined directly in &lt;code&gt;vite.config.ts&lt;/code&gt; and works for any project including plain JavaScript. &lt;code&gt;resolve.tsconfigPaths&lt;/code&gt; reads aliases from your &lt;code&gt;tsconfig.json&lt;/code&gt; and requires TypeScript. Use &lt;code&gt;tsconfigPaths&lt;/code&gt; if you want a single source of truth; use &lt;code&gt;alias&lt;/code&gt; for JS projects or monorepos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does Vite's server.proxy fix CORS errors?&lt;/strong&gt;&lt;br&gt;
Yes, but the real purpose is making dev match production. The proxy routes requests through the Vite dev server so the browser never makes a cross-origin request. No CORS header needed on your backend. It's cleaner than adding &lt;code&gt;Access-Control-Allow-Origin: localhost:5173&lt;/code&gt; to your server config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are Vite production sourcemaps safe to deploy?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;sourcemap: 'hidden'&lt;/code&gt; generates &lt;code&gt;.map&lt;/code&gt; files without referencing them in the bundle, so browsers won't load them. You can upload them to Sentry or similar for private stack trace decoding. Note: the &lt;code&gt;.map&lt;/code&gt; files are still built and will be deployed unless you add a step to strip &lt;code&gt;*.map&lt;/code&gt; files before uploading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What env variables does Vite expose to the browser?&lt;/strong&gt;&lt;br&gt;
Only variables prefixed with &lt;code&gt;VITE_&lt;/code&gt; by default (or your custom &lt;code&gt;envPrefix&lt;/code&gt;). Everything else in &lt;code&gt;.env&lt;/code&gt; is stripped at build time and never sent to the browser. That includes secrets like database passwords or API keys that don't have the prefix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does server.forwardConsole work with all frameworks?&lt;/strong&gt;&lt;br&gt;
Yes, it's a Vite dev server feature, not framework-specific. It works with Vue, React, Svelte, and any other Vite-based setup. Vite auto-enables it when it detects an AI coding agent via &lt;code&gt;@vercel/detect-agent&lt;/code&gt;; otherwise it defaults to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;forwardConsole&lt;/code&gt; and &lt;code&gt;tsconfigPaths&lt;/code&gt; are both opt-in and default to &lt;code&gt;false&lt;/code&gt;. The others (&lt;code&gt;proxy&lt;/code&gt;, &lt;code&gt;hmr.overlay&lt;/code&gt;, &lt;code&gt;resolve.alias&lt;/code&gt;, &lt;code&gt;server.open&lt;/code&gt;, &lt;code&gt;build.sourcemap&lt;/code&gt;, &lt;code&gt;envPrefix&lt;/code&gt;) have been around for a while but are easy to miss if you've never needed them.&lt;/p&gt;

&lt;p&gt;The full demo project is available at &lt;a href="https://github.com/ErikCH/vite-config-tips" rel="noopener noreferrer"&gt;https://github.com/ErikCH/vite-config-tips&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Here is me speaking at VueConf this year! &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%2Fdmyk36uejpwdmjyeh2u9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmyk36uejpwdmjyeh2u9.jpg" alt="Erik Speaking at VueConf" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Erik Hanchett, AWS Developer Advocate. He covers frontend development, AWS, and AI/agents at &lt;a href="https://programwitherik.com" rel="noopener noreferrer"&gt;programwitherik.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vite</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Feature Flags That Forgot to Leave</title>
      <dc:creator>Ian Johnson</dc:creator>
      <pubDate>Mon, 25 May 2026 17:11:38 +0000</pubDate>
      <link>https://stormkit.forem.com/tacoda/feature-flags-that-forgot-to-leave-4a0o</link>
      <guid>https://stormkit.forem.com/tacoda/feature-flags-that-forgot-to-leave-4a0o</guid>
      <description>&lt;p&gt;A feature flag goes into the codebase to make a rollout safer. The new behavior lives behind the flag. The team turns the flag on for one customer, then ten, then everyone. The rollout succeeds.&lt;/p&gt;

&lt;p&gt;The flag is still in the code.&lt;/p&gt;

&lt;p&gt;It is still in the code six months later. Still in the code a year later. The team that added it has rotated. The flag has been "on" for everyone for so long that nobody remembers the old behavior. The branch behind the false value is unreachable in any environment, and yet the code remains, and every reader has to mentally evaluate both branches every time they encounter the flag.&lt;/p&gt;

&lt;p&gt;Feature flag debt is the slowest-moving anti-pattern in most codebases. It does no damage on any given day, and it accumulates anyway. Agents make the accumulation worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  What flag debt costs
&lt;/h2&gt;

&lt;p&gt;A live feature flag in the code is not free. It is a branch: a real one, in the control flow sense, even if no environment actually traverses both sides.&lt;/p&gt;

&lt;p&gt;A reader has to evaluate both branches. A reviewer has to consider whether a change to one branch should also apply to the other. A test suite has to either cover both branches or accept that one of them is untested. A monitoring system that catches errors has to do so for code paths that, in production, might never run.&lt;/p&gt;

&lt;p&gt;When the flag was new and the rollout was live, all of this was worth it. After the rollout, none of it is. The cost stays; the value left.&lt;/p&gt;

&lt;p&gt;Multiply this by every flag your team has ever shipped and never cleaned up. The codebase becomes a thicket of dormant branches, each one a small cognitive tax, none of them individually large enough to be worth a cleanup PR. The team works around them, slowly, paying the tax in attention rather than in time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How agents make it worse
&lt;/h2&gt;

&lt;p&gt;Agents reason about both branches of a flag. Asked to refactor a function that contains a flag check, the agent will preserve the structure, update both branches, and present a diff that respects the conditional. The agent is doing the right thing. It does not know that one branch is dead. The cost is that every refactor touching flagged code touches dead code, which adds noise to the diff and time to the review.&lt;/p&gt;

&lt;p&gt;More subtly, agents will pattern-match against existing flag usage and produce new flag usage. A codebase with twenty stale flags teaches the agent that wrapping new behavior in a flag is the local idiom. The agent helpfully writes more flags. Each new flag has the same lifecycle problem the existing ones did.&lt;/p&gt;

&lt;p&gt;The combination is that flag debt does not just stay; it grows. The codebase that has tolerated flag accumulation produces an agent that produces more flag accumulation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lifecycle nobody runs
&lt;/h2&gt;

&lt;p&gt;Every feature flag has, in principle, a lifecycle. It is added. It is rolled out. It is fully enabled. It is cleaned up. The cleanup step is the one teams skip.&lt;/p&gt;

&lt;p&gt;The skip is structural, not lazy. The team that added the flag has moved on by the time it is fully rolled out. The cleanup is not anybody's current priority. There is no urgency. The system works whether the flag is cleaned up or not. There is no automated reminder, because most flag systems do not have one. So the cleanup sits in a backlog that grows by one row every time a new flag ships, and shrinks by one row almost never.&lt;/p&gt;

&lt;p&gt;The fix is not better intentions. It is making the cleanup a step in the rollout, not a follow-up to it. The flag is not "done" when it is fully enabled; it is done when the code is removed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tooling helps
&lt;/h2&gt;

&lt;p&gt;Modern feature flag platforms (LaunchDarkly, Unleash, Statsig, the open-source equivalents) increasingly include staleness detection. They report flags that have been at 100% (or 0%) for some period, flags with no usage, flags that nobody has updated in months. The reports give the team a target list without requiring anybody to remember.&lt;/p&gt;

&lt;p&gt;For teams not on a platform, the analog is a script. Walk the codebase, find every reference to a flag-checking function, cross-reference with the flag store. Output a table of flags by age and current value. Run it weekly. Anyone can write this script in an afternoon; the value is in actually looking at the output.&lt;/p&gt;

&lt;p&gt;The tooling does not delete the flags. It surfaces the ones that can be deleted. The deletion is still a human or agent decision, and it is still a code change. But it is no longer the question "what flags should we clean up?"; it is the question "should we clean up these specific flags this week?" The second question gets answered. The first does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the cleanup looks like
&lt;/h2&gt;

&lt;p&gt;Removing a flag is a small, well-defined refactor. The agent is good at it, given a clear instruction.&lt;/p&gt;

&lt;p&gt;Pick the flag. Determine the value it has been pinned to for the long term: usually &lt;code&gt;true&lt;/code&gt;, sometimes &lt;code&gt;false&lt;/code&gt;. Replace every reference to the flag's check with that value. Simplify the resulting conditionals: &lt;code&gt;if (true) { ... }&lt;/code&gt; becomes the body of the &lt;code&gt;if&lt;/code&gt;; &lt;code&gt;if (false) { ... }&lt;/code&gt; becomes nothing. Run the tests. The diff is mechanical. Most flags can be removed in a single PR by a single contributor in under an hour.&lt;/p&gt;

&lt;p&gt;The work scales. A team that removes one flag per week ends a year with fifty fewer flags. The cumulative effect on readability is meaningful.&lt;/p&gt;

&lt;h2&gt;
  
  
  First steps
&lt;/h2&gt;

&lt;p&gt;If your codebase has accumulated stale flags:&lt;/p&gt;

&lt;p&gt;Inventory them. Pull the list of every flag your team has ever defined. For each, note the current value, when it was last changed, and whether the rollout it was created for has concluded.&lt;/p&gt;

&lt;p&gt;Sort by age, descending. The top of the list is your cleanup target. Pick the oldest flag whose rollout is clearly done, one that has been at 100% for longer than anyone remembers, and remove it. One PR. Ship it.&lt;/p&gt;

&lt;p&gt;Add a step to your flag-creation process: every new flag has an owner and a target removal date, written into the flag's description in the flag platform. The dates do not have to be precise, but they have to exist. A flag without a removal plan is a flag that will never be removed.&lt;/p&gt;

&lt;p&gt;Add a recurring item to your team's weekly or biweekly review: stale flag report. Look at it. Pick one to clean up. Assign it. Move on.&lt;/p&gt;

&lt;p&gt;Add a rule to AGENTS.md: "When making changes that touch a feature flag, check whether the flag's rollout has concluded. If yes, propose removal of the flag in the same change. Do not introduce new feature flags without an owner and a target removal date in the flag's description."&lt;/p&gt;

&lt;p&gt;Feature flags are useful. The mistake is treating them as permanent fixtures rather than temporary scaffolding. Scaffolding stays up only as long as the construction needs it. After that, it is not scaffolding; it is junk in the yard. The same applies to flags.&lt;/p&gt;

&lt;p&gt;The codebase that uses flags well is one that adds them confidently because it trusts itself to remove them when the work is done. Building that trust is a matter of running the cleanup, repeatedly, until it becomes the default rather than the exception.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>agents</category>
      <category>devops</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why Trust Infrastructure Is Becoming the Hidden Layer of Donation Platforms</title>
      <dc:creator>Muneeb ur Rehman</dc:creator>
      <pubDate>Mon, 25 May 2026 17:09:20 +0000</pubDate>
      <link>https://stormkit.forem.com/muneeb_urrehman_8546ac5c/why-trust-infrastructure-is-becoming-the-hidden-layer-of-donation-platforms-2g35</link>
      <guid>https://stormkit.forem.com/muneeb_urrehman_8546ac5c/why-trust-infrastructure-is-becoming-the-hidden-layer-of-donation-platforms-2g35</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction: The Part of the Donation Stack Nobody Talks About&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Most conversations about donation technology focus on the donor experience: cleaner checkout flows, mobile-first design, recurring giving prompts, gamified fundraising. The UX layer gets the attention, gets the venture capital, and gets the press. But behind every successful gift processing system, there is a quieter and far less glamorous set of problems being solved, or in many cases not solved particularly well.&lt;br&gt;
These are the problems of trust infrastructure: the systems responsible for confirming that the organizations receiving donations are who they claim to be, that they remain in good legal standing, and that the platforms facilitating those gifts are compliant with the patchwork of state and federal regulations that govern charitable solicitation in the United States and abroad.&lt;br&gt;
It is not exciting work. There are no flashy demos. But when it breaks, the consequences can be significant: donations processed to organizations that have lost their tax-exempt status, platforms exposed to liability for facilitating unregistered solicitation across dozens of states, donors who claimed deductions that don't hold up to scrutiny. Trust infrastructure is the kind of thing you only notice when it fails.&lt;br&gt;
What's changed in the past several years is that this infrastructure is no longer just a compliance checkbox for large institutional players. As donation platforms have proliferated and per-transaction costs have dropped close to zero, the verification problem has scaled enormously. More platforms, more nonprofits, more jurisdictions, more edge cases. The technical systems designed to handle this have not always kept pace.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How Trust and Verification Became Infrastructure-Scale Problems&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There's a useful distinction between verification as a task and verification as infrastructure. Verifying that a specific nonprofit is in good standing with the IRS is a task. Doing that for tens of thousands of organizations, continuously, across changing data sources, with downstream consequences for payment processing and tax receipt generation, is an infrastructure problem. The two require fundamentally different approaches.&lt;br&gt;
Ten years ago, most donation platforms could get away with treating verification as a task. The typical platform served a limited roster of nonprofits, often pre-screened through manual onboarding, and the volume was manageable. Someone could check IRS Publication 78 or the Tax Exempt Organization Search directly, confirm the EIN, flag anything that looked wrong, and move on.&lt;br&gt;
That model has not scaled. Several forces conspired to make it unworkable.&lt;br&gt;
First, the volume. Platforms that aggregate charitable giving across thousands or millions of cause pages cannot manually verify each organization on a rolling basis. A nonprofit can lose its tax-exempt status, face a state enforcement action, or fall out of good standing in a single filing cycle. If your verification was done at onboarding and never revisited, you're carrying stale data.&lt;br&gt;
Second, the regulatory environment has grown considerably more complex. The National Association of State Charity Officials has been pushing for more uniformity in registration requirements, but the reality on the ground remains fragmented. A platform operating nationally may be subject to charitable solicitation registration requirements in over forty states, each with its own thresholds, exemptions, and renewal schedules. Managing that manually is, practically speaking, not possible.&lt;br&gt;
Third, and perhaps most importantly, the stakes have gone up. Donation platforms are no longer just moving money; they're often issuing tax receipts, providing compliance attestations, and functioning as fiduciaries in ways that carry real legal exposure. That shifts verification from a nice-to-have to a critical dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Specific Challenges That Make Nonprofit and Compliance Data So Difficult to Work With&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Anyone who has tried to build reliable data pipelines on top of public charity data sources will tell you the same thing: the data is messy, inconsistent, asynchronously updated, and structured in ways that do not lend themselves to programmatic consumption.&lt;br&gt;
The IRS Tax Exempt Organization Search is the canonical source for federal tax-exempt status, but it has real limitations. Updates lag reality by weeks or months in some cases. The data model does not always cleanly capture the nuances of subordinate organizations under a group exemption, or organizations that are in various stages of reinstatement after automatic revocation. Building a system that treats IRS data as ground truth without accounting for these edge cases will eventually produce errors.&lt;br&gt;
State charity registration data is even more challenging. There is no single national registry. Each state maintains its own database, with its own filing formats, its own definitions of who is required to register, and its own update cadence. Some states have made reasonable progress toward machine-readable public data. Others have not. The information you need may exist behind a portal designed for manual lookup, not API consumption.&lt;br&gt;
Then there are the definitional problems. What counts as a charitable organization for the purposes of a given state's registration requirements is not always identical to what the IRS considers tax-exempt. Some states exempt religious organizations broadly; others take a narrower view. Some states have gross receipts thresholds below which registration is not required; those thresholds vary. A platform serving nonprofits nationally has to reason about this complexity for each organization it hosts.&lt;br&gt;
The temporal dimension adds another layer of difficulty. An organization's status is not a static fact; it changes over time, sometimes abruptly. A nonprofit that was in perfect standing last quarter may have failed to file a required renewal, triggering automatic revocation. Building verification systems that check once and cache indefinitely is building systems that will fail quietly over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Practical Costs of Relying on Manual Workflows for Verification and Compliance&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Many platforms, particularly smaller ones, still rely on some version of manual verification. A team member checks EINs against the IRS database during onboarding. A spreadsheet tracks which nonprofits need renewal checks. Someone is supposed to flag anything that looks out of date. This works until it doesn't, and when it stops working, it tends to do so invisibly.&lt;br&gt;
The failure mode is not usually a dramatic incident. It's accumulated drift. An organization's status changes, the spreadsheet doesn't get updated, the platform continues processing donations, and six months later someone notices that receipts were being issued for gifts to an organization that had lost its exempt status four months ago. By that point, the remediation involves donor notifications, potential refunds, and the kind of legal review that nobody budgeted for.&lt;br&gt;
Manual workflows also create bottlenecks that are easy to underestimate. When a platform is onboarding new organizations at scale, having a human in the loop for verification creates a natural chokepoint. Teams end up either under-verifying to meet volume demands, or over-building manual processes that don't actually solve the underlying data quality problem.&lt;br&gt;
There's also the question of institutional knowledge. Manual verification processes tend to live in the heads of the people running them. When those people leave, the knowledge goes with them. What remains is a set of informal procedures that new team members reconstruct imperfectly, introducing inconsistency into a process that depends on consistency.&lt;br&gt;
The irony is that manual verification is often not even more accurate than well-designed automated systems. A human checking a nonprofit's status on a given day will get the right answer for that moment, but won't automatically know to check again when status changes. Automation, done properly, can run continuous checks that a human workforce simply cannot replicate.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Good Technical Architecture Looks Like When Built Around Trust Verification at Scale&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Building verification infrastructure that actually works at scale requires making some architectural decisions that are different from those you'd make for a simple lookup utility.&lt;br&gt;
The first is separating data ingestion from data serving. Rather than querying source databases in real time when a verification request comes in, robust systems maintain their own continuously updated copies of relevant data, with clear provenance tracking. This allows for fast, reliable responses even when upstream sources are slow or temporarily unavailable. It also allows for the kind of historical tracking that manual processes cannot provide: not just whether an organization is in good standing now, but what its status has been over time.&lt;br&gt;
The second architectural consideration is building around data source instability. Any system that depends on a single upstream source for critical compliance data has a fragility problem. Good implementations layer multiple sources, define explicit rules for conflict resolution, and surface confidence levels alongside results. When data sources disagree, the system should not silently pick one; it should flag the discrepancy for downstream handling.&lt;br&gt;
The third consideration is the API contract. Verification data is consumed by a wide range of downstream systems: payment processors, receipt generation engines, fraud detection workflows, reporting dashboards. The API surface needs to be designed with those consumers in mind, providing structured, queryable responses that carry enough context for consuming systems to make good decisions. Returning a simple boolean is rarely sufficient; consuming systems need to know not just whether an organization is currently verified, but under what conditions and with what caveats.&lt;br&gt;
Some tools in this space have started to address these architectural challenges in earnest. The &lt;a href="https://pactman.org/nonprofitcheckplus-api/landing" rel="noopener noreferrer"&gt;Pactman NonprofitCheck Plus API&lt;/a&gt;, for instance, is one example of a purpose-built tool that tries to consolidate nonprofit verification data into a queryable format suitable for programmatic integration, which is the kind of approach that becomes necessary once manual verification stops scaling. It sits within a broader ecosystem of compliance-adjacent tools that are collectively trying to make this data layer more reliable and more accessible.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Real-World Implementation Lessons from Platforms That Have Built This Well and Poorly&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The platforms that have built trust infrastructure well tend to share a few characteristics. They started thinking about verification as infrastructure early, before the complexity of their data problem had outpaced their capacity to manage it. They treated compliance data as a first-class engineering concern rather than an operational afterthought. And they made deliberate choices about where to build and where to buy.&lt;br&gt;
The build-versus-buy question is worth dwelling on. There is a tempting argument that verification data is too important to outsource, that a platform should own its entire compliance stack. This argument tends to underestimate how hard the data problem actually is. Maintaining current, accurate, multi-source verification data across all U.S. nonprofits is itself a full-time product problem. Most platforms are not in the business of solving that problem; they're in the business of facilitating donations. Buying a reliable data layer and building on top of it is often the more sensible architectural choice.&lt;br&gt;
On the implementation side, one pattern that comes up repeatedly in conversations with platform engineers is the importance of designing for auditability from the start. Verification isn't just about getting the right answer in real time; it's about being able to demonstrate that you had a reasonable basis for a decision at a given moment in time. When a regulatory question comes up six months later, you need logs, timestamps, and source attribution. Systems that don't track this information from the beginning find themselves unable to reconstruct it retroactively.&lt;br&gt;
Another common mistake is treating verification as a one-time event. As noted earlier, organizational status changes. Platforms that run verification at onboarding and then assume the answer is stable are building a system that will drift out of accuracy over time. The better approach is continuous or periodic re-verification, with alerting for status changes and clear policies for what happens when a previously verified organization falls out of good standing.&lt;br&gt;
The platforms that have gotten this wrong share a different set of characteristics. They typically treated compliance as someone else's problem for too long, kicked the infrastructure question down the road until scale forced their hand, and then had to retrofit verification into systems that weren't designed for it. Retrofitting is expensive, disruptive, and tends to produce less coherent results than building thoughtfully from the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What the Next Several Years Are Likely to Look Like for Trust Infrastructure in Charitable Giving&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The underlying pressures that have made trust infrastructure a pressing problem are not going away. If anything, they are intensifying.&lt;br&gt;
Regulatory attention to donor-advised funds, fiscal sponsorship arrangements, and cross-border giving has increased in recent years. The question of whether a platform bears responsibility for the compliance status of the organizations it hosts is not settled, but the direction of regulatory interest suggests that the answer is trending toward greater platform accountability. Platforms that haven't invested in reliable verification infrastructure will be in a more precarious position as that accountability question gets clearer answers.&lt;br&gt;
At the same time, donor expectations are shifting. Younger donors in particular express stronger preferences for knowing that their contributions are going to organizations with demonstrated legitimacy. The trust gap between institutional giving and direct-to-cause platforms is something that can be narrowed through transparent verification practices, but only if those practices are actually reliable.&lt;br&gt;
Machine learning applications in compliance monitoring are also worth watching. Several companies are beginning to apply pattern recognition to charity data to identify early signals of organizational stress before it becomes a public compliance failure. The ability to flag elevated risk based on filing patterns, leadership changes, or financial indicators, before a formal adverse action occurs, could meaningfully improve how platforms manage their organization rosters proactively rather than reactively.&lt;br&gt;
API standardization is another area where progress could be significant. Right now, the charity data ecosystem is fragmented across dozens of sources with varying formats and access models. Efforts to create more standardized programmatic access to official charity data would lower the cost of building reliable verification infrastructure considerably. This is a space where policy advocacy and technical standardization could compound each other's impact.&lt;br&gt;
The question of real-time verification is likely to become increasingly important as well. Processing a donation takes seconds. The verification checks that support that transaction should ideally run in near-real-time, with low enough latency that they can be embedded in transaction flows rather than run as asynchronous batch processes. Getting there requires both better upstream data and better infrastructure design.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion: Infrastructure Is Not Glamorous, But It Is Foundational&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There is a persistent temptation in technology to focus resources on the visible layer: the user interface, the experience, the front-end elements that donors and nonprofit administrators actually see and interact with. That focus is not wrong, but it has contributed to chronic underinvestment in the infrastructure that makes the visible layer trustworthy.&lt;br&gt;
Trust infrastructure in donation platforms is a genuine engineering and product challenge. It involves messy data, complex regulatory requirements, difficult architectural tradeoffs, and organizational dynamics that tend to prioritize visible work over invisible work. The platforms that get it right will be in a stronger position as regulatory scrutiny increases and donor expectations for legitimacy and transparency continue to rise.&lt;br&gt;
The good news is that the tools and approaches to address these challenges are maturing. The data layer is getting better. API-based verification services are more capable than they were five years ago. Engineering patterns for building reliable compliance infrastructure are better understood and more widely shared. The investment required to build this well is significant but not prohibitive.&lt;br&gt;
What the sector needs is for platform builders to take the invisible layer as seriously as the visible one. The donation happens in a moment; the trust that makes it possible is built over time, through systems that most donors will never directly encounter. That is precisely why it matters.&lt;/p&gt;

</description>
      <category>api</category>
      <category>nonprofit</category>
      <category>softwaredevelopment</category>
      <category>techinfrastructure</category>
    </item>
    <item>
      <title>XyPriss: Rethinking Core Performance and Zero-Trust Architecture in Modern Backends</title>
      <dc:creator>iDevo</dc:creator>
      <pubDate>Mon, 25 May 2026 17:08:37 +0000</pubDate>
      <link>https://stormkit.forem.com/idevo/xypriss-rethinking-core-performance-and-zero-trust-architecture-in-modern-backends-2idn</link>
      <guid>https://stormkit.forem.com/idevo/xypriss-rethinking-core-performance-and-zero-trust-architecture-in-modern-backends-2idn</guid>
      <description>&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%2Fu288bouu3zofugf3hkdt.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%2Fu288bouu3zofugf3hkdt.png" alt="XyPriss banner - Built for Performance, Engineered for Security, showing architectural principles like Zero-Trust, Native Performance, and Modular design" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After two years of intensive development and architectural refinement, &lt;strong&gt;XyPriss&lt;/strong&gt; has officially reached full maturity. With the release of the &lt;strong&gt;v9.10.16++&lt;/strong&gt; stable branch, the framework is now 100% production-ready. &lt;/p&gt;

&lt;p&gt;We designed XyPriss from the ground up as a secure-by-default backend framework, powered by native internals and engineered specifically to sustain heavy, production-grade systems.&lt;/p&gt;

&lt;p&gt;The goal was never to build &lt;em&gt;"just another framework"&lt;/em&gt;. The goal was to solve critical infrastructure bottlenecks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Architectural Pillars
&lt;/h3&gt;

&lt;p&gt;XyPriss shifts the paradigm of modern backend development through four key principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Trust Security:&lt;/strong&gt; Hardened by default. Security protocols and safe configurations are baked into the core, eliminating critical vulnerabilities before the first line of business logic is even written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Performance:&lt;/strong&gt; Driven by a high-performance native engine designed for low-level execution speed, minimal memory overhead, and extreme portability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modular by Design:&lt;/strong&gt; A highly flexible architecture that lets you scale components independently without introducing technical debt or breaking monolithic dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production Reliability:&lt;/strong&gt; Rigorously tested to ensure operational stability under high-concurrency production workloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Battle-Tested and Growing
&lt;/h3&gt;

&lt;p&gt;What started as an ambitious technical challenge two years ago has evolved into a stable, powerful ecosystem. With the stability achieved in the current v9.10.16++ release cycle, XyPriss is ready for deployment in mission-critical environments.&lt;/p&gt;

&lt;p&gt;Whether you are optimizing transaction pipelines, building high-throughput APIs, or auditing system security, we invite you to explore what we have built.&lt;/p&gt;




&lt;h3&gt;
  
  
  Links and Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation:&lt;/strong&gt; &lt;a href="https://xypriss.nehonix.com" rel="noopener noreferrer"&gt;xypriss.nehonix.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/Nehonix-Team/XyPriss" rel="noopener noreferrer"&gt;Nehonix-Team/XyPriss&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you appreciate the work and engineering behind this framework, please take a second to star (like) our repository on GitHub. It costs nothing but it deeply encourages the team and gives the project the visibility it needs to grow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Feel free to explore the repository, test the framework, or leave your technical feedback in the comments below.&lt;/em&gt; &lt;a class="mentioned-user" href="https://dev.to/typescripttutorials"&gt;@typescripttutorials&lt;/a&gt; &lt;/p&gt;

</description>
      <category>xypriss</category>
      <category>nehonix</category>
      <category>typescript</category>
      <category>express</category>
    </item>
    <item>
      <title>Designing Configuration for Scalable Treasure Hunts</title>
      <dc:creator>Lillian Dube</dc:creator>
      <pubDate>Mon, 25 May 2026 17:07:14 +0000</pubDate>
      <link>https://stormkit.forem.com/dev-architecture-blog/designing-configuration-for-scalable-treasure-hunts-506o</link>
      <guid>https://stormkit.forem.com/dev-architecture-blog/designing-configuration-for-scalable-treasure-hunts-506o</guid>
      <description>&lt;h2&gt;
  
  
  The Problem We Were Actually Solving
&lt;/h2&gt;

&lt;p&gt;At Veltrix, we're known for our real-time treasure hunts – a complex feature that involves querying a massive graph database, processing high-frequency event streams, and returning results in under 100ms. However, when we started to onboard more clients and scale our infrastructure, our operators consistently hit the same problem: configuring the system to handle the increased load became a nightmare. Our documentation, which followed the traditional approach of listing configuration options, wasn't helping – we knew something had to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried First (And Why It Failed)
&lt;/h2&gt;

&lt;p&gt;We attempted to solve this problem by introducing a centralized configuration service – an abstraction that would hide the complexity of configuration from our developers. Sounds good, right? In theory, this approach would allow us to simply tweak a single configuration file and have it propagate across the entire system. However, in practice, we soon realized that this approach led to a cascade of dependencies between services. Every time we wanted to make a change, we'd end up updating multiple configuration files, which would then necessitate a cascading series of service restarts. It was a total mess. We were still hitting the same problem, just in a different way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Decision
&lt;/h2&gt;

&lt;p&gt;After months of experimenting with different approaches, we decided to take a different route. We moved configuration into the application itself – using a technique called "configuration as code" (CAC). This allowed us to treat configuration as a first-class citizen, subject to the same version control and testing discipline as our code. We wrote a custom configuration framework that generated a configuration graph for each service based on the application code. It might sound simple, but it was a total game-changer. Our developers could now see exactly how configuration would be generated, and we could ensure that changes were properly versioned and tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  What The Numbers Said After
&lt;/h2&gt;

&lt;p&gt;After deploying the new configuration framework, we saw a significant reduction in mean time to recover (MTTR) from configuration-related issues. We measured this using a custom dashboard built on top of our Grafana installation, which tracked configuration-related errors and their impact on downstream services. It turned out that 75% of our configuration-related errors were due to invalid or missing configuration files – something that CAC helped us eliminate. The numbers told the story: our system was now more resilient, and our developers had more time to focus on building new features.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Do Differently
&lt;/h2&gt;

&lt;p&gt;Looking back, I would have done a few things differently. We could have explored using a configuration management tool like Ansible to automate the process of updating configuration files. We could have also taken advantage of tools like Hashicorp's Terraform to manage our infrastructure as code. However, at the end of the day, it was the simplicity and transparency of CAC that made it a winner. No more obscure configuration files or cascading service restarts – just clean, declarative code that everyone could understand. After experiencing the pain of over-abstracting configuration, I've become a proponent of the "configuration is code" approach. When it comes to designing configuration for scalable systems, I firmly believe that fewer abstractions are better.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
      <category>systems</category>
    </item>
    <item>
      <title>SSH Login Delays: The 10-Second Wait That Drives Us Crazy</title>
      <dc:creator>Schiff Heimlich</dc:creator>
      <pubDate>Mon, 25 May 2026 17:07:09 +0000</pubDate>
      <link>https://stormkit.forem.com/schiff_heimlich/ssh-login-delays-the-10-second-wait-that-drives-us-crazy-16f3</link>
      <guid>https://stormkit.forem.com/schiff_heimlich/ssh-login-delays-the-10-second-wait-that-drives-us-crazy-16f3</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Every sysadmin has been there: you SSH into a server and wait... and wait... 10 seconds later, you finally get a prompt. It's one of those small annoyances that wears on you over time.&lt;/p&gt;

&lt;p&gt;I ran into this again last week while troubleshooting a production server. The delay wasn't there before, something had changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Causes
&lt;/h2&gt;

&lt;p&gt;After digging into this enough times, I've found these usual suspects:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. DNS Resolution
&lt;/h3&gt;

&lt;p&gt;If your system can't resolve the hostname quickly, SSH will timeout before falling back to the IP. Check your &lt;code&gt;/etc/resolv.conf&lt;/code&gt; and consider adding the server's IP to &lt;code&gt;/etc/hosts&lt;/code&gt; if it's a frequent connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Host Key Verification
&lt;/h3&gt;

&lt;p&gt;First-time connections to new servers (or after key changes) trigger host key verification. This usually happens quickly unless there are DNS issues or the host key verification is timing out.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. PAM Configuration
&lt;/h3&gt;

&lt;p&gt;Sometimes PAM modules are configured with timeouts that cause delays. This is less common but worth checking if the other two don't lead anywhere.&lt;/p&gt;

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

&lt;p&gt;My go-to approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test with IP first&lt;/strong&gt;: &lt;code&gt;ssh user@192.168.1.100&lt;/code&gt; - if this is instant, DNS is the problem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check DNS&lt;/strong&gt;: &lt;code&gt;nslookup servername&lt;/code&gt; or &lt;code&gt;dig servername&lt;/code&gt; to see if resolution is slow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add to hosts&lt;/strong&gt;: If it's a frequent connection, add the IP to &lt;code&gt;/etc/hosts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check SSH config&lt;/strong&gt;: Look for any custom configurations that might be causing delays&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fix is usually simple once you identify the root cause. Most of the time, it's just DNS resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Talk
&lt;/h2&gt;

&lt;p&gt;This isn't some complex infrastructure issue - it's one of those small things that makes day-to-day work frustrating. But once you know what to look for, it's a 5-minute fix.&lt;/p&gt;

&lt;p&gt;What about you? Any other causes I've missed? I'm always running into new variations of this.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Schiff Heimlich | Sysadmin who's been bitten by this one too many times&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>dns</category>
      <category>devops</category>
      <category>sysadmin</category>
    </item>
    <item>
      <title>Building Production Multi-Agent Workflows in n8n: What 50 Deployments Taught Us</title>
      <dc:creator>Ankit Dhiman</dc:creator>
      <pubDate>Mon, 25 May 2026 17:06:44 +0000</pubDate>
      <link>https://stormkit.forem.com/ankitdhiman/building-production-multi-agent-workflows-in-n8n-what-50-deployments-taught-us-foi</link>
      <guid>https://stormkit.forem.com/ankitdhiman/building-production-multi-agent-workflows-in-n8n-what-50-deployments-taught-us-foi</guid>
      <description>&lt;p&gt;Most n8n AI workflow tutorials end at "it worked in testing." The gap between a demo and a production system handling 10,000 items/day with real money on the line is where the interesting problems live.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://chronexa.io" rel="noopener noreferrer"&gt;Chronexa&lt;/a&gt;, we've built 50+ multi-agent workflows for fintech compliance teams, legal document processing, AI SDR engines, and RAG-powered research assistants. Here's what we've learned about making them reliable.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Design Failure as a First-Class Concern
&lt;/h2&gt;

&lt;p&gt;Most n8n tutorials wire &lt;code&gt;main[0]\&lt;/code&gt;. Production workflows wire &lt;code&gt;main[0]\&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;main[1]\&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every HTTP Request node and AI node has two outputs in n8n: success (&lt;code&gt;main[0]\&lt;/code&gt;) and error (&lt;code&gt;main[1]\&lt;/code&gt;). Leaving the error branch unwired means failures disappear silently — you only find out when a client notices something is wrong three days later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pattern we use on every deployment:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;&lt;br&gt;
HTTP Request → main[0] → continue workflow&lt;br&gt;
             → main[1] → DLQ Sheet + Slack Alert&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;onError: 'continueErrorOutput'\&lt;/code&gt; on every AI and HTTP node. Wire &lt;code&gt;main[1]\&lt;/code&gt; to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Dead Letter Queue (DLQ)&lt;/strong&gt; Google Sheet or Baserow table with the failed item, timestamp, and error message&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Slack alert&lt;/strong&gt; to the ops channel with the item ID and a link to the DLQ row&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Never rely on a global workflow-level error trigger as a substitute for node-level error routing. The global trigger fires when the whole workflow crashes — but you want to capture partial failures item-by-item, not lose an entire batch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; On one fintech client's AML monitoring workflow, we caught 847 failed enrichment calls in the first week that would have silently dropped cases. The DLQ made every failure visible and recoverable.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. HITL — The Pattern That Makes AI Output Trustworthy
&lt;/h2&gt;

&lt;p&gt;Fully automated AI workflows fail silently in high-stakes contexts. Claude occasionally generates wrong company names, incorrect figures, or fabricated URLs. Without a human checkpoint, those errors reach customers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The HITL (Human-in-the-Loop) pattern:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;&lt;br&gt;
AI Node → Append to Review Sheet (status: "Pending")&lt;br&gt;
        → Wait for Webhook&lt;br&gt;
        → [Human reviews, sets status to "Approved" or "Rejected"]&lt;br&gt;
        → Approved: continue workflow&lt;br&gt;
        → Rejected: route to revision sub-workflow&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Implementation in n8n:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;After AI generation, write output to a Google Sheet / Baserow row with a "Status" column set to "Pending Review"&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;Wait node&lt;/strong&gt; configured to resume on webhook&lt;/li&gt;
&lt;li&gt;Set up a sheet trigger or webhook that fires when Status changes to "Approved"&lt;/li&gt;
&lt;li&gt;Add a 24-hour timeout check — if a row sits Pending too long, Slack-alert the reviewer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;When to use HITL:&lt;/strong&gt; Any workflow where AI output is customer-facing, regulatory, or financial. Skip it for internal data transformation pipelines where errors are low-stakes.&lt;/p&gt;

&lt;p&gt;Our AI SDR engine uses HITL for outbound email review. SDRs spend 45 minutes/day approving emails instead of 6 hours writing them — the workflow does the research and drafting, a human does the final check. Reply rates went from 2.1% to 6.8%.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Memory Management for Long-Running Agents
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Window Buffer Memory
&lt;/h3&gt;

&lt;p&gt;Best for conversational agents where recency matters. Set window size to &lt;strong&gt;10–20 messages&lt;/strong&gt; — beyond 20, you're paying for context that rarely helps.&lt;/p&gt;

&lt;h3&gt;
  
  
  RAG over Static Documents
&lt;/h3&gt;

&lt;p&gt;When your agent needs to reference a knowledge base (contracts, policies, product docs), vector retrieval beats pumping the full document into context every time.&lt;/p&gt;

&lt;p&gt;Setup: Pinecone or pgvector + n8n's Embeddings node + Information Retrieval chain. Cost difference at scale: a 50-page policy document passed to every query costs ~$0.08/query at Claude Sonnet pricing. RAG retrieval of 3 relevant chunks costs ~$0.004/query — 20x cheaper at volume.&lt;/p&gt;

&lt;h3&gt;
  
  
  Session Keys for Multi-User Deployments
&lt;/h3&gt;

&lt;p&gt;This is the one that bites people most often. If the same workflow handles multiple concurrent users with the default session ID, memory from User A bleeds into User B's conversation.&lt;/p&gt;

&lt;p&gt;Fix — scope session ID to a user identifier from the webhook payload:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;javascript&lt;br&gt;
sessionId: {{ $('Webhook').item.json.userId }}&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We've seen this misconfiguration cause a support bot to answer one user's question with another user's account details.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Rate Limiting, Backoff, and Concurrency
&lt;/h2&gt;

&lt;p&gt;Three failure modes that will bite you in production:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. API Rate Limits (OpenAI/Anthropic)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For bulk workflows processing hundreds of items, rate limits hit fast. Use n8n's built-in &lt;strong&gt;Retry on Fail&lt;/strong&gt; — set max retries to 3 with exponential backoff. For sustained bulk processing, add a Wait node between AI calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Webhook Concurrency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;n8n's default webhook concurrency is 5 simultaneous executions. For AI workflows where each execution makes multiple LLM calls, 5 concurrent workflows can spike to 50 simultaneous API calls.&lt;/p&gt;

&lt;p&gt;Fix: set &lt;code&gt;maxConcurrency: 2\&lt;/code&gt; on webhook triggers for AI-heavy workflows. It creates a queue rather than dropping requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Downstream API Timeouts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HTTP Request nodes have a 30-second default timeout. If your workflow calls slow external APIs, you'll see phantom failures. Set explicit &lt;code&gt;"timeout": 60000\&lt;/code&gt; on slow-API nodes, and wire the error output so timeouts go to the DLQ.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Production Checklist We Use Before Every Deployment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Error output (&lt;code&gt;main[1]\&lt;/code&gt;) wired on every HTTP Request and AI node&lt;/li&gt;
&lt;li&gt;[ ] DLQ sheet created and connected to error outputs&lt;/li&gt;
&lt;li&gt;[ ] Slack alert configured on failure with item ID and error details&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;saveSuccessfulExecution: false\&lt;/code&gt; set for high-volume workflows (prevents DB bloat)&lt;/li&gt;
&lt;li&gt;[ ] HITL step added for any customer-facing or regulatory output&lt;/li&gt;
&lt;li&gt;[ ] Session ID scoped to user/item (not default) for multi-user agents&lt;/li&gt;
&lt;li&gt;[ ] Rate limit buffer added — Wait node or Retry on Fail with backoff&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;maxConcurrency\&lt;/code&gt; set to 2 on webhook triggers for AI workflows&lt;/li&gt;
&lt;li&gt;[ ] Tested with 10× expected volume before go-live&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;errorWorkflow\&lt;/code&gt; field set to centralized error handler&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;The difference between an n8n demo and a production system is entirely in how you handle the 10% of cases that don't go right. Designing failure handling as a first-class architectural concern, adding HITL for trust, and managing memory and concurrency carefully is what separates a reliable automation from a liability.&lt;/p&gt;

&lt;p&gt;If you're building multi-agent workflows for real business use cases, start with the error output. Everything else follows from there.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ankit Dhiman is the founder of &lt;a href="https://chronexa.io" rel="noopener noreferrer"&gt;Chronexa&lt;/a&gt;, an AI automation agency that builds custom n8n workflows for mid-market B2B companies. We've open-sourced our workflow templates at &lt;a href="https://github.com/Chronexa/chronexa-n8n-workflows" rel="noopener noreferrer"&gt;github.com/Chronexa/chronexa-n8n-workflows&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>automation</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A 3-layer memory system that gives Claude Code persistent context across sessions.</title>
      <dc:creator>Ssanvi Builds</dc:creator>
      <pubDate>Mon, 25 May 2026 17:04:39 +0000</pubDate>
      <link>https://stormkit.forem.com/ssanvi_builds/a-3-layer-memory-system-that-gives-claude-code-persistent-context-across-sessions-1pab</link>
      <guid>https://stormkit.forem.com/ssanvi_builds/a-3-layer-memory-system-that-gives-claude-code-persistent-context-across-sessions-1pab</guid>
      <description>&lt;p&gt;Claude Code forgets everything between sessions. You explain your project, your architecture, your preferences and next session it's ground zero again.&lt;/p&gt;

&lt;p&gt;I spent 45 minutes setting this up manually. Debugging ports, copying tokens, configuring MCP servers by hand. Then days debugging the Smart Connections integration.&lt;/p&gt;

&lt;p&gt;So I built ObsiForge, one command that does all of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;obsiforge init --name myproject --path ~/vaults/myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;30 seconds + 2 plugin clicks. The rest of this article explains what it configures and why each layer matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;Three layers, each with a distinct job. No duplication. No redundancy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Layer 3: MEMORY.md&lt;/strong&gt; (pointers only) → "Where to find things"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer 2: Obsidian vault&lt;/strong&gt; (knowledge) → "What we know"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer 1: claude-mem&lt;/strong&gt; (observations) → "What happened this session"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Layer 3 - MEMORY.md (pointers, not content)
&lt;/h3&gt;

&lt;p&gt;Each project gets a MEMORY.md that points to where knowledge lives. It never stores knowledge itself, just pointers and rules.&lt;/p&gt;

&lt;p&gt;This is the only file Claude reads on every session start. ~800 tokens to know where everything is.&lt;/p&gt;

&lt;p&gt;The rules are simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NEVER store actual knowledge here, only pointers.&lt;/li&gt;
&lt;li&gt;Project context goes to the Obsidian vault (Layer 2).&lt;/li&gt;
&lt;li&gt;Session observations go to claude-mem (Layer 1).&lt;/li&gt;
&lt;li&gt;This file is a pointer only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The search tools are listed here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic search: &lt;code&gt;mcp__smart-connections__search_notes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Specific file: &lt;code&gt;mcp__obsidian-mcp-tools__get_vault_file&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Session history: &lt;code&gt;mcp__plugin_claude-mem_mcp-search__search&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Layer 2 — Obsidian vault (project knowledge)
&lt;/h3&gt;

&lt;p&gt;Each project has a vault with self-contained notes. No wikilinks, no "see also", each note has full context.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;project.md&lt;/code&gt; — architecture, stack, decisions, roadmap&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user.md&lt;/code&gt; — preferences, code style, what works/doesn't&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MEMORY.md&lt;/code&gt; — search tools, session lifecycle, vault index&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[other].md&lt;/code&gt; — assessments, gap analyses, ADRs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Smart Connections indexes these at block level (384-dim embeddings via bge-micro-v2, running locally inside Obsidian). The MCP server exposes &lt;code&gt;search_notes&lt;/code&gt; to Claude Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1 — claude-mem (session observations)
&lt;/h3&gt;

&lt;p&gt;Automated capture via hooks. Every tool use gets logged as an observation. At session start, the last 50 observations get injected into context. At session end, &lt;code&gt;/consolidate&lt;/code&gt; distills what matters into the vault.&lt;/p&gt;

&lt;p&gt;SQLite + Chroma (vector DB) running locally. Zero cloud dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  The session lifecycle
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;START → &lt;code&gt;/dashboard&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read 3 core notes (project.md, user.md, MEMORY.md)&lt;/li&gt;
&lt;li&gt;Check claude-mem for recent activity&lt;/li&gt;
&lt;li&gt;Smart Connections semantic search for related context&lt;/li&gt;
&lt;li&gt;Brief the user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;WORK → normal Claude Code session&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;claude-mem captures observations automatically&lt;/li&gt;
&lt;li&gt;Smart Connections available for semantic lookups&lt;/li&gt;
&lt;li&gt;Vault notes readable/writable via MCP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;END → &lt;code&gt;/consolidate&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search claude-mem for session observations&lt;/li&gt;
&lt;li&gt;Filter: what belongs in vault vs. what stays in claude-mem&lt;/li&gt;
&lt;li&gt;Update vault notes&lt;/li&gt;
&lt;li&gt;Report what was consolidated&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Smart Connections problem
&lt;/h2&gt;

&lt;p&gt;The Smart Connections plugin for Obsidian generates embeddings fine, bge-micro-v2, 384 dimensions, block-level indexing. The problem was the MCP server that bridges Claude Code to those embeddings.&lt;/p&gt;

&lt;p&gt;Its &lt;code&gt;search_notes&lt;/code&gt; function was doing regex matching. The code literally said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"For now, we'll do a simple keyword match since we don't have a way to generate embeddings for arbitrary text without the model."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every time Claude Code "searched semantically," it was grepping. A query like "how to handle offline data sync" would only find notes containing those exact words, not notes about "event sourcing" or "conflict resolution" which is the entire point of embeddings.&lt;/p&gt;

&lt;p&gt;The other search tools (&lt;code&gt;get_similar_notes&lt;/code&gt;, &lt;code&gt;get_embedding_neighbors&lt;/code&gt;) do real semantic search, but they require a pre-existing note path or a raw 384-dim vector. &lt;code&gt;search_notes&lt;/code&gt; is the only tool that accepts free text, and it's the one MCP clients call most often.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fix
&lt;/h3&gt;

&lt;p&gt;I added &lt;code&gt;@xenova/transformers&lt;/code&gt; to the MCP server and rewrote &lt;code&gt;searchByQuery&lt;/code&gt; to generate embeddings from the query text, then find nearest neighbors by cosine similarity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (regex):&lt;/strong&gt; 0 results — no note contains those exact words.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After (embeddings):&lt;/strong&gt; 5 results — similarity 0.60-0.63, conceptually relevant.&lt;/p&gt;

&lt;p&gt;I used Claude Code itself to diagnose the bug and write the fix. This is now PR #7 on the original repo.&lt;/p&gt;

&lt;p&gt;This is the kind of thing ObsiForge's &lt;code&gt;doctor&lt;/code&gt; command catches, if your semantic search isn't actually semantic, you want to know before you rely on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token economics (real data)
&lt;/h2&gt;

&lt;p&gt;Measured from an active project with 21 vault notes totaling 243KB:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Token cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Layer 3&lt;/td&gt;
&lt;td&gt;MEMORY.md (pointers)&lt;/td&gt;
&lt;td&gt;~800 tokens, loaded every session start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layer 2&lt;/td&gt;
&lt;td&gt;3 core vault notes&lt;/td&gt;
&lt;td&gt;~5,300 tokens on &lt;code&gt;/dashboard&lt;/code&gt; call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layer 1&lt;/td&gt;
&lt;td&gt;claude-mem (50 observations)&lt;/td&gt;
&lt;td&gt;~5,000-15,000 tokens auto-injected at start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layer 2&lt;/td&gt;
&lt;td&gt;Smart Connections query&lt;/td&gt;
&lt;td&gt;~300-800 tokens on demand per search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layer 2&lt;/td&gt;
&lt;td&gt;Additional vault note&lt;/td&gt;
&lt;td&gt;~1,000-4,500 tokens on demand per read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Without memory (baseline): re-explaining project context costs ~3,000-6,000 tokens per session. And Claude still doesn't have the full picture.&lt;/p&gt;

&lt;p&gt;With memory: ~6,100-20,000 tokens for full context. But you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture decisions that would take 10+ minutes to explain.&lt;/li&gt;
&lt;li&gt;Bug fixes from 3 weeks ago that Claude remembers.&lt;/li&gt;
&lt;li&gt;User preferences without re-stating them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without memory, to get the same context you'd need to manually re-explain:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you'd re-explain&lt;/th&gt;
&lt;th&gt;Token cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project architecture&lt;/td&gt;
&lt;td&gt;~4,200 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User preferences&lt;/td&gt;
&lt;td&gt;~640 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Past decisions and why&lt;/td&gt;
&lt;td&gt;~2,700-10,000 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What was tried and what failed&lt;/td&gt;
&lt;td&gt;~5,000-15,000 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total without memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10,000-30,000 tokens per session&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And the real problem isn't the cost, it's that you wouldn't remember what to include. The session from 3 weeks ago where approach X didn't work? You wouldn't think to mention it. The architectural decision from last month? You'd summarize it differently each time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real token savings: 1.5-2x less per session.&lt;/strong&gt; But what's priceless is that claude-mem captures "we tried X and it failed because Y" knowledge you wouldn't re-explain because you simply wouldn't remember it.&lt;/p&gt;

&lt;p&gt;The key insight: we never load all 60,700 tokens of the vault. The pointer file (800 tokens) tells Claude where things are, and it pulls knowledge on demand via semantic search. Most sessions need 2-3 vault reads and 1-2 searches.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Session type&lt;/th&gt;
&lt;th&gt;Searches&lt;/th&gt;
&lt;th&gt;Reads&lt;/th&gt;
&lt;th&gt;Tokens used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Quick (1 search, 1 read)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;~7,100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deep (3 searches, 5 reads)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;~18,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continuation (dashboard only)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;~6,100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;claude-mem's context injection (~5,000-15,000 tokens for 50 observations) is the main cost. But "we already tried X and it failed because Y" saves far more tokens than it costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's not automatic (and what I did about it)
&lt;/h2&gt;

&lt;p&gt;Consolidation is a skill, not a script.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/consolidate&lt;/code&gt; skill requires Claude's judgment: what knowledge belongs in the vault (permanent) vs. what stays in claude-mem (session-level). A script can't decide if "we switched from REST to gRPC" is a vault-worthy architectural decision or a temporary debugging note.&lt;/p&gt;

&lt;p&gt;What I did automate: at session end, a Stop hook runs that checks whether you're in a project with an Obsidian vault and reminds you to consolidate. The actual distillation still needs Claude's judgment, but you no longer have to remember to run &lt;code&gt;/consolidate&lt;/code&gt;, the system reminds you.&lt;/p&gt;

&lt;p&gt;Cross-project boundaries are solved by separate sessions. Each project gets its own vault, its own MEMORY.md, and its own &lt;code&gt;.mcp.json&lt;/code&gt;. When you work on project A, Claude loads project A's context. When you switch to project B, you open a new Claude Code session in project B's directory. No cross-contamination. claude-mem is global (it sees all sessions), but &lt;code&gt;/consolidate&lt;/code&gt; filters by project, so observations go to the right vault.&lt;/p&gt;

&lt;p&gt;Re-indexing happens inside Obsidian. If you add notes outside Obsidian, re-open Obsidian to trigger re-embedding. The Smart Connections plugin handles this automatically when it's running.&lt;/p&gt;

&lt;h2&gt;
  
  
  ObsiForge automates all of this
&lt;/h2&gt;

&lt;p&gt;The 3-layer architecture is a pattern, not a product. You can set it up manually, the steps above work. But the setup is fragile: wrong port, expired token, plugin version mismatch, and nothing works.&lt;/p&gt;

&lt;p&gt;ObsiForge handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugin download and configuration&lt;/li&gt;
&lt;li&gt;MCP server setup with port collision prevention&lt;/li&gt;
&lt;li&gt;Token generation and configuration&lt;/li&gt;
&lt;li&gt;MEMORY.md template with search tools&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/dashboard&lt;/code&gt; and &lt;code&gt;/consolidate&lt;/code&gt; skills&lt;/li&gt;
&lt;li&gt;Multi-vault support (separate ports, separate configs)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;obsiforge doctor&lt;/code&gt; — 9 health checks to diagnose any setup issue
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv tool &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/ssanvi-builds/ObsiForge
obsiforge init &lt;span class="nt"&gt;--name&lt;/span&gt; myproject &lt;span class="nt"&gt;--path&lt;/span&gt; ~/vaults/myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable 2 community plugins in Obsidian Settings (security requirement, not bypassable). Done.&lt;/p&gt;

&lt;p&gt;If you want to set it up manually, the steps in the original guide still work, but you'll probably spend some time instead of 30 seconds.&lt;/p&gt;

&lt;p&gt;github.com/ssanvi-builds/ObsiForge&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify your semantic search is actually semantic.&lt;/strong&gt; The &lt;code&gt;search_notes&lt;/code&gt; tool was regex for months. If your "semantic search" only finds exact keyword matches, it's not semantic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pointers over copies.&lt;/strong&gt; MEMORY.md stores ~800 tokens that point to 60,700 tokens of knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-contained notes beat wikilinks.&lt;/strong&gt; Each vault note has full context. No "see X for details" that breaks when X moves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The lifecycle matters more than the storage.&lt;/strong&gt; &lt;code&gt;/dashboard&lt;/code&gt; → work → &lt;code&gt;/consolidate&lt;/code&gt; is the loop. Without it, knowledge rots.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consolidation needs judgment.&lt;/strong&gt; Automate the reminder, not the action. A script can't decide if "we switched frameworks" is vault-worthy or just a session note.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate projects, separate sessions.&lt;/strong&gt; One vault per project, one Claude Code session per project. No cross-contamination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source tools can have quiet gaps.&lt;/strong&gt; The MCP server's most-called tool was its least-tested for semantic correctness. Test your tools' claims.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual setup takes 45+ minutes and breaks easily.&lt;/strong&gt; Automated setup takes 30 seconds. Use the tool.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;The smart-connections-mcp fix is &lt;a href="https://github.com/sterling315er/smart-connections-mcp/pull/7" rel="noopener noreferrer"&gt;PR #7&lt;/a&gt; on an MIT-licensed project.&lt;/p&gt;

&lt;p&gt;ObsiForge is open source and free: &lt;a href="https://github.com/ssanvi-builds/ObsiForge" rel="noopener noreferrer"&gt;github.com/ssanvi-builds/ObsiForge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 3-layer architecture is just a pattern, no special code needed, just discipline about what goes where.&lt;/p&gt;

&lt;p&gt;If you're building something similar, the key question isn't "what tool do I use?" but "what does each layer store, and who reads it?" Get that right, and the tools are interchangeable.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Trishul SNMP Suite 2.0.1: Better MIBs, Traps, and SNMP Labs</title>
      <dc:creator>Sumit Dhaka</dc:creator>
      <pubDate>Mon, 25 May 2026 16:57:17 +0000</pubDate>
      <link>https://stormkit.forem.com/tosumitdhaka/trishul-snmp-suite-201-better-mibs-traps-and-snmp-labs-196f</link>
      <guid>https://stormkit.forem.com/tosumitdhaka/trishul-snmp-suite-201-better-mibs-traps-and-snmp-labs-196f</guid>
      <description>&lt;p&gt;Trishul SNMP Suite is an SNMP lab and operations shell for people who need to simulate devices, walk targets, send and receive traps, browse MIB trees, and manage real vendor MIB corpora from one place.&lt;/p&gt;

&lt;p&gt;If you are new to the project, that is the short intro.&lt;/p&gt;

&lt;p&gt;If you last saw it around &lt;code&gt;1.2.5&lt;/code&gt;, &lt;code&gt;2.0.1&lt;/code&gt; is the point where the project stops feeling like “a useful UI with a lot of features” and starts feeling like a cleaner platform with a much stronger core.&lt;/p&gt;

&lt;p&gt;That is the real story of this release.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/tosumitdhaka/trishul-snmp-suite" rel="noopener noreferrer"&gt;github.com/tosumitdhaka/trishul-snmp-suite&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyhkc0cx33ugyrpvq7p2.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%2Fzyhkc0cx33ugyrpvq7p2.png" alt="Trishul SNMP Suite 2.0.1 demo" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get today
&lt;/h2&gt;

&lt;p&gt;Compared with the &lt;code&gt;1.2.x&lt;/code&gt; era, Trishul SNMP Suite now gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one FastAPI application serving the UI, API, and WebSocket layer&lt;/li&gt;
&lt;li&gt;one in-process SNMP runtime powered by the in-house &lt;code&gt;trishul-snmp&lt;/code&gt; library&lt;/li&gt;
&lt;li&gt;one bundle-first MIB compilation pipeline powered by the in-house &lt;code&gt;trishul-smi&lt;/code&gt; library&lt;/li&gt;
&lt;li&gt;SQLite-backed durable state for sessions, settings, bundles, and notification history&lt;/li&gt;
&lt;li&gt;one unified &lt;code&gt;/api/...&lt;/code&gt; surface instead of split route families&lt;/li&gt;
&lt;li&gt;a cleaner single-container deployment path&lt;/li&gt;
&lt;li&gt;better MIB inventory handling, smarter exports, richer trap workflows, and a more intuitive browser experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pages are still familiar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Dashboard&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Simulator&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Walk &amp;amp; Parse&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Traps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MIB Browser&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MIB Manager&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Settings&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the system underneath those pages is much more coherent now.&lt;/p&gt;

&lt;h2&gt;
  
  
  From 1.2.x to 2.0.1, in one view
&lt;/h2&gt;

&lt;p&gt;I do not want to turn this into a changelog dump, so here is the short version of the journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1.2.x&lt;/code&gt; established the operator experience: MIB Browser, realtime dashboard behavior, simulator improvements, trap workflows, drag-and-drop MIB upload, auto-validation, and a more usable UI&lt;/li&gt;
&lt;li&gt;later &lt;code&gt;1.x&lt;/code&gt; releases hardened the product with better security, better tests, better docs, better deployment, and a single-suite packaging path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2.0.0&lt;/code&gt; rebuilt the core runtime and MIB pipeline around a much cleaner architecture&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2.0.1&lt;/code&gt; is the release where that architecture starts paying off in the workflows users touch every day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the headline is not just “more features since &lt;code&gt;1.2.5&lt;/code&gt;.”&lt;/p&gt;

&lt;p&gt;The headline is that the same kind of workflows now run on a much better foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built &lt;code&gt;trishul-smi&lt;/code&gt; and &lt;code&gt;trishul-snmp&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the part I most wanted to share.&lt;/p&gt;

&lt;p&gt;As the project grew, two kinds of friction kept showing up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MIB compilation and compiled-data usage were too important to remain a loosely connected side concern.&lt;/li&gt;
&lt;li&gt;SNMP runtime behavior was too central to keep treating it like a set of worker-style runtime pieces that had to be coordinated from the outside.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wanted the product to have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a first-class compiled MIB artifact&lt;/li&gt;
&lt;li&gt;a shared in-memory representation that browser, catalog, trap enrichment, and runtime features could all rely on&lt;/li&gt;
&lt;li&gt;runtime control that lived inside the application instead of being orchestrated through extra process boundaries&lt;/li&gt;
&lt;li&gt;cleaner APIs for the exact behavior the product needed&lt;/li&gt;
&lt;li&gt;simpler debugging and testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why I moved core responsibilities into two in-house libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;trishul-smi&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;trishul-smi&lt;/code&gt; is the MIB compilation side of the platform.&lt;/p&gt;

&lt;p&gt;Instead of compiling MIBs and then treating the output as a loose set of files, the app now works with a bundle-first model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;versioned bundle storage&lt;/li&gt;
&lt;li&gt;compile metadata&lt;/li&gt;
&lt;li&gt;activation state&lt;/li&gt;
&lt;li&gt;compile history&lt;/li&gt;
&lt;li&gt;one active compiled bundle loaded for queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives Trishul a more reliable answer to questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which modules are active right now?&lt;/li&gt;
&lt;li&gt;which modules belong to which source group?&lt;/li&gt;
&lt;li&gt;which module is shadowed and why?&lt;/li&gt;
&lt;li&gt;what should the browser, trap catalog, and runtime resolve against?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;trishul-snmp&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;trishul-snmp&lt;/code&gt; is the runtime side of the platform.&lt;/p&gt;

&lt;p&gt;It lets the suite run the responder, manager-side operations, notification listener, trap and inform sending, and bundle-backed symbolic behavior inside the app itself.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no subprocess choreography as the main runtime model&lt;/li&gt;
&lt;li&gt;no shell-outs as the normal SNMP execution path&lt;/li&gt;
&lt;li&gt;no extra worker coordination just to keep trap, stats, and simulator state aligned&lt;/li&gt;
&lt;li&gt;fewer layers between the UI, state, and runtime behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was not “let’s build in-house libraries for the sake of it.”&lt;/p&gt;

&lt;p&gt;It was a practical decision: the product had reached a point where better internal control over the MIB pipeline and SNMP runtime would improve both developer velocity and operator experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the architecture looks like now
&lt;/h2&gt;

&lt;p&gt;A comparison table explains the shift better than a diagram:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Earlier line&lt;/th&gt;
&lt;th&gt;2.0.1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MIB compilation&lt;/td&gt;
&lt;td&gt;pysmi-style compilation and looser generated artifacts around the app.&lt;/td&gt;
&lt;td&gt;trishul-smi drives a bundle-first pipeline with versioned bundles, activation, source attribution, and export-friendly metadata.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catalog query source&lt;/td&gt;
&lt;td&gt;Browser and catalog views leaned on generated artifacts and pysnmp mibBuilder-style runtime views.&lt;/td&gt;
&lt;td&gt;The active in-memory bundle is the source of truth for browser, catalog, exports, and resolution.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SNMP runtime&lt;/td&gt;
&lt;td&gt;Subprocess-based pysnmp workers, with separate simulator and trap receiver processes and UDP loopback coordination.&lt;/td&gt;
&lt;td&gt;trishul-snmp runs responder, manager operations, trap send and receive, and symbolic behavior in-process.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App topology&lt;/td&gt;
&lt;td&gt;More glue between runtime pieces, route families, and cross-process status updates.&lt;/td&gt;
&lt;td&gt;One FastAPI application serves the UI, API, and WebSocket layer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State and stats&lt;/td&gt;
&lt;td&gt;More file-backed and process-coordination-heavy runtime state, including file-based stats flow.&lt;/td&gt;
&lt;td&gt;SQLite-backed state now covers settings, sessions, bundles, notification history, and persisted counters.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;More moving pieces to explain and reason about.&lt;/td&gt;
&lt;td&gt;One suite, one app surface, one cleaner container path.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That simplicity matters.&lt;/p&gt;

&lt;p&gt;It reduces the amount of glue code needed to keep everything coherent, and it makes features easier to add without creating a larger mess around them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What users will notice first
&lt;/h2&gt;

&lt;p&gt;All of that architecture work would not matter much if the workflows still felt awkward.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;2.0.1&lt;/code&gt;, they do not.&lt;/p&gt;

&lt;h3&gt;
  
  
  More trustworthy compiled MIB data
&lt;/h3&gt;

&lt;p&gt;This is one of the biggest practical improvements in the product.&lt;/p&gt;

&lt;p&gt;Trishul now handles compiled MIB data with much clearer source attribution and bundle semantics. It distinguishes the deduplicated active runtime view from the per-source-group inventory view. That becomes very important once you load overlapping vendor corpora or want bundle-specific exports instead of a blurred “everything together” view.&lt;/p&gt;

&lt;p&gt;The result is a more trustworthy MIB model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better duplicate and shadowed-module handling&lt;/li&gt;
&lt;li&gt;clearer active-versus-source inventory behavior&lt;/li&gt;
&lt;li&gt;better failed-module reporting&lt;/li&gt;
&lt;li&gt;more reliable compiled data for exports and downstream workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the kind of improvement that makes operators trust what the app is showing them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better trap workflows
&lt;/h3&gt;

&lt;p&gt;Trap handling is also much better in day-to-day use.&lt;/p&gt;

&lt;p&gt;The trap flow now supports richer varbind editing, including enum-aware varbind dropdown behavior that makes common notification work more natural. Trap history is also more coherent because stored events preserve the event-time view of resolution data instead of drifting with whatever the current toggle state happens to be.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better trap varbind authoring&lt;/li&gt;
&lt;li&gt;clearer trap history behavior&lt;/li&gt;
&lt;li&gt;stronger confidence in what a stored trap event actually represents&lt;/li&gt;
&lt;li&gt;better live operator experience around traps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For SNMP tooling, this matters a lot. Trap workflows become frustrating fast when the tool is “almost right.”&lt;/p&gt;

&lt;h3&gt;
  
  
  A smarter MIB Browser
&lt;/h3&gt;

&lt;p&gt;The MIB Browser was already one of the most visible features in the older line. In &lt;code&gt;2.0.1&lt;/code&gt;, it feels much more intentional.&lt;/p&gt;

&lt;p&gt;Search and type filtering work together more naturally. Filtered trees can auto-expand so users can actually see the result immediately. Interaction is also less fussy: larger click targets and smaller browser UX refinements make the tree feel more responsive and less fragile.&lt;/p&gt;

&lt;p&gt;That turns into better everyday behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;faster drill-down&lt;/li&gt;
&lt;li&gt;less hunting through collapsed branches&lt;/li&gt;
&lt;li&gt;more intuitive expand and collapse interaction&lt;/li&gt;
&lt;li&gt;fewer dead-click moments in the tree&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly the kind of improvement users notice even if they do not name it explicitly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better exports and catalog behavior
&lt;/h3&gt;

&lt;p&gt;Exports are now much more aligned with what the user actually selected.&lt;/p&gt;

&lt;p&gt;Source-group-scoped exports respect source-group membership instead of collapsing everything into the currently active deduplicated view. Export filenames are more useful. Stats export is also cleaner and does not drag the full runtime OID catalog into every export by default.&lt;/p&gt;

&lt;p&gt;That makes exported data feel like a real operational artifact rather than a generic dump.&lt;/p&gt;

&lt;h3&gt;
  
  
  More stable page-to-page behavior
&lt;/h3&gt;

&lt;p&gt;One quiet but important improvement in the &lt;code&gt;2.0.x&lt;/code&gt; line is that the app relies less on expensive reprocessing when users switch pages.&lt;/p&gt;

&lt;p&gt;Because the platform now has clearer persisted state and runtime ownership, dashboard counters, MIB views, and related status panels behave more predictably when moving between screens.&lt;/p&gt;

&lt;p&gt;That translates into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;less waiting&lt;/li&gt;
&lt;li&gt;fewer stuck loading states&lt;/li&gt;
&lt;li&gt;less repeated inventory work&lt;/li&gt;
&lt;li&gt;better confidence that the UI reflects the current runtime state&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Many smaller UI and UX refinements matter too
&lt;/h2&gt;

&lt;p&gt;Not everything valuable belongs in a release headline.&lt;/p&gt;

&lt;p&gt;Some of the improvements in &lt;code&gt;2.0.1&lt;/code&gt; are small on paper but meaningful in daily use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;broader click targets in browser trees&lt;/li&gt;
&lt;li&gt;more intuitive expand and collapse behavior&lt;/li&gt;
&lt;li&gt;better filtered auto-expansion&lt;/li&gt;
&lt;li&gt;cleaner loading and status feedback&lt;/li&gt;
&lt;li&gt;less friction in modal-driven flows&lt;/li&gt;
&lt;li&gt;more consistent page-to-page behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the kinds of changes that make the product feel sharper even when users cannot point to a single “killer feature.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this helps developers too
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to slow down a tooling project is to keep layering features on top of an architecture that is getting harder and harder to reason about.&lt;/p&gt;

&lt;p&gt;Eventually you pay for that in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;state bugs&lt;/li&gt;
&lt;li&gt;UI inconsistencies&lt;/li&gt;
&lt;li&gt;release risk&lt;/li&gt;
&lt;li&gt;painful debugging&lt;/li&gt;
&lt;li&gt;slower feature delivery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moving the platform toward &lt;code&gt;trishul-smi&lt;/code&gt; and &lt;code&gt;trishul-snmp&lt;/code&gt; changed that for Trishul SNMP Suite.&lt;/p&gt;

&lt;p&gt;For developers, the benefits are direct:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer layers to mentally unpack&lt;/li&gt;
&lt;li&gt;flatter service architecture&lt;/li&gt;
&lt;li&gt;clearer boundaries between compile, runtime, and UI concerns&lt;/li&gt;
&lt;li&gt;stronger testability&lt;/li&gt;
&lt;li&gt;better release validation and observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For users, the same architecture work shows up as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better reliability&lt;/li&gt;
&lt;li&gt;more predictable workflows&lt;/li&gt;
&lt;li&gt;cleaner logs&lt;/li&gt;
&lt;li&gt;easier deployment&lt;/li&gt;
&lt;li&gt;more trustworthy data in the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the kind of internal rewrite I like: one that results in visible product quality, not just prettier internal diagrams.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few snips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  One-shot install
&lt;/h3&gt;

&lt;p&gt;If you just want to try the released suite on a Docker host, this is the quickest path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LfsS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; install-trishul-snmp-suite.sh &lt;span class="se"&gt;\&lt;/span&gt;
  https://raw.githubusercontent.com/tosumitdhaka/trishul-snmp-suite/v2.0.1/install-trishul-snmp-suite.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bash install-trishul-snmp-suite.sh up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default access after startup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI: &lt;code&gt;http://localhost:8980&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;API docs: &lt;code&gt;http://localhost:8980/docs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;default login: &lt;code&gt;admin / admin123&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Unified API shape
&lt;/h3&gt;

&lt;p&gt;One part I like in the current release is that the API shape is much easier to explain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/meta
/api/health
/api/ws
/api/settings/*
/api/stats/*
/api/simulator/*
/api/walk/*
/api/traps/*
/api/mibs/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a small thing, but it makes the product easier to understand for both developers and operators.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trap send example
&lt;/h3&gt;

&lt;p&gt;The current trap flow is also easier to demonstrate with one clean request:&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;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"community"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IF-MIB::linkDown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"varbinds"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"oid"&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.3.6.1.2.1.2.2.1.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="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;That kind of simple, direct workflow is exactly what I wanted the platform to support better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;2.0.1&lt;/code&gt; matters
&lt;/h2&gt;

&lt;p&gt;I do not think &lt;code&gt;2.0.1&lt;/code&gt; should be read as “just the next point release.”&lt;/p&gt;

&lt;p&gt;&lt;code&gt;2.0.0&lt;/code&gt; did the heavy architectural lift. &lt;code&gt;2.0.1&lt;/code&gt; is where the system starts feeling polished enough that the benefits are obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more reliable compiled data&lt;/li&gt;
&lt;li&gt;better source-aware inventory and exports&lt;/li&gt;
&lt;li&gt;richer trap authoring&lt;/li&gt;
&lt;li&gt;smarter browsing&lt;/li&gt;
&lt;li&gt;quieter and more useful logs&lt;/li&gt;
&lt;li&gt;cleaner install and runtime defaults&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination is what makes the release interesting.&lt;/p&gt;

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

&lt;p&gt;If you are new to Trishul SNMP Suite, &lt;code&gt;2.0.1&lt;/code&gt; is a good point to try it because the platform is now much easier to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one app&lt;/li&gt;
&lt;li&gt;one runtime&lt;/li&gt;
&lt;li&gt;one MIB pipeline&lt;/li&gt;
&lt;li&gt;one installer path&lt;/li&gt;
&lt;li&gt;familiar operator pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you knew the older &lt;code&gt;1.2.x&lt;/code&gt; line, &lt;code&gt;2.0.1&lt;/code&gt; is where the project starts paying off the deeper work behind the scenes.&lt;/p&gt;

&lt;p&gt;The UI is better. The MIB data is more trustworthy. Trap workflows are better. The browser is more intuitive. The deployment story is simpler. And the in-house &lt;code&gt;trishul-smi&lt;/code&gt; and &lt;code&gt;trishul-snmp&lt;/code&gt; foundation gives the project a much stronger path forward.&lt;/p&gt;

&lt;p&gt;That is the release I wanted to ship.&lt;/p&gt;

&lt;p&gt;If you work with SNMP labs, MIB-heavy device testing, or trap-driven workflows, I would love to know what you would want to see next: deeper bundle controls, richer browser/catalog features, stronger simulator behavior, or more advanced trap tooling.&lt;/p&gt;

</description>
      <category>snmp</category>
      <category>python</category>
      <category>fastapi</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
