[{"data":1,"prerenderedAt":1070},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fimplementing-ralph-wiggum-loop-for-autonomous-ai-coding":204,"\u002Fblog\u002Fimplementing-ralph-wiggum-loop-for-autonomous-ai-coding-surround":1065},[4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200],{"title":5,"path":6,"stem":7},"You do not have time to not have tests","\u002Fblog\u002Fyou-do-not-have-time-to-not-have-tests","2.blog\u002F20211217.you-do-not-have-time-to-not-have-tests",{"title":9,"path":10,"stem":11},"Migrate Vue 2 with Vuetify and Jest to Vite and Vitest","\u002Fblog\u002Fmigrate-vue-2-with-vuetify-and-jest-to-vite-and-vitest","2.blog\u002F20220109.migrate-vue-2-with-vuetify-and-jest-to-vite-and-vitest",{"title":13,"path":14,"stem":15},"I am a Dark Matter Developer","\u002Fblog\u002Fi-am-a-dark-matter-developer","2.blog\u002F20220626.i-am-a-dark-matter-developer",{"title":17,"path":18,"stem":19},"Why using Conventional commits is useful","\u002Fblog\u002Fusing-conventional-commits","2.blog\u002F20240623.using-conventional-commits",{"title":21,"path":22,"stem":23},"Why you should make a toolbox repository","\u002Fblog\u002Fwhy-you-should-make-a-toolbox-repository","2.blog\u002F20240630.Why-you-should-make-a-toolbox-repository",{"title":25,"path":26,"stem":27},"Apache Airflow Part 1 - Why and Goals for a near Serverless ELT","\u002Fblog\u002Fapache-airflow-part-1-why-and-goals","2.blog\u002F20240710.apache-airflow-part-1-why-and-goals",{"title":29,"path":30,"stem":31},"Oh My Zsh on your server","\u002Fblog\u002Foh-my-zsh-on-your-server","2.blog\u002F20240711.oh-my-zsh-on-your-server",{"title":33,"path":34,"stem":35},"Fire tablet and YouTube Kids","\u002Fblog\u002Ffire-tablet-and-youtube-kids","2.blog\u002F20240714.fire-tablet-and-youtube-kids",{"title":37,"path":38,"stem":39},"Using Ollama and Continue as a GitHub Copilot Alternative","\u002Fblog\u002Fusing-ollama-and-continue-as-github-copilot-alternative","2.blog\u002F20240723.using-ollama-and-continue-as-github-copilot-alternative",{"title":41,"path":42,"stem":43},"Debugging Local Packages Made Easy with pnpm","\u002Fblog\u002Fdebugging-local-packages-with-pnpm-link","2.blog\u002F20250422.debugging local-packages-with-pnpm-link",{"title":45,"path":46,"stem":47},"Two Weeks with Cloudflare AI and Tools","\u002Fblog\u002Ftwo-weeks-with-cloudflare-ai-and-tools","2.blog\u002F20250509.two-weeks-with-cloudflare-aI-and-tools",{"title":49,"path":50,"stem":51},"Adding Prompts to VS Code - How I Learned to Stop Worrying and Love AI Context","\u002Fblog\u002Fadding-prompts-to-vscode","2.blog\u002F20250528.adding-prompts-to-vscode",{"title":53,"path":54,"stem":55},"My Best Practices","\u002Fblog\u002Fmy-best-practicies","2.blog\u002F20250607.my-best-practicies",{"title":57,"path":58,"stem":59},"Creating my own CLI Tool - Towles Tool","\u002Fblog\u002Ftowles-tool","2.blog\u002F20250607.towles-tool",{"title":61,"path":62,"stem":63},"Software Development Best Practices & ITIL","\u002Fblog\u002Fsoftware-engineering-and-itil-best-practices","2.blog\u002F20250612.software-engineering-and-itil-best-practices",{"title":65,"path":66,"stem":67},"Voice to Text","\u002Fblog\u002Fvoice-to-text","2.blog\u002F20250622.voice-to-text",{"title":69,"path":70,"stem":71},"Setting Up ComfyUI - A Better Alternative to Fooocus","\u002Fblog\u002Fcomfy-ui-setup","2.blog\u002F20250628.comfy-ui-setup",{"title":73,"path":74,"stem":75},"Voice to System","\u002Fblog\u002Fvoice-to-system","2.blog\u002F20250705.voice-to-system",{"title":77,"path":78,"stem":79},"Tips for Claude Code","\u002Fblog\u002Ftips-for-claude-code","2.blog\u002F20250713.tips-for-claude-code",{"title":81,"path":82,"stem":83},"Review That AI Code: Why I Read Every Line Generated Code","\u002Fblog\u002Freview-that-ai-code","2.blog\u002F20250720.review-that-ai-code",{"title":85,"path":86,"stem":87},"My Context Engineering Journey: From Dev Scripts to AI Collaboration","\u002Fblog\u002F20250803-1.my-context-engineering-journey","2.blog\u002F20250803-1.my-context-engineering-journey",{"title":89,"path":90,"stem":91},"Context Engineering at Scale: Enterprise Lessons and the Future of Development","\u002Fblog\u002F20250803-2.context-engineering-at-scale","2.blog\u002F20250803-2.context-engineering-at-scale",{"title":93,"path":94,"stem":95},"Check That Your Tools and Linters Do Not Burn Tokens","\u002Fblog\u002Fcheck-that-your-tools-and-linters-do-not-burn-tokens","2.blog\u002F20250806.check-that-your-tools-and-linters-do-not-burn-tokens",{"title":97,"path":98,"stem":99},"Markdown + AI: The Communication Protocol That Changes Everything","\u002Fblog\u002Fmarkdown-plus-ai-the-communication-protocol-that-changes-everything","2.blog\u002F20250814.markdown-plus-ai-the-communication-protocol-that-changes-everything",{"title":101,"path":102,"stem":103},"Finally: Type-Safe AI in Production (And Why I'm Here For It)","\u002Fblog\u002Ffinally-type-safe-ai-in-production-and-why-im-here-for-it","2.blog\u002F20250819.finally-type-safe-ai-in-production-and-why-im-here-for-it",{"title":105,"path":106,"stem":107},"Dotfiles: Masterpiece or Late Stage Picasso?","\u002Fblog\u002Fdotfiles-masterpiece-or-late-stage-picasso","2.blog\u002F20250822.dotfiles-masterpiece-or-late-stage-picasso",{"title":109,"path":110,"stem":111},"Beyond API Wrappers: Building State-Driven MCP Servers for Long-Horizon Agent Orchestration","\u002Fblog\u002Fbeyond-api-wrappers-mcp-servers","2.blog\u002F20250907.beyond-api-wrappers-mcp-servers",{"title":113,"path":114,"stem":115},"Why Vertical Integration Wins: A Software Engineer's Case for Owning Your Stack","\u002Fblog\u002Fwhy-i-bought-tesla-model-3-vertical-integration","2.blog\u002F20250928.why-i-bought-tesla-model-3-vertical-integration",{"title":117,"path":118,"stem":119},"The Min-Maxer's Trifecta: Building Tools for the Game You Actually Play","\u002Fblog\u002Fmin-maxer-trifecta","2.blog\u002F20251004.min-maxer-trifecta",{"title":121,"path":122,"stem":123},"Read The Source: Learning by Cutting Out The Middleman and RTFM","\u002Fblog\u002Fread-the-source","2.blog\u002F20251010.read-the-source",{"title":125,"path":126,"stem":127},"The Exponential Shift: Why AI Progress Feels Different Now","\u002Fblog\u002Fthe-exponential-shift","2.blog\u002F20251015.the-exponential-shift",{"title":129,"path":130,"stem":131},"Plan Mode for Your Problems, Edit Mode for Claude's","\u002Fblog\u002Fplan-mode-problems-edit-mode-solutions","2.blog\u002F20251019.plan-mode-problems-edit-mode-solutions",{"title":133,"path":134,"stem":135},"AWS Aurora DSQL Looked Perfect Until I Needed the Connection String","\u002Fblog\u002Faws-aurora-dsql-postgres-serverless-authentication","2.blog\u002F20251028.aws-aurora-dsql-postgres-serverless-authentication",{"title":137,"path":138,"stem":139},"Switchback: Browser History for Your Thoughts","\u002Fblog\u002Fswitchback-second-order-reasoning","2.blog\u002F20251205.switchback-second-order-reasoning",{"title":141,"path":142,"stem":143},"AI Pairing: Notes to Self","\u002Fblog\u002Fai-pairing-notes-to-self","2.blog\u002F20251216.ai-pairing-notes-to-self",{"title":145,"path":146,"stem":147},"I've Been Sleeping on Zellij","\u002Fblog\u002Fsleeping-on-zellij","2.blog\u002F20251229.sleeping-on-zellij",{"title":149,"path":150,"stem":151},"Implementing a Ralph Wiggum Loop: The Secret is Session Markers","\u002Fblog\u002Fimplementing-ralph-wiggum-loop-for-autonomous-ai-coding","2.blog\u002F20260114.implementing-ralph-wiggum-loop-for-autonomous-ai-coding",{"title":153,"path":154,"stem":155},"Goodhart's Law Ate My Context Window","\u002Fblog\u002Fgoodharts-law-ate-my-context-window","2.blog\u002F20260119.goodharts-law-ate-my-context-window",{"title":157,"path":158,"stem":159},"Claude Code's Hidden Multi-Agent System Is Real","\u002Fblog\u002Fclaude-code-hidden-multi-agent-system","2.blog\u002F20260124.claude-code-hidden-multi-agent-system",{"title":161,"path":162,"stem":163},"Free Printable Math Sheets for Kids — Number Chart, Skip Counting, Multiplication, and More","\u002Fblog\u002Ffree-printable-number-chart-and-coin-sheets","2.blog\u002F20260214.free-printable-number-chart-and-coin-sheets",{"title":165,"path":166,"stem":167},"We Are Near the End of the Exponential","\u002Fblog\u002Fnear-the-end-of-the-exponential","2.blog\u002F20260214.near-the-end-of-the-exponential",{"title":169,"path":170,"stem":171},"Free Printable Language Arts Sheets for Kids — Sight Words, Parts of Speech, Homophones, and More","\u002Fblog\u002Ffree-printable-sight-words-and-grammar-sheets","2.blog\u002F20260215.free-printable-sight-words-and-grammar-sheets",{"title":173,"path":174,"stem":175},"Interactive Code Execution with Artifacts","\u002Fblog\u002Finteractive-code-execution-with-artifacts","2.blog\u002F20260215.interactive-code-execution-with-artifacts",{"title":177,"path":178,"stem":179},"Free Printable Telling Time Worksheet for Kids — Clock Reference & Practice Sheet","\u002Fblog\u002Ffree-printable-telling-time-worksheet","2.blog\u002F20260216.free-printable-telling-time-worksheet",{"title":181,"path":182,"stem":183},"Claude Code Skills: Teaching AI Your Playbook","\u002Fblog\u002Fclaude-code-skills-guide","2.blog\u002F20260221.claude-code-skills-guide",{"title":185,"path":186,"stem":187},"Building a Multi-Agent Loan Approval System with Human-in-the-Loop","\u002Fblog\u002Fmulti-agent-loan-approval-human-in-the-loop","2.blog\u002F20260225.multi-agent-loan-approval-human-in-the-loop",{"title":189,"path":190,"stem":191},"The Inception of AI Infrastructure: Bottlenecks All the Way Down","\u002Fblog\u002Fbiggest-bottleneck-scaling-ai-compute","2.blog\u002F20260313.biggest-bottleneck-scaling-ai-compute",{"title":193,"path":194,"stem":195},"What I Tell Teams About Claude Code","\u002Fblog\u002Fwhat-i-tell-teams-about-claude-code","2.blog\u002F20260314.what-i-tell-teams-about-claude-code",{"title":197,"path":198,"stem":199},"The Hardest Part of AI Isn't the AI","\u002Fblog\u002Fthe-hardest-part-of-ai-isnt-the-ai","2.blog\u002F20260327.the-hardest-part-of-ai-isnt-the-ai",{"title":201,"path":202,"stem":203},"Claude Code Hooks: The Capability I Left on the Table","\u002Fblog\u002Fclaude-code-hooks-capability-left-on-the-table","2.blog\u002F20260401.claude-code-hooks-capability-left-on-the-table",{"id":205,"title":149,"authors":206,"badge":212,"body":214,"date":1055,"description":1056,"extension":1057,"image":1058,"meta":1061,"navigation":501,"path":150,"seo":1062,"status":1063,"stem":151,"__hash__":1064},"posts\u002F2.blog\u002F20260114.implementing-ralph-wiggum-loop-for-autonomous-ai-coding.md",[207],{"name":208,"to":209,"avatar":210},"Chris Towles","https:\u002F\u002Ftwitter.com\u002FChris_Towles",{"src":211},"\u002Fimages\u002Fctowles-profile-512x512.png",{"label":213},"Claude Code",{"type":215,"value":216,"toc":1047},"minimark",[217,226,237,242,250,253,258,261,276,280,288,295,298,309,313,316,319,355,365,372,375,388,408,414,422,427,440,448,453,768,773,877,886,890,899,902,909,913,947,950,956,960,963,976,986,989,1027,1030,1033,1043],[218,219,220,221,225],"p",{},"There's an AI coding pattern that lets you run seriously long-running agents - for hours at a time - that ship code while you sleep. It's called the ",[222,223,224],"strong",{},"Ralph Wiggum loop",", named after the haplessly persistent Simpsons character.",[218,227,228,229,236],{},"I'd been tinkering with this pattern since Claude Code's early skill system - trying to run loops in interactive sessions, wrestling with state management, burning through context limits. Then Matt Pocock ",[230,231,235],"a",{"href":232,"rel":233},"https:\u002F\u002Fwww.aihero.dev\u002Ftips-for-ai-coding-with-ralph-wiggum",[234],"nofollow","published his approach",", and one thing clicked immediately:",[218,238,239],{},[222,240,241],{},"Use a bash shell. Not an interactive session.",[218,243,244,245,249],{},"It sounds obvious in retrospect. Why was I trying to manage loops inside Claude Code's interactive session when I could just... run ",[246,247,248],"code",{},"claude"," from a bash while loop? Queue up the work, let Claude figure out what to do next, repeat until done.",[218,251,252],{},"After a weekend of burning through tokens, migrating from pnpm to Bun (and back), and discovering the critical importance of session markers, I finally got it working. Here's what I learned.",[254,255,257],"h2",{"id":256},"what-is-a-ralph-wiggum-loop","What is a Ralph Wiggum Loop?",[218,259,260],{},"The pattern is elegantly simple: a while loop that feeds Claude a prompt, Claude works on the code, and when Claude attempts to exit, a hook checks if work is truly done. If not, it re-feeds the same prompt. Each iteration carries forward all context - the modified files, git history, previous test results - allowing Claude to learn from its own output.",[218,262,263,264,269,270,275],{},"Matt Pocock describes it as \"a keep-it-simple-stupid approach to AI coding.\" There's an official ",[230,265,268],{"href":266,"rel":267},"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-code\u002Fblob\u002Fmain\u002Fplugins\u002Fralph-wiggum\u002FREADME.md",[234],"Claude Code plugin",", but the pattern was created by ",[230,271,274],{"href":272,"rel":273},"https:\u002F\u002Fghuntley.com\u002Fralph\u002F",[234],"Geoffrey Huntley",". It's been all over X and Reddit - but how do you leverage it in your own projects?",[254,277,279],{"id":278},"the-aha-moment-queue-dont-direct","The Aha Moment: Queue, Don't Direct",[218,281,282,283,287],{},"Before Matt's video, I was thinking about this wrong. I'd start an interactive Claude Code session, add tasks to a state file, then try to run a loop ",[284,285,286],"em",{},"inside"," the conversation. Complex prompt engineering. Hooks to detect exit conditions. State management within the session.",[218,289,290,291,294],{},"The insight from Matt's approach: ",[222,292,293],{},"let Claude decide what to work on",". You're not micro-managing each step. You queue up tasks, give Claude access to a state file, and run the CLI in a bash loop. Each iteration, Claude reads the state, picks a task, does the work, marks it done, and exits. The loop restarts, Claude picks the next task.",[218,296,297],{},"It's mechanical. It's simple. It works overnight while you sleep.",[218,299,300,301,304,305,308],{},"One thing that made a huge difference: ",[222,302,303],{},"task instructions in the system prompt",". towles-tool injects the current task and workflow rules into the system prompt via ",[246,306,307],{},"--append-system-prompt",", not just the user message. This keeps Claude focused on the current task much longer and more successfully than putting instructions in the prompt itself. The system prompt is \"always there\" in a way that user messages aren't.",[254,310,312],{"id":311},"the-token-burn-weekend-or-why-i-have-a-file-named-never_again","The Token Burn Weekend (Or: Why I Have a File Named NEVER_AGAIN)",[218,314,315],{},"One December weekend, I set up what I thought was a reasonable experiment: let Claude work autonomously on a complex feature - personas, chatbots, skills, database schema changes. I ran the loop overnight.",[218,317,318],{},"I woke up to this in my state file:",[320,321,326],"pre",{"className":322,"code":323,"language":324,"meta":325,"style":325},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","iteration: 10\nmax_iterations: 10\n","yaml","",[246,327,328,345],{"__ignoreMap":325},[329,330,333,337,341],"span",{"class":331,"line":332},"line",1,[329,334,336],{"class":335},"swJcz","iteration",[329,338,340],{"class":339},"sMK4o",":",[329,342,344],{"class":343},"sbssI"," 10\n",[329,346,348,351,353],{"class":331,"line":347},2,[329,349,350],{"class":335},"max_iterations",[329,352,340],{"class":339},[329,354,344],{"class":343},[218,356,357,360,361,364],{},[222,358,359],{},"10 iterations."," I'd set ",[246,362,363],{},"max_iterations: 10"," and gone to sleep. The commit message from that night says it all: I'd burned through all my tokens, and I'm on the $100 plan.",[218,366,367,368,371],{},"The state file got renamed to ",[246,369,370],{},".claude\u002Fralph-loop.local.md-NEVER_AGAIN",".",[218,373,374],{},"The problem wasn't just the raw token count. Each iteration built on the previous one's context. Even with compaction, Claude Code is much smarter in the first 40% of the context window than when it's full and trying to compact.",[218,376,377,378,383,384,387],{},"The ",[230,379,382],{"href":380,"rel":381},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Ftowles-tool\u002Fcommit\u002Fee6db37",[234],"commit that changed everything on 2026-01-11",": ",[246,385,386],{},"feat(ralph): auto-resume sessions per-task to prevent token burn",". That commit message tells the story. After the NEVER_AGAIN incident, I had to figure out how to preserve context between iterations but not fill up the context, find that sweet spot where Claude has enough context to be effective without burning through tokens unnecessarily.",[389,390,392],"callout",{"type":391},"warning",[218,393,394,397,398,401,402,405,406,371],{},[222,395,396],{},"Update (Jan 19):"," The section below was a mistake. I was optimizing for the wrong thing - making loops ",[284,399,400],{},"look"," fast instead of ",[284,403,404],{},"work"," effectively. See ",[230,407,153],{"href":154},[218,409,410],{},[411,412,413],"del",{},"## The Secret: Session Markers",[218,415,416],{},[411,417,418,419,371],{},"Assigning tasks to Claude Code in a \"headless\" manner (a bash loop) is half the battle. How do you give Claude the right context for each task without starting from scratch every time? Usually you'd write a plan.md file, right? But even with a half page of markdown, Claude still has a lot of intent to figure out. I needed to preserve context more effectively. My solution: ",[222,420,421],{},"session markers",[218,423,424],{},[411,425,426],{},"I think it was Boris Cherny who had tweeted about this, couldn't find it again - pointing out that Claude Code already has a way to resume sessions which forks them!",[218,428,429],{},[411,430,431,432,435,436,439],{},"Claude Code stores conversation history in JSONL files at ",[246,433,434],{},"~\u002F.claude\u002Fprojects\u002F",". Each file represents a session. If you can find the right session, you can resume from it with ",[246,437,438],{},"--resume \u003Csession-id>",", and Claude picks up exactly where it left off.",[218,441,442],{},[411,443,444,445,371],{},"The insight that changed everything: ",[222,446,447],{},"generate a random marker, have Claude output it during research, then search for that marker to find the session",[218,449,450],{},[411,451,452],{},"Something like:",[320,454,458],{"className":455,"code":456,"language":457,"meta":325,"style":325},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F From marker.ts - the core of the system\nexport const MARKER_PREFIX = 'RALPH_MARKER_';\n\nexport function generateMarker(): string {\n  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';\n  let result = '';\n  for (let i = 0; i \u003C 8; i++) {\n    result += chars.charAt(Math.floor(Math.random() * chars.length));\n  }\n  return result;\n}\n\nexport async function findSessionByMarker(marker: string): Promise\u003Cstring | null> {\n  const projectDir = getProjectDir();\n  \u002F\u002F ... search all .jsonl files for the marker\n  \u002F\u002F return the session ID (filename without .jsonl)\n}\n","typescript",[246,459,460,466,496,503,525,546,562,606,660,666,676,682,687,733,751,757,763],{"__ignoreMap":325},[329,461,462],{"class":331,"line":332},[329,463,465],{"class":464},"sHwdD","\u002F\u002F From marker.ts - the core of the system\n",[329,467,468,472,476,480,483,486,490,493],{"class":331,"line":347},[329,469,471],{"class":470},"s7zQu","export",[329,473,475],{"class":474},"spNyl"," const",[329,477,479],{"class":478},"sTEyZ"," MARKER_PREFIX ",[329,481,482],{"class":339},"=",[329,484,485],{"class":339}," '",[329,487,489],{"class":488},"sfazB","RALPH_MARKER_",[329,491,492],{"class":339},"'",[329,494,495],{"class":339},";\n",[329,497,499],{"class":331,"line":498},3,[329,500,502],{"emptyLinePlaceholder":501},true,"\n",[329,504,506,508,511,515,518,522],{"class":331,"line":505},4,[329,507,471],{"class":470},[329,509,510],{"class":474}," function",[329,512,514],{"class":513},"s2Zo4"," generateMarker",[329,516,517],{"class":339},"():",[329,519,521],{"class":520},"sBMFI"," string",[329,523,524],{"class":339}," {\n",[329,526,528,531,534,537,539,542,544],{"class":331,"line":527},5,[329,529,530],{"class":474},"  const",[329,532,533],{"class":478}," chars",[329,535,536],{"class":339}," =",[329,538,485],{"class":339},[329,540,541],{"class":488},"abcdefghijklmnopqrstuvwxyz0123456789",[329,543,492],{"class":339},[329,545,495],{"class":339},[329,547,549,552,555,557,560],{"class":331,"line":548},6,[329,550,551],{"class":474},"  let",[329,553,554],{"class":478}," result",[329,556,536],{"class":339},[329,558,559],{"class":339}," ''",[329,561,495],{"class":339},[329,563,565,568,571,574,577,579,582,585,587,590,593,595,597,600,603],{"class":331,"line":564},7,[329,566,567],{"class":470},"  for",[329,569,570],{"class":335}," (",[329,572,573],{"class":474},"let",[329,575,576],{"class":478}," i",[329,578,536],{"class":339},[329,580,581],{"class":343}," 0",[329,583,584],{"class":339},";",[329,586,576],{"class":478},[329,588,589],{"class":339}," \u003C",[329,591,592],{"class":343}," 8",[329,594,584],{"class":339},[329,596,576],{"class":478},[329,598,599],{"class":339},"++",[329,601,602],{"class":335},") ",[329,604,605],{"class":339},"{\n",[329,607,609,612,615,617,619,622,625,628,630,633,635,637,639,642,645,648,650,652,655,658],{"class":331,"line":608},8,[329,610,611],{"class":478},"    result",[329,613,614],{"class":339}," +=",[329,616,533],{"class":478},[329,618,371],{"class":339},[329,620,621],{"class":513},"charAt",[329,623,624],{"class":335},"(",[329,626,627],{"class":478},"Math",[329,629,371],{"class":339},[329,631,632],{"class":513},"floor",[329,634,624],{"class":335},[329,636,627],{"class":478},[329,638,371],{"class":339},[329,640,641],{"class":513},"random",[329,643,644],{"class":335},"() ",[329,646,647],{"class":339},"*",[329,649,533],{"class":478},[329,651,371],{"class":339},[329,653,654],{"class":478},"length",[329,656,657],{"class":335},"))",[329,659,495],{"class":339},[329,661,663],{"class":331,"line":662},9,[329,664,665],{"class":339},"  }\n",[329,667,669,672,674],{"class":331,"line":668},10,[329,670,671],{"class":470},"  return",[329,673,554],{"class":478},[329,675,495],{"class":339},[329,677,679],{"class":331,"line":678},11,[329,680,681],{"class":339},"}\n",[329,683,685],{"class":331,"line":684},12,[329,686,502],{"emptyLinePlaceholder":501},[329,688,690,692,695,697,700,702,706,708,710,713,716,719,722,725,728,731],{"class":331,"line":689},13,[329,691,471],{"class":470},[329,693,694],{"class":474}," async",[329,696,510],{"class":474},[329,698,699],{"class":513}," findSessionByMarker",[329,701,624],{"class":339},[329,703,705],{"class":704},"sHdIc","marker",[329,707,340],{"class":339},[329,709,521],{"class":520},[329,711,712],{"class":339},"):",[329,714,715],{"class":520}," Promise",[329,717,718],{"class":339},"\u003C",[329,720,721],{"class":520},"string",[329,723,724],{"class":339}," |",[329,726,727],{"class":520}," null",[329,729,730],{"class":339},">",[329,732,524],{"class":339},[329,734,736,738,741,743,746,749],{"class":331,"line":735},14,[329,737,530],{"class":474},[329,739,740],{"class":478}," projectDir",[329,742,536],{"class":339},[329,744,745],{"class":513}," getProjectDir",[329,747,748],{"class":335},"()",[329,750,495],{"class":339},[329,752,754],{"class":331,"line":753},15,[329,755,756],{"class":464},"  \u002F\u002F ... search all .jsonl files for the marker\n",[329,758,760],{"class":331,"line":759},16,[329,761,762],{"class":464},"  \u002F\u002F return the session ID (filename without .jsonl)\n",[329,764,766],{"class":331,"line":765},17,[329,767,681],{"class":339},[218,769,770],{},[411,771,772],{},"The workflow looks like this:",[320,774,778],{"className":775,"code":776,"language":777,"meta":325,"style":325},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# 1. Generate a marker\ntt ralph marker create\n# Output: RALPH_MARKER_abc12345\n\n# 2. Do your research with Claude, telling it to output the marker\n# \"When you've gathered all the context needed, output: RALPH_MARKER_abc12345\"\n\n# 3. Add tasks with the marker\ntt ralph task add \"Implement the feature\" --findMarker RALPH_MARKER_abc12345\n# ✓ Added task #1 with session: 7a9f3b2c...\n\n# 4. Run ralph - it automatically forks from the research session!\ntt ralph run\n","bash",[246,779,780,785,799,804,808,813,818,822,827,854,859,863,868],{"__ignoreMap":325},[329,781,782],{"class":331,"line":332},[329,783,784],{"class":464},"# 1. Generate a marker\n",[329,786,787,790,793,796],{"class":331,"line":347},[329,788,789],{"class":520},"tt",[329,791,792],{"class":488}," ralph",[329,794,795],{"class":488}," marker",[329,797,798],{"class":488}," create\n",[329,800,801],{"class":331,"line":498},[329,802,803],{"class":464},"# Output: RALPH_MARKER_abc12345\n",[329,805,806],{"class":331,"line":505},[329,807,502],{"emptyLinePlaceholder":501},[329,809,810],{"class":331,"line":527},[329,811,812],{"class":464},"# 2. Do your research with Claude, telling it to output the marker\n",[329,814,815],{"class":331,"line":548},[329,816,817],{"class":464},"# \"When you've gathered all the context needed, output: RALPH_MARKER_abc12345\"\n",[329,819,820],{"class":331,"line":564},[329,821,502],{"emptyLinePlaceholder":501},[329,823,824],{"class":331,"line":608},[329,825,826],{"class":464},"# 3. Add tasks with the marker\n",[329,828,829,831,833,836,839,842,845,848,851],{"class":331,"line":662},[329,830,789],{"class":520},[329,832,792],{"class":488},[329,834,835],{"class":488}," task",[329,837,838],{"class":488}," add",[329,840,841],{"class":339}," \"",[329,843,844],{"class":488},"Implement the feature",[329,846,847],{"class":339},"\"",[329,849,850],{"class":488}," --findMarker",[329,852,853],{"class":488}," RALPH_MARKER_abc12345\n",[329,855,856],{"class":331,"line":668},[329,857,858],{"class":464},"# ✓ Added task #1 with session: 7a9f3b2c...\n",[329,860,861],{"class":331,"line":678},[329,862,502],{"emptyLinePlaceholder":501},[329,864,865],{"class":331,"line":684},[329,866,867],{"class":464},"# 4. Run ralph - it automatically forks from the research session!\n",[329,869,870,872,874],{"class":331,"line":689},[329,871,789],{"class":520},[329,873,792],{"class":488},[329,875,876],{"class":488}," run\n",[218,878,879],{},[411,880,881,882,885],{},"Each task now carries its own ",[246,883,884],{},"sessionId",". When ralph runs that task, it forks from that session. Claude starts with all the codebase knowledge from the research phase - no more burning tokens re-discovering the same files, doing redundant work, or losing context between iterations.",[254,887,889],{"id":888},"real-results","Real Results",[218,891,892,893,898],{},"My first real test: ",[230,894,897],{"href":895,"rel":896},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Fblog\u002Fpull\u002F162",[234],"reviewing every blog post in my repository",". I created 37 tasks - one per post - ran ralph overnight, and woke up to grammar fixes, improved clarity, consistent formatting, all committed individually with meaningful messages.",[218,900,901],{},"I've since used it for harder tasks like converting this blog's AI chat from API-driven to websockets. Ralph with session markers worked first try the morning after - the previous two attempts (once partnering, once solo) had burned through my token quota without success.",[218,903,904],{},[905,906],"img",{"alt":907,"src":908},"Towles-tool ralph loop results","\u002Fimages\u002Fblog\u002F20260114-ralph-loop-terminal.png",[254,910,912],{"id":911},"lessons-learned","Lessons Learned",[914,915,916,923,929,935,941],"ol",{},[917,918,919,922],"li",{},[222,920,921],{},"Context is everything",". A loop without session preservation is just expensive repetition.",[917,924,925,928],{},[222,926,927],{},"The marker trick is the secret sauce",". Generate a random string, have Claude output it, search for it later. Simple but powerful.",[917,930,931,934],{},[222,932,933],{},"Start with HITL, then go AFK",". Matt's advice: run interactively first, verify it's working, then let it run autonomously.",[917,936,937,940],{},[222,938,939],{},"Set conservative iteration limits",". A 20-iteration loop is plenty - more work than you can do in a single night, and likely more than you can review in one sitting.",[917,942,943,946],{},[222,944,945],{},"Token efficiency compounds",". Do the work once, save the session, fork from it for subsequent tasks. This avoids redundant context rebuilding and saves both time and API credits.",[218,948,949],{},"I built token visualization into towles-tool to see where my quota was going. A treemap ended up being more informative than a flamegraph:",[218,951,952],{},[905,953],{"alt":954,"src":955},"Token usage treemap visualization showing Claude session costs","\u002Fimages\u002Fblog\u002F20260114-token-usage-treemap.png",[254,957,959],{"id":958},"try-it","Try It",[218,961,962],{},"The code is open source:",[964,965,966],"ul",{},[917,967,968,383,971],{},[222,969,970],{},"towles-tool",[230,972,975],{"href":973,"rel":974},"https:\u002F\u002Fgithub.com\u002FChrisTowles\u002Ftowles-tool",[234],"github.com\u002FChrisTowles\u002Ftowles-tool",[218,977,978,979,982,983,371],{},"Install with ",[246,980,981],{},"npm install -g @towles\u002Ftool"," and start with ",[246,984,985],{},"tt ralph --help",[218,987,988],{},"And install the Claude Code plugin:",[320,990,992],{"className":775,"code":991,"language":777,"meta":325,"style":325},"claude plugin marketplace add ChrisTowles\u002Ftowles-tool\nclaude plugin install tt@towles-tool --scope user\n",[246,993,994,1009],{"__ignoreMap":325},[329,995,996,998,1001,1004,1006],{"class":331,"line":332},[329,997,248],{"class":520},[329,999,1000],{"class":488}," plugin",[329,1002,1003],{"class":488}," marketplace",[329,1005,838],{"class":488},[329,1007,1008],{"class":488}," ChrisTowles\u002Ftowles-tool\n",[329,1010,1011,1013,1015,1018,1021,1024],{"class":331,"line":347},[329,1012,248],{"class":520},[329,1014,1000],{"class":488},[329,1016,1017],{"class":488}," install",[329,1019,1020],{"class":488}," tt@towles-tool",[329,1022,1023],{"class":488}," --scope",[329,1025,1026],{"class":488}," user\n",[218,1028,1029],{},"The Ralph Wiggum loop isn't magic - it's just a while loop. Claude Code is the magic. But add session forking and context preservation, and you get real leverage. Get those right, and you can ship while you sleep without blowing through your token quota.",[1031,1032],"hr",{},[218,1034,1035],{},[284,1036,1037,1038,1042],{},"Thanks to ",[230,1039,1041],{"href":232,"rel":1040},[234],"Matt Pocock"," for writing about Ralph Wiggum loops and inspiring this implementation.",[1044,1045,1046],"style",{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":325,"searchDepth":347,"depth":347,"links":1048},[1049,1050,1051,1052,1053,1054],{"id":256,"depth":347,"text":257},{"id":278,"depth":347,"text":279},{"id":311,"depth":347,"text":312},{"id":888,"depth":347,"text":889},{"id":911,"depth":347,"text":912},{"id":958,"depth":347,"text":959},"2026-01-14","How I turned towles-tool into an autonomous AI coding system using session markers to preserve context across iterations - and the weekend of mistakes that got me there.","md",{"src":1059,"alt":1060},"\u002Fimages\u002Fblog\u002F20260114-1530-ralph-wiggum-loop.png","A developer's desk at 3am illuminated by multiple monitors showing endless loops of terminal output and code, an empty coffee mug and scattered energy drink cans nearby. One monitor displays a glowing circular arrow symbol representing infinite iteration, another shows JSONL session files being connected like constellation lines. Dramatic blue screen glow contrasts with warm desk lamp creating noir atmosphere, shallow depth of field focusing on a sticky note reading ",{"draft":501},{"title":149,"description":1056},"published","ByTDw_2QFaknyJ9qGDfQhHa85TU8soenvQy5iA3ZPNA",[1066,1068],{"title":145,"path":146,"stem":147,"description":1067,"status":1063,"children":-1},"A non-tmux user finally discovers terminal multiplexers through Zellij",{"title":153,"path":154,"stem":155,"description":1069,"status":1063,"children":-1},"I optimized my AI coding loop for the wrong thing. It looked fast. It wasn't effective.",1776221196452]