<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.thempatel.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.thempatel.com/" rel="alternate" type="text/html" /><updated>2026-06-09T12:30:40+00:00</updated><id>https://www.thempatel.com/feed.xml</id><title type="html">thempatel</title><entry><title type="html">Getting agents to code like us</title><link href="https://www.thempatel.com/2026/06/06/slop.html" rel="alternate" type="text/html" title="Getting agents to code like us" /><published>2026-06-06T00:00:00+00:00</published><updated>2026-06-06T00:00:00+00:00</updated><id>https://www.thempatel.com/2026/06/06/slop</id><content type="html" xml:base="https://www.thempatel.com/2026/06/06/slop.html"><![CDATA[<p>Coding agents have completely reshaped the way I work. I don’t think this is going to come as a surprise to anyone who’s been using these tools in the last 3-6 months. I now spend most of my engineering time building plans and reviewing agent code.</p>

<p>I don’t know that I’ll ever stop wanting to review agent code. I understand that probably makes me much slower compared to people who accept it as-is and ship to prod, but at the very least it seems like I’m not the only one<sup id="fnref:company"><a href="#fn:company" class="footnote" rel="footnote" role="doc-noteref">1</a></sup>.</p>

<p>My rationale is twofold:</p>
<ol>
  <li>I echo the sentiments of those who talk about losing touch with code and its architecture. Despite my efforts to combat that, I still find myself asking “how did that thing work again?” Maybe it’s because I’m now covering a lot more breadth over a shorter period of time. Maybe I’m getting older. Maybe it’s both. I don’t remember finding myself in this position as often as I do now.</li>
  <li>If I’m going to be on the hook for the code I ship, then I want to know what’s in it and I want to build it with posterity in mind. I’ve spent quite a lot of time learning what actually works in production: why would I throw that all away? If I can use that experience to shape outcomes, why wouldn’t I?</li>
</ol>

<p>When I review agent code, I look for architecture or implementation problems. Architecture problems commonly arise from non-exhaustive planning where there was some gap in my understanding of the problem space that wasn’t filled by either my own research or the agent’s. Implementation problems commonly arise out of wrong architecture choices: solutions that don’t fit the framework, the language or even the structure of the existing codebase. These problems are not unique to agents.</p>

<p>Agents have introduced a new kind of implementation problem, one that arises out of the agent’s inherent stochasticity. Even when you get the architecture right, its taste in code structure and modularity is more informed by which branch of the decoding loop it took than some objective measure.</p>

<p>All of these scenarios produce code that you would expect a concientious engineer to cleanup. Agents are not concientious which is why we oftentimes find ourselves reviewing slop.</p>

<p>Partway through one of my review sessions, I asked myself a simple question: can the intuition I have about what makes code “clean” be automated? If it can be automated, can an agent use it?<sup id="fnref:architecture"><a href="#fn:architecture" class="footnote" rel="footnote" role="doc-noteref">2</a></sup></p>

<p>Static analysis has been in the engineering toolbelt for a very long time<sup id="fnref:history"><a href="#fn:history" class="footnote" rel="footnote" role="doc-noteref">3</a></sup> and tools<sup id="fnref:linters"><a href="#fn:linters" class="footnote" rel="footnote" role="doc-noteref">4</a></sup> that analyze programs are abundantly available and regularly used. One class of static analysis I haven’t seen used broadly<sup id="fnref:broadly"><a href="#fn:broadly" class="footnote" rel="footnote" role="doc-noteref">5</a></sup> is the kind of tool that tells you your code has too many conditionals, or that your functions are too big, or that you have an object with methods that don’t share any state. Essentially, the kind of tool that tells you how sloppy your code is.</p>

<p>I attribute this to two things:</p>

<ol>
  <li>Building consensus is hard<sup id="fnref:consensus"><a href="#fn:consensus" class="footnote" rel="footnote" role="doc-noteref">6</a></sup>. Even more so when it’s about something subjective like taste.</li>
  <li>There has, till recently, not been a generic tool that can automatically transform a body of code in a way that minimizes this kind of objective.</li>
</ol>

<p>I<sup id="fnref:credit"><a href="#fn:credit" class="footnote" rel="footnote" role="doc-noteref">7</a></sup> wrote <a href="https://github.com/thempatel/mdlr"><code class="language-plaintext highlighter-rouge">mdlr</code></a> to give agents that objective, because</p>

<ol>
  <li>I now have half the time to review 2-3x the code</li>
  <li>I need to be able to jump into any part of the diff or codebase and quickly get up to speed</li>
  <li>I want one tool that I can use across multiple programming languages</li>
  <li>Cleaning up dirty code is not my preferred method for staying sharp<sup id="fnref:sharp"><a href="#fn:sharp" class="footnote" rel="footnote" role="doc-noteref">8</a></sup></li>
</ol>

<hr />

<p><code class="language-plaintext highlighter-rouge">mdlr</code> scans a codebase and outputs a list of metrics and their associated symbols sorted in descending severity. Here’s an example output.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mdlr check --pretty
metric         symbol                       value  bucket
function_size  replay_endpoint_error::main  141    critical
cognitive      replay_endpoint_error::main  26     critical
cyclomatic     replay_endpoint_error::main  18     critical
</code></pre></div></div>

<p>Getting an agent to use this is very simple: ask it to run <code class="language-plaintext highlighter-rouge">mdlr prompt</code> and follow the instructions.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mdlr prompt

# Auto-Improve

Use mdlr to identify and improve modularity issues in the codebase.

## mdlr Reference

### Quick Start

# Analyze codebase (diff mode on branches, all files on main/master)
mdlr check

# Force all files even when on a branch
mdlr check -A

# Analyze specific directory or file
mdlr check src/metrics
mdlr check src/main.rs
...
</code></pre></div></div>

<p>Here’s an example that Claude was able to improve entirely on its own with this tool. This is part of a script I had it build to help me debug query timeouts in ClickHouse.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="c1"># ...argparse setup for --set, --delete, --gap, --explain, --output...
</span>    <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="p">.</span><span class="nf">parse_args</span><span class="p">()</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="p">.</span><span class="nf">exists</span><span class="p">():</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Error: </span><span class="si">{</span><span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="si">}</span><span class="s"> not found</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>
        <span class="n">sys</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="n">error</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">loads</span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="p">.</span><span class="nf">read_text</span><span class="p">())</span>
    <span class="n">endpoint_name</span> <span class="o">=</span> <span class="n">error</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">endpoint_name</span><span class="sh">"</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">endpoint_name</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Error: no endpoint_name found in error file</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>
        <span class="n">sys</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="c1"># Extract request from request_json (toJSONString output) or request
</span>    <span class="n">request</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">if</span> <span class="sh">"</span><span class="s">request_json</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">error</span><span class="p">:</span>
        <span class="n">request</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">loads</span><span class="p">(</span><span class="n">error</span><span class="p">[</span><span class="sh">"</span><span class="s">request_json</span><span class="sh">"</span><span class="p">])</span>
    <span class="k">elif</span> <span class="sh">"</span><span class="s">request</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">error</span><span class="p">:</span>
        <span class="n">request</span> <span class="o">=</span> <span class="n">error</span><span class="p">[</span><span class="sh">"</span><span class="s">request</span><span class="sh">"</span><span class="p">]</span> <span class="k">if</span> <span class="nf">isinstance</span><span class="p">(</span><span class="n">error</span><span class="p">[</span><span class="sh">"</span><span class="s">request</span><span class="sh">"</span><span class="p">],</span> <span class="nb">dict</span><span class="p">)</span> <span class="k">else</span> <span class="p">{}</span>

    <span class="c1"># Apply gap adjustment first
</span>    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">gap</span><span class="p">:</span>
        <span class="nf">apply_gap</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="nf">parse_duration</span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="n">gap</span><span class="p">),</span> <span class="n">endpoint_name</span><span class="p">)</span>

    <span class="c1"># Apply overrides
</span>    <span class="k">for</span> <span class="n">kv</span> <span class="ow">in</span> <span class="n">args</span><span class="p">.</span><span class="nb">set</span><span class="p">:</span>
        <span class="n">key</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="n">kv</span><span class="p">.</span><span class="nf">partition</span><span class="p">(</span><span class="sh">"</span><span class="s">=</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">_</span><span class="p">:</span>
            <span class="nf">print</span><span class="p">(</span>
                <span class="sa">f</span><span class="sh">"</span><span class="s">Error: invalid --set format </span><span class="sh">'</span><span class="si">{</span><span class="n">kv</span><span class="si">}</span><span class="sh">'</span><span class="s">, expected key=value</span><span class="sh">"</span><span class="p">,</span>
                <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">sys</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">request</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>

    <span class="c1"># Apply deletions
</span>    <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">args</span><span class="p">.</span><span class="n">delete</span><span class="p">:</span>
        <span class="n">request</span><span class="p">.</span><span class="nf">pop</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Endpoint:   </span><span class="si">{</span><span class="n">endpoint_name</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Request: </span><span class="si">{</span><span class="n">json</span><span class="p">.</span><span class="nf">dumps</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>

    <span class="c1"># ...load host + token from token file...
</span>    <span class="n">host</span><span class="p">,</span> <span class="n">token</span> <span class="o">=</span> <span class="nf">parse_token</span><span class="p">(</span><span class="n">token_path</span><span class="p">)</span>
    <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">Authorization</span><span class="sh">"</span><span class="p">:</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Bearer </span><span class="si">{</span><span class="n">token</span><span class="si">}</span><span class="sh">"</span><span class="p">}</span>

    <span class="c1"># Explain mode: hit /explain for each cte
</span>    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">explain</span><span class="p">:</span>
        <span class="n">ctes</span> <span class="o">=</span> <span class="nf">discover_ctes</span><span class="p">(</span><span class="n">endpoint_name</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">ctes</span><span class="p">:</span>
            <span class="c1"># ...error + exit if no .endpoint file found...
</span>            <span class="n">sys</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

        <span class="n">explain_dir</span> <span class="o">=</span> <span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="p">.</span><span class="n">parent</span> <span class="o">/</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="p">.</span><span class="n">stem</span><span class="si">}</span><span class="s">_explain</span><span class="sh">"</span>
        <span class="n">explain_dir</span><span class="p">.</span><span class="nf">mkdir</span><span class="p">(</span><span class="n">parents</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Explaining </span><span class="si">{</span><span class="nf">len</span><span class="p">(</span><span class="n">ctes</span><span class="p">)</span><span class="si">}</span><span class="s"> ctes...</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">cte</span> <span class="ow">in</span> <span class="n">ctes</span><span class="p">:</span>
            <span class="n">resp</span> <span class="o">=</span> <span class="n">httpx</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span>
                <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">host</span><span class="si">}</span><span class="s">/v0/endpoints/explain</span><span class="sh">"</span><span class="p">,</span>
                <span class="n">json</span><span class="o">=</span><span class="n">request</span><span class="p">,</span>
                <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span>
                <span class="n">timeout</span><span class="o">=</span><span class="mi">60</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">out_path</span> <span class="o">=</span> <span class="n">explain_dir</span> <span class="o">/</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">cte</span><span class="si">}</span><span class="s">.json</span><span class="sh">"</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">result</span> <span class="o">=</span> <span class="n">resp</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
                <span class="n">out_path</span><span class="p">.</span><span class="nf">write_text</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="nf">dumps</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">str</span><span class="p">))</span>
            <span class="k">except</span> <span class="n">json</span><span class="p">.</span><span class="n">JSONDecodeError</span><span class="p">:</span>
                <span class="n">out_path</span><span class="p">.</span><span class="nf">write_text</span><span class="p">(</span><span class="n">resp</span><span class="p">.</span><span class="n">text</span><span class="p">)</span>
            <span class="n">status</span> <span class="o">=</span> <span class="sh">"</span><span class="s">ok</span><span class="sh">"</span> <span class="k">if</span> <span class="n">resp</span><span class="p">.</span><span class="n">is_success</span> <span class="k">else</span> <span class="nf">str</span><span class="p">(</span><span class="n">resp</span><span class="p">.</span><span class="n">status_code</span><span class="p">)</span>
            <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">  </span><span class="si">{</span><span class="n">cte</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>

        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Explain output written to </span><span class="si">{</span><span class="n">explain_dir</span><span class="si">}</span><span class="s">/</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>

    <span class="c1"># Replay: POST to the endpoint
</span>    <span class="n">response</span> <span class="o">=</span> <span class="n">httpx</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span>
        <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">host</span><span class="si">}</span><span class="s">/v0/endpoints/</span><span class="si">{</span><span class="n">endpoint_name</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span>
        <span class="n">json</span><span class="o">=</span><span class="n">request</span><span class="p">,</span>
        <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span>
        <span class="n">timeout</span><span class="o">=</span><span class="mi">60</span><span class="p">,</span>
    <span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Status: </span><span class="si">{</span><span class="n">response</span><span class="p">.</span><span class="n">status_code</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
        <span class="n">output</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">dumps</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">str</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">json</span><span class="p">.</span><span class="n">JSONDecodeError</span><span class="p">:</span>
        <span class="n">output</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">text</span>

    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">output</span><span class="p">:</span>
        <span class="n">args</span><span class="p">.</span><span class="n">output</span><span class="p">.</span><span class="nf">write_text</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Written to </span><span class="si">{</span><span class="n">args</span><span class="p">.</span><span class="n">output</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
</code></pre></div></div>

<p>I have two arguments for why this is bad:</p>

<ol>
  <li>You can’t quickly skim this to get the function’s story. If I have to spend more than 5 seconds making heads or tails of what something does, it’s usually too big or poorly structured.<sup id="fnref:complex"><a href="#fn:complex" class="footnote" rel="footnote" role="doc-noteref">9</a></sup></li>
  <li>If you want to change this, you have to keep a lot of different requirements in your head to make sure nothing breaks when adding a new thing. I acknowledge that sometimes that’s a feature, not a bug.</li>
</ol>

<p>Here’s the whole thing afterward:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="c1"># ...same argparse setup...
</span>    <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="p">.</span><span class="nf">parse_args</span><span class="p">()</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="p">.</span><span class="nf">exists</span><span class="p">():</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Error: </span><span class="si">{</span><span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="si">}</span><span class="s"> not found</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>
        <span class="n">sys</span><span class="p">.</span><span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="n">endpoint_name</span><span class="p">,</span> <span class="n">request</span> <span class="o">=</span> <span class="nf">load_error_request</span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">gap</span><span class="p">:</span>
        <span class="nf">apply_gap</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="nf">parse_duration</span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="n">gap</span><span class="p">),</span> <span class="n">endpoint_name</span><span class="p">)</span>
    <span class="nf">apply_overrides</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="nb">set</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="n">delete</span><span class="p">)</span>

    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Endpoint:   </span><span class="si">{</span><span class="n">endpoint_name</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Request: </span><span class="si">{</span><span class="n">json</span><span class="p">.</span><span class="nf">dumps</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">stderr</span><span class="p">)</span>

    <span class="c1"># ...load host + token from token file...
</span>    <span class="n">host</span><span class="p">,</span> <span class="n">token</span> <span class="o">=</span> <span class="nf">parse_token</span><span class="p">(</span><span class="n">token_path</span><span class="p">)</span>
    <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">Authorization</span><span class="sh">"</span><span class="p">:</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Bearer </span><span class="si">{</span><span class="n">token</span><span class="si">}</span><span class="sh">"</span><span class="p">}</span>

    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">explain</span><span class="p">:</span>
        <span class="nf">run_explain</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">headers</span><span class="p">,</span> <span class="n">endpoint_name</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="nb">file</span><span class="p">)</span>

    <span class="nf">run_replay</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">headers</span><span class="p">,</span> <span class="n">endpoint_name</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="n">output</span><span class="p">)</span>
</code></pre></div></div>

<p>Here’s another example that surprised me<sup id="fnref:surprise"><a href="#fn:surprise" class="footnote" rel="footnote" role="doc-noteref">10</a></sup>, this time from <code class="language-plaintext highlighter-rouge">mdlr</code>’s own codebase. These test cases all repeated the same test setup code, which was surfaced via the code duplication metric.</p>

<p>Before:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">test_load_from_current_dir</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">temp</span> <span class="o">=</span> <span class="nn">TempDir</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">config_dir</span> <span class="o">=</span> <span class="n">temp</span><span class="nf">.path</span><span class="p">()</span><span class="nf">.join</span><span class="p">(</span><span class="s">".mdlr"</span><span class="p">);</span>
    <span class="nn">fs</span><span class="p">::</span><span class="nf">create_dir</span><span class="p">(</span><span class="o">&amp;</span><span class="n">config_dir</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nn">fs</span><span class="p">::</span><span class="nf">write</span><span class="p">(</span>
        <span class="n">config_dir</span><span class="nf">.join</span><span class="p">(</span><span class="s">"config.yaml"</span><span class="p">),</span>
        <span class="s">r#"
thresholds:
  dag_density:
    excellent: 0.3
    good: 0.8
    fair: 1.2
    poor: 1.8
"#</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="nf">.unwrap</span><span class="p">();</span>

    <span class="k">let</span> <span class="n">config</span> <span class="o">=</span> <span class="nf">load_from_dir</span><span class="p">(</span><span class="n">temp</span><span class="nf">.path</span><span class="p">())</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="n">config</span><span class="py">.thresholds.dag_density.excellent</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">);</span>
    <span class="c1">// Defaults still work for unspecified fields</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="n">config</span><span class="py">.thresholds.fan_in_max.excellent</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">);</span>
<span class="p">}</span>

<span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">test_load_disabled_metrics</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">temp</span> <span class="o">=</span> <span class="nn">TempDir</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">config_dir</span> <span class="o">=</span> <span class="n">temp</span><span class="nf">.path</span><span class="p">()</span><span class="nf">.join</span><span class="p">(</span><span class="s">".mdlr"</span><span class="p">);</span>
    <span class="nn">fs</span><span class="p">::</span><span class="nf">create_dir</span><span class="p">(</span><span class="o">&amp;</span><span class="n">config_dir</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nn">fs</span><span class="p">::</span><span class="nf">write</span><span class="p">(</span>
        <span class="n">config_dir</span><span class="nf">.join</span><span class="p">(</span><span class="s">"config.yaml"</span><span class="p">),</span>
        <span class="s">r#"
disabled_metrics:
  - lcom
  - duplication_pct
"#</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="nf">.unwrap</span><span class="p">();</span>

    <span class="k">let</span> <span class="n">config</span> <span class="o">=</span> <span class="nf">load_from_dir</span><span class="p">(</span><span class="n">temp</span><span class="nf">.path</span><span class="p">())</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">config</span><span class="nf">.is_disabled</span><span class="p">(</span><span class="s">"lcom"</span><span class="p">));</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">config</span><span class="nf">.is_disabled</span><span class="p">(</span><span class="s">"duplication_pct"</span><span class="p">));</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="o">!</span><span class="n">config</span><span class="nf">.is_disabled</span><span class="p">(</span><span class="s">"cyclomatic"</span><span class="p">));</span>
<span class="p">}</span>

<span class="c1">// ...and a third test with the same setup block...</span>
</code></pre></div></div>

<p>After:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// Write `.mdlr/config.yaml` under `root` with the given contents.</span>
<span class="k">fn</span> <span class="nf">write_config</span><span class="p">(</span><span class="n">root</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Path</span><span class="p">,</span> <span class="n">yaml</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">config_dir</span> <span class="o">=</span> <span class="n">root</span><span class="nf">.join</span><span class="p">(</span><span class="s">".mdlr"</span><span class="p">);</span>
    <span class="nn">fs</span><span class="p">::</span><span class="nf">create_dir_all</span><span class="p">(</span><span class="o">&amp;</span><span class="n">config_dir</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nn">fs</span><span class="p">::</span><span class="nf">write</span><span class="p">(</span><span class="n">config_dir</span><span class="nf">.join</span><span class="p">(</span><span class="s">"config.yaml"</span><span class="p">),</span> <span class="n">yaml</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="p">}</span>

<span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">test_load_from_current_dir</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">temp</span> <span class="o">=</span> <span class="nn">TempDir</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nf">write_config</span><span class="p">(</span>
        <span class="n">temp</span><span class="nf">.path</span><span class="p">(),</span>
        <span class="s">r#"
thresholds:
  dag_density:
    excellent: 0.3
    good: 0.8
    fair: 1.2
    poor: 1.8
"#</span><span class="p">,</span>
    <span class="p">);</span>

    <span class="k">let</span> <span class="n">config</span> <span class="o">=</span> <span class="nf">load_from_dir</span><span class="p">(</span><span class="n">temp</span><span class="nf">.path</span><span class="p">())</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="n">config</span><span class="py">.thresholds.dag_density.excellent</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">);</span>
    <span class="c1">// Defaults still work for unspecified fields</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="n">config</span><span class="py">.thresholds.fan_in_max.excellent</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">);</span>
<span class="p">}</span>

<span class="nd">#[test]</span>
<span class="k">fn</span> <span class="nf">test_load_disabled_metrics</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">temp</span> <span class="o">=</span> <span class="nn">TempDir</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nf">write_config</span><span class="p">(</span>
        <span class="n">temp</span><span class="nf">.path</span><span class="p">(),</span>
        <span class="s">r#"
disabled_metrics:
  - lcom
  - duplication_pct
"#</span><span class="p">,</span>
    <span class="p">);</span>

    <span class="k">let</span> <span class="n">config</span> <span class="o">=</span> <span class="nf">load_from_dir</span><span class="p">(</span><span class="n">temp</span><span class="nf">.path</span><span class="p">())</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">config</span><span class="nf">.is_disabled</span><span class="p">(</span><span class="s">"lcom"</span><span class="p">));</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">config</span><span class="nf">.is_disabled</span><span class="p">(</span><span class="s">"duplication_pct"</span><span class="p">));</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="o">!</span><span class="n">config</span><span class="nf">.is_disabled</span><span class="p">(</span><span class="s">"cyclomatic"</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<p><code class="language-plaintext highlighter-rouge">mdlr</code>’s goal isn’t to be an authority on what makes code good. I’m also not making the claim that optimizing software metrics will automatically give you perfectly clean code. The goals here are</p>

<ol>
  <li>Provide a tool that enables agents to think a little more like we do.</li>
  <li>Provide a tool that enables agents to produce directionally better code.</li>
  <li>Get people thinking more about the boundaries between what agents should do versus what traditional engineering can do.</li>
</ol>

<p>I’m not convinced<sup id="fnref:like_us"><a href="#fn:like_us" class="footnote" rel="footnote" role="doc-noteref">11</a></sup> that today’s agents are the final answer. The idea that we all just have to spin up as many agents as humanly possible to craft our world and review our work feels odd, especially when cheap deterministic tools can be so successful.</p>

<hr />

<p>You can find <code class="language-plaintext highlighter-rouge">mdlr</code> on GitHub: <a href="https://github.com/thempatel/mdlr">github.com/thempatel/mdlr</a>. Use it! Then come back and tell me what you think.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:company">
      <p>See Simon Willison in <a href="https://news.ycombinator.com/item?id=48322563">this HN thread</a>, Vicki Boykis on <a href="https://vickiboykis.com/2026/05/28/we-should-be-more-tired-than-the-model/">being more tired than the model</a>, Nolan Lawson on <a href="https://nolanlawson.com/2026/05/25/using-ai-to-write-better-code-more-slowly/">using AI to write better code, more slowly</a>, and Lalit Maganti on <a href="https://lalitm.com/post/building-syntaqlite-ai/">building SyntaQLite with AI</a>. <a href="#fnref:company" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:architecture">
      <p>There’s a deeper version of this question: dirty code is sometimes a symptom of poor architecture. Could an agent work backwards from that signal and realize the architecture is wrong? This was one of the original goals of this tool and will be the next area of exploration. <a href="#fnref:architecture" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:history">
      <p><a href="https://en.wikipedia.org/wiki/Programming_complexity">Programming complexity</a> and <a href="https://en.wikipedia.org/wiki/Software_metric">Software metric</a> <a href="#fnref:history" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:linters">
      <p>Insert every tool like <code class="language-plaintext highlighter-rouge">go vet</code>, <code class="language-plaintext highlighter-rouge">eslint</code>, <code class="language-plaintext highlighter-rouge">clippy</code>, <code class="language-plaintext highlighter-rouge">flake8</code>, etc. that is used daily, and some <a href="https://www.aivosto.com/">older</a> ones too. <a href="#fnref:linters" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:broadly">
      <p>I’m not saying these metrics and tools don’t exist, in fact many static analysis tools have these built in or available as community built plugins. There’s nothing truly novel or groundbreaking in this post. <a href="#fnref:broadly" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:consensus">
      <p>An extensive <a href="https://github.com/rust-lang/rust-clippy/issues/3793">conversation</a> about adding cognitive complexity to <code class="language-plaintext highlighter-rouge">clippy</code>. <a href="#fnref:consensus" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:credit">
      <p>Really, Claude deserves all the credit. This is yet another vibe-coded tool. I did read it though. <a href="#fnref:credit" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:sharp">
      <p>I broadly agree with Minas Karamanis in <a href="https://ergosphere.blog/posts/the-machines-are-fine/">The machines are fine. I’m worried about us.</a>, but I also agree with <a href="https://news.ycombinator.com/item?id=48322070">this HN comment</a>. Sometimes the minutiae of engineering can be deeply inconvenient, especially when I have a thing I need to do! I think what makes us valuable as engineers is under active metamorphosis, and I’m excited to see where we land. <a href="#fnref:sharp" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:complex">
      <p>I know someone is going to say: “Complex things are complicated! Sometimes you need a big function!”. Yes, I agree. This is more a rule of thumb than a law. I still think it’s only in very rare scenarios where a monolith is better suited to the occasion. <a href="#fnref:complex" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:surprise">
      <p>This is a kind of change I’ve found myself making many times when I used to write unit tests by hand. The fact that the tool got the agent to make this change automatically was ironically surprising. <a href="#fnref:surprise" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:like_us">
      <p>While I don’t agree that AI agents are a mistake, I do agree with Hotz in <a href="https://geohot.github.io/blog/jekyll/update/2026/05/24/the-eternal-sloptember.html">The Eternal Sloptember</a> that today’s coding agents don’t code the way we do. <a href="#fnref:like_us" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><summary type="html"><![CDATA[Coding agents have completely reshaped the way I work. I don’t think this is going to come as a surprise to anyone who’s been using these tools in the last 3-6 months. I now spend most of my engineering time building plans and reviewing agent code.]]></summary></entry><entry><title type="html">Origin</title><link href="https://www.thempatel.com/2021/09/20/origin.html" rel="alternate" type="text/html" title="Origin" /><published>2021-09-20T00:00:00+00:00</published><updated>2021-09-20T00:00:00+00:00</updated><id>https://www.thempatel.com/2021/09/20/origin</id><content type="html" xml:base="https://www.thempatel.com/2021/09/20/origin.html"><![CDATA[<p>Hi! The name is Milan. I’m a self-taught engineer doing what I love: building great software.</p>

<p>During college, I like many of my peers, decided that medical school was what I wanted to pursue. After 4 years of many sleepless nights, many extracurriculars (including a part-time job as a computer tech, some late night EMT shifts, scientific research and volunteer work abroad) I faced rejection from all 26 medical schools that I had applied to. Ouch.</p>

<p>I needed something to bide my time while I reapplied the following cycle but unfortunately, the only job I could find was as a barista at the very school I had just graduated from. This was humbling: while many of my peers had moved on to start their next big thing, I was still at the same institution, serving many of my younger peers who had yet to graduate.</p>

<p>Around the same time, I had interviewed at the Centers for Disease Control and Prevention for a job as a data manager. I was rejected. I was honest in the interview that I was only looking for a gap-year job before heading to medical school and they needed someone to stick around longer than that, so the timing just didn’t work out.</p>

<p>Fast forward a few grueling months and I got a call back from the same division I had interviewed with. Another team was in the market for someone who could work part-time for a short term project as a stool collector for a double-blind study they were about to setup. Yep, you read that right.</p>

<p>At the time I was desperate for any kind of job that would help make my resume stand out to medical schools in the following cycle and the 20 hours there would pay the same as what I was earning doing 40 at the coffee shop. Knowing that I also had to set myself up for financial success, I decided to do both: I would block off 20 hours during the week to make ends meet at the CDC and use the rest for shifts at the coffee shop.</p>

<p>There was some stipulation during the interview that I’d get to work with computers in addition to collecting stool which turned out, at least in the early stages, to not be the case. Although it had been a step up from the coffee shop in terms of prestige, I still had not achieved the impact I was searching for. During those 20 hours, I tried to be a go-getter: I went out of my way to find as many non-stool collecting opportunities as possible, hoping that the stars would align somehow, somewhere.</p>

<p>Eventually, one of my team leads gave me a project I’m sure she thought would keep me busy for a while. She was working on a project where she needed to figure out the ideal gene sequences to build an assay with, and a colleague helping her with the task was going through a huge spreadsheet filled with protein references and manually tagging them with metadata from NCBI. I’m not sure what exactly led her to ask me to work on it instead but at the time I didn’t ask too many questions.</p>

<p>Tagging all the proteins by hand would’ve taken weeks but it turned out that NCBI had a public API that could be used to fetch the information. I had some minimal experience with Python and I knew no one was really expecting the results for a while, so I decided to see if I could code something up. Three days later, I had a well fleshed out spreadsheet with thousands of tagged gene sequences and a sense of accomplishment.</p>

<p>In the following weeks, my team lead presented her work and mentioned that they were able to put everything together so fast because I had scripted something up to do all the hard parts. To my great fortune, her boss was there to hear the success and as it turned out, was in need for someone who could program in Python. I was promptly signed up for another 20 hours to come work for her, giving me 40 hours at the CDC. I consequently left my job as a barista.</p>

<p>I spent the next 2 years as a coding bootcamp-er of sorts. It was the best possible situation: during the evenings I’d study up on Python, engineering, and computer science fundamentals and during the day I’d get to apply the knowledge, slowly honing my craft. Through a series of epiphanies I realized that becoming a doctor wasn’t what I really wanted to do with my life. I also knew that I wanted to work as a software engineer in industry and the CDC wasn’t going to help me meet that long term goal, so I left for a contract software gig and the rest is history.</p>

<p>This anecdote is only the beginning of how I got to where I am today. I feel so fortunate to be born during such a vibrant period of human history. One where the democratization of knowledge has allowed many stories like mine to exist. My advice to you is this: dream big, take leaps of faith and don’t look back. You get one life, make the most of it!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Hi! The name is Milan. I’m a self-taught engineer doing what I love: building great software.]]></summary></entry></feed>