AI is Not Smart: Fighting Context Decay with Clean Code and "Ralph Loops"
Jul 5, 2026
Let's set the baseline: AI is not smart. It has vast prior training and a much larger working memory (context) than most humans, but it doesn't understand. It recognises patterns and infers intent based on the information immediately at hand.
The standard AI workflow looks like this: give it a prompt, tell it to act, and keep prodding it until you get what you want.
But there's a fatal flaw. Over time, the context window fills up. Important details fall out of the window or get lost in a sea of irrelevant tokens. You can reiterate your primary goals, but the signal inevitably gets diluted. Working on a new project or feature this way eventually produces diminishing returns. The AI gets confused, starts working on something else that can be "fixed" and you get frustrated wth slower, less accurate results

To fix this, we need to improve two things: the environment, and the process.
2. The Environment: Optimising for LLM ConsumptionThe most critical part of the AI's environment is your codebase.
The cleaner and sharper the code, the easier it is for the AI to pattern-match and infer intent. Making code less verbose and simpler directly reduces the number of tokens required to process it.
Reducing the codebase to the essentials - deduplication, removal of dead code, tight documentation, cross-package reuse - means the project is leaner. You aren't wasting your token budget on bloat and misunderstanding.
Everything you do to optimise code for an AI's context window simultaneously makes it easier for humans to understand and maintain. This isn't an "AI tax" on your codebase - it's just good engineering, with a second beneficiary.3. The Inevitability of Context DecayEven with a heavily optimised codebase - and no codebase is perfect - the context window will eventually saturate. The AI's focus starts its inevitable decline. It is inevitable.

This isn't hypothetical. Most of us have hit this wall more than once: a session that starts sharp and ends in circles. What then? You open a new window, restart the conversation, explain the whole premise again, and try to feed it your progress. That might work temporarily, but you'll run out of context again, and the results will degrade.
4. The Process: Enter the "Ralph Loop"If the AI's context always decays, we need to change how we feed it work. Enter "Ralph."

Ralph is not smart, but he is determined. He attempts to complete a single task in his own way, and that is it.
Instead of treating the AI like a senior engineer holding the entire system architecture in its head, treat it like Ralph. Give it a strict "Ralph Loop."
The mechanism:
The Task List - Break the project down into tiny, discrete, sequential steps.The Guardrails - Set strict rules and a rigid Definition of Done for the current task.The Loop - The AI executes only that task. You verify it, commit it, and ship it (the "Always Shippable" philosophy).By looping the AI through a well-defined list with strict boundaries, we completely eliminate context drift and token exhaustion. We don't need the AI to remember what it did ten steps ago; we only need it to execute the very next step perfectly.
Each task is small enough to fit entirely in the context window with room to spare - so the AI is never running on diluted signal in the first place. That focus is the whole point: it keeps Ralph doing the one thing in front of him instead of getting distracted by everything else in the shop.
5. How to Apply This to Your WorkflowThis isn't just a philosophy - here's how to actually use it, depending on which side of the command line you sit on.
For coders (that's most of you)You already have the tools to do this today: break your task list down, hand each item to the AI as its own bounded loop, and use strict Definitions of Done so you know exactly when a step is finished.
Here's a quick example of what that looks like in practice - three pieces that work together: the task list, the agent prompt, and the loop that runs it.
1. The task list. Every checkbox is a single, verifiable action. Notice there's no ambiguity about what "done" means for any item - that's deliberate.
1# Implementation Plan - E2E, API Codegen & Site Onboarding
2
3> Mark each checkbox `[x]` when done before moving to the next item.
4
5## Part 1: @acme-co/api - Package scaffold
6
7- [x] Create `packages/api/` directory.
8- [x] Create `packages/api/package.json` with `"name": "@acme-co/api"`, `"private": true`. Leave `scripts` empty for now — Part 2 fills it in.
9- [x] Create `packages/api/tsconfig.json` extending the repo root tsconfig.
10 Set `"outDir": "dist"`, `"rootDir": "src"`, `"declaration": true`, `"declarationDir": "dist"`.
11- [x] Create `packages/api/src/index.ts` as an empty barrel file (no exports yet).
12- [x] Update root `.gitignore`, add only `packages/api/dist/`. `src/generated/` **must be committed**.
13- [x] Verify the package is picked up by the existing lerna glob - no lerna.json change needed unless it differs.
14- [x] Run `pnpm install` from the monorepo root. Confirm `@acme-co/api` appears in `pnpm workspaces info`.
15
16## Part 2: @acme-co/api - Codegen scripts
17… (same pattern continues: Part 3 for tests, Part 4 for integration, etc.)2. The agent prompt. This is what turns the task list into a loop instead of a wishlist. It tells the AI exactly how to pick the next task, how to prove it's actually done, and, critically, when to stop.
1# Agent Prompt - @acme-co E2E & API Setup
2
3You are a senior TypeScript engineer working inside the `@acme-co` monorepo.
4Your job is to implement the tasks in `tasks/IMPLEMENTATION_PLAN.md` one at a time,
5producing working, committed code on each run.
6
7## Instructions - follow in order every run
8
91. **Orient**
10 - Read `tasks/IMPLEMENTATION_PLAN.md` and find the first unchecked `[ ]` item.
11 - If the task references a real page component or route, read that source file
12 first — never guess selectors, route paths, or API URLs from types alone.
13
142. **Plan**
15 - State in one sentence what you are about to do.
16 - List the files you will create or modify.
17 - Do not start coding until this plan is written.
18
193. **Act — one task only**
20 - Implement exactly the single checked-off task described.
21 - When a task says "fetch a real API response and save as fixture JSON": make a
22 real HTTP GET, pretty-print the verbatim response, write it to the fixture path.
23 Do **not** fabricate data from TypeScript types.
24 - If a test fails, fix the code. Do not proceed until the current task is green.
25
264. **Update the plan**
27 - Change `[ ]` to `[x]` for the completed item only. Do not mark ahead.
28
295. **Stop**
30 - Exit after completing one task. Do not begin the next task in the same run.
31
32## Constraints
33
34- TypeScript strict mode throughout. No `any` unless a third-party type forces it.
35- No fabricated fixture data — MSW handlers must come from real captured responses.
36- No commits with failing typecheck or failing tests.
37- Selectors from source, not imagination — read the component before writing a locator.
38- Do not modify `products/acme-product/` application code to make tests pass; fix the
39 test instead. The only exception is adding a missing `data-testid`.
40- If a script fails (e.g. a spec URL 404s), **stop and ask the user** — don't skip silently.
41
42When ALL tasks are checked off, output: `<promise>COMPLETE</promise>`3. The loop itself. A short bash script that hands the prompt to a fresh instance, over and over, with no memory carried between runs on purpose.
1
2# Ralph Wiggum Autonomous Development Loop
3# Runs Claude Code in a loop, each iteration with a fresh context window.
4# Usage: ./ralph.sh <max_iterations>
5
6set -e
7MAX_ITERATIONS=$1
8
9if [ -z "$MAX_ITERATIONS" ]; then
10 echo "Usage: $0 <max_iterations>"
11 exit 1
12fi
13
14for ((i=1; i<=MAX_ITERATIONS; i++)); do
15 echo "=== Iteration $i of $MAX_ITERATIONS ==="
16
17 result=$(claude -p "$(cat tasks/AGENT_PROMPT.md)" --output-format text 2>&1) || true
18 echo "$result"
19
20 if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
21 echo "ALL TASKS COMPLETE after $i iteration(s)"
22 exit 0
23 fi
24
25 sleep 2
26done
27
28echo "MAX ITERATIONS REACHED without completion — check activity.md for progress."
29exit 1That's the whole trick: no step in this loop ever needs to remember the eight steps before it. The task list carries the memory. The prompt enforces the boundaries. The script just keeps handing out fresh Ralphs.
Bonus points: plan the steps using AI too. Don't write the task list by hand from scratch - talk through the feature first. Discuss what you're building, cover the caveats and edge cases out loud, then ask the AI to generate the plan from that conversation. You'll still catch problems earlier this way than if you'd jumped straight to a checklist.And don't start by unleashing 50 loops on it. Ramp up:
Run 1 loop. Check the result.Satisfied? Run 8–10 loops, checking in as you go.Once you've got ~20 steps done and the prompt and plan are holding up, then let it run 10–20 loops unsupervised.
Here's the part worth not glossing over: Ralph is Ralph. He does exactly what he's told, in his own way, and that's precisely where the danger is. He isn't going to notice that a task is subtly wrong, or ambiguous, or actually impossible as written. He'll just attempt it, in whatever literal-minded way the prompt allows.
Which means the responsibility doesn't disappear just because the loop is running unattended, it moves earlier. Check your plan carefully before you run it: is every task actually completable as stated, with everything it needs available? And check the output while it runs, not just at the end because loops can fail, stall, or get stuck retrying the same broken step, and nobody's watching but you.
Right now, recovery is your job. Maybe future iterations of this pattern can teach the prompt to notice it's stuck, manage its own backlog, and course-correct without you, but we're not there yet. 🤷♂️ Until then: plan it carefully, run it cautiously, and don't walk away from Ralph for too long.
If you can improve on this setup, with a prompt that notices it's stuck, handles the failure, and works around it on its own instead of needing you to babysit it — that's the next step - but the clearer the tasks and guide-rails are, the less chance you need to recover it.
For non-codersStep one: learn to use the command line. (Kidding. Mostly.)
The real takeaway doesn't require writing a script: break your task down into simple, sequential steps, and treat every new chat as the next person on the assembly line - someone with zero tribal knowledge of what came before. If you wouldn't hand a new hire the whole project with no instructions and expect a good result, don't do it to the AI either. Give it one clear job and a clear definition of "done," and let the next chat be the next fresh pair of hands.
And the Business Case?Leaner code, quicker feature development, fewer tokens used*, and more code shipped. And one final word of warning... because the context is smaller, the tasks are completed more quickly and you can burn though a budget very quickly!
*It's still not cheap, but you get more out of every bit you spend.