<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ujja</title>
    <description>The latest articles on DEV Community by ujja (@ujja).</description>
    <link>https://dev.to/ujja</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png</url>
      <title>DEV Community: ujja</title>
      <link>https://dev.to/ujja</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ujja"/>
    <language>en</language>
    <item>
      <title>PlanetLedger — Turning Spending Into Environmental Awareness</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Sat, 18 Apr 2026 16:44:53 +0000</pubDate>
      <link>https://dev.to/ujja/planetledger-turning-spending-into-environmental-awareness-4b8f</link>
      <guid>https://dev.to/ujja/planetledger-turning-spending-into-environmental-awareness-4b8f</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-04-16"&gt;Weekend Challenge: Earth Day Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;PlanetLedger&lt;/strong&gt; — an AI-powered sustainability finance dashboard that turns your bank statements into environmental intelligence.&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%2F4cvbkw80vh3ju60ac4vs.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%2F4cvbkw80vh3ju60ac4vs.png" alt="landing page" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You upload a CSV or PDF bank statement, and an agent pipeline automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parses every transaction and categorises it against 20+ real Australian vendors (Woolworths, Chemist Warehouse, Didi, City Chic, Skechers, Aldi, IGA and more)&lt;/li&gt;
&lt;li&gt;Assigns a &lt;strong&gt;planet impact score&lt;/strong&gt; (GREEN / YELLOW / RED) per transaction based on category and spend size&lt;/li&gt;
&lt;li&gt;Aggregates spend into a &lt;strong&gt;category breakdown&lt;/strong&gt; — Fast Fashion, Grocery, Transport, Electronics, Hygiene, Food Delivery&lt;/li&gt;
&lt;li&gt;Runs a &lt;strong&gt;RAG-grounded insight pipeline&lt;/strong&gt; that generates personalised recommendations using your actual spending context&lt;/li&gt;
&lt;li&gt;Shows a &lt;strong&gt;gamified Planet Impact Score&lt;/strong&gt; dial (0–100) with unlockable badges (Conscious Spender → Low Impact Week → Planet Saver)&lt;/li&gt;
&lt;li&gt;Lets you chat with your personal agent ("Why is my impact high? What should I cut?")&lt;/li&gt;
&lt;li&gt;Runs a &lt;strong&gt;What-If Simulator&lt;/strong&gt; — drag a slider and instantly see how cutting food delivery by 30% changes your score&lt;/li&gt;
&lt;li&gt;Tracks a &lt;strong&gt;memory timeline&lt;/strong&gt; so the agent learns your patterns week over week&lt;/li&gt;
&lt;li&gt;Has a public &lt;strong&gt;/demo page&lt;/strong&gt; — no login required, try it with sample AU data before signing up&lt;/li&gt;
&lt;li&gt;The sample data is Australian, but &lt;strong&gt;any CSV using the &lt;code&gt;Date / Transaction / Debit / Credit / Balance&lt;/code&gt; schema works&lt;/strong&gt; — regardless of which bank or country it comes from&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The goal: make the invisible environmental cost of everyday spending visible and actionable — in seconds, not spreadsheets.&lt;/p&gt;

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

&lt;p&gt;👉 &lt;a href="https://planet-ledger.vercel.app/demo" rel="noopener noreferrer"&gt;Try the live demo — no login needed&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or sign in to upload your own AU bank statement (CSV or PDF) and get a personalised dashboard.&lt;/p&gt;

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


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ujjavala" rel="noopener noreferrer"&gt;
        ujjavala
      &lt;/a&gt; / &lt;a href="https://github.com/ujjavala/PlanetLedger" rel="noopener noreferrer"&gt;
        PlanetLedger
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;PlanetLedger&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;PlanetLedger is an agent-first sustainability finance dashboard that turns bank statements into environmental intelligence. Upload a CSV or PDF and get a personalised impact score, AI-powered insights, and adaptive recommendations — powered by an in-process event pipeline, Auth0 with FGA, and a persistent agent memory system.&lt;/p&gt;
&lt;p&gt;Flow: &lt;code&gt;User → Auth0 → PlanetLedger Agent → OpenClaw Pipeline → Insights + Notifications → UI&lt;/code&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stack&lt;/h2&gt;
&lt;/div&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;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Next.js 15.5 App Router + TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Auth0 v4&lt;/strong&gt; (&lt;code&gt;@auth0/nextjs-auth0&lt;/code&gt;) — middleware-based, zero route handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI / LLM&lt;/td&gt;
&lt;td&gt;LangChain + OpenAI &lt;code&gt;gpt-4o-mini&lt;/code&gt; / Google Gemini &lt;code&gt;gemini-1.5-flash&lt;/code&gt; (fallback)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rules engine&lt;/td&gt;
&lt;td&gt;Custom categorisation + scoring — deterministic, explainable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAG&lt;/td&gt;
&lt;td&gt;Context builder that grounds prompts in real spend data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF parsing&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pdf-parse&lt;/code&gt; v2 + AU bank statement regex extractor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event bus&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;OpenClaw&lt;/strong&gt; — homegrown in-process event-driven workflow runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cron&lt;/td&gt;
&lt;td&gt;Vercel Cron (&lt;code&gt;vercel.json&lt;/code&gt;) — weekly report every Monday 09:00 UTC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;Tailwind CSS,&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ujjavala/PlanetLedger" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

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

&lt;h3&gt;
  
  
  Stack
&lt;/h3&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;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Next.js 15.5 App Router + TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Auth0 v4 (@auth0/nextjs-auth0) — middleware-based, zero route handlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI / LLM&lt;/td&gt;
&lt;td&gt;LangChain + OpenAI gpt-4o-mini (primary) / Google Gemini gemini-1.5-flash (fallback)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rules engine&lt;/td&gt;
&lt;td&gt;Custom categorisation + scoring — deterministic, explainable, free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAG layer&lt;/td&gt;
&lt;td&gt;Context builder that grounds prompts in real spend data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF parsing&lt;/td&gt;
&lt;td&gt;pdf-parse v2 + AU bank statement regex extractor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSV parsing&lt;/td&gt;
&lt;td&gt;papaparse + AU format (Date / Transaction / Debit / Credit / Balance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event bus&lt;/td&gt;
&lt;td&gt;OpenClaw — homegrown event-driven workflow runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Styling&lt;/td&gt;
&lt;td&gt;Tailwind CSS v3, Space Grotesk font&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Agent Pipeline
&lt;/h3&gt;

&lt;p&gt;Five layers run in sequence every time you upload:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Parse&lt;/strong&gt;&lt;br&gt;
The CSV/PDF parser extracts raw rows into a typed &lt;code&gt;Transaction[]&lt;/code&gt;. For PDFs, a regex pass converts raw AU bank text (dates like &lt;code&gt;03 Dec 2022&lt;/code&gt;, amounts, CR/DR markers) into the same CSV format before parsing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Categorise&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;resolveCategory()&lt;/code&gt; maps merchant names to one of seven categories using regex + keyword matching against known AU vendors. Anything it can't match falls through to an LLM reclassification call (OpenAI or Gemini, temperature=0, 10 tokens max — cheap and fast).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Score&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;calculateImpactScore()&lt;/code&gt; runs the scoring engine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GREEN transaction → +10 pts, YELLOW → +5 pts, RED → -2 pts&lt;/li&gt;
&lt;li&gt;Normalised to 0–100 across transaction count&lt;/li&gt;
&lt;li&gt;Preference bonuses: &lt;code&gt;+8&lt;/code&gt; if user owns no car, &lt;code&gt;+3&lt;/code&gt; for low-income mode on RED transactions&lt;/li&gt;
&lt;li&gt;Weekly trend: ≥75 = "Improving", 45–74 = "Stable", &amp;lt;45 = "Needs Attention"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Build RAG Context&lt;/strong&gt;&lt;br&gt;
Before any insight or chat response, &lt;code&gt;buildRagContext()&lt;/code&gt; pulls together: last 7 days of transactions, top 2 categories by spend, top 3 merchants, and detected behaviour patterns. This context is injected into every prompt so the agent actually talks about &lt;em&gt;your&lt;/em&gt; data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Generate Insights&lt;/strong&gt;&lt;br&gt;
The insight pipeline fires &lt;code&gt;{ type: WARNING | POSITIVE | NEUTRAL, message }&lt;/code&gt; structured outputs and stores them with a 3-minute cache. Patterns like "3+ food delivery orders in a week" or "fast fashion spend &amp;gt; $50" trigger specific recommendations.&lt;/p&gt;

&lt;p&gt;Agent memory persists per-user (keyed by Auth0 &lt;code&gt;sub&lt;/code&gt;) and feeds back into the next run — so the agent gets smarter about your habits over time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Auth0 for Agents
&lt;/h3&gt;

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

&lt;p&gt;Auth0 v4 runs entirely via Next.js middleware — no &lt;code&gt;/api/auth/*&lt;/code&gt; route files needed. One line sets it up:&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="c1"&gt;// lib/auth0.ts&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;Auth0Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@auth0/nextjs-auth0/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Auth0Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// middleware.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;auth0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every API route checks an internal agent scope before doing anything. The scope check is now backed by a &lt;strong&gt;fine-grained authorisation (FGA)&lt;/strong&gt; rule table (&lt;code&gt;lib/auth/fga.ts&lt;/code&gt;) that maps &lt;code&gt;resource + action → required scope&lt;/code&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="c1"&gt;// lib/auth/fga.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;canPerform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FGAResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FGAAction&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FGA_RULES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;]?.[&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scopes (&lt;code&gt;read:transactions&lt;/code&gt;, &lt;code&gt;write:insights&lt;/code&gt;, &lt;code&gt;update:score&lt;/code&gt;) live as custom Auth0 claims — not OIDC scopes — which keeps agent permissions cleanly separated from OAuth. User preferences (&lt;code&gt;noCarOwnership&lt;/code&gt;, &lt;code&gt;lowIncomeMode&lt;/code&gt;) are stored as Auth0 custom claims so they survive across sessions.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Post-Login Action&lt;/strong&gt; (&lt;code&gt;lib/auth/actions/post-login.js&lt;/code&gt;) provisions new users on first login — setting &lt;code&gt;eco_tier: "starter"&lt;/code&gt; in &lt;code&gt;app_metadata&lt;/code&gt;, injecting custom claims, and enforcing MFA via &lt;code&gt;api.multifactor.enable("any")&lt;/code&gt;. Rolling sessions (&lt;code&gt;inactivityDuration: 1 day&lt;/code&gt;, &lt;code&gt;absoluteDuration: 7 days&lt;/code&gt;) keep users signed in without requiring frequent re-auth.&lt;/p&gt;

&lt;p&gt;The public &lt;code&gt;/demo&lt;/code&gt; page and &lt;code&gt;/api/upload/preview&lt;/code&gt; are excluded from the middleware matcher, so anyone can try the app without an account.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenClaw — the Event Bus
&lt;/h3&gt;

&lt;p&gt;OpenClaw is a lightweight in-process event system I built to wire up automation without reaching for a queue service.&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%2Fz4ped5n9ug221yvies02.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%2Fz4ped5n9ug221yvies02.png" alt=" " width="798" height="846"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four workflows register on startup:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workflow&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;autoInsightOnUpload&lt;/td&gt;
&lt;td&gt;transactions_uploaded&lt;/td&gt;
&lt;td&gt;Runs the full agent pipeline, caches insights&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;highImpactAlert&lt;/td&gt;
&lt;td&gt;high_impact_detected&lt;/td&gt;
&lt;td&gt;Pushes in-app alert notification with top offending categories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;weeklyReport&lt;/td&gt;
&lt;td&gt;weekly_report&lt;/td&gt;
&lt;td&gt;Full score + insights digest; pushes weekly notification to the bell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;scoreImprovedCelebration&lt;/td&gt;
&lt;td&gt;score_improved&lt;/td&gt;
&lt;td&gt;Pushes a celebration notification when the score rises after upload&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After an upload, &lt;code&gt;openClawChainedTrigger()&lt;/code&gt; fires the full sequence: &lt;code&gt;transactions_uploaded → score_calculated → insights_generated → score_improved&lt;/code&gt; (if the score increased). The route handler just returns the parsed data immediately while the pipeline runs.&lt;/p&gt;

&lt;p&gt;Vercel Cron fires &lt;code&gt;weekly_report&lt;/code&gt; every Monday at 09:00 UTC via &lt;code&gt;POST /api/cron/weekly-report&lt;/code&gt;, configured in &lt;code&gt;vercel.json&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The /demo Page
&lt;/h3&gt;

&lt;p&gt;One of the things I'm happiest about: the &lt;code&gt;/demo&lt;/code&gt; page works with zero auth and zero network calls. It's a Next.js server component that imports the sample CSV data as a TypeScript string constant and calls &lt;code&gt;parseTransactionsCsv()&lt;/code&gt; + &lt;code&gt;calculateImpactScore()&lt;/code&gt; directly at build time. It prebuilds as a &lt;strong&gt;static page&lt;/strong&gt; — instant load, no middleware, no DB.&lt;/p&gt;

&lt;p&gt;Premium features (AI chat, What-If Simulator, Memory Timeline) show as blurred locked panels with a lock icon — so visitors can see what they'd get after signing up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Earth Day Design Choices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Deep forest green hero gradient — earth tones throughout, nothing corporate-blue&lt;/li&gt;
&lt;li&gt;Category breakdown with proportional spend bars instead of raw numbers&lt;/li&gt;
&lt;li&gt;Impact score dial animates from red → amber → green when the page loads&lt;/li&gt;
&lt;li&gt;Real AU vendor recognition — the shops people in Australia actually use&lt;/li&gt;
&lt;li&gt;Every transaction shows its impact colour inline so the pattern is visible at a glance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Interesting Engineering Decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Why deterministic rules for categorisation, not LLM?&lt;/strong&gt;&lt;br&gt;
Rules are fast, free, and traceable. Every categorisation decision has an exact rule you can point to. I use the LLM only for the &lt;code&gt;"Other"&lt;/code&gt; fallback bucket — maybe 10–15% of transactions — where a keyword match doesn't exist. That keeps costs near zero and lets the rules engine run at build time on the demo page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why an in-memory store?&lt;/strong&gt;&lt;br&gt;
For a weekend build, an in-memory &lt;code&gt;Map&amp;lt;userId, UserMemory&amp;gt;&lt;/code&gt; is zero-infrastructure and good enough for single-server dev. Both stores are now anchored to &lt;code&gt;globalThis.__pl_*&lt;/code&gt; keys so HMR hot reloads in dev don't wipe your data. The entire storage layer is behind a &lt;code&gt;lib/store.ts&lt;/code&gt; interface — swapping to Redis or Postgres is one function replacement, not an architectural change.&lt;/p&gt;

&lt;p&gt;Agent memory specifically uses a &lt;strong&gt;file-backed store&lt;/strong&gt; (&lt;code&gt;.agent-memory/&amp;lt;fnv1a-hash&amp;gt;.json&lt;/code&gt;) with 30-day auto-expiry — so the agent's learned patterns survive server restarts, not just hot reloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why AU sample data, and can other countries use it?&lt;/strong&gt;&lt;br&gt;
The sample data is from an Australian bank (ANZ/CBA-style export), but the parser isn't locked to Australia. Any CSV that follows the &lt;code&gt;Date / Transaction / Debit / Credit / Balance&lt;/code&gt; column schema will parse correctly — regardless of the bank or country. The vendor categorisation rules are AU-focused right now (Woolworths, Chemist Warehouse, Didi, etc.), but the categorisation layer is just a map — adding UK, US, or EU merchants is additive. The "Why AU only" answer is really: nailing one set of vendors well beats vague coverage of five markets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going Further During the Weekend
&lt;/h2&gt;

&lt;p&gt;The core build came together fast, so I kept pushing. Here's what landed after the initial submission:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real multi-turn chat with what-if and doc Q&amp;amp;A&lt;/strong&gt;&lt;br&gt;
The chat engine was keyword-matching and templated. It's now a real multi-turn conversation — conversation history is injected as context so the agent remembers what you asked. You can ask "what if I reduce food delivery by 30%?" and the agent runs an actual score simulation. You can ask "how much did I spend on groceries last week?" and it queries your real transaction data. The RAG scaffolding was already there; wiring it up to GPT-4o was the last step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File-backed persistent agent memory&lt;/strong&gt;&lt;br&gt;
Agent memory moved from an in-memory &lt;code&gt;Map&lt;/code&gt; (lost on restart) to per-user &lt;code&gt;.agent-memory/&amp;lt;fnv1a-hash&amp;gt;.json&lt;/code&gt; files with 30-day auto-expiry. In dev they live at &lt;code&gt;.agent-memory/&lt;/code&gt;, in prod at &lt;code&gt;/tmp/planetledger-memory/&lt;/code&gt;. The agent's learned patterns now actually survive hotfixes and deploys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In-app notification bell&lt;/strong&gt;&lt;br&gt;
OpenClaw's &lt;code&gt;highImpactAlert&lt;/code&gt; and &lt;code&gt;weeklyReport&lt;/code&gt; were logging to console. Now they push structured notifications to an in-memory store, which a bell component polls every 60 seconds. Three notification types: 📊 Weekly Report, 🌱 Score Improved, ⚠️ High-Impact Alert. The &lt;code&gt;score_improved&lt;/code&gt; event is new too — fires automatically when an upload raises your score.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chained OpenClaw pipeline + Vercel Cron&lt;/strong&gt;&lt;br&gt;
The upload flow now fires a full event chain: &lt;code&gt;transactions_uploaded → score_calculated → insights_generated → score_improved&lt;/code&gt;. One call, four events, all in-process. The weekly report fires via Vercel Cron every Monday 09:00 UTC (&lt;code&gt;vercel.json&lt;/code&gt; + &lt;code&gt;/api/cron/weekly-report&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auth0 FGA, Post-Login Action, MFA, rolling sessions&lt;/strong&gt;&lt;br&gt;
The flat scope check got replaced with a proper FGA rule table (&lt;code&gt;resource + action → required scope&lt;/code&gt;). A Post-Login Action provisions new users on first login and enforces MFA. Rolling sessions mean users stay signed in across the week without re-authing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy hardening&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;email&lt;/code&gt; and merchant names are no longer stored in &lt;code&gt;UserContext&lt;/code&gt;, agent memory, or RAG prompts — they're PII-adjacent and don't need to be there. OpenClaw workflow logs pseudonymize user IDs via FNV-1a hash (&lt;code&gt;usr_XXXXXXXX&lt;/code&gt;). A &lt;code&gt;lib/privacy/sanitizer.ts&lt;/code&gt; module handles all redaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Still Next
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Persistent database&lt;/strong&gt;&lt;br&gt;
The transaction store is still in-memory (&lt;code&gt;Map&amp;lt;userId, UserMemory&amp;gt;&lt;/code&gt; anchored to &lt;code&gt;globalThis&lt;/code&gt; for HMR safety). Agent memory is file-backed now, but transactions, scores, and chat history need Postgres via Prisma for real persistence. The store interface is already abstracted — the migration is mostly additive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart parsing for all countries&lt;/strong&gt;&lt;br&gt;
The AU bank format is very specific. The next version should detect the bank format automatically — US (Plaid/OFX), UK (Monzo/Starling CSV), EU (SEPA), and AU — and route to the right parser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real CO₂ data&lt;/strong&gt;&lt;br&gt;
Right now impact scores are proxy-based (category + spend → colour). The right approach is to integrate an actual emissions API (like Climatiq or Patch) to get grams of CO₂e per transaction category, so the score means something measurable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email / push delivery&lt;/strong&gt;&lt;br&gt;
In-app notifications work. Email or mobile push (Resend, FCM) would make the weekly report actually reach users where they are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile-friendly upload&lt;/strong&gt;&lt;br&gt;
The upload panel works on desktop. A mobile-optimised flow — forwarding a bank statement email directly to PlanetLedger via a Cloudflare Email Worker — would massively reduce friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More AI agent capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Goal setting ("I want to reduce fast fashion spend by 40% this month") with progress tracking&lt;/li&gt;
&lt;li&gt;Carbon offset suggestions matched to your worst categories&lt;/li&gt;
&lt;li&gt;Peer comparison ("people with similar spending reduced food delivery by X%")- Surface proactive nudges (WARNING / TIP / CELEBRATION) from &lt;code&gt;lib/agent/nudges.ts&lt;/code&gt; — the engine is built, just needs an API route + UI hook&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of Auth0 for Agents&lt;/strong&gt; — Auth0 v4 middleware with zero route handlers; FGA rule table (&lt;code&gt;resource + action → scope&lt;/code&gt;) backing every agent action; Post-Login Action provisioning with MFA enforcement; rolling sessions (&lt;code&gt;inactivityDuration&lt;/code&gt; + &lt;code&gt;absoluteDuration&lt;/code&gt;); custom claims for preferences, eco_tier, and organization_id; scope check on every API route before any agent action runs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of GitHub Copilot&lt;/strong&gt; — Used end-to-end: scaffolding the agent pipeline, writing AU vendor categorisation rules, building the PDF regex extractor, generating type-safe API routes, implementing the FGA rule table and privacy sanitizer, designing the notification bell + polling architecture, building the chained OpenClaw pipeline, and iterating on UI components throughout.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>auth0challenge</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>Revisiting Idris in 2026: Is It Ready for Real Work?</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Tue, 14 Apr 2026 00:19:30 +0000</pubDate>
      <link>https://dev.to/ujja/revisiting-idris-in-2026-is-it-ready-for-real-work-1mco</link>
      <guid>https://dev.to/ujja/revisiting-idris-in-2026-is-it-ready-for-real-work-1mco</guid>
      <description>&lt;p&gt;Idris has always promised something bold: &lt;strong&gt;encode correctness directly into the type system&lt;/strong&gt;. In 2026, with Idris 2 firmly established, it’s worth revisiting whether that promise translates into production-grade reality.&lt;/p&gt;

&lt;p&gt;Short answer: &lt;em&gt;yes, in the right places&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idris 1 vs Idris 2
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Idris 1&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proof-of-concept era&lt;/li&gt;
&lt;li&gt;Slow compiler, heavy memory usage&lt;/li&gt;
&lt;li&gt;Research-focused ergonomics&lt;/li&gt;
&lt;li&gt;Effectively legacy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Idris 2&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete reimplementation&lt;/li&gt;
&lt;li&gt;Faster compilation and smaller core&lt;/li&gt;
&lt;li&gt;Multiple backends (Chez Scheme default, C available)&lt;/li&gt;
&lt;li&gt;Actively maintained and stable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re evaluating Idris today, Idris 2 is the only sensible choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea, in code
&lt;/h2&gt;

&lt;p&gt;Idris doesn’t just type-check values — it type-checks &lt;em&gt;facts&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Length-safe vectors
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight idris"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Nat &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Type &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Type &lt;/span&gt;&lt;span class="kr"&gt;where&lt;/span&gt;
  &lt;span class="kt"&gt;Nil&lt;/span&gt;  &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;S&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Concatenation &lt;em&gt;proves&lt;/em&gt; length correctness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight idris"&gt;&lt;code&gt;&lt;span class="nf"&gt;append :&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="kt"&gt;Nil&lt;/span&gt;       &lt;span class="n"&gt;ys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;
&lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No runtime checks. The compiler enforces the invariant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Totality: making partial logic illegal
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight idris"&gt;&lt;code&gt;&lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="nf"&gt;head :&lt;/span&gt; &lt;span class="kt"&gt;Vect&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;S&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="nb"&gt;head &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function cannot be called on an empty vector. Invalid states are unrepresentable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idris 2 ergonomics (the nitty-gritty)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compiler &amp;amp; performance&lt;/strong&gt;: Significantly faster than Idris 1, reasonable compile times&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error messages&lt;/strong&gt;: Improved structure, still proof-oriented and verbose&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tooling&lt;/strong&gt;: LSP support exists, interactive editing is powerful, docs are uneven&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usable, but not luxurious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linearity and resource safety
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight idris"&gt;&lt;code&gt;&lt;span class="nf"&gt;useOnce :&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;useOnce&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Linear types enable compile-time guarantees around resource usage: no double-use, no leaks, no implicit copying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Idris ready for production?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where Idris shines
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Protocols and state machines&lt;/li&gt;
&lt;li&gt;Parsers, DSLs, validation-heavy logic&lt;/li&gt;
&lt;li&gt;Compilers and interpreters&lt;/li&gt;
&lt;li&gt;Correctness-critical business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where it struggles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Small ecosystem&lt;/li&gt;
&lt;li&gt;Hiring challenges&lt;/li&gt;
&lt;li&gt;Interop overhead&lt;/li&gt;
&lt;li&gt;Not ideal for fast-moving CRUD apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Idris works best as a &lt;strong&gt;correctness core&lt;/strong&gt;, not a default full-stack choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mainline development or niche tool?
&lt;/h2&gt;

&lt;p&gt;Idris isn’t trying to replace Go, Rust, or TypeScript.&lt;/p&gt;

&lt;p&gt;It’s for teams asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if the compiler enforced our invariants?&lt;/li&gt;
&lt;li&gt;What if tests were secondary to types?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In 2026, Idris 2 is stable enough for real systems, &lt;strong&gt;if&lt;/strong&gt; your team is willing to think in types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final take
&lt;/h2&gt;

&lt;p&gt;Idris is no longer just a research curiosity.&lt;/p&gt;

&lt;p&gt;Idris 2 is production-capable for the right domains, offering unmatched guarantees at compile time.&lt;br&gt;&lt;br&gt;
If correctness is your top priority, Idris is quietly excellent.&lt;/p&gt;

</description>
      <category>idris</category>
      <category>programming</category>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Fourbidden: A Serious AI Solution to 2+2, With Maximum Ceremony and No Resolution</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Sun, 05 Apr 2026 10:04:34 +0000</pubDate>
      <link>https://dev.to/ujja/fourbidden-a-serious-ai-solution-to-22-with-maximum-ceremony-and-no-resolution-3p1g</link>
      <guid>https://dev.to/ujja/fourbidden-a-serious-ai-solution-to-22-with-maximum-ceremony-and-no-resolution-3p1g</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/aprilfools-2026"&gt;DEV April Fools Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;Fourbidden&lt;/strong&gt;, a fake AI product dedicated to solving one extremely serious global problem: &lt;code&gt;2+2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The joke is that the problem could not be smaller, but the app treats it like the final summit of machine reasoning.&lt;/p&gt;

&lt;p&gt;You ask a basic addition question, and instead of getting a basic addition answer, the app starts trying to &lt;strong&gt;sum up&lt;/strong&gt; its own importance.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;AI-generated loading statements that sound suspiciously strategic&lt;/li&gt;
&lt;li&gt;circular explainers that get more philosophical and less useful over time&lt;/li&gt;
&lt;li&gt;escalating terms and conditions that keep turning arithmetic into a compliance event&lt;/li&gt;
&lt;li&gt;procedural next steps designed to preserve momentum without producing closure&lt;/li&gt;
&lt;li&gt;dashboard widgets, warnings, and theatrical system language&lt;/li&gt;
&lt;li&gt;surprise interactions like panic overlays, chaos toasts, prank label swaps, and a hidden Konami-style chaos mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The T&amp;amp;C bit became one of my favorite parts of the whole thing.&lt;/p&gt;

&lt;p&gt;The user is effectively told that before they can move closer to understanding &lt;code&gt;2+2&lt;/code&gt;, they must first acknowledge expanding legal nonsense, accept more conditions, and agree to one more procedural step. Then another. Then another.&lt;/p&gt;

&lt;p&gt;So the core gag is not just overengineering. It is &lt;strong&gt;over-addition&lt;/strong&gt;: treating the smallest possible math question like a high-risk, high-governance product flow.&lt;/p&gt;

&lt;p&gt;It is a satire of software that cannot simply give you the answer, because it is too busy building a whole process around the answer.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Live demo: &lt;a href="https://ujjavala.github.io/fourbidden/" rel="noopener noreferrer"&gt;https://ujjavala.github.io/fourbidden/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Local version: &lt;code&gt;http://localhost:3000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Main routes:

&lt;ul&gt;
&lt;li&gt;Home: &lt;code&gt;/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;About: &lt;code&gt;/about&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Services: &lt;code&gt;/services&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/ujjavala/fourbidden" rel="noopener noreferrer"&gt;https://github.com/ujjavala/fourbidden&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key route surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/api/explain&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api/loading&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api/terms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api/steps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api/loop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api/widgets&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I wanted the app to feel like a glossy software product that exists entirely to avoid resolving &lt;code&gt;2+2&lt;/code&gt; in a straightforward way.&lt;/p&gt;

&lt;p&gt;So instead of making a single punchline screen, I built a full fake workflow around the idea of “solving” the problem while constantly refusing to complete it.&lt;/p&gt;

&lt;p&gt;Tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js 14 (App Router)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React + TypeScript&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google AI (Gemini API)&lt;/strong&gt; to generate the app's overblown explanations, loading copy, legal nonsense, escalation steps, loop logic, and widget chatter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom CSS&lt;/strong&gt; for the bright cinematic UI, orbit effects, shimmer, flashes, and overly dramatic motion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lucide React&lt;/strong&gt; for icon-driven UI accents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementation choices that shape the vibe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The main joke is taking the tiniest math problem and inflating it into a full-stack event.&lt;/li&gt;
&lt;li&gt;The interface looks polished enough to imply a seed round and a brand strategy deck.&lt;/li&gt;
&lt;li&gt;The T&amp;amp;C flow is central to the bit: the user keeps having to consent to more nonsense before progress can allegedly continue.&lt;/li&gt;
&lt;li&gt;The text stays intentionally circular and jargon-heavy so the app never gives the satisfaction of a clean conclusion.&lt;/li&gt;
&lt;li&gt;The click surprises add a second layer of April Fools chaos on top of the main workflow.&lt;/li&gt;
&lt;li&gt;There is a static fallback path so the absurdity still works even when live AI calls are unavailable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Leveraged Google AI
&lt;/h2&gt;

&lt;p&gt;Gemini is the narrative engine for the whole product illusion.&lt;/p&gt;

&lt;p&gt;I did not use it as a single chatbot response. I split the experience into multiple AI-backed roles so each part of the fake platform has its own voice and function.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/api/explain&lt;/code&gt;: produces long-form ceremonial non-answers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/loading&lt;/code&gt;: turns waiting into executive messaging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/terms&lt;/code&gt;: creates useless compliance clauses and acceptance loops around &lt;code&gt;2+2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/steps&lt;/code&gt;: invents process-heavy next actions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/loop&lt;/code&gt;: explains why completion is still not operationally appropriate&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/widgets&lt;/code&gt;: generates fake platform telemetry and side-channel noise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To keep that experience stable, I added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prompt caching with a short TTL&lt;/li&gt;
&lt;li&gt;retry and backoff handling for quota and rate-limit failures&lt;/li&gt;
&lt;li&gt;local fallback generators when Gemini is unavailable&lt;/li&gt;
&lt;li&gt;client-side static mode for static hosting environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That way the joke survives whether the AI is live, rate-limited, or completely absent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Google AI Usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google AI is not just providing flavor text here. It is powering the entire illusion that a hopelessly overbuilt software stack has been assembled to “solve” a single grade-school math prompt. Every stage of that ridiculous journey gets its own AI-generated nonsense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Ode to Larry Masinter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This app is proudly unnecessary. It manufactures protocol, ceremony, terms, gates, and pseudo-serious internet behavior around a task that should end instantly. It feels like the kind of thing that technically works while making arithmetic worse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Community Favorite&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I think the joke lands quickly: everyone understands &lt;code&gt;2+2&lt;/code&gt;, and everyone also recognizes software that delivers process instead of outcomes. Combining those two ideas made it easy to build something immediate, silly, and annoyingly plausible.&lt;/p&gt;

&lt;p&gt;If it makes people laugh and also mutter, "why does this feel plausible," then it did its job.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>418challenge</category>
      <category>showdev</category>
      <category>gemini</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Fri, 20 Mar 2026 11:35:27 +0000</pubDate>
      <link>https://dev.to/ujja/-141o</link>
      <guid>https://dev.to/ujja/-141o</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-story__hidden-navigation-link"&gt;I Built EchoHR: The HR System That Doesn’t Ghost You&lt;/a&gt;
    &lt;div class="crayons-article__cover crayons-article__cover__image__feed"&gt;
      &lt;iframe src="https://www.youtube.com/embed/D1zYQVfRA8w" title="I Built EchoHR: The HR System That Doesn’t Ghost You"&gt;&lt;/iframe&gt;
    &lt;/div&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Notion MCP Challenge Submission 🧠&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ujja" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" alt="ujja profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ujja" class="crayons-story__secondary fw-medium m:hidden"&gt;
              ujja
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                ujja
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3334932" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ujja" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;ujja&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 12&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" id="article-link-3334932"&gt;
          I Built EchoHR: The HR System That Doesn’t Ghost You
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/notionchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;notionchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mcp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mcp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;47&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              63&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

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

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

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>Big drop for EchoHR 🚀
🔧 Postgres queue + worker, idempotent + HMAC webhooks, retries/backoff, metrics
✨ Cleaner UX with hero video, logo, and clearer lifecycle
⚙️ More reliable setup + Docker flow (migrate seed worker)
Check out the blog for more 👇</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Tue, 17 Mar 2026 06:08:56 +0000</pubDate>
      <link>https://dev.to/ujja/big-drop-for-echohr-postgres-queue-worker-idempotent-hmac-webhooks-retriesbackoff-387</link>
      <guid>https://dev.to/ujja/big-drop-for-echohr-postgres-queue-worker-idempotent-hmac-webhooks-retriesbackoff-387</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-story__hidden-navigation-link"&gt;I Built EchoHR: The HR System That Doesn’t Ghost You&lt;/a&gt;
    &lt;div class="crayons-article__cover crayons-article__cover__image__feed"&gt;
      &lt;iframe src="https://www.youtube.com/embed/D1zYQVfRA8w" title="I Built EchoHR: The HR System That Doesn’t Ghost You"&gt;&lt;/iframe&gt;
    &lt;/div&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Notion MCP Challenge Submission 🧠&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ujja" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" alt="ujja profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ujja" class="crayons-story__secondary fw-medium m:hidden"&gt;
              ujja
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                ujja
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3334932" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ujja" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;ujja&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 12&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" id="article-link-3334932"&gt;
          I Built EchoHR: The HR System That Doesn’t Ghost You
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/notionchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;notionchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mcp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mcp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;47&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ujja/i-built-echohr-the-hr-system-that-doesnt-ghost-you-1c2i#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              63&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

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

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

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Enablers Who Helped Me Code Forward</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Tue, 10 Mar 2026 03:31:44 +0000</pubDate>
      <link>https://dev.to/ujja/the-enablers-who-helped-me-code-forward-cai</link>
      <guid>https://dev.to/ujja/the-enablers-who-helped-me-code-forward-cai</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/wecoded-2026"&gt;2026 WeCoded Challenge&lt;/a&gt;: Echoes of Experience&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sometimes the difference between giving up and moving forward is just one person who believes in you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I started coding when I was around nine years old.&lt;/p&gt;

&lt;p&gt;My first program was written in &lt;a href="https://en.wikipedia.org/wiki/Logo_(programming_language)" rel="noopener noreferrer"&gt;LOGO&lt;/a&gt;, where I spent hours writing tiny programs using a funny-looking triangular turtle that moved across the screen. You could tell it to move forward, turn, and draw shapes, and slowly patterns would emerge. To a kid, it felt magical. A few instructions and suddenly the computer was drawing something I had imagined.&lt;/p&gt;

&lt;p&gt;Back then I had no idea what a career in tech looked like. I just knew I loved making computers do things.&lt;/p&gt;

&lt;p&gt;One thing that made my journey different from many stories I hear today was the support I received at home. My family, especially my dad, supported my interest in computers wholeheartedly. At a time when many people still questioned whether girls should pursue technology, he never did. To him it was simple — if I enjoyed it, I should pursue it.&lt;/p&gt;

&lt;p&gt;That early encouragement made a huge difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Myth of the Solo Journey&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When people talk about careers in tech, the story is often about individual effort — perseverance, hard work, determination.&lt;/p&gt;

&lt;p&gt;And while those things matter, looking back I realise something else played an equally important role: &lt;strong&gt;enablers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Throughout my journey there were always people who gave me a small push forward at the right moment.&lt;/p&gt;

&lt;p&gt;Not huge dramatic gestures. Just small nudges that made a big difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The First Catalyst&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Early in my career I had a tech lead who noticed something about me before I fully recognised it myself.&lt;/p&gt;

&lt;p&gt;I loved &lt;strong&gt;clean code&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
I loved experimenting.&lt;br&gt;&lt;br&gt;
Hackathons excited me.&lt;/p&gt;

&lt;p&gt;Instead of letting that remain just a personal interest, he organised a &lt;strong&gt;hackathon within the team&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At the time it seemed like just a fun activity. But in reality, it gave me confidence. It validated that my curiosity and enthusiasm for building things mattered.&lt;/p&gt;

&lt;p&gt;Sometimes all someone needs is that small signal that their passion is worth investing in.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Finding My Voice&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Later in another organisation I faced a different challenge.&lt;/p&gt;

&lt;p&gt;I was technically confident, but &lt;strong&gt;public speaking terrified me&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Speaking up in meetings, presenting ideas, addressing a room full of people — those things didn't come naturally to me.&lt;/p&gt;

&lt;p&gt;An office head in that organisation noticed this and gently pushed me out of my comfort zone.&lt;/p&gt;

&lt;p&gt;Encouraging me to present.&lt;br&gt;&lt;br&gt;
Encouraging me to speak up.&lt;br&gt;&lt;br&gt;
Encouraging me to trust my voice.&lt;/p&gt;

&lt;p&gt;I still remember a very simple piece of advice he gave me.&lt;/p&gt;

&lt;p&gt;He said, &lt;em&gt;“Start small. Just say hi to people in the morning.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;His reasoning was simple. If I greeted people in the hallway or by the coffee machine, when I later saw them in a meeting room they wouldn’t feel like strangers anymore. The room would feel a little less intimidating.&lt;/p&gt;

&lt;p&gt;He also said something that stuck with me — smile. Maybe crack a small joke to ease the tension.&lt;/p&gt;

&lt;p&gt;It sounded almost too simple at the time, but it worked. Slowly those rooms full of unfamiliar faces started turning into rooms with colleagues I already knew, even if only through a quick morning hello.&lt;/p&gt;

&lt;p&gt;And little by little, speaking up didn’t feel so scary anymore.&lt;/p&gt;

&lt;p&gt;Today I speak about topics I care deeply about, especially &lt;strong&gt;identity and authentication in tech&lt;/strong&gt; — something I am incredibly passionate about.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Reality of Being Heard&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you’ve worked in tech long enough, you’ve probably seen this happen.&lt;/p&gt;

&lt;p&gt;Sometimes a woman's voice is ignored.&lt;/p&gt;

&lt;p&gt;Ideas get overlooked.&lt;br&gt;&lt;br&gt;
Comments go unheard.&lt;br&gt;&lt;br&gt;
Credit sometimes travels in unexpected directions.&lt;/p&gt;

&lt;p&gt;It happens.&lt;/p&gt;

&lt;p&gt;But another truth exists too.&lt;/p&gt;

&lt;p&gt;There are also people who &lt;strong&gt;amplify voices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;People who pause the room and say,&lt;br&gt;&lt;br&gt;
&lt;em&gt;"I think she was making a really good point."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;People who make sure ideas get the attention they deserve.&lt;/p&gt;

&lt;p&gt;Over time I’ve realised the tech industry isn't defined only by the people who silence voices.&lt;/p&gt;

&lt;p&gt;It’s also shaped by the people who make sure those voices are heard.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Recognising the Enablers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even today in my current workplace I am fortunate to work with amazing people who create that kind of environment.&lt;/p&gt;

&lt;p&gt;Looking back, my journey was never just about learning new technologies, frameworks, or systems.&lt;/p&gt;

&lt;p&gt;It was also about recognising the people who helped me move forward.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;enablers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The mentors.&lt;br&gt;&lt;br&gt;
The leaders.&lt;br&gt;&lt;br&gt;
The colleagues.&lt;br&gt;&lt;br&gt;
The allies.&lt;/p&gt;

&lt;p&gt;The people who saw potential and helped unlock it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Paying It Forward&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The biggest lesson from my journey is this:&lt;/p&gt;

&lt;p&gt;If you’ve had enablers in your life, the best thing you can do is &lt;strong&gt;become one for someone else&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Encourage the curious junior developer.&lt;br&gt;&lt;br&gt;
Support the quiet voice in the meeting.&lt;br&gt;&lt;br&gt;
Create spaces where people can experiment and grow.&lt;/p&gt;

&lt;p&gt;Sometimes a small push can change someone’s entire trajectory.&lt;/p&gt;

&lt;p&gt;I know it did for me.&lt;/p&gt;

&lt;p&gt;And to &lt;strong&gt;all the girls who want to code but feel like they can’t&lt;/strong&gt;,&lt;br&gt;&lt;br&gt;
to &lt;strong&gt;all the women and marginalised voices who sometimes feel unheard or silenced in tech&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Look around.&lt;/p&gt;

&lt;p&gt;There are often people who quietly support you, encourage you, and believe in you — sometimes even before you believe in yourself.&lt;/p&gt;

&lt;p&gt;Find those people.&lt;/p&gt;

&lt;p&gt;Recognise them.&lt;/p&gt;

&lt;p&gt;Hold on to them.&lt;/p&gt;

&lt;p&gt;Because once you identify the &lt;strong&gt;enablers&lt;/strong&gt; in your life, you’ll realise something powerful. You were never coding alone.&lt;/p&gt;

&lt;p&gt;And if you ever feel like you don’t belong in tech, remember this:&lt;/p&gt;

&lt;p&gt;Sometimes all it takes is one enabler to change your trajectory — and someday, that enabler might be you.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>wecoded</category>
      <category>dei</category>
      <category>career</category>
    </item>
    <item>
      <title>Rethinking AI Assistants: A Privacy-First Approach with Google Gemini</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Wed, 04 Mar 2026 11:09:32 +0000</pubDate>
      <link>https://dev.to/ujja/rethinking-ai-assistants-a-privacy-first-approach-with-google-gemini-4cm7</link>
      <guid>https://dev.to/ujja/rethinking-ai-assistants-a-privacy-first-approach-with-google-gemini-4cm7</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ujja/building-a-privacy-first-mobile-speech-assistant-using-google-gemini-59pm" class="crayons-story__hidden-navigation-link"&gt;Building a Privacy-First Mobile Speech Assistant Using Google Gemini&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/ujja/building-a-privacy-first-mobile-speech-assistant-using-google-gemini-59pm" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Built with Google Gemini: Writing Challenge&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ujja" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" alt="ujja profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ujja" class="crayons-story__secondary fw-medium m:hidden"&gt;
              ujja
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                ujja
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3293845" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ujja" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;ujja&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ujja/building-a-privacy-first-mobile-speech-assistant-using-google-gemini-59pm" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 28&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ujja/building-a-privacy-first-mobile-speech-assistant-using-google-gemini-59pm" id="article-link-3293845"&gt;
          Building a Privacy-First Mobile Speech Assistant Using Google Gemini
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/geminireflections"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;geminireflections&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gemini"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gemini&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/llm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;llm&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ujja/building-a-privacy-first-mobile-speech-assistant-using-google-gemini-59pm" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;25&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ujja/building-a-privacy-first-mobile-speech-assistant-using-google-gemini-59pm#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              14&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

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

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

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>geminireflections</category>
      <category>gemini</category>
      <category>llm</category>
    </item>
    <item>
      <title>CommonGround: Designing Digital Spaces for Safety, Healing, and Connection</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Wed, 04 Mar 2026 11:08:35 +0000</pubDate>
      <link>https://dev.to/ujja/commonground-designing-digital-spaces-for-safety-healing-and-connection-5gim</link>
      <guid>https://dev.to/ujja/commonground-designing-digital-spaces-for-safety-healing-and-connection-5gim</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ujja/building-safer-online-spaces-with-commonground-2746" class="crayons-story__hidden-navigation-link"&gt;Building Safer Online Spaces with CommonGround&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/ujja/building-safer-online-spaces-with-commonground-2746" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;DEV Weekend Challenge: Community&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ujja" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" alt="ujja profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ujja" class="crayons-story__secondary fw-medium m:hidden"&gt;
              ujja
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                ujja
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3295220" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ujja" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;ujja&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ujja/building-safer-online-spaces-with-commonground-2746" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 28&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ujja/building-safer-online-spaces-with-commonground-2746" id="article-link-3295220"&gt;
          Building Safer Online Spaces with CommonGround
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/weekendchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;weekendchallenge&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ujja/building-safer-online-spaces-with-commonground-2746" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;16&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ujja/building-safer-online-spaces-with-commonground-2746#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

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

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

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>What It Really Takes to Migrate 20+ Domains and 100+ SQL Tables from .NET to GraphQL</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Wed, 04 Mar 2026 11:07:25 +0000</pubDate>
      <link>https://dev.to/ujja/what-it-really-takes-to-migrate-20-domains-and-100-sql-tables-from-net-to-graphql-3deb</link>
      <guid>https://dev.to/ujja/what-it-really-takes-to-migrate-20-domains-and-100-sql-tables-from-net-to-graphql-3deb</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ujja/how-were-surviving-20-domains-and-100-sql-tables-while-migrating-our-legacy-net-backend-to-e38" class="crayons-story__hidden-navigation-link"&gt;How We’re Surviving 20+ Domains and 100+ SQL Tables While Migrating Our Legacy .NET Backend to GraphQL&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ujja" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" alt="ujja profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ujja" class="crayons-story__secondary fw-medium m:hidden"&gt;
              ujja
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                ujja
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3255443" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ujja" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;ujja&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ujja/how-were-surviving-20-domains-and-100-sql-tables-while-migrating-our-legacy-net-backend-to-e38" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 27&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ujja/how-were-surviving-20-domains-and-100-sql-tables-while-migrating-our-legacy-net-backend-to-e38" id="article-link-3255443"&gt;
          How We’re Surviving 20+ Domains and 100+ SQL Tables While Migrating Our Legacy .NET Backend to GraphQL
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/csharp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;csharp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/typescript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;typescript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/docker"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;docker&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dotnet"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dotnet&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ujja/how-were-surviving-20-domains-and-100-sql-tables-while-migrating-our-legacy-net-backend-to-e38" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;18&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ujja/how-were-surviving-20-domains-and-100-sql-tables-while-migrating-our-legacy-net-backend-to-e38#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

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

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

&lt;/div&gt;




</description>
      <category>csharp</category>
      <category>typescript</category>
      <category>docker</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Tech for good, built and shared on DEV 💛. 

I built a stutter-friendly app for calm, supportive, judgment-free speaking practice, with gentle feedback and privacy-first design at its core.

Built with Elm, Elixir, and Copilot CLI. Thoughts?</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Fri, 20 Feb 2026 23:22:59 +0000</pubDate>
      <link>https://dev.to/ujja/tech-for-good-built-and-shared-on-dev-i-built-a-stutter-friendly-app-for-calm-supportive-2e5n</link>
      <guid>https://dev.to/ujja/tech-for-good-built-and-shared-on-dev-i-built-a-stutter-friendly-app-for-calm-supportive-2e5n</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-story__hidden-navigation-link"&gt;I built a Stutter-Friendly App in 1 Day with Elm, Elixir, and Copilot&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;GitHub Copilot CLI Challenge Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ujja" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" alt="ujja profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ujja" class="crayons-story__secondary fw-medium m:hidden"&gt;
              ujja
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                ujja
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3256184" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ujja" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;ujja&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 14&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" id="article-link-3256184"&gt;
          I built a Stutter-Friendly App in 1 Day with Elm, Elixir, and Copilot
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/githubchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;githubchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/cli"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;cli&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/githubcopilot"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;githubcopilot&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;44&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              16&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

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

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

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>Is Creativity Dying in the Age of AI-Generated Websites?</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Wed, 18 Feb 2026 02:49:22 +0000</pubDate>
      <link>https://dev.to/ujja/is-creativity-dying-in-the-age-of-ai-generated-websites-5bmi</link>
      <guid>https://dev.to/ujja/is-creativity-dying-in-the-age-of-ai-generated-websites-5bmi</guid>
      <description>&lt;p&gt;Lately, I’ve been noticing a curious trend. I visit one website, and then another, and… it’s almost the same. Layouts feel eerily familiar, interactions feel almost identical, and the overall "feel" is uncanny. What’s even more striking is that many of these sites have emerged in just the last year or two.  &lt;/p&gt;

&lt;p&gt;It makes me wonder. Is AI actually stifling creativity? Or is it just accelerating convergence in design?  &lt;/p&gt;

&lt;p&gt;Many of these websites appear to be built end-to-end with AI-assisted tools. From layout to copy to interaction patterns, it feels like someone hit a "VibeCode" button and got the whole package. The upside is obvious. Faster development, consistent quality, and lower cost. The downside? They all start to look and feel the same.  &lt;/p&gt;

&lt;p&gt;I could be wrong, but it seems like the proliferation of these AI-driven templates might be leading to a kind of homogenisation. The uniqueness that used to come from a designer’s experimentation or a developer’s creative twist is now being replaced by AI "best practices." &lt;/p&gt;

&lt;p&gt;That’s not to say AI is inherently bad for innovation. It can supercharge ideas, help smaller teams punch above their weight, and unlock possibilities that were previously too time-consuming. But if everyone leans too heavily on AI-generated defaults, we might end up in a world where every new site looks like a slightly different clone of the last one.  &lt;/p&gt;

&lt;p&gt;So maybe the real challenge isn’t AI itself. It’s how we &lt;em&gt;use&lt;/em&gt; it. If we rely on it blindly, innovation can stagnate. But if we treat it as a creative partner, a tool rather than a template factory, there’s still room for fresh ideas, bold experiments, and genuine originality.  &lt;/p&gt;

&lt;p&gt;The question I keep coming back to is this. In a world where AI can do "most of it" automatically, how do we ensure we’re still pushing boundaries instead of just reproducing what already exists?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>vibecoding</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Sharing this because the mission matters 💛
I built a stutter friendly app that makes speaking practice calm, supportive, and judgment free, with gentle feedback and privacy first design at its core. It's built with Elm, Elixir, and Copilot CLI. Thoughts?</title>
      <dc:creator>ujja</dc:creator>
      <pubDate>Sun, 15 Feb 2026 22:01:16 +0000</pubDate>
      <link>https://dev.to/ujja/sharing-this-because-the-mission-matters-i-built-a-stutter-friendly-app-that-makes-speaking-3j76</link>
      <guid>https://dev.to/ujja/sharing-this-because-the-mission-matters-i-built-a-stutter-friendly-app-that-makes-speaking-3j76</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-story__hidden-navigation-link"&gt;I built a Stutter-Friendly App in 1 Day with Elm, Elixir, and Copilot&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;GitHub Copilot CLI Challenge Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ujja" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" alt="ujja profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ujja" class="crayons-story__secondary fw-medium m:hidden"&gt;
              ujja
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                ujja
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3256184" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ujja" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F439943%2F774d42c6-75e1-4247-8688-30020ce8f40a.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;ujja&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 14&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" id="article-link-3256184"&gt;
          I built a Stutter-Friendly App in 1 Day with Elm, Elixir, and Copilot
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/githubchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;githubchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/cli"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;cli&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/githubcopilot"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;githubcopilot&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;44&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ujja/i-build-a-stutter-friendly-app-in-1-day-with-elm-elixir-and-copilot-24a#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              16&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

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

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

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
  </channel>
</rss>
