<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.gr8ful.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.gr8ful.dev/" rel="alternate" type="text/html" /><updated>2026-09-08T05:53:43+00:00</updated><id>https://www.gr8ful.dev/feed.xml</id><title type="html">Gr8ful Dev</title><subtitle>The personal site and blog of Mark Richards (Gr8ful Dev) — software engineer, Rails and DOOH platform work, AI tooling experiments, and the occasional thought on perseverance.</subtitle><author><name>Mark Richards</name><email>mark@gr8ful.dev</email></author><entry><title type="html">Trying to make a local LLM do Rails work</title><link href="https://www.gr8ful.dev/2026/09/08/local-llm-rails-work.html" rel="alternate" type="text/html" title="Trying to make a local LLM do Rails work" /><published>2026-09-08T00:00:00+00:00</published><updated>2026-09-08T00:00:00+00:00</updated><id>https://www.gr8ful.dev/2026/09/08/local-llm-rails-work</id><content type="html" xml:base="https://www.gr8ful.dev/2026/09/08/local-llm-rails-work.html"><![CDATA[<p>I spent the last while trying to answer a simple question: can a model running on my own hardware do real Rails dev-agent work, if I hand it the right documentation?</p>

<p>The short answer: sometimes. And the journey there taught me more about benchmarking than about models.</p>

<!--more-->

<h2 id="the-starting-idea">The starting idea</h2>

<p>The thesis was that local models could do accurate, timely Rails work — <em>if</em> a RAG layer injected the right docs at the right moment. I’d seen hand-picked doc excerpts lift every local model I tried to a perfect score on a recall harness. Those were ceiling tests — they measured what a <em>human</em> retriever could achieve, not a real system.</p>

<p>So I built the retrieval layer properly. Extracted a corpus from the pinned Rails 8 container image, tiered it, hybrid dense + lexical retrieval, RRF fusion, the works.</p>

<p>Real retrieval reached about 56% recall at rank 5. The oracle’s ceiling had been 100%.</p>

<h2 id="what-the-ab-actually-measured">What the A/B actually measured</h2>

<p>Six agentic trials ran. Zero solved. Every one killed by the wall clock.</p>

<p>That’s when I stopped trusting the scoreboard and started reading the transcripts. Across all six runs, the agent used <code class="language-plaintext highlighter-rouge">bash</code> and <em>nothing else</em>. Zero edit calls. In the worst case, it ran a probe at step 17, got the answer it needed, and re-ran that identical probe <strong>61 more times</strong>.</p>

<p>The failure wasn’t knowledge acquisition. It was converting a known answer into an edit.</p>

<h2 id="the-control-that-changed-my-mind">The control that changed my mind</h2>

<p>I ran an Opus model through the same harness — no docs at all — and it passed the task first try. Then I ran a matched pair with and without RAG on a harder task: both failed with byte-identical diffs. The RAG made zero difference.</p>

<p>The models weren’t failing because they didn’t know the API. They were failing on judgement — one even identified the second bug in its uncertainty notes, then scoped it out as a “pre-existing upstream quirk.” Documentation doesn’t fix a judgement call.</p>

<h2 id="the-four-lines-that-finally-worked">The four lines that finally worked</h2>

<p>The breakthrough came from a completely different angle: a stopping rule.</p>

<blockquote>
  <p><em>Investigate for at most 10 tool calls, then make your edit. If you are still uncertain after that, implement your best solution anyway and verify it by running <code class="language-plaintext highlighter-rouge">bin/rails test</code> — do not keep investigating instead of deciding. You must leave a change on disk.</em></p>
</blockquote>

<p>Same model, same harness, same everything — 28 calls instead of 87, three edits, finished in 21 minutes, and it <strong>stopped voluntarily</strong>. The first local run in the whole programme to judge itself done; all nine before it were killed by the clock.</p>

<p>It also routed around its own knowledge gap — it never found Rails 8’s <code class="language-plaintext highlighter-rouge">rate_limit</code> API, so it hand-rolled a mutex-guarded sliding window instead. For that task, the missing training data simply wasn’t the constraint.</p>

<h2 id="the-boundary">The boundary</h2>

<p>Then I ran it overnight on harder tasks, seven runs, each with a different intervention on top of the stopping rule. One task passed a third time — with a <em>different</em> solution than the two earlier passes, so it was re-deriving, not memorising. Everything else failed.</p>

<p>The honest read: repetition is the discriminator. The failures ran 20–82% duplicate tool calls; the passes ran 0%. Four prompt interventions failed to move that needle. One “definition of done” prompt made the model act — then it monkey-patched the removed API back globally and broke the app’s own test suite. Instructing for completeness without constraining method produces sweeping wrong changes.</p>

<h2 id="what-id-do-differently">What I’d do differently</h2>

<p>The best lessons were the embarrassing ones:</p>

<ul>
  <li>I A/B-tested a task that 15 of 18 frontier models also score zero on. Filter tasks by pass rate first, retrieval rank second.</li>
  <li>I claimed the tool-case patch shipped when it hadn’t. Verify inside the container the runner actually uses.</li>
  <li>I trusted a health metric that only ever improved — it was hashing truncated command strings and hiding a 47× duplicate. Measure repetition on full arguments.</li>
  <li>I wrote a strategic conclusion into the index hours before a second task buried it. One pass on one easy task is a lead, not a finding.</li>
</ul>

<h2 id="where-it-landed">Where it landed</h2>

<p>The strategic consequence is actually encouraging: the factory is viable on hardware I already own. The lever isn’t more docs or a better model — it’s prompt and loop design, which is the cheapest lever of all.</p>

<p>The caveat is the n=1. One pass on one easy task, even replicated three times with different solutions, is a lead. The overnight runs drew the boundary. That’s how it goes: you find the thing that works, then you find out exactly how narrow it is.</p>

<p>Be patient and persevere.</p>]]></content><author><name>Mark Richards</name></author><summary type="html"><![CDATA[Six months of benchmarking local models against a Rails dev-agent benchmark — the retrieval layer I built, the runs that failed, and the four lines of prompt that finally worked.]]></summary></entry><entry><title type="html">Sinclair Spectrum</title><link href="https://www.gr8ful.dev/2020/12/28/sinclair-spectrum.html" rel="alternate" type="text/html" title="Sinclair Spectrum" /><published>2020-12-28T00:00:00+00:00</published><updated>2020-12-28T00:00:00+00:00</updated><id>https://www.gr8ful.dev/2020/12/28/sinclair-spectrum</id><content type="html" xml:base="https://www.gr8ful.dev/2020/12/28/sinclair-spectrum.html"><![CDATA[<p>The year was 1985, the computer was a Sinclair Spectrum 48k.</p>

<p><img class="pull-left" src="/images/chuckie.jpg" alt="chuckie" /></p>

<p>I was still under 8 years old when Santa brought me a computer.  I don’t know what inspired him, I think maybe my cousin or parents friends had one.  Either way, it was a bloody great present, even though I had no idea what I was meant or could do with it.  I read the manual, drew some lines and circles and coloured them in Cyan or Magenta.  I eventually found a programming book and not knowing code I copied each line in verbatum.  However, I didnt know how to save the program or compile it.  So all I had was a few hundred lines of <code>basic</code>.  I was looking at the cover of the book and expected to have some sort of arcade type experience running.  However, on reflection the game was a simple numerical exercise like noughts and crosses. It did break my heart and utterly piss me off when I had to turn the computer off and lose all that effort.  Thus demonstrating that for somethings you need some tuition and purpose.  I suppose at ages seven and eleven months that is a lesson that may go over your head…</p>]]></content><author><name>Mark</name></author><summary type="html"><![CDATA[The origins of interest]]></summary></entry></feed>