<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>Om Rajguru — Dev Notes</title>
<link>https://www.omrajguru.com/devnotes</link>
<description>Technical notes and experiments.</description>
<language>en-us</language>
<atom:link href="https://www.omrajguru.com/devnotes/feed.xml" rel="self" type="application/rss+xml" />
<item>
<title>Building Fix My India: A Platform to Bridge Citizens and Government</title>
<link>https://www.omrajguru.com/devnotes/fixmyindia</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/fixmyindia</guid>
<pubDate>Wed, 19 Aug 2026 13:57:56 GMT</pubDate>
<dc:creator>Tiya</dc:creator>
<description>A look at why I built a platform for citizens to report civic issues and track government response, and what it does so far.</description>
<content:encoded>&lt;p&gt;I have been building something for the past few weeks called Fix My India.&lt;/p&gt;&lt;p&gt;The idea is simple. Citizens report civic issues like potholes, water supply problems, broken streetlights, or sanitation complaints. Government departments see these reports, respond, and update the status until the issue is resolved.&lt;/p&gt;&lt;p&gt;I wanted a place where nothing filed just disappears. Every request goes on a public feed. You can search it, filter it by category or status, and click into any request to see a live status tracker: Submitted, Under Review, In Progress, Resolved. If a department responds officially, that response shows up on the request too.&lt;/p&gt;&lt;p&gt;On the citizen side, signing up takes seconds. Filing a request is one form: title, category, description, exact location.&lt;/p&gt;&lt;p&gt;On the government side, I built in a verification gate. Staff accounts only work with authentic .gov.in or .nic.in emails, and an admin has to approve the account before dashboard access opens up. This was important to me. I did not want this to be a platform that works against government, I wanted it to help government departments see what citizens are dealing with and respond faster.&lt;/p&gt;&lt;p&gt;Once verified, staff get a dashboard scoped to their department, with the request queue sorted by status. Updating a request lets them change its status, post an official response, and add internal notes. Every change is logged, so the record stays accurate for everyone looking at it.&lt;/p&gt;&lt;p&gt;This is still early. I am building it in public, phase by phase, and there is a lot more to add.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Bringing Development and Reliability Together</title>
<link>https://www.omrajguru.com/devnotes/sdlc</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/sdlc</guid>
<pubDate>Tue, 09 Jun 2026 14:49:46 GMT</pubDate>
<dc:creator>Om</dc:creator>
<description>I recently started a private initiative called SDLC, a framework that combines software development and reliability practices into a single lifecycle. It is my attempt to create a clearer and more consistent way of building and maintaining software from start to finish.</description>
<content:encoded>&lt;p&gt;Today, I wanted to share a small initiative I have been working on called SDLC. SDLC stands for Software Development Life Cycle, but for me, it has become more than the standard definition of planning, designing, building, testing, deploying, and maintaining software. It started from a simple observation. Building software that feels consistent, pays attention to detail, and remains reliable over time often requires a lot of deliberate effort. As both a developer and researcher, I wanted a clearer set of standards that could guide not just how software is built, but how it should evolve throughout its entire life.&lt;/p&gt;&lt;p&gt;For a long time, I relied on my own Site Reliability Engineering standards for the projects I built. They helped define expectations around reliability, operations, and maintenance, and they worked well once software was already running. The problem was that they did not cover the earlier parts of the journey. Stages such as idea validation, planning, architecture, and design existed outside that framework. Over time, I felt the need for a single process that could connect the entire journey rather than focusing on only one part of it.&lt;/p&gt;&lt;p&gt;That led to the creation of this SDLC framework. It brings together traditional software development practices and reliability principles into one continuous lifecycle: Vision, Discovery, Planning, Architecture, Design, Build, Verify, Release, Operate, Scale, Evolve, and Retire. The goal is not to introduce a new methodology or claim that existing approaches are insufficient. It is simply a framework that reflects how I want to approach software creation going forward. By having a consistent set of standards from the first idea to the final retirement of a product, I can make decisions more deliberately and build systems that remain maintainable over time. I am sharing it today because it has already helped bring more structure to how I think about software, and I expect it will continue to evolve as I learn and build more.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Shelf</title>
<link>https://www.omrajguru.com/devnotes/shelf</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/shelf</guid>
<pubDate>Tue, 19 May 2026 12:14:00 GMT</pubDate>
<dc:creator>Om</dc:creator>
<description>I built Shelf because my ideas and thoughts were scattered across every note-taking app I had ever tried. Every time I sat down with Claude to think through an important decision, all of that context stayed behind in those apps, invisible to the conversation. I wanted one place that Claude could actually reach into.</description>
<content:encoded>&lt;p&gt;Every developer I know has the same problem. The knowledge that matters, the opinions formed after three failed approaches, the architectural decisions made at 11pm, the preferences refined over years of building, lives in a graveyard of note-taking apps. Notion pages. Apple Notes. Obsidian vaults. Bear drafts. The ideas are there. The context is there. But when you open a conversation with Claude and need that context to make a real decision, you are starting from zero every single time. I got tired of that. So I built Shelf.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/omrajguru/shelf/&quot;&gt;Repo&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Shelf is a self-hostable web app and MCP server for personal knowledge. Self-hostable means you run it on your own infrastructure, either on your laptop or on a cloud service you control. You own the data, the server, and the database. Shelf has no accounts to log into, no subscription, and zero LLM calls inside the system itself. It is purely storage and retrieval, with an MCP server on top that gives Claude direct access to everything you have saved.&lt;/p&gt;&lt;p&gt;MCP stands for Model Context Protocol. It is an open standard that defines how AI clients like Claude communicate with external tools and data sources during a conversation. Think of it as a structured bridge. On one side is Claude. On the other side is your data. MCP defines the exact language they speak so Claude can call your tools, receive structured responses, and weave that information into its answers. Shelf implements this protocol so your stored knowledge becomes part of every conversation you have.&lt;/p&gt;&lt;p&gt;Shelf exposes five tools over MCP. The first is &lt;code&gt;shelf_search&lt;/code&gt;, which runs a full-text search across all your entries. Full-text search means the system scans the actual words in your content and returns entries that match your query. The second tool is &lt;code&gt;shelf_dump&lt;/code&gt;, which saves a new entry and optionally tags it with a source label so you know where it came from. The third is &lt;code&gt;shelf_rules&lt;/code&gt;, which returns every entry you have marked as a rule. Rules are standing instructions for Claude, the things you want it to always factor in when talking to you. The fourth is &lt;code&gt;shelf_pinned&lt;/code&gt;, which returns your highest-priority reference entries. The fifth is &lt;code&gt;shelf_list&lt;/code&gt;, which shows your entries in reverse chronological order with pinned items at the top. These five tools cover every meaningful way an AI interacts with a personal knowledge store.&lt;/p&gt;&lt;p&gt;The storage layer is built to be swappable. By default, Shelf uses SQLite through Node&apos;s built-in &lt;code&gt;node:sqlite&lt;/code&gt; module. SQLite is a file-based database that lives entirely on your machine as a single file. There is no database server to run, no network connection involved, and no external account to create. You run &lt;code&gt;npm run db:init&lt;/code&gt; once and a file called &lt;code&gt;shelf.db&lt;/code&gt; appears in your project directory. That file is your entire database. For cloud deployments, Shelf ships with a full Supabase adapter. Supabase is a hosted Postgres database service with a generous free tier. Postgres is a production-grade relational database used by large-scale applications worldwide. You switch one environment variable, &lt;code&gt;SHELF_STORAGE_ADAPTER=supabase&lt;/code&gt;, and Shelf routes all storage operations through Supabase instead of your local file.&lt;/p&gt;&lt;p&gt;There are two setup paths and I designed them to serve genuinely different people. The local path is for developers comfortable in a terminal. You clone the repository, run four commands, and Shelf is live at &lt;code&gt;localhost:3000&lt;/code&gt; with an MCP server ready for Claude Desktop. The whole process takes about three minutes. The cloud path is for anyone who wants Shelf reachable from every device, including the browser version of Claude.ai. You fork the repository on GitHub, create a free Supabase project, paste one SQL migration file into Supabase&apos;s query editor, and deploy to Vercel. Vercel is a hosting platform that builds and serves your Next.js application for free on their infrastructure. That path takes about ten minutes with zero terminal commands.&lt;/p&gt;&lt;p&gt;The cloud setup works because Vercel hosts both the web app and the MCP server under the same URL. Your web interface lives at &lt;code&gt;https://your-shelf.vercel.app&lt;/code&gt; and the MCP endpoint lives at &lt;code&gt;https://your-shelf.vercel.app/api/mcp&lt;/code&gt;. When you add that endpoint as a custom connector in Claude.ai&apos;s settings under Connectors, Claude gains access to your Shelf tools from any browser on any device. You save an entry from your phone on the way to a meeting. You reference it from your laptop that afternoon. Supabase keeps both in sync because both point to the same database.&lt;/p&gt;&lt;p&gt;The technical foundation is Next.js 14, a React framework built and maintained by Vercel. React is a JavaScript library for building user interfaces. Shelf uses Next.js in a deliberate way: the web UI and standard API routes live in the App Router, which is Next.js&apos;s newer file-based routing system, and the MCP server lives in the Pages Router, which is the older routing system. The MCP server requires the Pages Router because it needs direct access to Node&apos;s raw HTTP request and response objects. The App Router abstracts those away in a way that breaks the MCP transport layer. Both routing systems coexist in the same project without conflict. The MCP SDK handles two transport modes from the same tool registration code: stdio for Claude Desktop, where the process communicates through standard input and output streams, and Streamable HTTP for Claude.ai, where communication happens over a standard web request.&lt;/p&gt;&lt;p&gt;Every storage adapter in Shelf implements a shared TypeScript interface called &lt;code&gt;StorageAdapter&lt;/code&gt;. TypeScript is a version of JavaScript that adds type annotations, meaning you declare the exact shape your data takes and the TypeScript compiler verifies that your code respects those shapes. The &lt;code&gt;StorageAdapter&lt;/code&gt; interface declares the methods every adapter must implement: saving entries, retrieving them, searching them, updating them, and deleting them. The web app and MCP server write code against this interface and have zero knowledge of which database sits underneath. The adapter handles every database-specific detail in isolation. Adding a new adapter for any database means implementing this one interface and registering it in the factory file. The architecture makes contribution a well-scoped task.&lt;/p&gt;&lt;p&gt;I made one architectural decision that I consider the most important one in the entire project. Shelf has zero LLM calls internally. There is no summarization on ingest, no embeddings generation, and no AI-powered relevance ranking. An embedding is a numerical representation of text used to measure semantic similarity between documents, the approach many AI-powered knowledge tools use to find conceptually related content. Shelf skips all of that. The search is full-text, meaning it matches the exact words you type against the exact words in your entries. This makes Shelf fast, free to run, and completely predictable. What you write is exactly what Claude receives. Your knowledge stays in your words, in your phrasing, with your original meaning intact.&lt;/p&gt;&lt;p&gt;One setup detail worth calling out is the Supabase migration. A database migration is a SQL script that creates the tables and indexes your application needs. SQL is the language used to define and query relational databases. Shelf ships the migration as a single file at &lt;code&gt;supabase/migrations/0001_init.sql&lt;/code&gt;. You open Supabase&apos;s SQL editor in the browser, paste the file contents, and run it. The editor confirms success with &quot;No rows returned.&quot; That one step creates everything the Supabase adapter needs. There is no migration CLI to install, no local Postgres to run, and no version tracking to set up for a first deployment.&lt;/p&gt;&lt;p&gt;The project is fully open source under the MIT license. MIT means you can use Shelf, modify it, host it, fork it, and build on top of it for any purpose, personal or commercial, as long as you include the original license text. The codebase is organized so that the entry points for contributors are obvious. The adapter directory holds all storage implementations alongside the shared interface they implement. The MCP tools directory holds each tool as a separate file. The web components directory separates layout, shelf-specific UI, and generic UI elements. Every layer is a standalone concern. You can read one directory and understand it fully without needing to hold the entire codebase in your head.&lt;/p&gt;&lt;p&gt;Shelf is for the kind of person whose thinking happens in fragments across many places. The entries you store do not need to be polished. They can be half-formed opinions, preferences you have refined over time, decisions you made and the reasoning behind them, rules you want Claude to always apply when talking with you. The more you put in, the richer every Claude conversation becomes. A shelf with fifty entries is a meaningfully better thinking partner than one with five. The tool is straightforward to run. The habit of dumping your knowledge into it, the same way you would leave yourself a quick note, is what compounds into something genuinely useful over time.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</content:encoded>
</item>
<item>
<title>How I Would Serve Exam Results to 14 Lakh Students at Once Without Breaking a Sweat</title>
<link>https://www.omrajguru.com/devnotes/scaling</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/scaling</guid>
<pubDate>Sat, 02 May 2026 13:40:00 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>A deep-dive into a static-first, multi-CDN system design that serves 14,00,000 concurrent exam result requests at sub-200ms latency with zero database dependency in the hot path.</description>
<content:encoded>&lt;p&gt;Imagine fourteen lakh students, all opening the same URL at the same second. They have been waiting months for this result. The anxiety is real, the traffic spike is guaranteed, and the margin for error is zero. I designed this system knowing that the worst possible outcome is a student seeing someone else&apos;s marksheet, and the second worst is the system going down entirely. Every architectural choice I made flows from those two constraints. Scale is a solved problem if you pick the right abstraction. The real question is what that abstraction should be, and in this case, the answer is deceptively straightforward: treat every exam result as a static file that already exists before the first student ever makes a request. This shifts the entire conversation from &quot;how do I scale my database&quot; to &quot;how do I make sure my CDN is healthy.&quot;&lt;/p&gt;
&lt;p&gt;The standard approach to building a result portal looks like this: a student submits a roll number, the request hits a load balancer, the load balancer routes it to an application server, the application server queries a database, the database returns a row, and the server formats and returns a response. That pipeline works fine at ten thousand requests per second. At five lakh requests per second, the database becomes the wall. No amount of connection pooling or read replicas changes the fundamental physics of a relational database under that kind of write-read pressure. I have seen systems built exactly this way collapse within ninety seconds of results going live, with engineers scrambling to add read replicas while students are getting timeout errors. The architecture I am describing here makes that entire failure mode irrelevant by removing the database from the path that students ever touch.&lt;/p&gt;
&lt;p&gt;The core idea is pre-generation. A pre-generation pipeline is a process that runs before results go public and converts every student record stored in a database into a static JSON file and a PDF stored in object storage. In this case, that object storage is Amazon S3, which is a managed file storage service that can serve files at effectively unlimited scale. For fourteen lakh students, the JSON files total about 2.8 gigabytes and the PDFs total about 168 gigabytes. Those numbers sound large but S3 handles them without any configuration changes. Once these files exist in S3, the database has already done its job. It contributed its data to the files. Its work is complete. What remains is purely a file-serving problem, and file-serving is something content delivery networks were purpose-built to handle.&lt;/p&gt;
&lt;p&gt;A content delivery network, or CDN, is a globally distributed network of servers called edge nodes. Each edge node is a server located physically close to groups of users. When a student in Pune requests their result, the CDN serves that file from an edge node in Mumbai instead of routing the request all the way to a data center. This reduces latency, which is the time a packet takes to travel from the user to the server and back. It also means that the origin server, which is the server where the file actually lives, receives only a fraction of the total requests. The CDN caches the file after the first fetch and serves it from memory for every subsequent request. At the scale I am designing for, the CDN absorbs ninety-five to ninety-nine percent of all traffic. The backend infrastructure barely registers the load.&lt;/p&gt;
&lt;p&gt;I use three CDN providers in this design: Akamai as the primary, Cloudflare as the secondary, and Fastly as the backup. Running multiple CDN providers in parallel is called a multi-CDN strategy. DNS-based traffic steering, handled through AWS Route 53 or NS1, directs requests to the appropriate CDN based on health checks. If Akamai&apos;s health checks fail, Route 53 automatically redirects traffic to Cloudflare within seconds. If Cloudflare also fails, traffic moves to Fastly. Each CDN independently serves from S3 as its origin. This removes the single point of failure that a single-CDN architecture introduces. A single CDN provider going down on result day is a real risk. It has happened to production systems at scale. Running three providers means I need all three to fail simultaneously before students notice anything.&lt;/p&gt;
&lt;p&gt;The pre-generation pipeline follows a specific timeline relative to result publication. At twelve hours before results go live, the source database, which is an Aurora PostgreSQL instance, enters a data freeze. No further writes are permitted. This guarantees that the data I generate files from is identical to the data students will expect. At eight hours before, I load every result record into DynamoDB. DynamoDB is a fully managed NoSQL database that scales horizontally without any configuration. It serves as the fast-query fallback layer in case a student hits the API directly rather than the CDN. At six hours before, I preload Redis, which is an in-memory data store, with the complete dataset of 2.8 gigabytes. Redis is fast enough to return a result in under one millisecond. At four hours before, the PDF generation job runs, converting every result record into a formatted PDF and uploading it to S3. At two hours before, I optionally warm the CDN cache by prefetching files from S3 to edge nodes, so the first student request hits cache rather than origin. At T=0, I flip a feature flag that makes results visible and purge the CDN cache to force a fresh fetch of the live flag state.&lt;/p&gt;
&lt;p&gt;The file structure on S3 follows a predictable pattern: /results//.json for the result data and /results//.pdf for the marksheet. When a student enters their roll number and date of birth on the frontend, the JavaScript running in their browser computes the exact S3 path and requests it through the CDN. The CDN checks its cache. On a hit, it returns the file instantly. On a miss, it fetches from S3, stores the response in cache, and returns it. The date of birth validation happens on the client side for the CDN path and on the server side only if the student ends up hitting the fallback API. This is an important security consideration: the CDN path serves pre-signed URLs for PDFs, meaning each PDF URL is cryptographically signed with an expiry time and is tied to specific access parameters. A student who tries to guess another student&apos;s roll number will get a file, but accessing the PDF requires a valid signature that the frontend only generates after verifying the date of birth.&lt;/p&gt;
&lt;p&gt;Caching strategy varies by resource type. The root HTML page at &quot;/&quot; gets a 300-second TTL, which means edge nodes serve it from cache for five minutes before checking for updates. Static assets like JavaScript and CSS bundles get a one-year TTL because I use content-addressed filenames that change when the file changes. Result JSON files get a 60-second TTL with stale-while-revalidate behavior. Stale-while-revalidate means the CDN serves the cached version immediately to the user while fetching a fresh copy from origin in the background. This keeps latency low even when the cache is technically expired. PDF files get a 24-hour TTL because they are static and will never change once generated. Together, these TTLs mean the CDN serves almost every request from memory while still refreshing fast enough to reflect any emergency corrections.&lt;/p&gt;
&lt;p&gt;The API layer exists as a fallback and for internal operations, but it does not sit in the hot path. I run it on ECS Fargate, which is a serverless container execution environment on AWS. Fargate scales horizontally based on load without me provisioning individual servers. The API accepts requests only from the CDN&apos;s IP ranges, meaning students cannot bypass the CDN and hit the API directly. When a request does reach the API layer because of a CDN miss or a validation step, it first checks Redis. If Redis has the result, it returns it immediately. If Redis misses, it queries DynamoDB. If DynamoDB misses, it falls back to Aurora PostgreSQL. This three-tier fallback ensures no student request returns an error as long as at least one storage layer is functional. In practice, the Redis layer serves everything. Its entire dataset fits in memory and has been preloaded before result time.&lt;/p&gt;
&lt;p&gt;The Redis cluster runs on ElastiCache Serverless, which is AWS&apos;s managed Redis offering that scales capacity automatically. The full 2.8-gigabyte dataset of result records fits comfortably in memory. In-memory storage means retrieval time stays consistently below one millisecond at the ninety-ninth percentile. I preload Redis at T-6 hours by running a batch job that reads every record from DynamoDB and writes it into Redis in pipeline mode. Pipeline mode batches multiple Redis write commands into a single network round trip, making the preload fast enough to complete in under thirty minutes even for fourteen lakh records. DynamoDB runs in on-demand capacity mode, meaning AWS automatically allocates read and write units as needed without me setting a fixed capacity ceiling. This ensures DynamoDB never throttles requests even if Redis has a cold start and pushes unexpected load down the chain.&lt;/p&gt;
&lt;p&gt;Security in this system operates at multiple layers simultaneously. TLS 1.3, which is the latest version of the transport layer security protocol that encrypts data in transit, is enforced across every endpoint. Backend services run inside private subnets within a Virtual Private Cloud. A Virtual Private Cloud, or VPC, is an isolated network segment on AWS where resources are invisible to the public internet unless explicitly exposed. The Application Load Balancer, which sits between the CDN and the API layer, uses security group rules that accept connections only from known CDN IP ranges. IAM policies follow least-privilege rules, meaning each service has permission to do exactly what it needs and nothing more. Secrets like database credentials and signing keys live in AWS Secrets Manager rather than environment variables. No personally identifiable information appears in log outputs. PDF access requires a signed URL with an expiry window of fifteen minutes, making it time-limited and tied to a specific request context.&lt;/p&gt;
&lt;p&gt;The waiting room is the last line of defense before backend overload, and in this architecture it only activates if the CDN fails. I implement it using Cloudflare Waiting Room, which holds users in a virtual queue and admits them at a configurable rate. I set the initial active user limit to two to three lakh and tune the admission rate dynamically based on observed backend load. Cloudflare Waiting Room works at the edge, meaning it intercepts requests before they reach any origin server and holds overflow users on Cloudflare&apos;s infrastructure. The waiting room protects the API layer in the rare scenario where CDN traffic suddenly redirects to origin at scale. Without it, a CDN failure would translate directly into five lakh simultaneous requests hitting Fargate containers, which would cascade into Redis and then DynamoDB. The waiting room acts as a pressure valve that prevents that cascade.&lt;/p&gt;
&lt;p&gt;The multi-region strategy uses AWS ap-south-1 in Mumbai as the primary region and ap-south-2 in Hyderabad as the disaster recovery region. All data is replicated to the secondary region continuously. Aurora PostgreSQL uses Global Database, which replicates across regions with a replication lag under one second. DynamoDB uses Global Tables, which provide active-active replication meaning both regions can serve reads and writes simultaneously. Route 53 runs health checks against both regions every ten seconds. If the primary region fails, Route 53 detects the failure within thirty seconds and updates DNS records to point to the secondary region. CDN origins also have regional fallback configured, so the CDN switches origin endpoints without requiring DNS propagation to complete. My target recovery time objective is sixty seconds, meaning students experience at most one minute of degraded service during a full regional failure.&lt;/p&gt;
&lt;p&gt;Observability in this system centers on three things: CDN cache hit ratio, latency percentiles, and error rates. Cache hit ratio tells me whether the CDN is doing its job. If that number drops below ninety percent, it means a large portion of requests are hitting origin, which puts pressure on the API layer. I track latency at the fiftieth, ninety-fifth, and ninety-ninth percentiles. The ninety-fifth percentile target is 200 milliseconds and the ninety-ninth percentile target is 500 milliseconds. Anything above those thresholds triggers an alert. Error rates are segmented by status code: 4xx errors indicating client-side issues like invalid roll numbers and 5xx errors indicating server-side failures. I use Datadog for application-level metrics and AWS CloudWatch for infrastructure metrics. CDN logs from both Akamai and Cloudflare stream into a central log aggregation pipeline so I can correlate events across providers in real time.&lt;/p&gt;
&lt;p&gt;Failure scenarios map cleanly to the layered architecture. If Akamai goes down, Route 53 moves traffic to Cloudflare within seconds and students see a brief delay at most. If Redis fails entirely, every request falls to DynamoDB, which runs in on-demand mode and absorbs the load. The latency increases from sub-millisecond to single-digit milliseconds but the system keeps responding. If DynamoDB has a regional failure, Aurora PostgreSQL takes over as the source of truth. Aurora is not in the hot path by design, so this path is slow but functional. If the entire Mumbai region fails, Route 53 and CDN origin failover redirect traffic to Hyderabad within sixty seconds. The system is designed so that each failure degrades performance gradually rather than causing a hard outage. Students may notice slower responses in a cascading failure scenario. They will still get their results.&lt;/p&gt;
&lt;p&gt;The thing I find most satisfying about this architecture is what result day looks like for the engineering team. The CDN cache hit ratio sits at ninety-seven percent. The API layer processes a few hundred requests per second instead of five lakh. Redis memory usage holds steady at the preloaded 2.8 gigabytes. Aurora&apos;s connection count barely moves because it serves no student traffic. The Fargate containers handling the fallback API run at fifteen percent CPU utilization. Every metric is green. Fourteen lakh students get their results in under 200 milliseconds. The system is, in every meaningful sense, bored. That is the design goal. The system should handle the biggest traffic spike of the year the same way it handles a Tuesday afternoon. When you build around static assets and CDN-first delivery, peak load becomes a configuration concern rather than an engineering emergency.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>I Built a Claude Skill That Audits Your Code for Edge Cases Before They Reach Production</title>
<link>https://www.omrajguru.com/devnotes/interruptions</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/interruptions</guid>
<pubDate>Fri, 01 May 2026 04:21:16 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>interruptions is a Claude skill that walks your code through 12 failure categories, writes a full audit, and fixes issues in order of severity.</description>
<content:encoded>&lt;p&gt;Every product I shipped had edge cases I missed. I found them the hard way: through user reports, midnight rollbacks, and refund spirals that should have been caught during review. The pattern repeated across projects: the happy path worked, but the real world found gaps I had overlooked. A phone call mid-payment. A network drop during an upload. Two tabs racing each other to submit the same form. These are the moments that define whether a product feels reliable or fragile. I kept thinking there had to be a structured way to find these failures before users did. That question became interruptions.&lt;/p&gt;
&lt;p&gt;interruptions is a Claude skill. A Claude skill is a set of instructions and references you install into your Claude environment, and it activates when you ask Claude specific questions. Once installed, this skill triggers whenever you ask Claude to audit a flow, find what could go wrong, or stress test a feature. Claude then walks your code through 12 structured categories of failure modes, writes a comprehensive audit report to a Markdown file called &lt;code&gt;interruptions-audit.md&lt;/code&gt;, and waits for you to read it and confirm before touching anything. After you confirm, Claude helps you fix each issue in order of severity. The installation takes one command: &lt;code&gt;npx skills add omrajguru05/interruptions&lt;/code&gt;. From that point, the skill is available across Claude Code, Claude Desktop, and Claude.ai.&lt;/p&gt;
&lt;p&gt;The 12 categories exist because failure modes cluster into recognizable patterns. I pulled these patterns from years of shipping and watching the same classes of bugs appear across different products and teams. UX and user psychology covers how users behave irrationally, accidentally, or in ways your design overlooked. Security covers replay attacks, insecure direct object references, frontend tampering, and weak authentication. An insecure direct object reference happens when a user can guess or modify a URL parameter to access data that belongs to another user. Design and visual state covers how the UI communicates, or fails to communicate, what happened after an action. System flow and logic design covers breakdowns in workflow sequencing and state transitions.&lt;/p&gt;
&lt;p&gt;The remaining categories go deeper into the infrastructure and data layers. State and data integrity covers situations where the frontend, backend, and cache hold different versions of the same truth at the same time. Network and infrastructure covers timeouts, lost responses, and partial requests that leave the system in an ambiguous state. Concurrency and race conditions covers two operations happening simultaneously and producing a result that neither operation intended in isolation. Payment and transaction integrity covers the class of errors where money is involved and the cost of a mistake is real. Device and environment covers actual behavior differences across operating systems, browsers, and screen sizes that synthetic testing often overlooks. Synthetic testing means running automated scripts against your code in a controlled environment, which produces different results from a real user on a real device with a slow connection and five background tabs open.&lt;/p&gt;
&lt;p&gt;The final three categories address the boundaries of your inputs and your error paths. Accessibility and inclusion covers screen reader compatibility, keyboard navigation, right-to-left language support, zoom behavior, and color contrast ratios. Data validation and input handling covers malformed, extreme, or intentionally hostile input that reaches your backend. Error handling and recovery covers what happens after a failure and whether a user has a path forward, or is left with a generic toast message and a phone call to support. Each category has its own set of questions, red flags, and example fixes stored inside a references file that Claude loads during the audit. These references come from real production failures observed across multiple product types and team sizes. The checklist in &lt;code&gt;references/checklist.md&lt;/code&gt; is the canonical source the skill reads from during each audit run. It is also the file where community contributions make the biggest difference.&lt;/p&gt;
&lt;p&gt;When you trigger the skill, the audit phase runs first. Claude greets you, asks which flow or file you want audited, and then walks the 12 categories against your code one by one. The output is a structured audit written to &lt;code&gt;interruptions-audit.md&lt;/code&gt;, a Markdown file that lives in your project directory. Each finding in that file includes a severity rating, a file and line reference pointing to the exact location in your code, and a concrete fix with enough context to understand the change. Severity ratings follow a consistent scale so you can prioritize what to address first. The audit covers every category regardless of which flow you asked about, because failures in one area often trace back to a gap in another. After the audit is complete, the skill pauses and waits for you to read it.&lt;/p&gt;
&lt;p&gt;This waiting behavior is intentional and the most important design decision in the entire skill. Edge case fixes touch payment paths, authentication logic, and state machines. A state machine is a structure that tracks every possible state your application can be in, and which transitions between those states are valid. If Claude starts implementing changes before you read the audit, you lose the understanding of why each change is being made. So the skill holds at step four and asks you to read the audit and confirm in plain words before a single fix is applied. This confirmation gate is the difference between a tool that helps you ship better code and one that rewrites your codebase in ways you have to reverse engineer afterward. You stay in control of what gets changed and when.&lt;/p&gt;
&lt;p&gt;The fix phase runs under a strict set of safety rules I designed to prevent the skill from creating problems while solving them. Before any fix is applied, the skill checks that you are on a working branch, inventories your test, typecheck, and lint commands, and glances at your CI configuration to flag branches that auto-deploy to production. CI, which stands for continuous integration, is an automated system that runs your tests and checks whenever you push code. For each individual fix, the skill produces the smallest possible diff. A diff is a record of exactly which lines changed in a file and how they changed. The skill touches the function in question and its direct callers, shows you the planned change before applying it on high-risk paths, and runs your test suite after each edit. When a fix causes an existing test to fail, the skill stops entirely rather than rewriting the test to make the failure disappear.&lt;/p&gt;
&lt;p&gt;The project accepts contributions, and the contribution bar is high by design. The edge case checklist is a production tool, and the quality of its output depends on the quality of what goes into it. You can add new edge case scenarios across any of the 12 categories, improve clarity on existing ones, or propose an entirely new category if you find a recurring failure pattern that the current structure misses. Every contribution needs three things: a concrete scenario describing the failure, an impact section describing what goes wrong for the user or the system, and a suggested safeguard describing how to prevent or handle the failure. Vague descriptions belong outside the checklist. Specific, reproducible failure paths belong inside it. The process is: fork the repository, create a branch, make your changes, and submit a pull request with a clear explanation of what you changed and why it improves the project.&lt;/p&gt;
&lt;p&gt;I built interruptions because asking a developer to hold twelve distinct failure categories in their head during a focused review is an exercise in futility. A structured checklist handed to Claude and run against every flow is fundamentally more reliable than human memory and far more objective than a self-review written by the person who already &quot;knows&quot; the code works. This skill surfaces exactly what you missed, documents it clearly, and waits for your confirmation before helping you address each finding in order of priority. To ensure stability, the fix phase executes only one change at a time, followed by immediate test verification so you can see the impact of every individual tweak before moving to the next.&lt;/p&gt;
&lt;p&gt;If you run this on a flow and it flags a bug you were seconds away from shipping to production, then it is doing exactly what I built it to do.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>The Persistence of Intent</title>
<link>https://www.omrajguru.com/devnotes/intent</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/intent</guid>
<pubDate>Wed, 29 Apr 2026 12:41:13 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>Software should remember what the user intended, even when the connection fails or the page refreshes. We are rethinking how state survives reality.</description>
<content:encoded>&lt;p&gt;Imagine you have spent several minutes refining a complex dashboard. You have set the date ranges, toggled the specific filters, and drilled down into the exact data points that tell your story. You copy the link from your browser address bar and send it to a colleague to show them what you found. When they click that link, they see a blank slate. The filters are gone. The context is lost. You realize that your application only existed in that specific moment on your specific screen.&lt;/p&gt;
&lt;p&gt;Now consider the person using your app while moving through a city. They fill out a detailed form, providing thoughtful input. They tap the button to submit their work just as their device loses its connection to the network. Instead of the data being preserved, it simply vanishes. A generic notification tells them to try again later. These are not just minor inconveniences. They are moments where the technology fails to respect the time and effort the user has invested.&lt;/p&gt;
&lt;p&gt;We have reached a point where we treat these issues as expected behaviors. Developers spend hours writing repetitive logic to synchronize the interface with the URL or to manage the fragile state of a network request. We write the same lines of code for every new project, trying to bridge the gap between what the user sees and what the system remembers. We have inadvertently accepted that application state is a fleeting thing that lives and dies in temporary memory.&lt;/p&gt;
&lt;p&gt;The URL is one of the most fundamental structures of the web. It was designed to be a permanent reference to a specific resource. Yet in many modern applications, the URL has become an afterthought. We allow important navigation and filter states to exist only in the memory of the current session. When a user interacts with the back button or refreshes their browser, the interface breaks because we stopped treating the URL as a reliable source of truth.&lt;/p&gt;
&lt;p&gt;The challenge of working offline is often treated with the same lack of permanence. Most tools assume a perfect, constant connection to the internet. When that connection falters, the application stops functioning. We have grown accustomed to building software for ideal conditions, testing our work on high speed networks while our users navigate a world of tunnels, basements, and rural gaps. We lack a standard way to ensure that a user’s data is safe regardless of their signal strength.&lt;/p&gt;
&lt;p&gt;These two problems are usually treated as separate technical hurdles. One is seen as a routing issue and the other as a data synchronization issue. Because they are handled by different tools and different libraries, they never communicate. We continue to build fragmented systems where the user’s intent is easily lost between the layers. We have not yet unified the way an application understands where it is and what it is holding.&lt;/p&gt;
&lt;p&gt;A better experience is possible. It is an experience where you define your data once and the system handles the rest. In this environment, every meaningful change in the interface is automatically reflected in the URL, making every state shareable and persistent. In this environment, the application is inherently resilient. It waits for the network to return and ensures that no piece of information is ever discarded. The developer does not write complex synchronization logic because the system is designed to be stable by default.&lt;/p&gt;
&lt;p&gt;This is a difficult problem to solve correctly. It requires a fundamental shift in how we think about the relationship between the user, the browser, and the server. We have been exploring a way to make this level of persistence feel natural and effortless for everyone involved. We are building a foundation that treats user intent as something that should never be lost. If these challenges represent the friction you feel in your daily work, there is more to discuss soon. Something new is being prepared.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>How to stop Claude from scanning your entire codebase every session</title>
<link>https://www.omrajguru.com/devnotes/claude</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/claude</guid>
<pubDate>Tue, 28 Apr 2026 10:39:40 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>WebDNA generates a single manifest file at build time. Claude reads that instead of crawling your files. Here is how to set it up.</description>
<content:encoded>&lt;p&gt;If you use Claude or Cursor on a real project, you have probably hit the point where it starts reading every file just to understand what the codebase looks like. It is not doing anything wrong. It just has no other way to get context. So it scans, and that scan costs tokens every single session.&lt;/p&gt;
&lt;p&gt;I wrote about WebDNA a while back. The short version is that it is a Next.js plugin that generates a JSON file at build time describing your routes, components, API endpoints, and brand tokens. AI agents read that file first instead of crawling your source.&lt;/p&gt;
&lt;p&gt;Since the first post I have added a two-tier manifest system so you can exclude private routes and sensitive components from what the AI sees, a fallback API route at /api/webdna for agents that cannot access .well-known directories, and a linter that catches missing descriptions and undeclared auth scopes before they become a problem.&lt;/p&gt;
&lt;p&gt;If you want to try it on your project, the full setup guide is at &lt;a href=&quot;https://webdna.omraj.guru/&quot;&gt;webdna.omraj.guru&lt;/a&gt;. It takes about five minutes and works with any Next.js project using App Router or Pages Router.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Building a Home for My Work</title>
<link>https://www.omrajguru.com/devnotes/home</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/home</guid>
<pubDate>Mon, 27 Apr 2026 16:45:00 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>I needed a space that proved I could build what I promised. This is how I moved my projects into a dedicated, high-standard home.</description>
<content:encoded>&lt;p&gt;Building projects.omrajguru.com was a necessity born from a shift in my professional trajectory. My previous website was essentially a digital forest where many different ideas lived together under one roof. It housed my software engineering thoughts, product design musings, and unpolished poetry alongside raw daily logs and technical tutorials. While that variety represented my curiosity, it created a diluted impression for potential clients. When I decided to pursue freelancing seriously as my primary income source, I realized my projects needed a dedicated space where they wouldn&apos;t be buried under &quot;quickships&quot; or &quot;dev notes.&quot; People needed to see my capabilities clearly so they could trust me with their own visions and products.&lt;/p&gt;
&lt;p&gt;The shift into freelancing meant that my digital presence was no longer just a hobby but the very engine that would fund my life. This pressure forced me to sit down and explore tech stacks with a level of scrutiny I had never applied to my personal work before. My primary requirement was that this new home must align perfectly with my personal design language. Not many people realize that I spent an entire year developing a specific visual system that reflects exactly who I am. I eventually converted this entire philosophy into a specialized skill for Claude so I could deploy it consistently across different web projects. It was non-negotiable that the new site felt like an extension of this identity.&lt;/p&gt;
&lt;p&gt;Beyond aesthetics, I needed a system that was incredibly functional and flexible while remaining portable and quick to manage. There is a specific kind of irony in being a developer who wants things to be fast and frictionless, but I have learned that hurdles in the workflow are where creative ideas go to die. If I spend all my time maintaining the infrastructure or fighting with a rigid CMS, I lose the energy required to actually document the work. I wanted a portal that felt like a professional tool but functioned with the ease of a modern application. This required a stack that could handle complexity without imposing a tax on my daily productivity or my creative flow.&lt;/p&gt;
&lt;p&gt;I have always been an admirer of the OpenAI website, particularly after exploring how they utilized Contentful to manage their complex structure. I loved their use of components and the way their design felt both structured and easy to use across different content types. As a developer, I felt a strong urge to master this platform because I knew that someday a client might demand it for their own high-scale product. To satisfy this curiosity, I actually built a smaller research website to house my findings. However, Contentful had one major drawback that I could not ignore which was the pricing model. The jump from a free trial to three hundred dollars a month was not reasonable for my current needs.&lt;/p&gt;
&lt;p&gt;The cost barrier of Contentful eventually led me to land on Sanity as my primary choice for content management. I had been attempting to learn Sanity for a long time, but I struggled to pull it off according to my specific Site Reliability Engineering standards (fn1). Despite the initial steep learning curve, I decided that I would sit down and not get up until I had truly finished this implementation. There is a specific mindset required to build a product of this caliber, and I had to accept that greatness is an iterative process. You simply cannot expect to reach the level of a company like Apple on your very first day of development.&lt;/p&gt;
&lt;p&gt;During this process, a close friend told me that you cannot become Apple without doing exactly what they did in the first place. This piece of advice resonated deeply with me and shaped my final decision regarding the technology stack. I chose Next.js because it provides the perfect balance between high performance interactivity and superior SEO, which is absolutely critical for a professional portfolio. By leveraging features like Static Site Generation and Incremental Static Regeneration, the site delivers near-instant page loads for complex project case studies. This ensures that the content remains fresh and easily indexable by search engines while maintaining a premium and cinematic user experience for every visitor.&lt;/p&gt;
&lt;p&gt;Next.js also allowed me to implement smooth Framer Motion animations and rich media blocks without compromising on core web vitals. To host this architecture, Vercel was the only logical choice because it is the native home for the framework. Its global edge network ensures that high-resolution project images and interactive components are delivered with ultra-low latency to users all around the world. Features like Preview Deployments allow for frictionless testing of new &quot;Premium Components&quot; before they are pushed to the live production environment. By automatically handling SSL and global CDN distribution, Vercel let me focus entirely on the design and storytelling aspects of my work.&lt;/p&gt;
&lt;p&gt;Sanity became the backbone of the project because it treats content as data rather than just static text. This distinction is essential for a portfolio that relies on complex and interactive components rather than basic paragraphs. Unlike traditional CMS platforms that limit users to a basic rich text editor, Sanity’s Structured Content approach allowed me to define highly specialized schemas. I could build out specific blocks for interactive charts, comparison sliders, and live code sandboxes. This flexibility is powered by Portable Text, which provides a JSON-based format that my Next.js frontend can easily parse and render into the custom-styled React components I had already built.&lt;/p&gt;
&lt;p&gt;The editorial experience within Sanity Studio is another reason why this stack is so superior for a solo freelancer. The studio is seamlessly embedded directly into the application at a specific route, providing a real-time collaborative environment. I can manage my work posts, adjust SEO metadata, and preview my changes instantly without ever having to leave my own domain. When combined with the power of GROQ, which is Sanity’s query language, and the next-sanity client, the project can fetch only the specific data needed for each page. This keeps the site lightning-fast and responsive even as my body of work grows more complex and detailed over the coming years.&lt;/p&gt;
&lt;p&gt;Once the tech stack was finalized, I used my own Site Reliability Engineering book (fn2) to handle the scaffolding of the project. This book is a Claude skill I developed over five years to ensure quality and strict design adherence. I used the Claude Opus 4.7 model to create a detailed manifest file (fn3) that served as the blueprint for the entire application. I then connected all the essential tools and credentials into a local environment file (fn4) to prepare for the build. Claude Opus 4.7 was selected because it represents a landmark leap in AI coding ability with significantly higher resolution rates on production tasks.&lt;/p&gt;
&lt;p&gt;The performance of Opus 4.7 is backed by impressive benchmarks, showing a thirteen percent improvement over previous versions. It can run autonomously for hours, catching its own mistakes and performing proofs on systems code before even starting the writing process. I found it incredibly impressive that it could handle a full million-token context window, making it perfect for working on large and integrated codebases. It took roughly thirty minutes to create the initial version of the app, and it actually got everything right on the very first try. This success was a combination of the model’s capabilities and the specific skills I had pre-installed to guide it.&lt;/p&gt;
&lt;p&gt;The most important part of the build was the creation of custom components that power the storytelling aspect of my project case studies. I sat down and explored the OpenAI website again, opening my Obsidian vault to write down twenty-eight specific components I wanted to implement. These components needed to be tailored to my specific use cases and aligned with my love for the Apple design language. I organized these ideas with the help of Gemini 3.1 Pro, which helped me categorize them and explain their functions in simple sentences. Then I sat down without the internet to manually iterate on the design tokens and refine the visual identity.&lt;/p&gt;
&lt;p&gt;My storytelling components include things like the ChartBlock, which renders dynamic and interactive charts to prove performance gains with visual evidence. I also implemented a SandboxBlock that allows users to interact with a live code environment directly on the page. This makes my technical expertise tangible and verifiable for any potential client who wants to see the code in action. The ComparisonBlock provides an interactive before-and-after slider for images, which is the most effective way to showcase the impact of a redesign. I also added a VersusBlock to highlight winners and trade-offs between two different technical solutions to show my reasoning.&lt;/p&gt;
&lt;p&gt;Core feature components like the FeaturedGrid and ProjectCard handle the main logic and display of the portfolio&apos;s structure. The ProjectCard serves as the visual entry point for each project, using optimized thumbnails to hook the user and encourage them to read more. I also built a SearchFilter that provides real-time filtering for categories and tech tags so recruiters can find specific skills instantly. The PortableTextRenderer acts as the central orchestrator that maps the Sanity data to my React components. This system ensures that everything I write in the CMS renders perfectly as a premium and custom-styled element on the frontend.&lt;/p&gt;
&lt;p&gt;The structural foundation of the site includes components like the Navbar, which I designed to function almost like a dynamic island. This reinforces the professional and polished feel of the entire application, ensuring that the brand identity is consistent on every page. I also included a NewsletterForm to turn passive visitors into a community by allowing me to push updates directly to those interested in my work. Every part of the UI, from the buttons to the containers, follows the same structural rules to prevent any design drift. This cohesive system makes the entire site feel like a single, well-thought-out product.&lt;/p&gt;
&lt;p&gt;Once all the components were defined, I gave the final manifest to Claude and asked it to build the entire library. This process took over forty-five minutes because of the complexity of the skills involved, but the output was exceptionally good. The resulting site is not just a collection of links but a high-performance engine that showcases my work with the precision it deserves. I am proud to share this story because it represents the culmination of years of learning and a commitment to high engineering standards. It is a testament to what is possible when you combine the right tools with a clear and focused vision.&lt;/p&gt;
&lt;p&gt;Building this platform has taught me that the tools we choose are just as important as the code we write. By selecting a stack that rewards structure and performance, I have created a home for my projects that can grow alongside my career. I no longer feel the friction of a cluttered website, and I can now present my work with the same level of care that I put into the projects themselves. This journey from a messy digital garden to a streamlined project portal has been one of the most rewarding experiences of my professional life. It proves that with enough focus, you can build a digital presence that truly reflects your standards.&lt;/p&gt;
&lt;p&gt;I hope this detailed breakdown of my process provides some insight into how modern portfolios can be engineered for both beauty and utility. The combination of Next.js, Sanity, and advanced AI models has allowed me to reach a level of quality that would have been impossible just a few years ago. By treating my portfolio as a product, I have ensured that I am ready for the next chapter of my career as a freelancer. This site is now the definitive home for my vision, and I look forward to seeing how it evolves as I continue to build and document new things. Thank you for following along with this little story of how I built my new home.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;(fn1)&lt;/strong&gt; SRE standards refer to my personal Site Reliability Engineering benchmarks for uptime, code modularity, and deployment safety.&lt;br&gt;
&lt;strong&gt;(fn2)&lt;/strong&gt; The SRE book is a custom knowledge base and Claude skill developed over five years to enforce best practices.&lt;br&gt;
&lt;strong&gt;(fn3)&lt;/strong&gt; The Claude.md file serves as a comprehensive system prompt and project blueprint for AI-assisted development.&lt;br&gt;
&lt;strong&gt;(fn4)&lt;/strong&gt; The .env.local file stores the necessary API keys and environment variables required to link the frontend with Sanity and Vercel.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Better typography, built automatically</title>
<link>https://www.omrajguru.com/devnotes/typesnap</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/typesnap</guid>
<pubDate>Fri, 24 Apr 2026 18:52:00 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>Eliminate font-induced layout shifts and manual preloading with a build tool that automatically detects, matches, and optimizes your typography.</description>
<content:encoded>&lt;p&gt;Web performance is often a game of managing trade-offs, but typography should not be one of them. For years, developers have manually balanced the visual appeal of custom fonts against the technical debt of layout shifts. To solve this properly, you generally have to coordinate three distinct parts: early preloading, font-display strategies, and metric-matched fallback stacks. Getting these right is a repetitive and error-prone process that persists even in modern frameworks.&lt;/p&gt;
&lt;p&gt;TypeSnap is a new command-line tool and build plugin designed to handle this entire workflow through static analysis. It scans your project to identify every font you use, whether they are hosted locally, pulled from Google Fonts, or declared in your Tailwind configuration. Once it understands your font landscape, it generates the necessary assets to ensure your site loads efficiently and remains visually stable while files are being fetched.&lt;/p&gt;
&lt;p&gt;The tool focuses on three specific outputs. It creates preload tags so the browser knows to prioritize font files the moment a user lands on your site. It also ensures every font declaration includes the appropriate display rules to prevent invisible text. Finally, it generates a CSS fallback stack using a database of font metrics. This adjusts the size and spacing of system fonts so they occupy the same space as your custom brand fonts, effectively eliminating the jump in layout when the primary font finishes loading.&lt;/p&gt;
&lt;p&gt;TypeSnap is not a runtime library or a font hosting service. It operates entirely during your build process, meaning it adds no weight to your production bundle. It is built to work seamlessly with Vite and Next.js, and it can even be integrated into your continuous integration pipeline to prevent new font issues from reaching your users. By automating the technical requirements of web typography, it lets you focus on design without worrying about the performance cost.&lt;/p&gt;
&lt;p&gt;This project is entering its final stages of preparation and will be available for general use in three days. By shifting the burden of font optimization from the developer to the build tool, TypeSnap makes a stable and fast web the default state for your project.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Building My Own AI-Powered iCloud</title>
<link>https://www.omrajguru.com/devnotes/foundationdb</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/foundationdb</guid>
<pubDate>Mon, 20 Apr 2026 00:52:00 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>Tired of juggling multiple free-tier accounts, I engineered a custom, hybrid-cloud backend-as-a-service using Apple’s database of choice, FoundationDB, and integrated it directly into my AI coding workflow via a private MCP server.</description>
<content:encoded>&lt;p&gt;As a developer with an ever-growing portfolio, I reached a breaking point with &quot;Free Tier sprawl.&quot; Juggling a dozen Supabase accounts for a dozen different projects wasn&apos;t just messy—it was inefficient. To solve this, I decided to build my own unified backend UI inspired by Supabase but powered by FoundationDB (FDB). Choosing FDB was a nod to my love for Apple’s engineering; it’s the same distributed transactional engine they use to power iCloud. By building my own &quot;layer&quot; on top of FDB, I’ve gained the ability to scale my projects indefinitely without ever hitting a subscription ceiling.&lt;/p&gt;
&lt;p&gt;The infrastructure is where this project truly breathes, utilizing a sophisticated dual-hosted hybrid cloud model. I host the core data storage and heavy-duty processing in my home lab to maintain total ownership and zero costs, while leveraging AWS to host the public-facing UI and API gateway. This setup gives me the best of both worlds: the raw privacy and economy of a self-hosted environment combined with the global uptime and low-latency edge presence of a major cloud provider. It’s a rock-solid foundation that feels as snappy as a native Apple service.&lt;/p&gt;
&lt;p&gt;The real &quot;secret sauce&quot; of this build is the integration of a custom Model Context Protocol (MCP) server. I’ve developed specific &quot;skills&quot; for my private MCP server that allow Claude Code to interact directly with my FoundationDB instance. While I’m coding, the AI isn’t just guessing—it has the power to read schemas, push updates, and perform live read/write operations directly to my database. This creates a seamless loop where the AI understands my data layer as deeply as I do, turning my IDE into a command center for my entire project ecosystem.&lt;/p&gt;
&lt;p&gt;This &quot;massive win&quot; is more than just a way to save on hosting fees; it’s a customized developer experience tailored to how I think and build. By combining the legendary reliability of FoundationDB with a hybrid AWS-home setup and AI-driven automation, I’ve built a platform that can grow with me for years. I no longer spend time configuring infrastructure for new ideas—I just tell my AI what to build, and the foundation is already there, waiting.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Introducing the HIG Compliance Auditor for Claude Code</title>
<link>https://www.omrajguru.com/devnotes/auditor</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/auditor</guid>
<pubDate>Tue, 07 Apr 2026 09:20:00 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>The HIG Compliance Auditor is a custom skill for Claude Code designed to automate the technical review of software projects against Apple’s Human Interface Guidelines.</description>
<content:encoded>&lt;p&gt;The HIG Compliance Auditor is a custom skill for Claude Code designed to automate the technical review of software projects against Apple’s Human Interface Guidelines. This skill enables Claude to perform deep scans of local repositories to identify design violations, generate structured compliance reports, and apply remediation changes directly within the terminal environment.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Functional Overview of the Skill&lt;/h3&gt;
&lt;p&gt;The HIG Compliance Auditor functions as a specialized extension for Claude Code that focuses on design system integrity. By adding this skill to your development environment, you provide Claude with the specific logic and documentation required to audit Swift, SwiftUI, UIKit, and web technologies. The tool identifies inconsistencies in typography, color systems, and layout by cross-referencing your code against official Apple standards.&lt;/p&gt;
&lt;p&gt;This skill covers the full spectrum of Apple platforms, including iOS, iPadOS, macOS, watchOS, tvOS, and visionOS. It also incorporates checks for App Store Review Guidelines and AI transparency requirements. By integrating these checks directly into the Claude Code workflow, the auditor removes the guesswork associated with manual compliance checks and reduces the risk of rejection during the App Store review process.&lt;/p&gt;
&lt;h3&gt;Technical Capabilities and Remediation&lt;/h3&gt;
&lt;p&gt;When initiated, the auditor generates a detailed report that categorizes compliance issues into specific severity tiers. This allows developers to prioritize critical failures that could impact user experience or platform approval. The skill enables Claude to analyze complex interface elements, such as Liquid Glass materials and spatial layout principles, to ensure a high-fidelity implementation of the Apple ecosystem&apos;s visual language.&lt;/p&gt;
&lt;p&gt;A primary feature of this skill is the ability to perform automated remediation. Claude suggests multiple fix options and, upon user approval, applies these changes directly to the source code. To maintain technical transparency, every modification includes an inline attribution that references the exact section of the Human Interface Guidelines being addressed.&lt;/p&gt;
&lt;h3&gt;Installation and Integration&lt;/h3&gt;
&lt;p&gt;I developed this skill to transition design auditing from a manual documentation search to an automated workflow within Claude Code. Because the tool is a custom skill, it allows Claude to act as a persistent reference guide for maintaining platform-specific standards throughout the development lifecycle.&lt;/p&gt;
&lt;p&gt;The HIG Compliance Auditor is available for installation via the repository at &lt;a href=&quot;https://github.com/omrajguru05/hig-compliance-auditor&quot;&gt;github.com/omrajguru05/hig-compliance-auditor&lt;/a&gt;. By cloning the repository and adding the skill to your Claude Code configuration, you can begin running comprehensive audits directly inside your terminal to ensure your project meets Apple’s rigorous design and accessibility standards. You can also view more of my projects and tools at &lt;a href=&quot;https://om.bearblog.dev/projects/&quot;&gt;https://om.bearblog.dev/projects/&lt;/a&gt;.&lt;/p&gt;</content:encoded>
</item>
<item>
<title>WebDNA: A structured interface for AI agents</title>
<link>https://www.omrajguru.com/devnotes/interface</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/interface</guid>
<pubDate>Mon, 06 Apr 2026 11:27:00 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>Every website currently forces AI tools to guess how they work. WebDNA provides a zero-configuration standard for Next.js projects to share their architecture, design tokens, and component logic in a machine-readable format.</description>
<content:encoded>&lt;p&gt;When I watch an AI agent or a coding tool interact with a website today, the process feels inefficient. These models are essentially forced to squint at raw HTML and minified JavaScript bundles while attempting to reverse-engineer the original intent of the developer. They miss the relationship between components, they lose the nuances of brand colors, and they struggle to understand the shape of underlying APIs. I built WebDNA to solve this by creating a bridge between the way humans write code and the way machines need to consume it.&lt;/p&gt;
&lt;p&gt;The core idea is a manifest that lives at a predictable location on your server. By integrating directly into the Next.js build process, WebDNA automatically scans your project and generates a blueprint of your site. It looks at your route tree, extracts design tokens from your Tailwind configuration, and maps out your component hierarchy. This happens without requiring any manual documentation from the developer. It turns the implicit knowledge stored in your codebase into an explicit, structured briefing for any AI that visits your site.&lt;/p&gt;
&lt;p&gt;This system moves beyond existing solutions like sitemaps or basic text files. While those tools offer a list of URLs or high-level summaries, they do not explain the design system or the specific data requirements of a dynamic route. WebDNA provides that missing context. It allows a developer to define which parts of a site are private and which components serve specific roles, ensuring that when an AI tool accesses the site, it does so with a full understanding of the constraints and the brand guidelines.&lt;/p&gt;
&lt;p&gt;Security and privacy are foundational to this standard. The manifest is a static JSON file that cannot execute code and is read-only by design. I have included features like element-level exclusion, where a simple attribute can hide specific sections of a page from the AI manifest. This ensures that developers remain in total control of what information is shared. It is about providing consent-based, structured access rather than leaving AI tools to scrape whatever they can find.&lt;/p&gt;
&lt;p&gt;My goal with WebDNA is to make the web more accessible to the next generation of software tools. By making the architecture of a site discoverable, we reduce the friction and errors that occur when AI tries to navigate or modify web projects. It is a simple addition to a configuration file that provides a significant upgrade in how machines perceive and interact with the work we build. Information about the package and the specification is available on GitHub and through the official documentation.&lt;/p&gt;
&lt;p&gt;Official documentation: &lt;a href=&quot;https://webdna.omraj.guru/&quot;&gt;webdna.omraj.guru&lt;/a&gt;&lt;/p&gt;</content:encoded>
</item>
<item>
<title>I Am Building WebDNA: A Zero-Config AI Context Standard for the Web</title>
<link>https://www.omrajguru.com/devnotes/webdna</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/webdna</guid>
<pubDate>Wed, 01 Apr 2026 18:37:00 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>Every AI agent that touches your website is flying blind. It squints at raw HTML, guesses your component structure, and forces you to re-explain your own project from scratch every single session. I got tired of that problem, so I decided to build the fix.</description>
<content:encoded>&lt;h2&gt;The Problem I Could Not Ignore&lt;/h2&gt;
&lt;p&gt;I spend a significant amount of my development time working with agentic tools. Claude Code, Cursor, Windsurf -- these tools are genuinely useful, but they share a fundamental flaw: they have no structured understanding of the website they are working on. Every new session, I find myself doing the same thing. Explaining the route structure. Pasting in component trees. Describing the brand language. Pointing out which API endpoints exist and what they expect.&lt;/p&gt;
&lt;p&gt;This is not a workflow problem. It is an infrastructure problem. The web has no standard way to hand an AI agent a structured briefing about a website before it starts working. And that missing layer is costing developers real time, every single day.&lt;/p&gt;
&lt;p&gt;The existing standards do not solve this. &lt;code&gt;llms.txt&lt;/code&gt;, proposed as an AI-friendly content layer, operates closer to &lt;code&gt;robots.txt&lt;/code&gt; -- it tells AI what it can read, but gives it no understanding of the site&apos;s structure, components, or design system. &lt;code&gt;sitemap.xml&lt;/code&gt; handles page discovery for search crawlers, not semantic understanding. MCP (Model Context Protocol) is a powerful protocol that has seen strong adoption across Claude, OpenAI, and Google Gemini in 2025 and into 2026, but it requires a custom server per project -- a setup cost that is simply too high for most developers building standard websites and apps. OpenAPI specs cover API surfaces but say nothing about UI, brand, or layout.&lt;/p&gt;
&lt;p&gt;There is a gap. A significant one. And I want to fill it.&lt;/p&gt;
&lt;h2&gt;What WebDNA Is&lt;/h2&gt;
&lt;p&gt;WebDNA is a build-time generated, framework-native manifest served at a standardised URL that gives any AI agent a complete, structured briefing about a website before it touches anything.&lt;/p&gt;
&lt;p&gt;The analogy I keep coming back to: when a new designer joins your team, you hand them a brand guidelines document before they open Figma. You do not make them reverse-engineer the design system from the live site. Right now, every AI that works on your codebase has to do exactly that -- reverse-engineer everything from raw HTML and scattered source files. WebDNA is that brand guidelines document, auto-written by your framework on every single build.&lt;/p&gt;
&lt;p&gt;The core principles I am designing around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zero config by default.&lt;/strong&gt; It works out of the box. No setup, no YAML, no configuration file required to get started.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always in sync.&lt;/strong&gt; Because it is generated directly from your build process, it cannot go stale. The moment your code changes, your WebDNA changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Framework-native.&lt;/strong&gt; This is not a file you write manually. It is a file your framework produces.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consent-first.&lt;/strong&gt; Private routes, auth-gated content, and dynamic data are never exposed without explicit developer consent and user-initiated authorization flows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read-only, always.&lt;/strong&gt; AI agents can read WebDNA. They cannot write to it. This is a core security principle, not a limitation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open standard.&lt;/strong&gt; No vendor lock-in. Any framework should be able to implement it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What the Output Looks Looks Like&lt;/h2&gt;
&lt;p&gt;WebDNA is a JSON file served at &lt;code&gt;/.well-known/webdna.json&lt;/code&gt;. Here is a representative example of what it looks like for a portfolio site:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;meta&quot;: {
    &quot;name&quot;: &quot;My Portfolio&quot;,
    &quot;description&quot;: &quot;Personal portfolio and blog by Om Rajguru&quot;,
    &quot;version&quot;: &quot;1.0.0&quot;,
    &quot;generatedAt&quot;: &quot;2026-04-01T12:00:00Z&quot;,
    &quot;tier&quot;: &quot;custom&quot;
  },
  &quot;brand&quot;: {
    &quot;colors&quot;: {
      &quot;primary&quot;: &quot;#0F172A&quot;,
      &quot;accent&quot;: &quot;#6366F1&quot;,
      &quot;background&quot;: &quot;#FFFFFF&quot;,
      &quot;text&quot;: &quot;#1E293B&quot;
    },
    &quot;typography&quot;: {
      &quot;heading&quot;: &quot;Cal Sans&quot;,
      &quot;body&quot;: &quot;Inter&quot;
    },
    &quot;tone&quot;: &quot;Professional, minimal, direct&quot;
  },
  &quot;routes&quot;: {
    &quot;/&quot;: {
      &quot;type&quot;: &quot;static&quot;,
      &quot;description&quot;: &quot;Homepage with hero section and featured work grid&quot;
    },
    &quot;/blog/[slug]&quot;: {
      &quot;type&quot;: &quot;dynamic&quot;,
      &quot;dataSource&quot;: &quot;/api/posts&quot;,
      &quot;schema&quot;: {
        &quot;title&quot;: &quot;string&quot;,
        &quot;body&quot;: &quot;richtext&quot;,
        &quot;author&quot;: &quot;string&quot;,
        &quot;publishedAt&quot;: &quot;date&quot;,
        &quot;tags&quot;: &quot;string[]&quot;
      }
    },
    &quot;/dashboard&quot;: {
      &quot;type&quot;: &quot;private&quot;,
      &quot;requiresAuth&quot;: true,
      &quot;auth&quot;: &quot;oauth2&quot;,
      &quot;scopes&quot;: [&quot;read:profile&quot;, &quot;read:orders&quot;],
      &quot;exclude&quot;: true
    }
  },
  &quot;components&quot;: {
    &quot;Navbar&quot;: &quot;Top navigation bar with logo and 4 page links&quot;,
    &quot;HeroSection&quot;: &quot;Full-width hero with headline, subtext, and CTA button&quot;,
    &quot;BlogCard&quot;: &quot;Card showing post title, date, tag, and excerpt&quot;,
    &quot;Footer&quot;: &quot;Links, social icons, and copyright notice&quot;
  },
  &quot;api&quot;: {
    &quot;/api/posts&quot;: {
      &quot;method&quot;: &quot;GET&quot;,
      &quot;description&quot;: &quot;Returns all published blog posts&quot;,
      &quot;example_request&quot;: &quot;/api/posts?limit=10&amp;#x26;tag=design&quot;,
      &quot;example_response&quot;: {
        &quot;title&quot;: &quot;Building a Design System&quot;,
        &quot;author&quot;: &quot;Om Rajguru&quot;,
        &quot;publishedAt&quot;: &quot;2026-03-01&quot;,
        &quot;slug&quot;: &quot;building-a-design-system&quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a single file, an AI agent gets the site name and description, the complete color palette and typography, every route and its type (static, dynamic, or private), the data schema for dynamic routes, every component with a plain-English description, and API endpoints with real usage examples.&lt;/p&gt;
&lt;p&gt;This is everything I would tell a new developer on my first day pairing with them. Structured, machine-readable, and always current.&lt;/p&gt;
&lt;h2&gt;Two Tiers, One Principle&lt;/h2&gt;
&lt;p&gt;WebDNA has two operating modes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WebDNA Auto&lt;/strong&gt; is the default. No configuration required. It generates on every build, captures everything public, and gets served at &lt;code&gt;/.well-known/webdna.json&lt;/code&gt;. For portfolios, blogs, landing pages, and marketing sites, this is the only thing you ever need.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WebDNA Custom&lt;/strong&gt; is for developers who need granular control. You get page-level exclusions through a config file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// webdna.config.js
module.exports = {
  webdna: {
    exclude: [&quot;/pricing&quot;, &quot;/internal&quot;],
    privateRoutes: [&quot;/dashboard&quot;, &quot;/settings&quot;]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And element-level exclusions through a single HTML attribute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;#x3C;p data-webdna=&quot;exclude&quot;&gt;
  This paragraph is completely invisible to any AI reading WebDNA.
&amp;#x3C;/p&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Custom output lives at &lt;code&gt;/.well-known/webdna-custom.json&lt;/code&gt;. AI agents check for the Custom version first and fall back to Auto if it does not exist. The fallback logic is simple, predictable, and requires nothing from the developer.&lt;/p&gt;
&lt;h2&gt;Static File or Live API Route&lt;/h2&gt;
&lt;p&gt;One decision I spent considerable time thinking through is how WebDNA behaves on sites where content is dynamic. A blog that pulls posts from a CMS cannot produce a complete picture at build time. A SaaS app with per-tenant route structures cannot serve a single static file for all users.&lt;/p&gt;
&lt;p&gt;The solution I landed on mirrors how Next.js handles &lt;code&gt;sitemap.xml&lt;/code&gt;. WebDNA is static by default. When the framework detects dynamic data sources, it automatically becomes a live API route that reflects the current state of the site on every request. For Next.js ISR projects, it revalidates on the configured interval. For full SaaS apps with multi-tenant architectures, it becomes a tenant-scoped endpoint served per subdomain:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;acme.yourapp.com/.well-known/webdna.json
google.yourapp.com/.well-known/webdna.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each tenant sees only their own routes and data. Cross-tenant leakage is impossible by design, because each endpoint is scoped to the authenticated session.&lt;/p&gt;
&lt;p&gt;The developer never selects the mode manually. The framework detects it.&lt;/p&gt;
&lt;h2&gt;Private Routes and the Auth Model&lt;/h2&gt;
&lt;p&gt;One of the harder problems in this space is how AI agents should handle auth-gated content. The two approaches people use today are both bad: either share credentials with the AI tool (insecure) or block AI entirely from private routes (unusable).&lt;/p&gt;
&lt;p&gt;WebDNA takes a different path. Private routes declare their OAuth 2.0 scopes directly in the manifest:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&quot;/dashboard&quot;: {
  &quot;type&quot;: &quot;private&quot;,
  &quot;requiresAuth&quot;: true,
  &quot;auth&quot;: &quot;oauth2&quot;,
  &quot;scopes&quot;: [&quot;read:profile&quot;, &quot;read:orders&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When an AI agent encounters a private route, it initiates a consent prompt. The user explicitly approves access. The agent receives a scoped, time-limited token. The token expires. No persistent access without re-consent. No credentials stored in or transmitted through the WebDNA file.&lt;/p&gt;
&lt;p&gt;This is the same pattern as granting a third-party app access to your Google Calendar or GitHub repositories. It is well-understood, widely implemented, and secure. I am not inventing a new auth model. I am applying an established one to a problem where it is currently absent.&lt;/p&gt;
&lt;h2&gt;The Read-Only Guarantee&lt;/h2&gt;
&lt;p&gt;I want to address this directly because it will come up: WebDNA is read-only, and that is permanent.&lt;/p&gt;
&lt;p&gt;Allowing AI agents to write back to WebDNA would introduce prompt injection risk (a malicious agent could embed instructions that manipulate other AI agents reading the file later), silent drift (descriptions diverge from actual code without the developer knowing), and a fundamental collapse of trust in the standard itself. The entire value of WebDNA rests on it being a reliable, developer-authored source of truth. Write access destroys that.&lt;/p&gt;
&lt;p&gt;If AI feedback on WebDNA quality is ever desirable, it will go through a separate, opt-in suggestions endpoint that requires explicit developer approval before anything changes -- surfaced as a pull request, never auto-merged. The Dependabot model. AI opens a PR, developer merges it. Feedback yes, write access no.&lt;/p&gt;
&lt;h2&gt;The Validator&lt;/h2&gt;
&lt;p&gt;WebDNA ships with a linter from day one. Run it with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx webdna lint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It catches issues like routes marked private with no auth scope declared, components with no description, dynamic routes with no schema, and &lt;code&gt;data-webdna&lt;/code&gt; attributes on non-existent elements. Think ESLint, but for your WebDNA configuration. It will integrate with VS Code for inline squiggles, CI/CD pipelines for build-time enforcement, and pre-commit hooks.&lt;/p&gt;
&lt;h2&gt;How WebDNA Compares to What Exists Today&lt;/h2&gt;
&lt;p&gt;I want to be honest about the landscape here. There are real solutions trying to solve adjacent problems. This is how I see the current state:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;&lt;code&gt;sitemap.xml&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;MCP&lt;/th&gt;
&lt;th&gt;WebDNA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Purpose&lt;/td&gt;
&lt;td&gt;Page discovery&lt;/td&gt;
&lt;td&gt;AI content permissions&lt;/td&gt;
&lt;td&gt;Structured data access&lt;/td&gt;
&lt;td&gt;Full AI website briefing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup required&lt;/td&gt;
&lt;td&gt;Auto in Next.js&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Server per project&lt;/td&gt;
&lt;td&gt;Zero config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Component info&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brand and design tokens&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic content schema&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live API examples&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth and private routes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-tenant support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Element-level exclusion&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validator&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Always in sync&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (manual)&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write access&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;No (by design)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;MCP is genuinely good at what it does, and its adoption has been rapid across 2025. But it is designed for structured, permissioned data access at an infrastructure level. WebDNA is designed for the much simpler, much more common case: a developer who wants their AI coding tools to understand their website without setting up a server. These are complementary tools, not competing ones.&lt;/p&gt;
&lt;h2&gt;The Roadmap&lt;/h2&gt;
&lt;p&gt;Development is starting now. Here is the plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1&lt;/strong&gt; is the Next.js Plugin MVP. I am building &lt;code&gt;next-webdna&lt;/code&gt; as a standalone NPM package with a single activation flag (&lt;code&gt;webdna: true&lt;/code&gt; in &lt;code&gt;next.config.js&lt;/code&gt;), auto-generation from the route tree and Tailwind tokens at build time, automatic static/dynamic mode detection, and the published open spec for the JSON format.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2&lt;/strong&gt; adds WebDNA Custom: the config file, element-level exclusions, and the separate custom output endpoint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3&lt;/strong&gt; introduces live API route mode for dynamic sites, OAuth scope declaration per private route, and CMS adapter plugins for Contentful, Sanity, and Notion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4&lt;/strong&gt; handles multi-tenant support with subdomain and tenant-ID based scoping and full per-session data isolation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5&lt;/strong&gt; ships the validator: the CLI tool, VS Code extension, and CI/CD integration guide.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 6&lt;/strong&gt; is the push for broader adoption: an RFC to Next.js and Vercel for native integration, adapters for SvelteKit, Astro, and Nuxt, and direct outreach to the teams building Cursor, Windsurf, Claude Code, and GitHub Copilot to build native WebDNA reading into their context engines.&lt;/p&gt;
&lt;h2&gt;What Comes Next&lt;/h2&gt;
&lt;p&gt;The project is private during development. I am building in the open in the sense that I am documenting the thinking here, but the repository will go public when Phase 1 reaches a usable state. If you want to follow along, this blog is the place to do it.&lt;/p&gt;
&lt;p&gt;I am also genuinely interested in feedback on the spec. If you work on an agentic tool and have thoughts on what context you wish you had when working on a website, I would like to hear from you. If you are building on Next.js and have a use case this does not cover, same thing. The spec is a draft. The best time to shape it is before the first line of plugin code ships.&lt;/p&gt;
&lt;p&gt;The web deserves a proper AI context layer. I am going to build one.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;WebDNA is an original concept. Development started April 2026.&lt;/em&gt;&lt;/p&gt;</content:encoded>
</item>
<item>
<title>Is Your Project Ready to Launch? I Built a Skill to Find Out</title>
<link>https://www.omrajguru.com/devnotes/launch</link>
<guid isPermaLink="true">https://www.omrajguru.com/devnotes/launch</guid>
<pubDate>Wed, 01 Apr 2026 03:35:25 GMT</pubDate>
<dc:creator>Om Rajguru</dc:creator>
<description>Shipping fast is great. Shipping ready is better. Here&apos;s how I stopped guessing and started knowing.</description>
<content:encoded>&lt;p&gt;Shipping fast is great. Shipping ready is better. Here&apos;s how I stopped guessing and started knowing.&lt;/p&gt;
&lt;p&gt;I used to think I had a solid launch checklist. It lived in a doc somewhere, it had checkboxes, and I told myself I would actually use it. Spoiler: I did not always use it. Features would go out missing a monitoring alert, or a README that said &quot;TODO,&quot; or a rollback plan that existed only in my head. Every time, the feeling was the same. That quiet dread of realizing something got missed after it was already live.&lt;/p&gt;
&lt;p&gt;So I built something to fix that. Launch Readiness is a skill I created to make pre-launch checks feel less like homework and more like a conversation. Instead of digging through a doc I inevitably forgot to update, I can just ask. It walks through the things that actually matter before a release: documentation, monitoring, rollback strategy, stakeholder sign-off, and more. It does not let me skip ahead. It asks, it listens, and it flags what is missing.&lt;/p&gt;
&lt;p&gt;What I love most about it is that it changed how my team thinks about launches. We stopped treating readiness as a formality and started treating it as a real conversation. The skill is not a gatekeeper. It is more like a thoughtful colleague who asks the right questions at the right time, and genuinely wants the launch to go well.&lt;/p&gt;
&lt;p&gt;The best part is that you can try it yourself right now. Setup is straightforward, and within a few minutes you will have a launch process that actually holds up under pressure.&lt;/p&gt;
&lt;p&gt;Launching something you built is exciting. I want that excitement to last past day one. This is my small contribution to making that happen.&lt;/p&gt;</content:encoded>
</item>
</channel>
</rss>