<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Rithwik Shetty</title><description>Notes and essays from Rithwik Shetty on building software and working with AI.</description><link>https://rithwikshetty.com/</link><language>en</language><item><title>Relying on AI without losing yourself</title><link>https://rithwikshetty.com/articles/2026-03-22-relying-on-ai-without-losing-yourself/</link><guid isPermaLink="true">https://rithwikshetty.com/articles/2026-03-22-relying-on-ai-without-losing-yourself/</guid><description>AI outages reveal how much thinking we&apos;ve outsourced, and why resilience means using the speed without losing the skill.</description><pubDate>Sun, 22 Mar 2026 00:00:00 GMT</pubDate><content:encoded>Andrej Karpathy tossed out the phrase “intelligence brownout” at an [event](https://www.youtube.com/watch?v=LCEmiRjPEtQ) a while ago to describe what happens when AI systems go down. It’s one of those terms that sounds slightly ridiculous and yet weirdly spot‑on. Because I’ve felt it. Not a total blackout (I don’t suddenly forget how to code or write), but definitely a flicker. Productivity stutters, confidence wobbles, and I find myself staring at my screen like someone just unplugged a part of my brain.

One of the bigger reminders hit [last June](https://www.marketwatch.com/story/chatgpt-outage-shows-just-how-many-people-are-using-ai-at-work-6dcf482f), when ChatGPT went down for over 10 hours. Google searches for &quot;OpenAI status&quot; spiked in the US with over 500,000 queries. OpenAI’s own [post-mortem](https://status.openai.com/incidents/01JXCAW3K3JAE0EP56AEZ7CBG3/write-up) says a *routine OS update* on cloud GPU hosts knocked many nodes off the network, pushing ChatGPT’s error rate to ~35% (API ~25%) at peak. Depending on who you ask, the disruption lasted about 10-15 hours.

Sure, AI makes us faster. But more quietly, it starts making calls we used to make. Brownouts reveal where those calls have drifted, and whether we can still operate when the lights dim.

 

### What brownouts reveal

People love to say AI is just another tool. But that’s a lazy comparison. Calculators replaced arithmetic, compilers replaced translation, search replaced retrieval. Apart from automating a task, AI seeps into how you approach problems, how you weigh options, how you decide what matters. When it goes down (*which will happen from time to time*), yes you lose speed; but more importantly, you notice how much of your own judgment you’ve handed over without realising.

&lt;Callout type=&quot;info&quot;&gt;
In the 2025 [Stack Overflow survey](https://survey.stackoverflow.co/2025/ai), **84%** of developers are using or planning to use AI tools, and **51%** of pros say they use them **daily**.
&lt;/Callout&gt;

### The lazy dev’s dream (and nightmare)

Before AI coding assistants, debugging was this messy ritual: Google the error message, skim Stack Overflow threads, open twelve tabs of docs, copy‑paste until something half‑worked. Ugly, yes. But it forced you to actually understand what was happening. You had to learn, whether you liked it or not.

Enter AI: now I can just explain the issue in plain English. The model suggests fixes, writes the code, handles syntax, edge cases, boilerplate. I don’t need ten tabs open. I don’t even need to remember the exact method signature. It feels like having a senior dev permanently on call: patient, tireless, and very confident.

But a lot of the time, that “senior dev” is drunk. When I was learning frontend, I leaned hard on AI. I’d ask for a feature and get back 300‑line code dumps. I didn’t know enough to question it, so I shipped it. Weeks later, once I had a clearer handle on component architecture, state management, and performance budgets, I realised my codebase was packed with extra dependencies and messy patterns. Cleaning it up took forever. AI didn’t save me time; it just pushed the pain down the road.
That’s a nightmare scenario. You get speed today at the cost of long-term debt you don’t even see piling up.

On the flip side, it’s also been a &quot;teacher&quot;. I had no idea about small accessibility details (managing focus traps, announcing dynamic state changes) until the model pointed them out. That nudge opened up a corner of frontend craft I’d been skipping. It felt like a mentor dropping the exact UI detail I didn’t know I was missing.

So which is it, crutch or mentor? Honestly, in the most cliché way possible, it’s both. AI can make you smarter or lazier. It depends on whether you treat it as autopilot or as a co‑pilot. If you just accept whatever it spits out, you’ll atrophy. If you let it point the way and then dig deeper yourself, you’ll level up faster than you thought possible.

&lt;AIDuality /&gt;

### The cycle of dependency

I see it less as a straight line and more like a wave. Productivity shoots up when you first plug AI into your workflow, then dips when you hit the messy side effects, then stabilizes once you learn how to manage it. And the cycle keeps repeating.

&lt;ProductivityCurve /&gt;

When I say “productivity” here, treat it as your yardstick: whatever you use to tell if the work is going well: shipping pace, how clean reviews feel, how little rework you do, or something else entirely.

**Stage 1.** At the start, AI just makes everything feel faster. You’re moving quickly, skipping over boilerplate, and shipping in days what would’ve taken weeks. But then reality shows up. The code is messy, the dependencies are bloated, and you don’t really understand why it works. Productivity slumps, and not because you’ve lost the tool: you have to stop and untangle what it produced. That’s when you start learning the quirks of the model, the patterns you should accept, and the ones you should immediately rewrite. After that learning curve, your baseline actually shifts upward.

**Stage 2.** Right. Things look good again. Until your AI decides to take a day off. When the system you’ve been leaning on suddenly disappears, your confidence drops along with your speed. You realise how much of the “thinking” you’d quietly outsourced. The slump is steep because you don’t just have to keep coding; you have to rebuild your own decision‑making muscles. For some people, this drop lands them almost all the way back at Section 1. For others, it’s smaller but still painful. The severity of that cliff says a lot about how resilient (or fragile) your relationship with AI has become.

**Stage 3.** Eventually you recover. You adapt to the AI outage, rebuild some of your own intuition, and move forward again. It looks like the “old” cycle of programming: progress, stall, debug, repeat. But it’s not a full reset as you now carry whatever new skills you picked up during the outage. That means your long‑term baseline keeps trending upward, even if the slope is jagged.

Look at the dashed line in the chart. That’s the resilience path: an *ideal slump*. Productivity still drops when the tools go away, but not catastrophically. The outage slows you down without knocking you back to square one. That’s the version where you’ve kept enough manual reps and built enough of your own judgment that AI is a booster, not a crutch.

### The confidence problem

If Cursor vanished tomorrow, I’d still write code, just slower, crankier, and with more caffeine. The bigger risk is when you stop trusting your own judgment without the tool. If every architecture decision, bug fix, and naming choice needs AI to validate it, the outage isn’t just inconvenient. It’s destabilising.

&lt;FragilityLayers /&gt;

Developers don’t lose productivity first; they lose confidence. Confidence is what lets you tackle unfamiliar problems, make trade‑offs, and actually own your work. Brownouts sting because we’ve quietly been renting judgment instead of building it.

We used to joke about hallucinations. GPT-3.5 would invent APIs, GPT-4o would get overconfident, and you could usually spot the cracks. But as each generation improves (GPT-5.4, Claude 4.6, Gemini 3.1), the failures aren’t always obvious anymore. The code compiles, the explanation sounds airtight, the trade-off analysis feels reasonable. That’s exactly what makes the dependency more fragile. You don’t notice the flaws piling up because they’re subtle, hidden behind the polish.

And here’s the deeper question: what does that do to our *identity* as developers? A craft is partly defined by the parts you can’t outsource. If debugging intuition, naming, and problem decomposition (the actual thinking parts) are consistently handed to AI, then what exactly is “yours” in the work? When the lights flicker, you notice which parts of your craft you still own, and which parts you’ve quietly outsourced.

The danger isn’t that AI literally steals our intelligence. The danger is that we confuse its convenience with our capability. We stop flexing our own judgment because the machine is so damn quick at flexing for us. And then, when the machine stutters, we realise we’ve let parts of our identity atrophy.

### The cultural divide

Not everyone even notices these brownouts. I know plenty of people who barely touch AI tools. For them, outages are irrelevant. At most, they might complain when a service they use hiccups because some hidden AI dependency failed.

Meanwhile, AI-native users (devs glued to Copilot and Cursor, students writing essays with ChatGPT, marketers drafting campaigns) feel like their entire workflow just flatlined. That gap is striking. For one group, brownouts are a mild inconvenience. For the other, they’re existential.

&lt;OutageImpact /&gt;

The same outage exposes a [gap](https://survey.stackoverflow.co/2025/ai) in how people experience their own skills. And that gap will shrink as AI seeps into everything. Even people who “don’t use AI” will feel it indirectly.

### Habits that help

Having used AI-assisted coding tools for a few years, I’d recommend these rules. But honestly, I often ignore them myself and just “go with the vibes”:
- Decide first, ask AI second. Draft your own plan, API shape, or naming before you prompt.
- Manual reps on basics weekly (no AI). Write a small function, debug with docs only.
- Write a one‑paragraph rationale before generating code: why this approach, what trade‑offs.
- Treat AI output like a PR: diff it, test it, replace boilerplate with your patterns.
- Keep a debt log for AI‑introduced dependencies and patterns to revisit.

In other words: habits that keep you near the dotted line, not the cliff.

### Living with the flicker
I don’t think AI dependency is bad. It’s inevitable. Humans have always extended their muscles and memory with tools. What’s different now is that we’re extending our reasoning. That’s why outages feel personal; like someone dimmed the lights in your head.

Dependency only turns toxic when we stop thinking for ourselves. That doesn’t mean shunning AI or pretending to be some manual‑only purist. The point is to draw the line: let AI accelerate the grunt work, but don’t outsource the judgment that defines your craft. Brownouts are reminders to check where that line is, and whether it’s slipped.

If you can’t code without AI, are you really coding, or just typing prompts? I don’t have a grand answer. What I do have are a handful of habits and a willingness to be slower on purpose now and then. That’s enough to make sure my name stays on the work. The outage just flickers the lights long enough to make me check where the line is.</content:encoded></item><item><title>The clever version kept losing</title><link>https://rithwikshetty.com/articles/2026-03-20-the-clever-version-kept-losing/</link><guid isPermaLink="true">https://rithwikshetty.com/articles/2026-03-20-the-clever-version-kept-losing/</guid><description>I built an AI workspace for my colleagues. Every time I reached for the clever option, it lost to the boring one.</description><pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate><content:encoded>I built an AI workspace for my colleagues: a chat interface wired up to our own documents, so you can ask a question and get an answer grounded in the source material. Useful, and fairly boring on paper. I was the only developer on it, with colleagues waiting to use it and stakeholders asking how it was going.

Going in, I assumed the hard parts would be technical: the model, the retrieval, keeping the code from buckling under its own weight. That&apos;s not where the pain came from. Almost all of it came from moments where I had a boring option and a clever one, and picked the clever one. It cost me every time. What follows is where that happened, and what I&apos;d tell myself if I could start again.

## I lived on Streamlit for seven months

I started on Streamlit, like a lot of people do. You write Python, add a few decorators, and you&apos;ve got a web app by the afternoon. No frontend, no API design, nothing to deploy. For proving an idea it&apos;s genuinely hard to beat. I could change a line, refresh, and show a stakeholder something working the same morning they asked for it.

Then I stayed. Six, seven months in, still on it, still patching. What began as a simple data tool had quietly become a workflow app with file uploads, sessions, background jobs, and multi-page navigation. Each addition felt reasonable on its own. Together they pushed Streamlit miles past what it was built for.

The cracks were specific. Streamlit re-runs your whole script on most interactions, which is fine until each run is firing LLM calls and shuffling state around. I was writing custom CSS to hide that it was Streamlit, hand-rolling session management before the framework supported it properly, and watching the thing wobble the moment more than a couple of people used it at once. Users would click, see nothing happen, and refresh, which kicked off the expensive work all over again. Each of those workarounds was me choosing another clever patch over the boring rewrite.

&lt;StreamlitCliff /&gt;

I knew the signs months before I acted. I was spending more time fighting the framework than building features, and people kept calling the app &quot;rough.&quot; Sunk cost was part of it: I had months of work tangled up in it, and a rewrite felt like going backwards. But the bigger problem was that the call was mine alone, and I kept not making it. I kept trying out one more feature on the prototype, waiting for traction to tell me it was time to build properly. Inside a business that signal arrives slowly. Adoption is gradual, and the formal go-ahead is slower still. The right move was to stop experimenting the moment the concept felt concrete, build the real thing, and ask for forgiveness later.

The rewrite to a proper web application took a while and paid off the moment it landed. Proper loading states, real error handling, an interface that didn&apos;t feel like a demo. The lesson is dull and I&apos;ll repeat it anyway: use a prototyping tool to prove the idea, and once the concept is concrete, treat what you&apos;ve built as scaffolding and move on.

## My RAG pipeline lost to a single call

The retrieval engine behind the chat went through the same cycle, and it&apos;s the one that still stings. I&apos;d read the papers on multi-step reasoning and watched the demos where an agent &quot;thinks&quot; its way through a hard question. So instead of plain retrieval and generation, I built a pipeline: retrieve, analyse the gaps, retrieve again to fill them, synthesise, format. Five steps, each its own LLM call, each with its own prompt and its own way of going wrong.

It looked great in a diagram. Stakeholders loved watching it work through a query step by step. Then a user asked a straightforward question during testing, and my clever pipeline took over a minute to return an answer that was worse than the obvious alternative. The analyse step had invented a detail. The re-retrieve step had dropped the context that actually mattered. I ran the same question through plain retrieval plus one well-prompted call and got a better answer in about fifteen seconds.

&lt;RagDetour /&gt;

I&apos;d been optimising for how sophisticated the system looked, not for whether it helped anyone. Users didn&apos;t want to watch the machine reason. They wanted an accurate answer quickly, and every extra step I&apos;d added was one more place for it to go wrong.

I still reach for agentic frameworks (LangGraph, AutoGen) for demos and quick exploration. They&apos;re good at that. In production they came straight back out.

## Getting the documents into shape

For an app whose whole job was answering questions from our documents, I spent remarkably little time thinking about the documents. I assumed that work was done because we had them: years of company documents, templates, compliance guidelines, technical specs, all sitting in repositories someone described as &quot;well-organised and up to date.&quot; The small samples looked clean.

The full corpus was a different animal. Some PDFs had real text, others were scans that needed OCR. Word files were full of embedded objects and version artefacts that wrecked retrieval. Documents marked &quot;current&quot; turned out to be superseded by newer copies stored somewhere else. Compliance lines that should have been standard had a dozen near-identical variants whose small wording differences changed their legal meaning. We spent weeks just working out which documents were actually authoritative.

Then came the part that really hurt: most answers needed context spread across different repositories. The technical requirements lived in one place, the compliance detail in another, the historical outcomes in a CRM in a different format again. We tried to fix it by indexing everything, and the more we indexed, the worse retrieval got. Any change to any document triggered re-indexing that could break search for hours.

What worked was the opposite. Define the smallest set of documents that gives a useful answer, clean that, and get retrieval solid on it before adding anything else. When we finally cut back to the core documents people actually referenced, answer quality jumped. The instinct to cover everything was the thing holding us back.

## It worked until five people used it at once

The backend underneath all of this was FastAPI, and it was fine in testing, because I tested like a polite single user: one request, wait for it, then the next. Real users don&apos;t do that. They fire off several questions at once, switch document sets, and refresh when something feels slow.

The architecture couldn&apos;t take it. Each request ran the full retrieval and generation pipeline synchronously in the main thread: vector searches, ranking dozens of chunks, embedding calls, then generation. One patient user was fine. Three people running real analyses at the same time made the server unresponsive. Polling made it worse, because slow jobs meant the frontend was constantly asking &quot;done yet?&quot;, piling cheap status checks on top of the expensive work. And background document ingestion was running on the same box, fighting live requests for the same resources.

The fix was a different shape, found mostly through desperation. Server-sent events let the server push progress to the client instead of the client asking on a loop.

&lt;StatHighlight
  stat=&quot;70%&quot;
  description=&quot;of our API traffic disappeared the day we replaced polling with server-sent events.&quot;
  detail=&quot;Same work underneath. We just stopped asking &apos;are we there yet?&apos; on a timer.&quot;
/&gt;

Celery moved the heavy retrieval and generation onto background workers, so a request could return a task ID straight away and report progress as the work ran. Redis cached the repeated queries and held session state. None of this made the underlying work faster. It made the app feel responsive while the work happened, which turned out to be the part users cared about. Moving the work onto queues had a side benefit I hadn&apos;t planned for: I could finally see it. Queue lengths and worker times showed exactly where things backed up, which the synchronous version had kept invisible. The real lesson: you design for concurrency up front. You can&apos;t bolt it on once people are already hammering the thing.

## The same mistake, away from the code

The pattern wasn&apos;t limited to architecture. Before we&apos;d even shipped a first version, we&apos;d set up Linear with story points, grooming sessions, and burndown charts. We spent something like a quarter of our time writing tickets and updating statuses for features that didn&apos;t exist yet. We once spent forty-five minutes debating the priority of a request from a single user who hadn&apos;t opened the product in weeks, while real bug reports sat in the backlog because they weren&apos;t &quot;groomed.&quot; The tickets gave us a comforting sense of progress while we built things nobody needed. Heavy process belongs to a product that has found its shape. Early on, a short list of the next few things to do was plenty.

Feedback was its own trap. Users couldn&apos;t tell me what they wanted from a workflow they&apos;d never used. They&apos;d ask for &quot;better search&quot; and then, the moment they saw a working system, discover they actually needed to trace answers back to source documents and check the original compliance wording. Fair enough. Seeing it working cut the other way too: every demo turned into a brainstorming session about contract analysis or compliance checking, which felt like enthusiasm and behaved like scope creep. And the feedback disagreed with itself. One user loved the chat interface, another wanted structured forms, a third wanted everything automated while a fourth wanted manual control over every step. You can&apos;t average those preferences into a product. Someone has to pick.

The harder problem was getting time with them at all: demos cancelled, sessions slipping by weeks. What eventually worked was treating feedback like a proper meeting instead of a favour: a recurring slot, a specific agenda (&quot;Tuesday we decide the filtering options&quot;), and saying plainly that feedback delays push delivery dates by the same amount. I learned to build that waiting time into the plan instead of crunching for it at the end.

Deployment humbled me the usual way. Everything ran on my machine, where I had broad permissions, localhost everywhere, and services set up exactly how I liked them. The cloud had none of that. SSL requirements that didn&apos;t exist locally, network restrictions, permission errors, environment variables that weren&apos;t set. The fix is cheap and I skipped it anyway: stand up a production-like environment early and keep deploying to it as you go, so the surprises arrive one at a time instead of all at once on launch day.

## If I could start again

Looking back, nearly all my pain came from overcomplicating the architecture and underrating the boring parts. The good stretches were the simple ones: a single API call, a small clean dataset, a scrappy version in front of a real user. The bad ones were every time I fell for a framework or a process before I understood the problem it was meant to solve.

The technology choices mattered less than I expected. React or Vue, Postgres or Mongo: I agonised over those calls and they barely changed the outcome. The human parts (managing expectations, chasing feedback, working out what people actually needed) were harder than any of the code.

I&apos;d build it again. I&apos;d just assume from day one that the clever version is going to lose, and reach for the boring one first.</content:encoded></item></channel></rss>