<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://ralphstarter.ai/blog</id>
    <title>ralph-starter - AI-Powered Autonomous Coding from Specs to Production Blog</title>
    <updated>2026-04-08T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://ralphstarter.ai/blog"/>
    <subtitle>ralph-starter - AI-Powered Autonomous Coding from Specs to Production Blog</subtitle>
    <icon>https://ralphstarter.ai/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Spec Driven Development with ralph-starter]]></title>
        <id>https://ralphstarter.ai/blog/spec-driven-development-ralph-starter</id>
        <link href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter"/>
        <updated>2026-04-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How ralph-starter brings Spec Driven Development to any AI coding agent, with native OpenSpec support, spec validation, and multi-source spec fetching.]]></summary>
        <content type="html"><![CDATA[<p>Spec Driven Development is the biggest shift in AI coding since agents learned to run tests. Here is how ralph-starter fits in.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-problem-with-just-prompt-it">The problem with "just prompt it"<a href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter#the-problem-with-just-prompt-it" class="hash-link" aria-label="Direct link to The problem with &quot;just prompt it&quot;" title="Direct link to The problem with &quot;just prompt it&quot;" translate="no">​</a></h2>
<p>Most people use AI coding agents the same way: type a sentence, hit enter, hope for the best. "Add user auth." "Fix the sidebar." Three words and vibes.</p>
<p>I did this for weeks. The agent would generate something that looked plausible but missed what I actually wanted. I blamed the tool, but the problem was me. I was not giving it enough context.</p>
<p>Then I started writing specs -- not essays, just 10-20 lines describing what I actually wanted, how to verify it, and where things should go. The difference was night and day. 2 loops instead of 5. $0.50 instead of $3. Correct output instead of close-but-wrong.</p>
<p>This pattern has a name now: <strong>Spec Driven Development (SDD)</strong>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-sdd-landscape">The SDD landscape<a href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter#the-sdd-landscape" class="hash-link" aria-label="Direct link to The SDD landscape" title="Direct link to The SDD landscape" translate="no">​</a></h2>
<p>Three frameworks are leading the SDD conversation:</p>
<table><thead><tr><th>Tool</th><th>Philosophy</th><th>Lock-in</th></tr></thead><tbody><tr><td><strong>OpenSpec</strong> (Fission AI)</td><td>Lightweight, fluid, tool-agnostic</td><td>None</td></tr><tr><td><strong>Spec-Kit</strong> (GitHub)</td><td>Heavyweight, rigid 5-phase gates</td><td>GitHub ecosystem</td></tr><tr><td><strong>Kiro</strong> (AWS)</td><td>Full IDE with built-in agents</td><td>AWS account required</td></tr></tbody></table>
<p>OpenSpec organizes specs into changes with <code>proposal.md</code>, <code>design.md</code>, <code>tasks.md</code>, and requirement specs using RFC 2119 keywords (SHALL, MUST, SHOULD). It is the lightest of the three.</p>
<p>Spec-Kit enforces five phases: constitution, specification, plan, tasks, implement. Thorough but heavy.</p>
<p>Kiro bundles everything into a VS Code fork with agent hooks and EARS notation. Powerful but locked to AWS.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="where-ralph-starter-fits">Where ralph-starter fits<a href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter#where-ralph-starter-fits" class="hash-link" aria-label="Direct link to Where ralph-starter fits" title="Direct link to Where ralph-starter fits" translate="no">​</a></h2>
<p>ralph-starter takes a different angle: <strong>your specs already exist somewhere</strong>.</p>
<p>They are in GitHub Issues. Linear tickets. Notion docs. Figma designs. OpenSpec directories. Why rewrite them in a new format?</p>
<p>ralph-starter pulls specs from where they already live:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># From GitHub issues</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> myorg/myrepo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--label</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"ready"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># From OpenSpec directories</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> openspec:add-auth</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># From Linear tickets</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Mobile App"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># From a Notion doc</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> notion </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"https://notion.so/spec-abc123"</span><br></span></code></pre></div></div>
<p>Then it runs autonomous loops: build context, spawn agent, collect output, run validation (lint/build/test), commit, repeat until done.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="new-in-v050-openspec--spec-validation">New in v0.5.0: OpenSpec + spec validation<a href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter#new-in-v050-openspec--spec-validation" class="hash-link" aria-label="Direct link to New in v0.5.0: OpenSpec + spec validation" title="Direct link to New in v0.5.0: OpenSpec + spec validation" translate="no">​</a></h2>
<p>We just shipped native OpenSpec support and a spec validator:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># List all OpenSpec changes in the project</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter spec list</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Validate spec completeness (0-100 score)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter spec validate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Validate before running -- stops if spec is too thin</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> openspec:my-feature --spec-validate</span><br></span></code></pre></div></div>
<p>The validator checks for:</p>
<ul>
<li class="">Proposal or rationale section (why are we building this?)</li>
<li class="">RFC 2119 keywords (SHALL, MUST -- formal requirements)</li>
<li class="">Given/When/Then acceptance criteria (testable conditions)</li>
<li class="">Design section (how to build it)</li>
<li class="">Task breakdown (implementation steps)</li>
</ul>
<p>A spec scoring below 40/100 gets flagged before the agent starts. This saves tokens on underspecified work.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-new-spec-command">The new spec command<a href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter#the-new-spec-command" class="hash-link" aria-label="Direct link to The new spec command" title="Direct link to The new spec command" translate="no">​</a></h2>
<p><code>ralph-starter spec</code> gives you a CLI for spec operations:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Validate all specs in the project</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter spec validate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># List available specs (auto-detects OpenSpec, Spec-Kit, or raw)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter spec list</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Show completeness summary</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter spec summary</span><br></span></code></pre></div></div>
<p>It auto-detects whether you are using OpenSpec format, GitHub Spec-Kit format, or plain markdown specs.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-numbers">The numbers<a href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter#the-numbers" class="hash-link" aria-label="Direct link to The numbers" title="Direct link to The numbers" translate="no">​</a></h2>
<table><thead><tr><th>Metric</th><th>Without specs</th><th>With specs</th></tr></thead><tbody><tr><td>Loops per task</td><td>5</td><td>2</td></tr><tr><td>Cost per task</td><td>~$3.00</td><td>~$0.50</td></tr><tr><td>Output accuracy</td><td>Hit or miss</td><td>Consistent</td></tr><tr><td>Time writing spec</td><td>0 min</td><td>3 min</td></tr></tbody></table>
<p>The 3 minutes spent writing a spec save 15 minutes of iteration and debugging. The spec is the leverage.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-is-next">What is next<a href="https://ralphstarter.ai/blog/spec-driven-development-ralph-starter#what-is-next" class="hash-link" aria-label="Direct link to What is next" title="Direct link to What is next" translate="no">​</a></h2>
<p>We are working on:</p>
<ul>
<li class=""><strong>Spec coverage tracking</strong> -- which requirements have been implemented?</li>
<li class=""><strong>Spec-to-test generation</strong> -- Given/When/Then to test stubs</li>
<li class=""><strong>Living specs</strong> -- specs that update as implementation diverges</li>
</ul>
<p>SDD is not a fad. It is the natural evolution of AI-assisted coding. The spec is the interface between human intent and machine execution. The clearer the spec, the better the output.</p>
<p>ralph-starter is open source, MIT licensed: <a href="https://github.com/multivmlabs/ralph-starter" target="_blank" rel="noopener noreferrer" class="">github.com/multivmlabs/ralph-starter</a></p>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="sdd" term="sdd"/>
        <category label="openspec" term="openspec"/>
        <category label="specs" term="specs"/>
        <category label="workflow" term="workflow"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How ralph-starter Converts Figma Designs to Pixel-Perfect Code]]></title>
        <id>https://ralphstarter.ai/blog/figma-to-code-visual-validation</id>
        <link href="https://ralphstarter.ai/blog/figma-to-code-visual-validation"/>
        <updated>2026-03-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Convert Figma designs to production-ready code with pixel-by-pixel visual validation. ralph-starter v0.4.0 introduces a three-layer comparison pipeline that catches layout, color, and typography mismatches automatically.]]></summary>
        <content type="html"><![CDATA[<p>I ran <code>ralph-starter figma</code>, pasted a Figma URL, picked my tech stack, and walked away. When I came back, the generated landing page matched the Figma design at 98.2% pixel accuracy. The AI agent had caught its own font-size mismatch, fixed it, and passed a strict visual comparison — all without me writing a single line of code.</p>
<p>This is how Figma-to-code should work. Here is exactly how it does.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-figma-to-code-gap">The Figma-to-code gap<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#the-figma-to-code-gap" class="hash-link" aria-label="Direct link to The Figma-to-code gap" title="Direct link to The Figma-to-code gap" translate="no">​</a></h2>
<p>Every developer has been here: you get a Figma design, spend hours eyeballing spacing values, manually extracting colors, guessing which font weight the designer used, and then the design review comes back with 30 comments about misaligned elements.</p>
<p>Tools like the official Figma MCP and others try to solve this, but most of them break down when the designer did not use Auto Layout. Real-world Figma files are messy — absolute positioning, nested frames without constraints, text layers with overrides.</p>
<p>ralph-starter takes a different approach. It reads the raw Figma node tree via the REST API and calculates positioning and z-index from the actual coordinates of each element. It does not depend on how the designer organized the layers.</p>
<p>Messy Figma file? Works the same.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="one-command-ralph-starter-figma">One command: <code>ralph-starter figma</code><a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#one-command-ralph-starter-figma" class="hash-link" aria-label="Direct link to one-command-ralph-starter-figma" title="Direct link to one-command-ralph-starter-figma" translate="no">​</a></h2>
<p>The v0.4.0 release adds an interactive wizard that handles the full workflow:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter figma</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Figma to Code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Design to code </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> one </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">command</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">? Figma design URL: https://figma.com/design/ABC123/Dashboard</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">? What would you like to build? responsive dashboard with sidebar nav</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">? Tech stack? Next.js + TypeScript + Tailwind CSS </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">Detected</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">? Which model? Claude Opus </span><span class="token number">4.6</span><span class="token plain"> — maximum quality </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">Recommended</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Four steps:</p>
<ol>
<li class=""><strong>Paste the Figma URL.</strong> Any design file link works — no special setup or plugins needed.</li>
<li class=""><strong>Describe what to build.</strong> A short natural-language description of the component or page.</li>
<li class=""><strong>Pick your tech stack.</strong> Auto-detected from your <code>package.json</code>. Supports Next.js, React, Vue, Nuxt, Svelte, Astro, and plain HTML.</li>
<li class=""><strong>Choose a model.</strong> ralph-starter detects which AI coding agents you have installed (Claude Code, Cursor, Codex, Gemini CLI, GitHub Copilot, etc.) and shows the relevant models.</li>
</ol>
<p>Under the hood, it extracts a complete technical spec from the Figma API — typography, colors, spacing, images, icons, font detection — and passes it to the AI agent along with an implementation plan. The agent works in an autonomous loop: write code, validate with lint and build, commit, repeat.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="three-layer-visual-validation">Three-layer visual validation<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#three-layer-visual-validation" class="hash-link" aria-label="Direct link to Three-layer visual validation" title="Direct link to Three-layer visual validation" translate="no">​</a></h2>
<p>The real differentiator in v0.4.0 is the visual validation pipeline. After each coding iteration, ralph-starter doesn't just check if the code builds — it checks if it <em>looks right</em>.</p>
<h3 class="anchor anchorTargetStickyNavbar_RDz4" id="layer-1-pixel-comparison-pixelmatch">Layer 1: Pixel comparison (pixelmatch)<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#layer-1-pixel-comparison-pixelmatch" class="hash-link" aria-label="Direct link to Layer 1: Pixel comparison (pixelmatch)" title="Direct link to Layer 1: Pixel comparison (pixelmatch)" translate="no">​</a></h3>
<p>ralph-starter starts your dev server, captures a full-page screenshot with Playwright, and runs <a href="https://github.com/mapbox/pixelmatch" target="_blank" rel="noopener noreferrer" class="">pixelmatch</a> against a screenshot of the Figma design. If the pixel difference is under 2%, it passes immediately. Zero LLM cost.</p>
<h3 class="anchor anchorTargetStickyNavbar_RDz4" id="layer-2-llm-vision-analysis">Layer 2: LLM vision analysis<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#layer-2-llm-vision-analysis" class="hash-link" aria-label="Direct link to Layer 2: LLM vision analysis" title="Direct link to Layer 2: LLM vision analysis" translate="no">​</a></h3>
<p>When the pixel diff exceeds 2%, things get interesting. ralph-starter sends three images to an LLM vision API:</p>
<ul>
<li class="">The original Figma design screenshot</li>
<li class="">The implementation screenshot</li>
<li class="">A diff overlay where red pixels highlight the mismatches</li>
</ul>
<p>The model returns actionable, numbered issues:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">1. Header font should be 88px serif, currently 40px sans-serif</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">2. Section gap should be ~80px, currently ~20px</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">3. Button border-radius should be 8px, currently square</span><br></span></code></pre></div></div>
<p>The agent then fixes each issue in the next loop iteration.</p>
<h3 class="anchor anchorTargetStickyNavbar_RDz4" id="layer-3-strict-gate">Layer 3: Strict gate<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#layer-3-strict-gate" class="hash-link" aria-label="Direct link to Layer 3: Strict gate" title="Direct link to Layer 3: Strict gate" translate="no">​</a></h3>
<p>After fixes are applied, the pipeline runs pixelmatch again with a strict 2% threshold. This catches anything the LLM missed — sub-pixel rendering differences are fine, but real layout or color mismatches get flagged for another round.</p>
<p>Here is what a typical run looks like end-to-end:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">→ Capturing implementation screenshot</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">→ Running pixel comparison</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Pixel diff: </span><span class="token number">8.3</span><span class="token plain">% </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">14,231</span><span class="token plain"> pixels differ</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> — analyzing</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">→ Sending to LLM vision </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> semantic analysis</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token number">1</span><span class="token plain">. Header font should be 88px serif, currently 40px sans-serif</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token number">2</span><span class="token plain">. Section gap should be ~80px, currently ~20px</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">→ Agent fixing </span><span class="token number">2</span><span class="token plain"> issues</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">→ Re-running strict pixel comparison</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Pixel diff: </span><span class="token number">1.1</span><span class="token plain">% — strict check passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✓ Visual validation passed</span><br></span></code></pre></div></div>
<p>Playwright and sharp are auto-installed the first time visual validation runs. No manual setup needed.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-gets-extracted-from-figma">What gets extracted from Figma<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#what-gets-extracted-from-figma" class="hash-link" aria-label="Direct link to What gets extracted from Figma" title="Direct link to What gets extracted from Figma" translate="no">​</a></h2>
<p>ralph-starter does not just grab colors and text. The full extraction includes:</p>
<ul>
<li class=""><strong>Typography</strong>: font family, size, weight, line height, letter spacing, text decoration</li>
<li class=""><strong>Colors</strong>: fills, strokes, gradients, opacity values</li>
<li class=""><strong>Spacing</strong>: padding, margins, gaps calculated from element coordinates</li>
<li class=""><strong>Layout</strong>: auto-layout properties, constraints, absolute positioning</li>
<li class=""><strong>Images and icons</strong>: downloaded at correct scale, optimized with sharp</li>
<li class=""><strong>Fonts</strong>: Google Fonts detected and configured in your project automatically</li>
<li class=""><strong>Component variants</strong>: component properties and variant metadata preserved</li>
<li class=""><strong>Effects</strong>: shadows, blurs, and other layer effects</li>
</ul>
<p>Five extraction modes are available: <code>spec</code> (default), <code>tokens</code>, <code>components</code>, <code>assets</code>, and <code>content</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="works-with-any-ai-coding-agent">Works with any AI coding agent<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#works-with-any-ai-coding-agent" class="hash-link" aria-label="Direct link to Works with any AI coding agent" title="Direct link to Works with any AI coding agent" translate="no">​</a></h2>
<p>ralph-starter is agent-agnostic. The Figma wizard works with:</p>
<ul>
<li class=""><strong>Claude Code</strong> (Claude Opus 4.6, Sonnet 4.5)</li>
<li class=""><strong>Cursor</strong> (any model)</li>
<li class=""><strong>OpenAI Codex</strong> (o3, o4-mini)</li>
<li class=""><strong>Gemini CLI</strong> (Gemini models)</li>
<li class=""><strong>GitHub Copilot</strong></li>
<li class=""><strong>OpenCode</strong></li>
<li class=""><strong>Amp</strong></li>
</ul>
<p>Skills (Tailwind v4, React best practices, design systems) are auto-injected into the agent's context, so it generates code that follows current best practices regardless of which agent you choose.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="try-it">Try it<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#try-it" class="hash-link" aria-label="Direct link to Try it" title="Direct link to Try it" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token function" style="color:rgb(80, 250, 123)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-g</span><span class="token plain"> ralph-starter@latest</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter figma</span><br></span></code></pre></div></div>
<p>Or without installing:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter figma</span><br></span></code></pre></div></div>
<p>The tool is free and open source. Costs come from the AI agent you choose — typically $0.10 to $1.00 per page depending on complexity and model.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="beyond-figma">Beyond Figma<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#beyond-figma" class="hash-link" aria-label="Direct link to Beyond Figma" title="Direct link to Beyond Figma" translate="no">​</a></h2>
<p>ralph-starter is not just for Figma. The same autonomous loop works with specs from GitHub issues, Linear tickets, Notion pages, URLs, PDFs, and plain text files. Point it at a spec, pick an agent, and let it build.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">42</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--label</span><span class="token plain"> ready </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> notion </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"API Spec"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/figma-to-code-visual-validation#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/docs/sources/figma">Figma wizard CLI docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/sources/figma">Figma integration guide</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/advanced/validation">Visual validation docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/intro">Supported agents</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/guides/cost-tracking">Cost tracking guide</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/community/changelog">Full v0.4.0 changelog</a></li>
<li class=""><a href="https://github.com/multivmlabs/ralph-starter" target="_blank" rel="noopener noreferrer" class="">GitHub repository</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="figma" term="figma"/>
        <category label="visual-validation" term="visual-validation"/>
        <category label="design-to-code" term="design-to-code"/>
        <category label="tutorial" term="tutorial"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[ralph-starter vs doing it manually]]></title>
        <id>https://ralphstarter.ai/blog/ralph-starter-vs-manual</id>
        <link href="https://ralphstarter.ai/blog/ralph-starter-vs-manual"/>
        <updated>2026-02-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I tracked one full sprint week. 6 tasks manual, 6 with ralph-starter. 45 min vs 12 min per task. $1.87 total for the automated half.]]></summary>
        <content type="html"><![CDATA[<p>I tracked one full week of development. Half the tasks with ralph-starter, half by hand. Same sprint, same project, same me, same coffee intake (a lot).</p>
<p>Look, I have been telling people ralph-starter saves time for weeks, but I realized I had never actually measured it. I was just vibing on the feeling that things were faster. That is not great. So I ran an honest experiment on myself.</p>
<p>12 features from the sprint backlog. All had clear specs in <a class="" href="https://ralphstarter.ai/blog/ralph-starter-with-linear">Linear</a>. Endpoints, bug fixes, component updates, tests. Nothing exotic -- the kind of stuff that fills up every sprint everywhere.</p>
<p>I split them down the middle. 6 done manually (IDE open, ChatGPT tab, write code, run tests, fix, commit, repeat). 6 with ralph-starter.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="manual-the-way-i-have-been-doing-it-for-years">Manual: the way I have been doing it for years<a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual#manual-the-way-i-have-been-doing-it-for-years" class="hash-link" aria-label="Direct link to Manual: the way I have been doing it for years" title="Direct link to Manual: the way I have been doing it for years" translate="no">​</a></h2>
<p>Read the ticket. Think about approach. Open files. Start coding. Hit a snag, open ChatGPT, paste context, get a suggestion back, realize it is not quite right, spend 10 minutes adapting it. Run tests. Something fails. Fix it. Run lint. Fix that too. Commit. Push. Open PR. You know this loop. You have lived this loop.</p>
<p>Average: <strong>45 minutes per task</strong> for a total of about 4.5 hours of focused work.</p>
<p>And honestly, "focused" is generous. A chunk of that time was me being a human clipboard between ChatGPT and my editor. The AI was helpful but I was the integration layer. I was the glue code.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="ralph-starter-the-other-way">ralph-starter: the other way<a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual#ralph-starter-the-other-way" class="hash-link" aria-label="Direct link to ralph-starter: the other way" title="Direct link to ralph-starter: the other way" translate="no">​</a></h2>
<p>Read ticket. Label it "ralph-ready". Run one command. Go do something else. Review the PR when it shows up.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> ENG </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> ENG-71 </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fetching spec from Linear: ENG-71</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → </span><span class="token string" style="color:rgb(255, 121, 198)">"Add email validation to signup form"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">4</span><span class="token plain"> passed, </span><span class="token number">1</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing: regex pattern </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> edge </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">case</span><span class="token plain"> emails</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">5</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. clean ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Opening PR </span><span class="token comment" style="color:rgb(98, 114, 164)">#112...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 1m 38s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.23 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">17,640</span><br></span></code></pre></div></div>
<p>Average: <strong>12 minutes per task</strong> -- and most of that was waiting while I worked on other stuff. The actual hands-on time for all 6 was about 1.2 hours. Reading the PR, checking the diff, approving or leaving a comment. That is it.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="quality">Quality<a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual#quality" class="hash-link" aria-label="Direct link to Quality" title="Direct link to Quality" translate="no">​</a></h2>
<p>Both approaches produced working code. Tests passed, lint passed. The ralph-starter PRs were more verbose in places -- the AI writes way more error handling and comments than I would. I would have skipped half those try/catch blocks. Probably better practice, but yeah, I am lazier than the AI.</p>
<p>Nothing needed major rework either way. The AI code was not worse. It was just... more cautious than I am.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="where-ralph-starter-won">Where ralph-starter won<a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual#where-ralph-starter-won" class="hash-link" aria-label="Direct link to Where ralph-starter won" title="Direct link to Where ralph-starter won" translate="no">​</a></h2>
<p><strong>Consistency.</strong> Every single PR had tests, passed lint, passed build. When I code manually I sometimes skip writing tests for small changes -- "it is just a tiny fix, I will add tests later." (I never add tests later.) The validation loop does not let the AI get away with that. I talked about this in the <a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">Ralph Wiggum technique</a> post -- the loop enforces discipline that I personally do not have.</p>
<p><strong>Throughput.</strong> 6 features in the time I would normally do 2, maybe 3 -- closer to 3.5x once you factor in all the context switching overhead from doing things manually.</p>
<p><strong>Cost.</strong> The 6 ralph-starter tasks cost $1.87 total in API spend -- six tasks for less than two dollars. I <a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">track costs carefully</a> now and this is pretty typical.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="where-i-won">Where I won<a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual#where-i-won" class="hash-link" aria-label="Direct link to Where I won" title="Direct link to Where I won" translate="no">​</a></h2>
<p><strong>Complex design decisions.</strong> One task needed choosing between two data modeling approaches. The AI would have just picked one and run with it. I needed to think through tradeoffs, talk to the team, consider what happens next quarter. Ralph Wiggum vibes do not work here -- <em>"I choo-choo-choose you!"</em> is not a valid data modeling strategy.</p>
<p><strong>Knowing stuff the AI does not.</strong> On a refactoring task, I knew a certain pattern was going to be deprecated next sprint. The AI had no idea. It would have happily written more of the old pattern and felt great about it. Sometimes you need the person who was in last week's meeting.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-i-took-away-from-this">What I took away from this<a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual#what-i-took-away-from-this" class="hash-link" aria-label="Direct link to What I took away from this" title="Direct link to What I took away from this" translate="no">​</a></h2>
<p>ralph-starter is better than me at "turn this spec into code." Faster, more consistent, less lazy about error handling. I am better than the AI at "figure out what we should build."</p>
<p>So now I focus on three things: writing <a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">clear specs</a> (AI input), reviewing PRs (AI output), and architecture decisions (AI blind spot). The mechanical part in between -- translating spec to code -- ralph-starter does that. And it does not get distracted by Slack.</p>
<p>Want to run your own comparison?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token function" style="color:rgb(80, 250, 123)">npm</span><span class="token plain"> i </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-g</span><span class="token plain"> ralph-starter</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter init</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> YOUR_ISSUE </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><br></span></code></pre></div></div>
<p>Pick a task you would normally do by hand. Time yourself both ways. I think you will be surprised.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/why-i-built-ralph-starter">Why I built ralph-starter</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">Specs are the new code</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">The Ralph Wiggum technique</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-with-linear">ralph-starter with Linear</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">Prompt caching saved me $47</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/intro">Getting started docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/cli/auto">Auto mode docs</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="comparison" term="comparison"/>
        <category label="productivity" term="productivity"/>
        <category label="workflow" term="workflow"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[I tried 5 AI coding agents with ralph-starter]]></title>
        <id>https://ralphstarter.ai/blog/five-ai-coding-agents</id>
        <link href="https://ralphstarter.ai/blog/five-ai-coding-agents"/>
        <updated>2026-02-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I ran the same JWT auth task on Claude Code, Cursor, Codex CLI, and OpenCode. Real times, real costs, real results.]]></summary>
        <content type="html"><![CDATA[<p>ralph-starter works with multiple coding agents. I use Claude Code for basically everything, but I wanted to actually test the others on real tasks instead of just assuming. So I ran the same task on Claude Code, Cursor, Codex CLI, and OpenCode over the past few weeks. Some surprises, some not.</p>
<p>Quick note: ralph-starter auto-detects which agents you have installed. Checks in order: Claude Code, Cursor, Codex, OpenCode. Uses the first one it finds. You can also be explicit:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add pagination to /api/users"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> claude-code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Agent: Claude Code v1.0.16 </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">auto-detected</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Mode: autonomous </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">--dangerously-skip-permissions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Output: stream-json</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop </span><span class="token number">1</span><span class="token plain">/3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span></code></pre></div></div>
<p>Swapping agents is just a flag:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> claude-code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> cursor</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> codex</span><br></span></code></pre></div></div>
<p>For this comparison I ran the same task -- "add JWT auth middleware with tests" -- on each agent. Same project, same spec, same validation pipeline. Tried to make it as fair as possible.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="claude-code">Claude Code<a href="https://ralphstarter.ai/blog/five-ai-coding-agents#claude-code" class="hash-link" aria-label="Direct link to Claude Code" title="Direct link to Claude Code" translate="no">​</a></h2>
<p>My daily driver, and honestly it's not close. Fastest for autonomous loops because of <a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">prompt caching</a> -- 90% less on input tokens after the first loop -- and the stream-json output lets ralph-starter track progress in real time. But the real reason I keep coming back: it just handles multi-file changes without flinching. Create a middleware file, write tests for it, update 3 route files, wire it all together. Done. Other agents sometimes get nervous about touching too many files.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add JWT auth middleware"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> claude-code </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 1m 22s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.28 </span><span class="token operator">|</span><span class="token plain"> Loops: </span><span class="token number">2</span><span class="token plain">/3</span><br></span></code></pre></div></div>
<p><code>npm i -g @anthropic-ai/claude-code</code></p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="cursor">Cursor<a href="https://ralphstarter.ai/blog/five-ai-coding-agents#cursor" class="hash-link" aria-label="Direct link to Cursor" title="Direct link to Cursor" translate="no">​</a></h2>
<p>Cursor is good if you're already living in the Cursor IDE. It indexes your workspace, so it knows your project structure out of the box. The catch is it's more interactive by nature -- autonomous mode requires some extra config to work smoothly.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add JWT auth middleware"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> cursor </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 2m 48s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.41 </span><span class="token operator">|</span><span class="token plain"> Loops: </span><span class="token number">3</span><span class="token plain">/3</span><br></span></code></pre></div></div>
<p>Slower and 46% more expensive than Claude Code on the same task. It needed all 3 loops to finish. Got there eventually, but I wouldn't pick it for batch processing a bunch of issues. If you're already a Cursor user and want to stay in that ecosystem, it works. Otherwise I'd go with Claude Code.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="codex-cli">Codex CLI<a href="https://ralphstarter.ai/blog/five-ai-coding-agents#codex-cli" class="hash-link" aria-label="Direct link to Codex CLI" title="Direct link to Codex CLI" translate="no">​</a></h2>
<p>OpenAI's entry. It supports <code>--auto-approve</code> for autonomous mode, which is nice. The code it produces is clean and conservative -- it's the "measure twice, cut once" agent. Doesn't try to do too much at once. The flip side is it won't tackle big multi-file refactors the way Claude Code will. It kind of plays it safe, which is fine for straightforward features but frustrating when you need it to be bold.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add JWT auth middleware"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> codex </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 2m 15s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.35 </span><span class="token operator">|</span><span class="token plain"> Loops: </span><span class="token number">2</span><span class="token plain">/3</span><br></span></code></pre></div></div>
<p><code>npm i -g codex</code></p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="opencode">OpenCode<a href="https://ralphstarter.ai/blog/five-ai-coding-agents#opencode" class="hash-link" aria-label="Direct link to OpenCode" title="Direct link to OpenCode" translate="no">​</a></h2>
<p>The newest one, and it supports <code>--auto</code> for autonomous mode. I'll be real: it's the least polished of the bunch right now. I've gotten decent results on smaller, focused tasks -- single-file stuff, utility functions, that kind of thing. But the JWT middleware task tripped it up because it needed to coordinate changes across multiple files. It kept getting confused about which file it had already edited. Still early days though, and it's improving fast.</p>
<p><code>npm i -g opencode</code></p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-actually-matters">What actually matters<a href="https://ralphstarter.ai/blog/five-ai-coding-agents#what-actually-matters" class="hash-link" aria-label="Direct link to What actually matters" title="Direct link to What actually matters" translate="no">​</a></h2>
<p>After running all these comparisons, the validation pipeline matters way more than which agent you pick. Tests, lint, build -- those catch mistakes regardless of who wrote the code. A weaker agent that iterates 5 times with test feedback produces better code than a strong agent running once with no tests. The loop is the product, not the agent. That is the whole <a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">Ralph Wiggum technique</a>.</p>
<p>My actual config:</p>
<div class="language-yaml codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-yaml codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token key atrule">agent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> claude</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">auto_commit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">max_iterations</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token number">50</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">validation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> npm test</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> npm run build</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> npm run lint</span><br></span></code></pre></div></div>
<p>If one agent doesn't work for a task, I just switch. ralph-starter is agent-agnostic on purpose -- the loop executor and validation pipeline work the same regardless of which AI is doing the coding.</p>
<p>My honest advice? If you're starting fresh, install Claude Code. It's what I use for 95% of my work, the <a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">prompt caching</a> makes it the cheapest option for loops, and it handles multi-file tasks better than anything else I've tried. If you already have something installed, start with that. Don't overthink it.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span></code></pre></div></div>
<p>It'll detect what you have and set things up. Pick one and start looping.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/five-ai-coding-agents#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">The Ralph Wiggum technique</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">Prompt caching saved me $47</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup">ralph-starter + Claude Code: the full setup</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/cli/run">Agent configuration docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/cli/init">ralph-starter init docs</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="agents" term="agents"/>
        <category label="claude-code" term="claude-code"/>
        <category label="cursor" term="cursor"/>
        <category label="codex" term="codex"/>
        <category label="comparison" term="comparison"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Ralph Wiggum technique explained in 2 minutes]]></title>
        <id>https://ralphstarter.ai/blog/ralph-wiggum-technique</id>
        <link href="https://ralphstarter.ai/blog/ralph-wiggum-technique"/>
        <updated>2026-02-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The Ralph Wiggum technique is running AI coding agents in loops until done. Created by Geoffrey Huntley, now used by Claude Code and others.]]></summary>
        <content type="html"><![CDATA[<p>The Ralph Wiggum technique is running AI coding agents in autonomous loops until the task is done. You give it a job, walk away, come back to a PR. That is the whole idea.</p>
<p>The technique was created by <a href="https://ghuntley.com/" target="_blank" rel="noopener noreferrer" class="">Geoffrey Huntley</a>, an open source developer in Australia who started experimenting with autonomous AI coding loops in mid-2025. His <a href="https://github.com/ghuntley/how-to-ralph-wiggum" target="_blank" rel="noopener noreferrer" class="">original implementation</a> was almost disappointingly simple: a bash while loop that feeds the same prompt to Claude over and over until the task is done. It went viral by the end of 2025 and has since been adopted by <a href="https://github.com/anthropics/claude-code/blob/main/plugins/ralph-wiggum/README.md" target="_blank" rel="noopener noreferrer" class="">Anthropic's Claude Code</a>, <a href="https://github.com/vercel-labs/ralph-loop-agent" target="_blank" rel="noopener noreferrer" class="">Vercel's AI SDK</a>, and others.</p>
<p>People always ask about the name. Yes, it is the Simpsons character. Ralph approaches everything with pure, unfiltered confidence and persistence. <em>"I'm learnding!"</em> He just... keeps going. And that is exactly what you want the AI to do.</p>
<p>Instead of treating the AI as a chat partner you go back and forth with, copy error, paste into chat, get fix, paste back, run tests, repeat, you treat it as a worker that iterates until done. You step out of the loop entirely.</p>
<p>Traditional AI coding (the clipboard dance):</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">You: "build this feature"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">AI: generates code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">You: *runs tests* "tests fail, here's the error"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">AI: generates fix</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">You: *runs lint* "linter is angry about unused imports"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">AI: another fix</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">You: *runs tests again* "ok now commit it"</span><br></span></code></pre></div></div>
<p>That is 4 round trips. Each one takes you 30 seconds to a minute because you have to context switch, copy output, paste it, wait for a response. It adds up fast.</p>
<p>Ralph Wiggum technique:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">You: "build this feature, run tests, fix errors, commit when done"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">AI: loops autonomously until everything passes</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">You: *reviews PR*</span><br></span></code></pre></div></div>
<p>One input. One output. Everything in between is handled.</p>
<p>The difference is not just convenience. The AI can iterate <em>fast</em> without waiting on a human to relay errors. It reads the error output directly, understands what went wrong, fixes it, re-runs validation. All in seconds. No clipboard involved.</p>
<p>Here is what it looks like in practice with ralph-starter:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add user registration with email/password"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--build</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Created: src/auth/register.ts, src/auth/__tests__/register.test.ts</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">3</span><span class="token plain"> passed, </span><span class="token number">2</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Test failure: bcrypt not imported</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing: adding bcrypt </span><span class="token function" style="color:rgb(80, 250, 123)">import</span><span class="token plain"> and </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">hash</span><span class="token plain"> logic</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">5</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">1</span><span class="token plain"> issue </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">unused variable</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">3</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing lint: removing unused </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">`</span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">salt</span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">`</span><span class="token plain"> variable</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. clean ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running build</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. success ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 1m 44s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.34 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">26,190</span><br></span></code></pre></div></div>
<p>Three loops, under 2 minutes, 34 cents. The agent saw the bcrypt error, fixed it, saw the lint warning, fixed that too -- I did not touch anything.</p>
<p>The loop executor runs the coding agent, checks the result against your test suite, lint, and build. If anything fails, the failure becomes context for the next loop. The agent sees the exact error message and fixes it. Just like Ralph Wiggum -- <em>"I bent my Wookiee"</em> -- it acknowledges the problem and keeps going.</p>
<p>Three things prevent it from going off the rails:</p>
<p><strong>Circuit breaker</strong> trips after 3 consecutive identical failures or 5 of the same error, so it does not keep burning tokens on something that is stuck. I have seen this save me money when a task genuinely needed a different approach.</p>
<p><strong>Completion detector</strong> verifies that files actually changed before accepting "I'm done" from the agent. Without this, the AI occasionally claims it finished without actually writing anything -- learned that one the hard way.</p>
<p><strong>Cost tracker</strong> runs in real time so you see what you are spending per iteration. Transparency matters when you are <a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">running lots of loops</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-works-and-what-does-not">What works and what does not<a href="https://ralphstarter.ai/blog/ralph-wiggum-technique#what-works-and-what-does-not" class="hash-link" aria-label="Direct link to What works and what does not" title="Direct link to What works and what does not" translate="no">​</a></h2>
<p>Best tasks for the Ralph Wiggum technique: well-defined inputs and outputs. Add an endpoint, fix a bug that has a failing test, implement a component from a <a class="" href="https://ralphstarter.ai/blog/figma-to-code-one-command">design spec</a>. Things where "done" is clear.</p>
<p>Worst tasks: vague ones like "make the code better" or "improve performance." The AI has no target to iterate toward. I learned this the hard way when I tried to <a class="" href="https://ralphstarter.ai/blog/automating-entire-workflows">batch process 10 issues</a> and the vague ones hit the circuit breaker every time.</p>
<p>Good specs, good tests, let the ralph loop handle the rest. That is the technique in one sentence.</p>
<p>Want to try the Ralph Wiggum technique on your own project?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task here"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p><em>"Hi, Super Nintendo Chalmers!"</em> -- just let Ralph do his thing.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/ralph-wiggum-technique#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/why-i-built-ralph-starter">Why I built ralph-starter</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/my-first-ralph-loop">My first ralph loop</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">Specs are the new code</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/figma-to-code-one-command">Figma to code in one command</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/intro">Getting started docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/cli/run">Loop executor docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/faq">FAQ about the technique</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-wiggum" term="ralph-wiggum"/>
        <category label="technique" term="technique"/>
        <category label="ai-coding" term="ai-coding"/>
        <category label="autonomous" term="autonomous"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Specs are the new code]]></title>
        <id>https://ralphstarter.ai/blog/specs-are-the-new-code</id>
        <link href="https://ralphstarter.ai/blog/specs-are-the-new-code"/>
        <updated>2026-02-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A clear 10-line spec gets you a working PR in 2 loops. A vague one-liner wastes 5 loops and costs 3x more. The spec is the code now.]]></summary>
        <content type="html"><![CDATA[<p>I spend more time writing specs than writing code now, and my output went up, not down. That genuinely surprised me.</p>
<p>When I started using ralph-starter I was writing lazy one-liners. "Add user auth." "Fix the sidebar." Three words and vibes. You can guess what happened. The AI generated something that looked plausible but completely missed what I actually wanted. I would look at the PR and think, "that is not even close to what I meant."</p>
<p>I blamed the tool for like two weeks, but the problem was me.</p>
<p>So I started writing real specs. Not essays -- I do not have time for that. Just clear, specific descriptions of what I actually want.</p>
<p>What I used to write:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Add authentication to the app</span><br></span></code></pre></div></div>
<p>What I write now:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Add JWT auth to the Express API.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- POST /api/auth/login takes { email, password }, validates against users table</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- Return { token, expiresIn } on success, 401 with { error } on failure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- Token TTL: 24h</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- Auth middleware goes in src/middleware/auth.ts (check Authorization: Bearer header)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">- Tests: login success, login failure, protected route without token</span><br></span></code></pre></div></div>
<p>That second spec is maybe 10 lines and took me 3 minutes to write. But it tells the agent exactly what to build, where to put it, and how to verify it works. ralph-starter turns that into an implementation plan and the agent nails it in 2 to 3 loops.</p>
<p>The difference is ridiculous:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Bad spec: vague task, agent guesses wrong</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"Add authentication to the app"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5 → tests failed </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">wrong auth strategy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5 → tests failed </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">missing middleware</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">3</span><span class="token plain">/5 → tests failed </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">wrong token </span><span class="token function" style="color:rgb(80, 250, 123)">format</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">4</span><span class="token plain">/5 → tests passed ✓ but not what I wanted</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 3m 45s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.94 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">71,203</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Good spec: clear requirements, agent nails it</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">42</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5 → tests: </span><span class="token number">2</span><span class="token plain"> passed, </span><span class="token number">1</span><span class="token plain"> failed </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">token expiry</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5 → tests: </span><span class="token number">3</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 1m 12s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.27 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">19,844</span><br></span></code></pre></div></div>
<p>Same feature. Same agent. Same model. The only difference was the spec. 67 cents and 2 minutes I did not need to spend. Better spec, fewer loops, <a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">less cost</a>, better code.</p>
<p>And this is exactly why the GitHub, <a class="" href="https://ralphstarter.ai/blog/ralph-starter-with-linear">Linear</a>, Notion integrations matter so much. You are probably already writing specs there. ralph-starter just pulls them directly. No copy-paste, no "let me summarize this ticket for the AI."</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> myorg/myrepo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">42</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><br></span></code></pre></div></div>
<p>After running hundreds of tasks, I am pretty confident about this: the quality of the PR is directly proportional to the quality of the issue. I have started treating it as a law of nature.</p>
<p>It completely changed how I write tickets. Every issue now has a clear description of what needs to happen. Not "improve the thing" but "response time of /api/users should be under 200ms." Acceptance criteria as a checklist. Technical context when it matters, like "we use Prisma" or "follow the pattern in <code>src/api/orders.ts</code>."</p>
<p>My whole workflow flipped. Before AI coding I spent maybe 10% of my time planning and 90% implementing. Now it is 40% writing specs and 60% reviewing output. Total time is less, quality is higher, and here is the bonus I did not expect: the specs double as documentation for what was built and why.</p>
<p>So if you are using ralph-starter and the output is not good enough, the fix is almost always in the spec -- not in the tool, not in the agent, not in the model.</p>
<p>Want to see the difference good specs make?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span></code></pre></div></div>
<p>Write a detailed issue, point ralph-starter at it, and watch what happens.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/specs-are-the-new-code#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/why-i-built-ralph-starter">Why I built ralph-starter</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-with-linear">ralph-starter with Linear</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">Prompt caching saved me $47</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">The Ralph Wiggum technique</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/guides/prd-workflow">PRD workflow guide</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/sources/overview">Sources overview</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="specs" term="specs"/>
        <category label="workflow" term="workflow"/>
        <category label="philosophy" term="philosophy"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Prompt caching saved me $47 last month]]></title>
        <id>https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars</id>
        <link href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars"/>
        <updated>2026-02-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Prompt caching gives 90% off input tokens after the first loop. My bill dropped from $109 to $62 last month without changing anything.]]></summary>
        <content type="html"><![CDATA[<p>I run ralph-starter a lot. Multiple tasks per day, 3 to 7 loops each. Last month I checked my Anthropic dashboard and the total was $62, almost scrolled past it, but then I looked at the prompt caching line and did the math. Without caching? $109. I saved $47 by literally doing nothing.</p>
<p>Ok so let me explain why this blew my mind.</p>
<p>Every time ralph-starter runs Claude Code in a loop, that first iteration ships everything over: system prompt, project files, the spec, the implementation plan. All fresh tokens, expensive. But Claude's prompt caching stores all of that server-side, so on loop 2, 3, 4 those same tokens cost 90% less. You basically get a discount for repeating yourself.</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Regular input:  $3.00 per million tokens</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Cache write:    $3.75 per million (first time, slight premium)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Cache read:     $0.30 per million (90% off)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Output:         $15.00 per million tokens</span><br></span></code></pre></div></div>
<p>Think about a 5-loop task. Something like 80% of the input tokens are identical every single iteration. The system prompt, the spec, your project context -- none of that changes between loops. The only new stuff is validation feedback, like test errors or lint output. So after loop 1, you are paying $0.30/M instead of $3.00/M on most of your input. Ten times cheaper, for free.</p>
<p>ralph-starter tracks all of this automatically. After every run you see exactly what you spent, no extra setup:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add pagination to /api/users"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">4</span><span class="token plain"> passed, </span><span class="token number">1</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Fixing: off-by-one </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> page calculation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">5</span><span class="token plain"> passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 1m 48s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.31 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">28,412</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Cost Breakdown:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Loop </span><span class="token number">1</span><span class="token plain">: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.22 </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">cache </span><span class="token function" style="color:rgb(80, 250, 123)">write</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Loop </span><span class="token number">2</span><span class="token plain">: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.09 </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">cache read, </span><span class="token number">90</span><span class="token plain">% savings on 22K input tokens</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Cache savings: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.18</span><br></span></code></pre></div></div>
<p>31 cents for pagination, tests, and a commit. I used to spend more than that on a single ChatGPT message and still have to copy-paste the code myself.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-affects-your-costs">What affects your costs<a href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars#what-affects-your-costs" class="hash-link" aria-label="Direct link to What affects your costs" title="Direct link to What affects your costs" translate="no">​</a></h2>
<p>More loops = more cache hits. Simple math. A 1-loop task barely benefits because the context gets cached but never reused. A 5-loop task though? Loops 2 through 5 all ride on that cached context. This is why the <a class="" href="https://ralphstarter.ai/blog/my-first-ralph-loop">ralph loop design</a> matters -- iteration is basically free once you have paid for the first pass.</p>
<p>Bigger specs also mean more tokens getting cached, so the absolute savings on subsequent loops go up. A detailed spec with acceptance criteria costs more on loop 1, sure, but the savings compound after that.</p>
<p>Oh and the Batch API is a completely different beast. <code>ralph-starter auto --batch</code> uses the Anthropic Batch API at a flat 50% discount on all tokens. Catch is it takes up to 24 hours and no tool use, but for straightforward tasks where you do not need results right now? Worth it. I wrote about that in the <a class="" href="https://ralphstarter.ai/blog/automating-entire-workflows">batch processing post</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-actually-helped-me-cut-costs">What actually helped me cut costs<a href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars#what-actually-helped-me-cut-costs" class="hash-link" aria-label="Direct link to What actually helped me cut costs" title="Direct link to What actually helped me cut costs" translate="no">​</a></h2>
<p>My first week came in at $35 and I panicked a little. Looked at the cost tracker and immediately saw the problem: I was setting <code>--loops 10</code> on everything. A task that completes in 2 loops does not need 10. I was being lazy with the flag and paying for it.</p>
<p>Now I keep it simple: <code>--loops 3</code> for easy stuff, <code>--loops 5</code> for complex things. I almost never go higher.</p>
<p>But the biggest cost optimization is not a caching trick -- it is writing <a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">better specs</a>. A clear spec means the agent gets it right in fewer loops, which means fewer API calls. A spec that lands in 2 iterations instead of 7 saves you way more than any caching ever could.</p>
<p>Want to see your own cost breakdown?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span></code></pre></div></div>
<p>Every run shows token usage and cost automatically. No extra config needed.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/my-first-ralph-loop">My first ralph loop</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">Specs are the new code</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/automating-entire-workflows">Automating entire workflows</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup">ralph-starter + Claude Code setup</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/guides/cost-tracking">Cost tracking guide</a></li>
<li class=""><a href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching" target="_blank" rel="noopener noreferrer" class="">Prompt caching docs</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="cost" term="cost"/>
        <category label="prompt-caching" term="prompt-caching"/>
        <category label="optimization" term="optimization"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How I ship tasks from Linear every day with AI]]></title>
        <id>https://ralphstarter.ai/blog/ralph-starter-with-linear</id>
        <link href="https://ralphstarter.ai/blog/ralph-starter-with-linear"/>
        <updated>2026-02-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[My daily workflow with ralph-starter and Linear. Morning standup, label tickets ralph-ready, batch process while I work on the hard stuff.]]></summary>
        <content type="html"><![CDATA[<p>Linear is where my team plans work. ralph-starter is where it gets built. I have been running this combo every single day for weeks now, and I want to show you exactly what my workflow looks like.</p>
<p>Every morning I open Linear and check the sprint. Tickets that are well-specified -- clear inputs, clear outputs -- I process with ralph-starter. Tickets that need thinking or architecture decisions? Those I handle myself. The split is usually 60/40 in ralph-starter's favor, which means I spend most of my day on the hard problems.</p>
<p>Setup is quick. One command:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> linear.apiKey lin_api_xxxxx</span><br></span></code></pre></div></div>
<p>For a single ticket:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> ENG </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> ENG-42 </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fetching spec from Linear: ENG-42</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → </span><span class="token string" style="color:rgb(255, 121, 198)">"Add retry logic to webhook delivery"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Priority: High </span><span class="token operator">|</span><span class="token plain"> Labels: backend, webhooks</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">6</span><span class="token plain"> passed, </span><span class="token number">2</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing: retry delay calculation off by one</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">8</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Opening PR </span><span class="token comment" style="color:rgb(98, 114, 164)">#94...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 1m 51s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.22 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">16,830</span><br></span></code></pre></div></div>
<p>It hits the Linear GraphQL API, pulls the title, description, priority, labels, sub-issues -- everything. All of that becomes context for the coding agent. The agent does not just see "add retry logic." It sees the full ticket with all the context your team wrote.</p>
<p>For batch processing I filter by label. We use "ralph-ready" for tickets that are groomed:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter auto </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--source</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> ENG </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--label</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"ralph-ready"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--limit</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Fetched </span><span class="token number">5</span><span class="token plain"> issues from Linear </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">sorted by priority</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain">:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Urgent:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ENG-89: Fix auth token expiry handling</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  High:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ENG-91: Add retry logic to webhook delivery</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ENG-93: Rate limit the public API</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Medium:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ENG-95: Add dark mode to settings</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ENG-97: Update user avatar component</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Processing</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span></code></pre></div></div>
<p>What Linear gives you that GitHub does not (at least not as cleanly) is structured data. Every ticket has priority (urgent, high, medium, low), status, labels -- and ralph-starter uses priority for task ordering, so urgent tickets get processed first.</p>
<p>My typical day looks like this: morning standup, I see 3 or 4 tickets assigned to me. I label the straightforward ones "ralph-ready" and kick off auto mode. While that runs, I work on the complex ticket that actually needs my brain. By the time I finish the hard work, ralph-starter has PRs waiting for my review. I wrote about this batch workflow in more detail in <a class="" href="https://ralphstarter.ai/blog/automating-entire-workflows">automating entire workflows</a> -- same idea, different source.</p>
<p>One thing that works really well is writing acceptance criteria as a checklist in Linear:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Acceptance:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">[ ] Endpoint returns JSON response with { data, meta } shape</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">[ ] Tests cover happy path and error case</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">[ ] No lint warnings</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">[ ] Build succeeds</span><br></span></code></pre></div></div>
<p>ralph-starter extracts those checkboxes from the ticket body and uses them as completion criteria. The agent knows it needs to satisfy each point before signaling done. This is why <a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">specs matter so much</a> -- the better your Linear tickets, the better the PRs.</p>
<p>The tickets that work best are the ones with clear inputs and outputs. "Add this endpoint", "Fix this test", "Update this component to match the new design." The ones that need a human are where the approach is not obvious, where you need to ask "should we even build this?"</p>
<p>Clear instructions work, vague ones don't -- same as with a human developer, really.</p>
<p>Want to connect your Linear workspace?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token function" style="color:rgb(80, 250, 123)">npm</span><span class="token plain"> i </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-g</span><span class="token plain"> ralph-starter</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter init</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> linear.apiKey lin_api_your_key_here</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> YOUR-PROJECT </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> YOUR-ISSUE </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/ralph-starter-with-linear#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/automating-entire-workflows">Automating entire workflows</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">Specs are the new code</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup">ralph-starter + Claude Code setup</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/sources/linear">Linear integration docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/cli/auto">Auto mode docs</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="linear" term="linear"/>
        <category label="workflow" term="workflow"/>
        <category label="daily-use" term="daily-use"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Automating entire workflows with ralph-starter]]></title>
        <id>https://ralphstarter.ai/blog/automating-entire-workflows</id>
        <link href="https://ralphstarter.ai/blog/automating-entire-workflows"/>
        <updated>2026-02-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[ralph-starter runs Ralph Wiggum loops. Fetch a spec, run the AI agent, check tests/lint/build, feed errors back, repeat. Here is how it works and why I built it.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://github.com/multivmlabs/ralph-starter" target="_blank" rel="noopener noreferrer" class="">ralph-starter</a> is a CLI tool that orchestrates AI coding agents in autonomous loops. You give it a task (or point it at a GitHub issue, a Linear ticket, a Notion page), it runs the agent, checks if tests pass, if lint is clean, if build works. If something fails it feeds the error back to the agent and loops again. When everything passes it commits, pushes, and opens a PR.</p>
<p>It supports Claude Code, Cursor, Codex CLI, OpenCode, Gemini CLI, Copilot, Amp, and Openclaw. You do not need to pick one in advance, it auto-detects what you have installed.</p>
<p>It is open source, MIT licensed. I built it because I was tired of being the middleman between my terminal and my AI chat window.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="why-i-built-it">Why I built it<a href="https://ralphstarter.ai/blog/automating-entire-workflows#why-i-built-it" class="hash-link" aria-label="Direct link to Why I built it" title="Direct link to Why I built it" translate="no">​</a></h2>
<p>I was using AI coding assistants every day. Claude, ChatGPT, Copilot, whatever was available. And the workflow was always the same: I read a ticket, I open the editor, I start coding, I get stuck, I open the AI chat, I paste the context, I get a suggestion, I adapt it, I paste it back. Then I run tests. Something breaks. I go back to the chat, paste the error, get a fix, paste that back. Lint complains. Another round trip. Then I commit, push, open a PR.</p>
<p>That is like 12 steps and I was doing it 5 to 8 times a day. The AI was doing the hard part (writing the code) and I was just the relay moving text between windows. I felt like a human clipboard.</p>
<p>So I wrote a script that does the relay for me. The script takes a spec, sends it to the agent, runs my test suite, and if something fails it sends the error output back to the agent automatically. No copying, no pasting, no switching windows. The agent sees the error and fixes it on its own.</p>
<p>That script grew into ralph-starter.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="where-it-is-most-useful">Where it is most useful<a href="https://ralphstarter.ai/blog/automating-entire-workflows#where-it-is-most-useful" class="hash-link" aria-label="Direct link to Where it is most useful" title="Direct link to Where it is most useful" translate="no">​</a></h2>
<p>ralph-starter works best when you have:</p>
<ol>
<li class=""><strong>A clear spec.</strong> "Add /health endpoint that returns 200 with JSON body <code>{ status: 'ok' }</code>" finishes in 1 loop. "Make the app better" will still run, the agent will analyze your codebase and pick something to improve, but it might take 4 loops and the result might not be what you wanted. The more specific the spec, the fewer loops and the better the output.</li>
<li class=""><strong>Tests.</strong> The loop needs something to validate against. If you have no tests the agent does not know when it is done.</li>
<li class=""><strong>Routine implementation work.</strong> Endpoints, bug fixes, component updates, adding tests, config changes. The stuff that fills up a sprint backlog.</li>
</ol>
<p>Vague specs do not break it, they just cost more. "Refactor the auth system" with no details will make the agent try different approaches each loop until the circuit breaker trips. "Add JWT middleware at src/middleware/auth.ts using bcrypt, httpOnly cookies, add tests for login success and failure" finishes in 2 loops because the agent knows exactly what done looks like.</p>
<p>I use it every day for the mechanical parts of development. I still do the thinking, the architecture, the spec writing. ralph-starter handles the translation from spec to code.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="getting-started">Getting started<a href="https://ralphstarter.ai/blog/automating-entire-workflows#getting-started" class="hash-link" aria-label="Direct link to Getting started" title="Direct link to Getting started" translate="no">​</a></h2>
<p>You can start from an idea and ralph-starter will generate the spec for you. Or you can point it at an existing GitHub issue or Linear ticket and it fetches the spec automatically.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Install and initialize</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span></code></pre></div></div>
<p><code>ralph-starter init</code> detects your project type (Node.js, Python, Rust, Go), finds which agents you have installed, and sets up your validation commands (test, lint, build). If it finds a Ralph Playbook in your project it picks up AGENTS.md, IMPLEMENTATION_PLAN.md, and your prompt files automatically.</p>
<p>Run your first task with an inline spec:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add a /ping endpoint that returns pong"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>Or point it at a GitHub issue or Linear ticket:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># From GitHub</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> rubenmarcus/ralph-starter </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># From Linear</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> ENG </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> ENG-71 </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><br></span></code></pre></div></div>
<p>To connect GitHub, Linear, Notion, or Figma as spec sources, use the config commands:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> github.token ghp_xxx</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> linear.apiKey lin_api_xxx</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> notion.apiKey ntn_xxx</span><br></span></code></pre></div></div>
<p><code>ralph-starter setup</code> configures the CLI agent preferences. Integrations are managed through <code>ralph-starter config</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="how-the-loop-works">How the loop works<a href="https://ralphstarter.ai/blog/automating-entire-workflows#how-the-loop-works" class="hash-link" aria-label="Direct link to How the loop works" title="Direct link to How the loop works" translate="no">​</a></h2>
<p>The loop executor follows this sequence:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">1. Fetch spec (GitHub issue, Linear ticket, inline text)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">2. Create branch (auto/42-health-endpoint)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">3. Run agent with the spec as prompt</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">4. Run validations: test → lint → build</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">5. If any validation fails → feed error output back to agent → go to step 3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">6. If all pass → commit, push, open PR</span><br></span></code></pre></div></div>
<p>The validation step is configurable in <code>ralph-starter.config.yaml</code>:</p>
<div class="language-yaml codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-yaml codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token key atrule">validation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> pnpm test</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> pnpm lint</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> pnpm build</span><br></span></code></pre></div></div>
<p>When a validation fails, ralph-starter takes the stderr/stdout and builds context for the next iteration. The context includes the original spec, the diff of what changed, and the full validation output. The agent sees <code>TypeError: Cannot read property 'id' of undefined at src/routes/user.ts:42</code> and knows exactly what to fix.</p>
<p>The agent does not get a summary. It gets the raw error. This is faster than me copying the error into a chat window because there is zero delay between failure and the next attempt.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="real-example-building-a-landing-page-from-a-github-issue">Real example: building a landing page from a GitHub issue<a href="https://ralphstarter.ai/blog/automating-entire-workflows#real-example-building-a-landing-page-from-a-github-issue" class="hash-link" aria-label="Direct link to Real example: building a landing page from a GitHub issue" title="Direct link to Real example: building a landing page from a GitHub issue" translate="no">​</a></h2>
<p>Here is a real run. I pointed ralph-starter at a GitHub issue that asked for a landing page for a London pet shop. The spec had 8 tasks (header, hero, services, gallery, testimonials, contact form, footer, polish).</p>
<p>ralph-starter detected 28 installed skills (frontend-design, tailwind, responsive-web-design, etc.), picked the relevant ones for the task, and started the loop with Claude Code.</p>
<p>The loop ran for 2 iterations. First iteration completed 5 out of 8 tasks (Project Setup, Header &amp; Navigation, Hero Section, Services Section, Featured Pets Gallery). Second iteration picked up the remaining tasks (Testimonials, Contact Form, Footer, Polish). It stopped automatically when no file changes were detected for 2 consecutive iterations.</p>
<p>Final result:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Cost Summary:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Tokens: 47.0K (764 in / 46.2K out)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Cost: $0.606 ($0.348/iteration avg)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop completed!</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Exit reason: completed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Iterations: 2</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Total duration: 8m 19s</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Total cost: $0.696 (47.0K tokens)</span><br></span></code></pre></div></div>
<p>8 minutes. 69 cents. A full landing page with React components, Tailwind styling, and responsive layout. I did not open the editor at all.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-it-actually-costs">What it actually costs<a href="https://ralphstarter.ai/blog/automating-entire-workflows#what-it-actually-costs" class="hash-link" aria-label="Direct link to What it actually costs" title="Direct link to What it actually costs" translate="no">​</a></h2>
<p>I personally use the Claude Max Plan, so my per-task cost is effectively zero on top of the monthly subscription. But ralph-starter tracks token usage either way, and for users on pay-per-token plans the numbers are worth knowing.</p>
<p>On the Anthropic API, a typical task runs <strong>$0.10 to $0.40</strong>. The reason it stays low is prompt caching. The first loop sends the full context at $3.00 per million input tokens. Loops 2, 3, 4 reuse the cached portion at $0.30 per million — 90% less. Most tasks finish in 2 to 3 loops, so the bulk of the input is already cached after the first one. I wrote the detailed breakdown with exact numbers <a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">here</a>.</p>
<p>You are not locked into Claude either. ralph-starter supports <strong>OpenRouter</strong>, which gives you access to cheaper models like <strong>Kimi K2</strong>, <strong>MiniMax</strong>, <strong>DeepSeek</strong>, and others. Some of these cost a fraction of what Claude or GPT-4 charge per token, and they work well for straightforward tasks. You can mix and match — use Claude Code for complex multi-file changes and a cheaper model for simple fixes.</p>
<p>Before each run, ralph-starter shows you an estimate so you know what to expect, and after each run it shows the actual cost breakdown: tokens in, tokens out, cache hits, cost per iteration.</p>
<p>A few things that help keep costs down regardless of which model you use:</p>
<ul>
<li class=""><strong>Good specs</strong> mean fewer loops. Clear acceptance criteria = agent knows when it is done.</li>
<li class=""><strong>Prompt caching</strong> saves 90% on input tokens after the first loop (on models that support it).</li>
<li class=""><strong>Circuit breaker</strong> stops tasks that are stuck, so you do not burn money on something unsolvable.</li>
<li class=""><strong>Skills</strong> teach the agent patterns so it gets things right faster (fewer iterations = less cost).</li>
<li class=""><strong>OpenRouter</strong> lets you pick the cheapest model that can handle each task.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="batch-mode-10-issues-8-prs">Batch mode: 10 issues, 8 PRs<a href="https://ralphstarter.ai/blog/automating-entire-workflows#batch-mode-10-issues-8-prs" class="hash-link" aria-label="Direct link to Batch mode: 10 issues, 8 PRs" title="Direct link to Batch mode: 10 issues, 8 PRs" translate="no">​</a></h2>
<p>During sprint grooming I label issues as "auto-ready". These are the well defined tickets with clear specs. Then I run a single command and go get lunch:</p>
<p>ralph-starter picks up all matching issues, shows the estimate for each, and starts the Ralph Wiggum loop one by one:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># From GitHub</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter auto </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--source</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> multivmlabs/ralph-starter </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--label</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"auto-ready"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--limit</span><span class="token plain"> </span><span class="token number">10</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># From Linear</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter auto </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--source</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> ENG </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--label</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"auto-ready"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--limit</span><span class="token plain"> </span><span class="token number">10</span><br></span></code></pre></div></div>
<p>It works with both GitHub Issues and Linear tickets. Each issue gets its own branch, its own loop, its own PR:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">[1/10] Issue #145: Add health check endpoint</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &gt; Branch: auto/145</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &gt; 2 loops &gt; Validation: passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &gt; PR #151 created</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">[2/10] Issue #147: Add rate limit headers</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &gt; Branch: auto/147</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &gt; 1 loop &gt; Validation: passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &gt; PR #152 created</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">[3/10] Issue #150: Improve performance</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &gt; 3 loops &gt; Circuit breaker tripped. Skipping.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Completed: 8/10 | Failed: 2/10</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Total cost: $1.84</span><br></span></code></pre></div></div>
<p>8 out of 10. The 2 that failed were vague tickets. One was "Improve performance" with no metrics or targets. The agent tried different optimizations each loop but had nothing to validate against. The circuit breaker tripped after 3 loops.</p>
<p>The other was a refactoring ticket that referenced a discussion from a team meeting. The agent did not have that context.</p>
<p>The circuit breaker trips after 3 consecutive identical failures or 5 of the same error type. It prevents burning tokens on something the agent cannot solve.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="picking-an-agent">Picking an agent<a href="https://ralphstarter.ai/blog/automating-entire-workflows#picking-an-agent" class="hash-link" aria-label="Direct link to Picking an agent" title="Direct link to Picking an agent" translate="no">​</a></h2>
<p>You can be explicit about which agent to use:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> claude-code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> codex</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--agent</span><span class="token plain"> cursor</span><br></span></code></pre></div></div>
<p>Or let ralph-starter auto-detect. It checks what you have installed and uses the first one it finds.</p>
<p>I use Claude Code daily because prompt caching makes the loops cheaper and stream-json output lets ralph-starter track progress in real time. But the loop executor and validation pipeline are the same for all agents. I ran the same JWT auth task on <a class="" href="https://ralphstarter.ai/blog/five-ai-coding-agents">4 different agents</a> and they all got there, just with different loop counts and costs.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="why-i-keep-building-it">Why I keep building it<a href="https://ralphstarter.ai/blog/automating-entire-workflows#why-i-keep-building-it" class="hash-link" aria-label="Direct link to Why I keep building it" title="Direct link to Why I keep building it" translate="no">​</a></h2>
<p>I did a <a class="" href="https://ralphstarter.ai/blog/ralph-starter-vs-manual">side-by-side comparison</a> of 12 tasks from the same sprint. 6 manual, 6 with ralph-starter. Same project, same type of work. The ralph-starter tasks averaged 12 minutes of my attention vs 45 minutes coding manually. Code quality was comparable.</p>
<p>Now I spend my time on three things: writing clear specs (the input), reviewing PRs (the output), and architecture decisions (the part the AI cannot do). Everything in between, the mechanical translation of spec to code, ralph-starter handles that.</p>
<p>Every PR it produces passes tests, lint, and build. When I code manually I sometimes skip tests for small changes -- the validation loop does not let the agent skip anything, and honestly that discipline is better than what I do on my own.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="about-the-name">About the name<a href="https://ralphstarter.ai/blog/automating-entire-workflows#about-the-name" class="hash-link" aria-label="Direct link to About the name" title="Direct link to About the name" translate="no">​</a></h2>
<p>The name comes from the <a href="https://ghuntley.com/ralph/" target="_blank" rel="noopener noreferrer" class="">Ralph Wiggum technique</a>. You give the AI a task and let it keep going until done. No micro-managing. <a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">Full explanation here</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="links">Links<a href="https://ralphstarter.ai/blog/automating-entire-workflows#links" class="hash-link" aria-label="Direct link to Links" title="Direct link to Links" translate="no">​</a></h2>
<p>ralph-starter is open source, MIT licensed.</p>
<ul>
<li class=""><a href="https://github.com/multivmlabs/ralph-starter" target="_blank" rel="noopener noreferrer" class="">GitHub</a></li>
<li class=""><a href="https://ralphstarter.ai/" target="_blank" rel="noopener noreferrer" class="">Docs</a></li>
<li class=""><a href="https://www.npmjs.com/package/ralph-starter" target="_blank" rel="noopener noreferrer" class="">npm</a></li>
</ul>
<p>Related posts:</p>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">The Ralph Wiggum technique</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">Specs are the new code</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/five-ai-coding-agents">I tried 5 AI coding agents with ralph-starter</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">Prompt caching saved me $47</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-vs-manual">ralph-starter vs doing it manually</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/figma-to-code-one-command">Building a full app from a Figma file in one command</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-with-linear">How I use ralph-starter with Linear every day</a></li>
</ul>
<p>If you try it, open an issue or drop a star. All feedback is welcome.</p>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="auto-mode" term="auto-mode"/>
        <category label="github" term="github"/>
        <category label="batch-processing" term="batch-processing"/>
        <category label="ralphwiggum" term="ralphwiggum"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building a full app from a Figma file in one command]]></title>
        <id>https://ralphstarter.ai/blog/figma-to-code-one-command</id>
        <link href="https://ralphstarter.ai/blog/figma-to-code-one-command"/>
        <updated>2026-02-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Pointed ralph-starter at a 12-screen Figma dashboard file and had working React components before the weekend. 87 cents total.]]></summary>
        <content type="html"><![CDATA[<p>A designer handed me a Figma file on Friday afternoon with 12 screens for a dashboard. My immediate thought was "cool, that is next week gone." Instead I pointed ralph-starter at it and had working React components before I left for the weekend.</p>
<p>You know the Figma-to-code dance. Squint at the inspector panel. Copy hex colors one at a time. Guess at spacing values. Eyeball the layout. Realize the padding was 24 not 20. Go back. Fix it. Repeat for every single frame. I have lost days of my life to this.</p>
<p>So I tried something. I just pointed ralph-starter at the Figma file to see what would happen. Honestly expected it to fall apart. It did not.</p>
<p>The integration has 5 modes. The one I reach for most is <code>components</code> -- it reads your Figma file and generates actual component code.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> figma </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"https://figma.com/file/ABC123/Dashboard"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --figma-mode components </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --figma-framework react </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  --max-iterations </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fetching from Figma API</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">12</span><span class="token plain"> frames, </span><span class="token number">34</span><span class="token plain"> components found</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Generating implementation plan</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Created: </span><span class="token number">14</span><span class="token plain"> files </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> src/components/</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">8</span><span class="token plain"> passed, </span><span class="token number">3</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing </span><span class="token function" style="color:rgb(80, 250, 123)">import</span><span class="token plain"> paths and missing props</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">10</span><span class="token plain"> passed, </span><span class="token number">1</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">3</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing: Sidebar component missing responsive breakpoint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">11</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. clean ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 4m 18s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.87 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">67,412</span><br></span></code></pre></div></div>
<p>What happens under the hood: ralph-starter hits the Figma API, pulls every component and frame, converts the design data into specs, and the coding agent implements each one. 87 cents for a 12-screen dashboard scaffold. I checked the number twice.</p>
<p>It is not pixel-perfect -- the agent works from structural data, not screenshots. But the component breakdown and layout are right, so you end up tweaking CSS values instead of writing everything from scratch. I spent maybe 2 hours polishing what would have taken me 2 full days.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-5-modes-yes-there-are-5">The 5 modes (yes, there are 5)<a href="https://ralphstarter.ai/blog/figma-to-code-one-command#the-5-modes-yes-there-are-5" class="hash-link" aria-label="Direct link to The 5 modes (yes, there are 5)" title="Direct link to The 5 modes (yes, there are 5)" translate="no">​</a></h2>
<p><strong>Spec</strong> (default) converts frames to markdown specs. I use this when I want the AI to understand the design intent before touching any code.</p>
<p><strong>Tokens</strong> extracts your design system -- colors, typography, spacing. Exports to CSS, SCSS, JSON, or Tailwind. This one was a pleasant surprise:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter integrations fetch figma </span><span class="token string" style="color:rgb(255, 121, 198)">"ABC123"</span><span class="token plain"> --figma-mode tokens --figma-format tailwind</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Extracted design tokens:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    → </span><span class="token number">24</span><span class="token plain"> colors </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">primary, secondary, neutral, semantic</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    → </span><span class="token number">6</span><span class="token plain"> font sizes + </span><span class="token number">4</span><span class="token plain"> font weights</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    → </span><span class="token number">8</span><span class="token plain"> spacing values</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    → </span><span class="token number">4</span><span class="token plain"> border radius values</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Written to: tailwind.config.tokens.js</span><br></span></code></pre></div></div>
<p><strong>Components</strong> generates actual code. React, Vue, Svelte, Astro, Next.js, Nuxt, HTML -- pick your poison:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter integrations fetch figma </span><span class="token string" style="color:rgb(255, 121, 198)">"ABC123"</span><span class="token plain"> --figma-mode components --figma-framework react</span><br></span></code></pre></div></div>
<p><strong>Assets</strong> exports icons and images with download scripts.</p>
<p><strong>Content</strong> extracts text content for static sites.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-i-actually-did-with-the-dashboard">What I actually did with the dashboard<a href="https://ralphstarter.ai/blog/figma-to-code-one-command#what-i-actually-did-with-the-dashboard" class="hash-link" aria-label="Direct link to What I actually did with the dashboard" title="Direct link to What I actually did with the dashboard" translate="no">​</a></h2>
<p>I ran tokens first to get the Tailwind config right, then components for the React code, two commands in maybe 10 minutes total. And I had a working foundation to start refining.</p>
<p>Setup is dead simple, just a personal access token from Figma:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> figma.token figd_xxxxx</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_FKkL alert alert--success"><div class="admonitionHeading_H9K2"><span class="admonitionIcon_K48H"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Figma Plan Matters</div><div class="admonitionContent_Dn6j"><p>The free/starter plan limits you to <strong>6 API requests per month</strong> -- that is barely one fetch. For real development, you need a <strong>Professional plan with a Dev seat</strong> ($12/month), which gives you 10+ requests per minute. Responses are cached locally so repeated runs are free.</p></div></div>
<p>The reason this works at all is <a class="" href="https://ralphstarter.ai/blog/my-first-ralph-loop">the loop</a>. The agent does not just generate code and stop. It generates, runs tests, sees what broke, fixes it, runs again. By loop 3 or 4 you have components that actually render and pass lint. Same <a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">Ralph Wiggum technique</a> I use for everything else -- just pointed at a design file instead of a GitHub issue. I did not even plan it this way. It just... worked.</p>
<p>Want to try it with your own Figma file?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> figma.token figd_your_token_here</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> figma </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"your-figma-url"</span><span class="token plain"> --figma-mode components --figma-framework react --max-iterations </span><span class="token number">5</span><br></span></code></pre></div></div>
<p>You can also pick your model with <code>--model</code>. Sonnet is fast and cheap for UI work, Opus is better for complex state logic:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Fast + cheap (recommended for most Figma workflows)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> figma </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"your-figma-url"</span><span class="token plain"> --figma-mode components </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--model</span><span class="token plain"> claude-sonnet-4-5-20250929 --max-iterations </span><span class="token number">5</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Maximum quality</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> figma </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"your-figma-url"</span><span class="token plain"> --figma-mode components </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--model</span><span class="token plain"> claude-opus-4-6 --max-iterations </span><span class="token number">3</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/figma-to-code-one-command#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/my-first-ralph-loop">My first ralph loop: what actually happens</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">The Ralph Wiggum technique</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/specs-are-the-new-code">Specs are the new code</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/sources/figma">Figma integration docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/guides/workflow-presets">Workflow presets</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="figma" term="figma"/>
        <category label="design-to-code" term="design-to-code"/>
        <category label="tutorial" term="tutorial"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[ralph-starter + Claude Code: the full setup]]></title>
        <id>https://ralphstarter.ai/blog/ralph-starter-claude-code-setup</id>
        <link href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup"/>
        <updated>2026-01-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Zero to your first automated PR with ralph-starter and Claude Code. Install, init, run, and get a working PR in under 2 minutes.]]></summary>
        <content type="html"><![CDATA[<p>I wanted to write the post I wish existed when I started: how to go from zero to your first automated PR with ralph-starter and Claude Code. No fluff, just the steps.</p>
<p>Claude Code is the best agent I use with ralph-starter. Prompt caching makes loops cheap, stream-json output lets ralph-starter track progress in real time, and it handles multi-file changes without breaking a sweat.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="install">Install<a href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup#install" class="hash-link" aria-label="Direct link to Install" title="Direct link to Install" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token function" style="color:rgb(80, 250, 123)">npm</span><span class="token plain"> i </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-g</span><span class="token plain"> @anthropic-ai/claude-code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">npm</span><span class="token plain"> i </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-g</span><span class="token plain"> ralph-starter</span><br></span></code></pre></div></div>
<p>You need <code>ANTHROPIC_API_KEY</code> in your environment. Quick sanity check:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ claude </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--version</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">claude-code </span><span class="token number">1.0</span><span class="token plain">.16</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--version</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter </span><span class="token number">0.6</span><span class="token plain">.2</span><br></span></code></pre></div></div>
<p>If both work, you are ready.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="init">Init<a href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup#init" class="hash-link" aria-label="Direct link to Init" title="Direct link to Init" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">cd</span><span class="token plain"> your-project</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter init</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Detected: Node.js project </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">package.json found</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Agent: Claude Code </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">claude-code v1.0.16</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Created:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ✓ AGENTS.md — validation commands</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ✓ PROMPT_build.md — agent build instructions</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ✓ PROMPT_plan.md — planning phase prompt</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ✓ .ralph/config.yaml — project config</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Run your first task:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><br></span></code></pre></div></div>
<p>This detects your project type (Node, Python, Rust, Go) and reads <code>package.json</code> to find test/build/lint commands. Creates a few files:</p>
<ul>
<li class=""><code>AGENTS.md</code> with validation commands</li>
<li class=""><code>PROMPT_build.md</code> and <code>PROMPT_plan.md</code> for agent behavior</li>
<li class=""><code>.ralph/config.yaml</code></li>
</ul>
<p>The config is straightforward:</p>
<div class="language-yaml codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-yaml codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token key atrule">agent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> claude</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">code</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">auto_commit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">max_iterations</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token number">50</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">validation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> npm test</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> npm run build</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> npm run lint</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="first-task">First task<a href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup#first-task" class="hash-link" aria-label="Direct link to First task" title="Direct link to First task" translate="no">​</a></h2>
<p>Pick something small for your first run:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add a health check endpoint at /api/health"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Created: src/api/health.ts, src/api/__tests__/health.test.ts</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">5</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 47s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.11 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">8,924</span><br></span></code></pre></div></div>
<p>47 seconds. 11 cents. A working health endpoint with tests.</p>
<p>Under the hood, ralph-starter launches Claude Code with <code>--dangerously-skip-permissions</code> for autonomous mode and <code>--output-format stream-json</code> so it can track progress in real time. You do not need to know this, but I think it is cool.</p>
<p>After loop 1 your context gets cached. Loops 2, 3, 4 reuse that cache at 90% less cost. On a 5-loop task you pay full price only on the first iteration. I wrote more about this in <a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">prompt caching saved me $47</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="auto-prs-from-github">Auto PRs from GitHub<a href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup#auto-prs-from-github" class="hash-link" aria-label="Direct link to Auto PRs from GitHub" title="Direct link to Auto PRs from GitHub" translate="no">​</a></h2>
<p>You can also go straight from a GitHub issue to a PR:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ gh auth login</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> myorg/myrepo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">42</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fetching spec from GitHub issue </span><span class="token comment" style="color:rgb(98, 114, 164)">#42...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → </span><span class="token string" style="color:rgb(255, 121, 198)">"Add rate limiting to /api/users endpoint"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">7</span><span class="token plain"> passed, </span><span class="token number">1</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing: rate limit header format</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">8</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Opening PR </span><span class="token comment" style="color:rgb(98, 114, 164)">#87...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 2m 12s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.19 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">18,340</span><br></span></code></pre></div></div>
<p>Creates branch, runs loops, commits, pushes, opens PR. For multiple issues at once:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter auto </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--source</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> myorg/myrepo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--label</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"auto-ready"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--limit</span><span class="token plain"> </span><span class="token number">5</span><br></span></code></pre></div></div>
<p>I label issues "auto-ready" when they have clear specs and <a class="" href="https://ralphstarter.ai/blog/automating-entire-workflows">run this once or twice a week</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="one-thing-that-made-a-big-difference">One thing that made a big difference<a href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup#one-thing-that-made-a-big-difference" class="hash-link" aria-label="Direct link to One thing that made a big difference" title="Direct link to One thing that made a big difference" translate="no">​</a></h2>
<p>Add specific context in <code>.claude/CLAUDE.md</code>. Things like "we use Tailwind", "tests in <code>__tests__/</code>", "follow pattern in <code>src/api/</code>". The more specific you are, the better the output gets. I have seen first-loop success rate go from maybe 40% to 70% just by adding a few lines of project context.</p>
<p>Ready to try it?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/why-i-built-ralph-starter">Why I built ralph-starter</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/my-first-ralph-loop">My first ralph loop</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars">Prompt caching saved me $47</a></li>
<li class=""><a href="https://docs.anthropic.com/en/docs/claude-code" target="_blank" rel="noopener noreferrer" class="">Claude Code docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/cli/run">ralph-starter CLI reference</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/guides/cost-tracking">Cost tracking guide</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="claude-code" term="claude-code"/>
        <category label="setup" term="setup"/>
        <category label="tutorial" term="tutorial"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[My first ralph loop: what actually happens]]></title>
        <id>https://ralphstarter.ai/blog/my-first-ralph-loop</id>
        <link href="https://ralphstarter.ai/blog/my-first-ralph-loop"/>
        <updated>2026-01-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Walk-through of a real ralph-starter loop from start to PR. What happens at each step and why the loop design matters.]]></summary>
        <content type="html"><![CDATA[<p>I keep saying "I type one command and get a PR" and people want to know what actually happens in between. So let me walk you through a real one.</p>
<p>Say you want to add a dark mode toggle to your settings page. Nothing crazy, but enough to touch a few files. You run:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add dark mode toggle to settings page"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>First thing ralph-starter does is detect your coding agent. It prefers Claude Code but works with Cursor, Codex, OpenCode too. Then it reads your <code>AGENTS.md</code> to find your test/lint/build commands. No guessing -- it knows how <em>your</em> project validates code.</p>
<p>Loop 1 starts. The agent gets the task with full project context, reads your files, creates the components. First pass usually gets the structure right but something breaks -- which is fine, that is the whole point of loops.</p>
<p>Here is what the real terminal output looked like:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add dark mode toggle to settings page"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Planning implementation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">2</span><span class="token plain"> passed, </span><span class="token number">1</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Test failure: ThemeContext is not exported from </span><span class="token string" style="color:rgb(255, 121, 198)">'./contexts'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing: adding ThemeContext export</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">3</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">2</span><span class="token plain"> issues found</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">3</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing lint issues </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">unused import, missing </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">type</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">3</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. clean ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 1m 32s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.29 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">45,218</span><br></span></code></pre></div></div>
<p>Test failure goes back as context for loop 2. Agent sees the exact error -- <code>ThemeContext is not exported</code> -- and fixes it. Loop 2 passes tests but lint complains about an unused import. Loop 3 cleans that up.</p>
<p>Three loops, about 90 seconds total. The other 2 loops never ran because the task completed early -- ralph-starter stops as soon as everything passes so you are not wasting tokens.</p>
<p>You also get a cost summary at the end:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Cost Summary:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Tokens: 45K (32K in / 13K out)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Cost: $0.29 (3 iterations)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  Cache savings: $0.12</span><br></span></code></pre></div></div>
<p>29 cents for a feature with tests that pass and clean lint. I used to spend 20 minutes doing this exact thing by hand.</p>
<p>There is a circuit breaker too -- if the agent fails the same way 3 consecutive times, it stops instead of burning tokens on something that is stuck. As Ralph Wiggum would say, <em>"I bent my Wookiee"</em> -- sometimes you just have to stop and try a different approach.</p>
<p>Want to try it yourself?</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token function" style="color:rgb(80, 250, 123)">npm</span><span class="token plain"> i </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-g</span><span class="token plain"> ralph-starter</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter init</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"your first task"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><br></span></code></pre></div></div>
<p>Three commands and you are in the loop. If you want to understand <a class="" href="https://ralphstarter.ai/blog/why-i-built-ralph-starter">why I built this in the first place</a>, I wrote about that too.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/my-first-ralph-loop#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/why-i-built-ralph-starter">Why I built ralph-starter</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup">ralph-starter + Claude Code: the full setup</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/cli/run">Loop executor docs</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/advanced/circuit-breaker">Circuit breaker</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/advanced/validation">Validation pipeline</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="tutorial" term="tutorial"/>
        <category label="loops" term="loops"/>
        <category label="getting-started" term="getting-started"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Why I built ralph-starter]]></title>
        <id>https://ralphstarter.ai/blog/why-i-built-ralph-starter</id>
        <link href="https://ralphstarter.ai/blog/why-i-built-ralph-starter"/>
        <updated>2026-01-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I was copy-pasting between ChatGPT and my editor 20 times a day. So I wrote a bash script that did it for me. That script became ralph-starter.]]></summary>
        <content type="html"><![CDATA[<p>Do you know when you have a GitHub issue with the full spec, and then you open Claude or ChatGPT, copy the issue, paste there, get code back, paste in your editor, run tests, something breaks, go back to chat, paste the error? I was doing this 20 times a day. Twenty. I counted.</p>
<p>The AI was doing the hard part. I was just the middleman moving text around. A glorified clipboard manager, basically.</p>
<p>So one night I wrote a bash script. Nothing fancy -- it pulled the issue body with <code>gh</code>, piped it into Claude Code, ran the tests, and if they failed it sent the error back and let Claude try again. I ran it, went to make coffee, came back. There was a working PR sitting there. I had not touched my keyboard once.</p>
<p>That was the moment. I literally said out loud: "why was I doing this by hand?"</p>
<p>That script became ralph-starter.</p>
<p>Here is what it looks like now:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">$ ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> myorg/myrepo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">42</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--pr</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">1</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fetching spec from GitHub issue </span><span class="token comment" style="color:rgb(98, 114, 164)">#42...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Generating implementation plan</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Writing code with Claude Code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">3</span><span class="token plain"> passed, </span><span class="token number">1</span><span class="token plain"> failed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">🔄 Loop </span><span class="token number">2</span><span class="token plain">/5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Fixing </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">test</span><span class="token plain"> failures</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">. </span><span class="token number">4</span><span class="token plain"> passed ✓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committing changes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Opening PR </span><span class="token comment" style="color:rgb(98, 114, 164)">#87...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ Done </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> 2m 34s </span><span class="token operator">|</span><span class="token plain"> Cost: </span><span class="token variable" style="color:rgb(189, 147, 249);font-style:italic">$0</span><span class="token plain">.08 </span><span class="token operator">|</span><span class="token plain"> Tokens: </span><span class="token number">12,847</span><br></span></code></pre></div></div>
<p>Your specs already live somewhere -- GitHub, Linear, Notion, Figma. There is no reason to copy them manually into a chat window.</p>
<p>One command. Fetches the spec, makes a branch, runs the AI in loops with your tests as the guardrails, commits, opens a PR. You review it like any other PR from your team. No ceremony.</p>
<p>I use this every day now. Linear tickets in the morning, ralph-starter processes them while I work on the hard stuff, and I review PRs after lunch. It does not replace thinking about architecture -- but it handles the mechanical part of turning specs into code. The part that was eating my day.</p>
<p>The name comes from the <a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">Ralph Wiggum technique</a>. As Ralph would say: <em>"I'm learnding!"</em> -- and honestly, that is exactly what the loop does. You give the AI a task and let it keep going until done. No prompting back and forth. Just autonomous iteration.</p>
<p>ralph-starter is open source because AI coding tooling is evolving so fast that the community can push it further than I could alone. And honestly, I want to see what people build with it.</p>
<p>If you want to try it:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npx ralph-starter init</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="references">References<a href="https://ralphstarter.ai/blog/why-i-built-ralph-starter#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://ralphstarter.ai/blog/my-first-ralph-loop">My first ralph loop: what actually happens</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-starter-claude-code-setup">ralph-starter + Claude Code: the full setup</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/blog/ralph-wiggum-technique">The Ralph Wiggum technique explained</a></li>
<li class=""><a href="https://github.com/multivmlabs/ralph-starter" target="_blank" rel="noopener noreferrer" class="">GitHub repo</a></li>
<li class=""><a class="" href="https://ralphstarter.ai/docs/intro">Getting started docs</a></li>
<li class=""><a href="https://www.npmjs.com/package/ralph-starter" target="_blank" rel="noopener noreferrer" class="">npm package</a></li>
</ul>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ralph-starter" term="ralph-starter"/>
        <category label="story" term="story"/>
        <category label="ai-coding" term="ai-coding"/>
        <category label="open-source" term="open-source"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Let your tests guide the AI]]></title>
        <id>https://ralphstarter.ai/blog/validation-driven-development</id>
        <link href="https://ralphstarter.ai/blog/validation-driven-development"/>
        <updated>2026-01-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[AI-generated code that looks perfect can blow up at runtime. Adding tests to the loop lets the agent catch and fix its own mistakes.]]></summary>
        <content type="html"><![CDATA[<p>The first time I let an AI agent write code without running tests, it produced something that looked perfect. Clean code, nice comments, the works. Blew up at runtime. The second time, I added <code>--test</code> and the agent caught its own mistake and fixed it in the next loop. That's when I realized: the tests aren't just for me anymore. They're for the agent.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="how-this-actually-works">How this actually works<a href="https://ralphstarter.ai/blog/validation-driven-development#how-this-actually-works" class="hash-link" aria-label="Direct link to How this actually works" title="Direct link to How this actually works" translate="no">​</a></h2>
<p>So when you pass <code>--test</code> to ralph-starter, every loop ends with your test suite running. If something fails, the error output goes straight back into the agent's context. It reads the failure, figures out what it got wrong, and tries again. Basically your tests become the agent's to-do list.</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add Stripe webhook handler"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><br></span></code></pre></div></div>
<p>Here's what that actually looked like on a Stripe webhook handler I built last week:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop 1: Implementing webhook handler...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  FAIL src/webhooks/stripe.test.ts</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    x should verify webhook signature (8ms)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      Error: No signatures found matching the expected signature for payload</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → 1 test failed. Feeding errors back to agent.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop 2: Fixing signature verification...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Added raw body parsing middleware for webhook route</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  PASS src/webhooks/stripe.test.ts</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ✓ should verify webhook signature (12ms)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ✓ should handle checkout.session.completed (5ms)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ✓ should return 400 for unknown events (3ms)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running linter... 1 issue</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    src/webhooks/stripe.ts:14:7 - 'event' is defined but never used</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop 3: Removing unused variable...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running tests... passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Running linter... passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Done in 3 loops.</span><br></span></code></pre></div></div>
<p>The thing that blew my mind: the agent saw <code>No signatures found matching the expected signature for payload</code> and just... knew it needed raw body parsing. I didn't tell it that. The test output was specific enough. That's the Stripe webhook gotcha that trips up every developer the first time, and the agent figured it out from the error message alone. Took me like 20 minutes of Googling when I first hit it myself.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="your-tests-are-basically-the-spec">Your tests are basically the spec<a href="https://ralphstarter.ai/blog/validation-driven-development#your-tests-are-basically-the-spec" class="hash-link" aria-label="Direct link to Your tests are basically the spec" title="Direct link to Your tests are basically the spec" translate="no">​</a></h2>
<p>This flips the whole workflow on its head. Instead of describing what you want in a prompt and hoping the output is correct, you write tests that define correct behavior and let the agent figure out the implementation.</p>
<p>If you already do TDD, this is basically what you've been training for. Write your tests first, then:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"make the failing tests pass"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><br></span></code></pre></div></div>
<p>Each failing test becomes a requirement, and when they all pass, the task is done.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="setting-it-up">Setting it up<a href="https://ralphstarter.ai/blog/validation-driven-development#setting-it-up" class="hash-link" aria-label="Direct link to Setting it up" title="Direct link to Setting it up" translate="no">​</a></h2>
<p>In your config file, just tell ralph-starter what to run:</p>
<div class="language-yaml codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-yaml codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># ralph.config.yaml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">validation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pnpm test"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pnpm lint"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">build</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pnpm build"</span><br></span></code></pre></div></div>
<p>Or pass them as flags:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"fix the auth bug"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pytest -x"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"ruff check ."</span><br></span></code></pre></div></div>
<p>That <code>-x</code> flag on pytest is a pro tip, by the way. It stops at the first failure, so the agent gets one focused error instead of a wall of 47 failures. Way more useful.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-ive-learned-about-good-validation-setups">What I've learned about good validation setups<a href="https://ralphstarter.ai/blog/validation-driven-development#what-ive-learned-about-good-validation-setups" class="hash-link" aria-label="Direct link to What I've learned about good validation setups" title="Direct link to What I've learned about good validation setups" translate="no">​</a></h2>
<p><strong>Fast tests matter a lot.</strong> The agent runs your suite on every loop. If your tests take 10 minutes, a 5-loop run takes close to an hour. If they take 10 seconds, you're done in a few minutes. I learned this the hard way on a project with a 7-minute test suite. Now I usually point the agent at a subset:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"fix payment processing"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pnpm test -- --testPathPattern=payment"</span><br></span></code></pre></div></div>
<p><strong>Specific error messages make a huge difference.</strong> Compare these two test failures:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Bad: agent has to guess what went wrong</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">AssertionError: expected false to be true</span><br></span></code></pre></div></div>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Good: agent knows exactly what to fix</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Expected status code 201 for POST /api/users</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Received status code 400 with body: {"error": "email is required"}</span><br></span></code></pre></div></div>
<p>The first one forces the agent to guess. The second one tells it exactly what is missing. More information in your test output means fewer loops and less money.</p>
<p><strong>Type checking is worth adding too.</strong> It catches a totally different class of bugs. I add it as another validator:</p>
<div class="language-yaml codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-yaml codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token key atrule">validation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pnpm test"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">lint</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pnpm lint"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">typecheck</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"pnpm tsc --noEmit"</span><br></span></code></pre></div></div>
<p>Every validator runs after every loop, and the agent does not move on until all of them pass.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="when-to-skip-auto-commit">When to skip auto-commit<a href="https://ralphstarter.ai/blog/validation-driven-development#when-to-skip-auto-commit" class="hash-link" aria-label="Direct link to When to skip auto-commit" title="Direct link to When to skip auto-commit" translate="no">​</a></h2>
<p>I'll be honest, I don't always trust the agent enough to commit automatically. When I'm trying a new type of task, I run without <code>--commit</code> first so I can look at the diff:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add rate limiting"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--lint</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Review what the agent did</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">git</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">diff</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Commit if it looks good</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token function" style="color:rgb(80, 250, 123)">git</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">add</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-A</span><span class="token plain"> </span><span class="token operator">&amp;&amp;</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">git</span><span class="token plain"> commit </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">-m</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"feat: add rate limiting"</span><br></span></code></pre></div></div>
<p>Once I trust the pattern for a given type of task, I add <code>--commit</code> and let it ship. That trust builds over time. Took me maybe a week before I stopped reviewing every diff.</p>
<hr>
<p>Details on all the validation options are in the <a class="" href="https://ralphstarter.ai/docs/advanced/validation">validation config docs</a>.</p>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="testing" term="testing"/>
        <category label="validation" term="validation"/>
        <category label="quality" term="quality"/>
        <category label="best-practices" term="best-practices"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[From spec to code in one command]]></title>
        <id>https://ralphstarter.ai/blog/connect-your-tools</id>
        <link href="https://ralphstarter.ai/blog/connect-your-tools"/>
        <updated>2026-01-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Your specs already live in GitHub, Linear, or Notion. One command pulls them into ralph-starter and starts coding.]]></summary>
        <content type="html"><![CDATA[<p>Every feature you build starts with a spec that already exists somewhere. GitHub issue, Linear ticket, Notion doc. It's already written. The annoying part is getting it into your AI tool without losing half of it.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-problem-i-kept-running-into">The problem I kept running into<a href="https://ralphstarter.ai/blog/connect-your-tools#the-problem-i-kept-running-into" class="hash-link" aria-label="Direct link to The problem I kept running into" title="Direct link to The problem I kept running into" translate="no">​</a></h2>
<p>I'd open a GitHub issue, read through the description and comments, mentally summarize it, then type a prompt for Claude that captured... maybe 60% of what was actually in the issue. The linked design doc? Forgot to include it. The acceptance criteria someone added in comment #3? Missed that too.</p>
<p>The spec was right there. I was just a really bad copy-paster. And you know what's dumb? I did this for months before it occurred to me that a script could just fetch the issue directly.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="so-i-made-it-one-command">So I made it one command<a href="https://ralphstarter.ai/blog/connect-your-tools#so-i-made-it-one-command" class="hash-link" aria-label="Direct link to So I made it one command" title="Direct link to So I made it one command" translate="no">​</a></h2>
<p>ralph-starter just pulls the spec directly and feeds it to the agent:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> myorg/api </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">42</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>What happens here: it authenticates with GitHub using your existing <code>gh</code> CLI session, grabs issue #42 -- body, all comments, labels, linked references, everything -- and hands it all to the coding agent. Then the agent implements the feature, runs your tests after each loop, and commits when everything passes.</p>
<p>No tab-switching, no summarizing, no "let me paste the relevant parts." The agent gets the raw spec, the whole thing.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="github-issues-and-prs">GitHub issues and PRs<a href="https://ralphstarter.ai/blog/connect-your-tools#github-issues-and-prs" class="hash-link" aria-label="Direct link to GitHub issues and PRs" title="Direct link to GitHub issues and PRs" translate="no">​</a></h2>
<p>This is the one I use the most, by far. Just point it at an issue:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> owner/repo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">123</span><br></span></code></pre></div></div>
<p>It pulls the title, body, comments, file references. If the issue links to other issues, those come along too. Basically the agent sees everything your team wrote -- which is usually way more context than what I'd remember to paste.</p>
<p>PRs work the same way, which is great for when you get review feedback and don't want to fix 12 nits by hand:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> owner/repo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">456</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">3</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="linear-tickets">Linear tickets<a href="https://ralphstarter.ai/blog/connect-your-tools#linear-tickets" class="hash-link" aria-label="Direct link to Linear tickets" title="Direct link to Linear tickets" translate="no">​</a></h2>
<p>If your team uses Linear, same deal:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> linear </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> PROJ </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> PROJ-123 </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>Grabs the ticket description, sub-issues, attachments, priority. One thing I've noticed: Linear tickets tend to be really well-structured compared to GitHub issues, so the agent gets cleaner input and the results are usually better on the first try. Not always, but noticeably.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="notion-pages">Notion pages<a href="https://ralphstarter.ai/blog/connect-your-tools#notion-pages" class="hash-link" aria-label="Direct link to Notion pages" title="Direct link to Notion pages" translate="no">​</a></h2>
<p>For teams that write everything in Notion (I've been there):</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> notion </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"page-id"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><br></span></code></pre></div></div>
<p>The page content gets converted to markdown, and child pages and linked databases come along for the ride. This is especially nice for those longer specs -- you know, the ones with 3 sections and a table and a "Notes from the last meeting" block. Try pasting all of that into a chat window. Actually, don't.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="local-files-and-urls">Local files and URLs<a href="https://ralphstarter.ai/blog/connect-your-tools#local-files-and-urls" class="hash-link" aria-label="Direct link to Local files and URLs" title="Direct link to Local files and URLs" translate="no">​</a></h2>
<p>Sometimes the spec is just a markdown file in your repo:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> ./specs/auth-feature.md </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>Or a URL:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"https://example.com/spec.md"</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="combining-sources-this-is-the-good-part">Combining sources (this is the good part)<a href="https://ralphstarter.ai/blog/connect-your-tools#combining-sources-this-is-the-good-part" class="hash-link" aria-label="Direct link to Combining sources (this is the good part)" title="Direct link to Combining sources (this is the good part)" translate="no">​</a></h2>
<p>OK so the thing I actually use the most in practice is combining a GitHub issue with extra local context:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> owner/repo </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">123</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--context</span><span class="token plain"> ./docs/api-conventions.md </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>The agent gets the issue spec plus your project conventions in one shot. This is where the quality jumps noticeably. Before I started doing this, the agent would generate code that worked but didn't follow our patterns -- wrong naming conventions, different error handling style, that kind of thing. Now it matches the rest of the codebase on the first try most of the time.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="setting-up-auth">Setting up auth<a href="https://ralphstarter.ai/blog/connect-your-tools#setting-up-auth" class="hash-link" aria-label="Direct link to Setting up auth" title="Direct link to Setting up auth" translate="no">​</a></h2>
<p>One-time setup, takes like 30 seconds:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># GitHub (uses your existing gh CLI login)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">gh auth login</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Linear</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> linear.apiKey lin_api_xxx</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Notion</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter config </span><span class="token builtin class-name" style="color:rgb(189, 147, 249)">set</span><span class="token plain"> notion.token secret_xxx</span><br></span></code></pre></div></div>
<hr>
<p>The full list of supported sources is in the <a class="" href="https://ralphstarter.ai/docs/sources/overview">integrations guide</a>.</p>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="integrations" term="integrations"/>
        <category label="github" term="github"/>
        <category label="linear" term="linear"/>
        <category label="notion" term="notion"/>
        <category label="workflow" term="workflow"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Why autonomous AI coding loops work]]></title>
        <id>https://ralphstarter.ai/blog/why-autonomous-coding</id>
        <link href="https://ralphstarter.ai/blog/why-autonomous-coding"/>
        <updated>2026-01-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I spent months copy-pasting between ChatGPT and my editor before I realized the loop itself was the problem, not the AI.]]></summary>
        <content type="html"><![CDATA[<p>I spent months copy-pasting code between ChatGPT and my editor before I realized I was the bottleneck.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="the-back-and-forth-tax">The back-and-forth tax<a href="https://ralphstarter.ai/blog/why-autonomous-coding#the-back-and-forth-tax" class="hash-link" aria-label="Direct link to The back-and-forth tax" title="Direct link to The back-and-forth tax" translate="no">​</a></h2>
<p>You know the drill. Open ChatGPT, describe what you want, get some code back, paste it into your editor, run it, something breaks, copy the error, go back to the chat, paste the error, get a new version, paste that in. I was doing this maybe 15-20 times a day. For months.</p>
<p>And every round trip you lose a little bit of context. The model half-forgets what it suggested two messages ago. You lose track of which version you pasted where. Meanwhile you're the one running tests, reading stack traces, deciding what to try next.</p>
<p>At some point I realized the AI was doing the easy part -- generating code -- and I was doing everything else. Basically a clipboard manager with opinions.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="what-if-the-agent-just-kept-going">What if the agent just... kept going?<a href="https://ralphstarter.ai/blog/why-autonomous-coding#what-if-the-agent-just-kept-going" class="hash-link" aria-label="Direct link to What if the agent just... kept going?" title="Direct link to What if the agent just... kept going?" translate="no">​</a></h2>
<p>So the idea behind ralph-starter is stupid simple. Instead of you being the middleman, the agent does the whole thing:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token string" style="color:rgb(255, 121, 198)">"add user authentication with JWT"</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>It reads your codebase, writes code, runs your tests. If something fails, it reads the error and fixes it. Then runs tests again. Over and over until things pass or it runs out of loops. You just... go do something else.</p>
<p>Here's a real run from last week:</p>
<div class="language-text codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-text codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop 1: Read codebase, generated auth middleware and routes</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Tests: 3 failed (missing bcrypt import, wrong token expiry, no error handler)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop 2: Fixed imports, updated token config, added error handling</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Tests: 1 failed (error handler not catching expired tokens)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop 3: Added expired token case to error handler</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Tests: passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Lint: 2 warnings (unused import, missing return type)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Loop 4: Cleaned up lint issues</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Tests: passed, Lint: passed, Build: passed</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  → Committed: feat: add JWT authentication</span><br></span></code></pre></div></div>
<p>Four loops, zero copy-pasting, zero babysitting. I reviewed the diff after and it was clean -- I made coffee during loop 2.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="why-this-works-better-than-chatting">Why this works better than chatting<a href="https://ralphstarter.ai/blog/why-autonomous-coding#why-this-works-better-than-chatting" class="hash-link" aria-label="Direct link to Why this works better than chatting" title="Direct link to Why this works better than chatting" translate="no">​</a></h2>
<p>The big difference is context. In a chat, the model kind of forgets what it tried two messages ago. In a loop, the agent sees everything -- its own previous attempts, the full test output, the whole history. It doesn't start over each time.</p>
<p>And errors become free instructions, which is the part that really clicked for me. When <code>TypeError: Cannot read properties of undefined</code> shows up in the test output, the agent gets that exact string -- you don't have to describe the problem. It reads the stack trace and acts on it. That is the stuff I was doing manually before, and honestly the agent is better at it than me because it does not skip lines.</p>
<p>A chat session might take 15-20 messages to land on working code. A loop usually finishes in 3-5 iterations because each one does real work, validates it, and course-corrects. You're paying for results, not conversation.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="where-it-actually-works-and-where-it-doesnt">Where it actually works (and where it doesn't)<a href="https://ralphstarter.ai/blog/why-autonomous-coding#where-it-actually-works-and-where-it-doesnt" class="hash-link" aria-label="Direct link to Where it actually works (and where it doesn't)" title="Direct link to Where it actually works (and where it doesn't)" translate="no">​</a></h2>
<p>This is not magic though. It works really well when you have:</p>
<ul>
<li class=""><strong>A clear spec.</strong> "Add password reset flow per the design in issue #42" works great. "Make the auth better" does not.</li>
<li class=""><strong>Tests.</strong> Even crappy ones. Tests give the agent a finish line. Without them it's just vibes.</li>
<li class=""><strong>A linter and type checker.</strong> More automated checks = more signal for the agent to self-correct.</li>
</ul>
<p>The tasks where I've had the best results: implementing a well-scoped feature from a GitHub issue, fixing a bug with a reproducible test case, refactoring code that has good coverage.</p>
<p>Where it falls apart: vague requirements with no tests, greenfield projects with no structure yet, anything that needs human judgment about UX. I tried it on a "redesign the dashboard" task once and... yeah. Don't do that.</p>
<h2 class="anchor anchorTargetStickyNavbar_RDz4" id="it-gets-even-better-with-real-specs">It gets even better with real specs<a href="https://ralphstarter.ai/blog/why-autonomous-coding#it-gets-even-better-with-real-specs" class="hash-link" aria-label="Direct link to It gets even better with real specs" title="Direct link to It gets even better with real specs" translate="no">​</a></h2>
<p>One more thing that made a huge difference. Instead of writing a prompt from scratch, you can point it at an actual GitHub issue:</p>
<div class="language-bash codeBlockContainer_DOIF theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_fO46"><pre tabindex="0" class="prism-code language-bash codeBlock_QGo5 thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_qEdg"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ralph-starter run </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--from</span><span class="token plain"> github </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--project</span><span class="token plain"> myorg/api </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--issue</span><span class="token plain"> </span><span class="token number">42</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--loops</span><span class="token plain"> </span><span class="token number">5</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--test</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(189, 147, 249);font-style:italic">--commit</span><br></span></code></pre></div></div>
<p>This fetches the full issue body, comments, linked context -- all of it. The agent gets the same spec your team wrote for a human developer. Except it doesn't skim. It reads the whole thing, every comment, every acceptance criterion. Honestly it's more thorough than I am.</p>
<hr>
<p>If you want to try it, <a class="" href="https://ralphstarter.ai/docs/intro">the quickstart takes about two minutes</a>.</p>]]></content>
        <author>
            <name>Ruben Marcus</name>
            <uri>https://github.com/rubenmarcus</uri>
        </author>
        <category label="ai" term="ai"/>
        <category label="coding" term="coding"/>
        <category label="automation" term="automation"/>
    </entry>
</feed>