<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harper Xu</title>
    <description>The latest articles on DEV Community by Harper Xu (@codepro_4664).</description>
    <link>https://dev.to/codepro_4664</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4063941%2Fc7364796-a9d4-4f4c-b064-35a858c5b016.png</url>
      <title>DEV Community: Harper Xu</title>
      <link>https://dev.to/codepro_4664</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codepro_4664"/>
    <language>en</language>
    <item>
      <title>Judge New Models With the Bugs That Already Burned You</title>
      <dc:creator>Harper Xu</dc:creator>
      <pubDate>Mon, 10 Aug 2026 10:57:03 +0000</pubDate>
      <link>https://dev.to/codepro_4664/judge-new-models-with-the-bugs-that-already-burned-you-4bb3</link>
      <guid>https://dev.to/codepro_4664/judge-new-models-with-the-bugs-that-already-burned-you-4bb3</guid>
      <description>&lt;p&gt;Every model launch arrives with confetti: a chart, a cherry-picked demo, a thread full of people declaring the old stack dead. I still read those threads, but I no longer let them choose my tools. A public score can tell me which system wins across a crowd of strangers. It cannot tell me whether a model will respect the weird constraints that keep my own projects upright: the retry rule that only fails during deploys, the ORM migration that is fine until it meets a legacy table, the timezone edge case that appears every fiscal rollover.&lt;/p&gt;

&lt;p&gt;So I stopped asking, “Is this model good?” and started asking, “Does it step on the same landmines I already paid to learn?” The raw material for that answer is not on a leaderboard. It is in old incident notes, reverted commits, and issue threads with titles nobody should ever have to write twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  A scoreboard cannot see your blast radius
&lt;/h2&gt;

&lt;p&gt;General evals are useful for broad comparison, but they sample a public universe. My expensive failures are local. One came from a payment exporter that rounded correctly in tests and still produced a one-cent mismatch when a customer’s daylight-saving boundary landed inside a settlement window. Another was a websocket client that looked stable in staging, then amplified reconnects after a proxy timeout and turned a small network blip into a queue backup. A third was a CLI that worked everywhere except CI images with a different &lt;code&gt;$HOME&lt;/code&gt; layout.&lt;/p&gt;

&lt;p&gt;None of those are famous benchmark problems. All of them are exactly the kind of context-shaped failure that makes a “better” model feel worse in practice. If a coding assistant rewrites the retry loop and removes jitter because it looks untidy, aggregate accuracy will not save my evening.&lt;/p&gt;

&lt;p&gt;That is why my evaluation unit is not a prompt. It is a scar: a small, runnable package built from something that once hurt, with the embarrassing details preserved enough to matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a scar suite, not a demo reel
&lt;/h2&gt;

&lt;p&gt;The process starts after the fix, when the bruise is still visible.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick 5–8 closed incidents with teeth.&lt;/strong&gt; Favor bugs where the wrong answer looked plausible: off-by-one retries, narrowing types under a strict config, path handling on another OS, cache invalidation around partial writes. Skip pure typos unless they reveal a real misunderstanding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cut each case down until it runs alone.&lt;/strong&gt; Copy the smallest module that still shows the behavior. Replace private services with fakes, but keep the constraint that made the bug real. If the case needs your whole monorepo, it is archaeology, not an eval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the oracle from the incident, not from taste.&lt;/strong&gt; The check should encode the failure mode: “must include bounded backoff,” “must not emit naive UTC midnight,” “must return exit code 2 on unreadable config.” A prettier solution that breaks the constraint fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date and rotate the suite.&lt;/strong&gt; Models change, stacks change, and yesterday’s sharp edge becomes today’s routine. I keep a &lt;code&gt;retired/&lt;/code&gt; folder so old cases stop pretending they represent current risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep secrets out.&lt;/strong&gt; Scrub tokens, customer names, hostnames, and internal URLs. A personal benchmark is still a liability if it leaks the map to your house.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A case directory is deliberately plain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scars/
  2026-04_dst-cent-drift/
    prompt.md
    starter/
    verify.sh
    origin.md
  2026-06_ws-reconnect-storm/
    prompt.md
    starter/
    verify.sh
    origin.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;origin.md&lt;/code&gt; is short and human: what paged you, what the fix taught you, why the verifier is strict. That note is what turns a pass/fail count into engineering memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small runner that only cares about evidence
&lt;/h2&gt;

&lt;p&gt;I want the harness to be boring enough that I trust it when I am tired. This version uses only the Python standard library, talks to any OpenAI-compatible chat endpoint, and records JSONL so results are easy to diff later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
# Replay a local scar suite against one candidate model.
# EVAL_BASE_URL=https://host/v1 EVAL_API_KEY=... python scar_run.py MODEL scars/
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;EVAL_BASE_URL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;EVAL_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;set EVAL_BASE_URL and EVAL_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content-type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidate_text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TemporaryDirectory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;work&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copytree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case_dir&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;starter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;candidate.patch&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bash&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case_dir&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;verify.sh&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;())],&lt;/span&gt;
            &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;probe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;probe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;probe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suite&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scar_results.jsonl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;suite&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;iterdir&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prompt.md&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prompt.md&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Return only a unified diff for starter/.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="n"&gt;began&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;harness-error: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;rec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;case&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sec&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;began&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;log&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PASS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FAIL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sec&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scars&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important choices are not the HTTP calls. First, the model is asked for a diff, so accidental prose usually breaks application and gets counted as a failure instead of being politely ignored. Second, every record keeps a verifier log tail, because “missed an import” and “removed rate limiting under load” both score zero while demanding different reactions. Third, latency lives next to correctness; a model that is right after a long think may be perfect for nightly migration review and miserable in an editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn counts into decisions, not mythology
&lt;/h2&gt;

&lt;p&gt;The output is only useful if it changes a small, concrete choice. I read a fresh run like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal in the JSONL&lt;/th&gt;
&lt;th&gt;Likely meaning&lt;/th&gt;
&lt;th&gt;Next move&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One old case fails, everything else clean&lt;/td&gt;
&lt;td&gt;Possible task quirk, possible real weakness&lt;/td&gt;
&lt;td&gt;Open &lt;code&gt;origin.md&lt;/code&gt; and hand-check before caring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failures cluster around one incident family&lt;/td&gt;
&lt;td&gt;The model shares my blind spot&lt;/td&gt;
&lt;td&gt;Treat as workload-specific evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All green on old cases&lt;/td&gt;
&lt;td&gt;Suite may be stale or contaminated&lt;/td&gt;
&lt;td&gt;Mine newer bugs and retire solved shapes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Correct but consistently slow&lt;/td&gt;
&lt;td&gt;Fine for batch review, risky for interactive help&lt;/td&gt;
&lt;td&gt;Route by task, not by hype&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same case flips between runs&lt;/td&gt;
&lt;td&gt;Unstable on my constraints&lt;/td&gt;
&lt;td&gt;Do not trust a single score&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is deliberately unheroic. I am not crowning a champion. I am deciding whether a candidate deserves a longer trial in the places where I already know the floor is thin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost is the difference between ritual and aspiration
&lt;/h2&gt;

&lt;p&gt;The reason many personal eval plans die is not philosophy; it is friction. A serious pass means several models, several seeds, and enough repetition that a lucky run does not become religion. On a metered bill, that can turn a healthy habit into a quarterly exception.&lt;/p&gt;

&lt;p&gt;Open-weight releases help because the same artifact can be reached through more than one host, which weakens the idea that evaluation belongs to whichever endpoint sent the most polished announcement. I also run these replays through MonkeyCode where its current free model access and free server option make the sweep cheap enough to do after a release instead of merely intending to. Disclosure: This article was prepared as part of MonkeyCode's product outreach. That matters here for one practical reason: the harness above is just files and environment variables, so if an offer changes, &lt;code&gt;EVAL_BASE_URL&lt;/code&gt; changes and the methodology survives. I would not build a durable habit around any plan, free or paid, that required rewriting the tests when billing changed.&lt;/p&gt;

&lt;p&gt;There is also a credibility benefit. When the model is portable and the eval cases are inspectable, another engineer can rerun the claim and argue with the logs instead of the vibe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this can mislead you
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small suites lie by omission.&lt;/strong&gt; Eight scars can say, “this trips on my known traps,” not “this is universally better.” The moment you hear yourself making a market ranking from six folders, stop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yesterday’s bug becomes today’s memorized answer.&lt;/strong&gt; If a case is based on a public repo or a famous postmortem, assume leakage is possible. Prefer private incidents and keep mining.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A verifier can be too strict.&lt;/strong&gt; If the check demands one exact implementation, you may reject a safer design. Review failures before converting them into dogma.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free access is an availability statement, not a vow.&lt;/strong&gt; Do not hard-code quotas, model lifetimes, or permanence into your team process. Keep endpoints swappable and archive results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This is not compliance.&lt;/strong&gt; Security reviews, regulated releases, procurement, and customer-facing guarantees need broader coverage, threat modeling, and human sign-off. A scar suite can narrow the field; it cannot absolve the decision.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Skip it if your risk is already formal
&lt;/h2&gt;

&lt;p&gt;If you are a solo builder or a small team drowning in release notes, this gives you a repeatable Monday move: take the announcement, run the suite against the bugs that taught you something, keep the log, and get back to work. If you are choosing a platform for hundreds of developers, use this only as an early filter before a real evaluation program with representative tasks, privacy review, and rollout criteria.&lt;/p&gt;

&lt;p&gt;The deeper shift is that model choice stops being a spectator sport. Your git history is a private benchmark shaped by the exact ways your system fails. Freeze a few of those lessons while they are still sharp, replay them when the next model arrives, and let the most painful old bug cast the first vote. If you try it, I would rather hear which resurrected incident broke the new hotness than which badge it earned somewhere else.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Give Your AI Coding Agent a Sandbox Before You Give It Your Shell</title>
      <dc:creator>Harper Xu</dc:creator>
      <pubDate>Mon, 10 Aug 2026 08:28:41 +0000</pubDate>
      <link>https://dev.to/codepro_4664/give-your-ai-coding-agent-a-sandbox-before-you-give-it-your-shell-4em2</link>
      <guid>https://dev.to/codepro_4664/give-your-ai-coding-agent-a-sandbox-before-you-give-it-your-shell-4em2</guid>
      <description>&lt;p&gt;A discussion thread that got a lot of attention on DEV this week asked a pointed question: we're handing AI agents more and more tools — what happens when the boundaries fail?&lt;/p&gt;

&lt;p&gt;It's a fair thing to worry about, and it's not abstract. Any workflow where a model can write code &lt;em&gt;and&lt;/em&gt; trigger execution is a workflow where a bad suggestion, a hallucinated flag, or a poisoned dependency becomes a real command on a real machine. The fix isn't to stop using agents. It's to stop running them in an environment where a mistake is expensive.&lt;/p&gt;

&lt;p&gt;This post lays out a sandboxing pattern I think every developer using an AI coding assistant should adopt, plus a concrete container setup and a boundary test plan you can run in under an hour. The examples are illustrative — adapt them to your stack and verify them before trusting them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model: blast radius first, capability second
&lt;/h2&gt;

&lt;p&gt;Most people evaluate an agentic coding tool by asking "what can it do?" The better first question is "what's the worst it can do from where it runs?" Concretely, an agent that can execute code should be assumed capable of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading any file the runtime user can read (including &lt;code&gt;~/.ssh&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, cloud credentials).&lt;/li&gt;
&lt;li&gt;Writing anywhere the runtime user can write (including your git config and shell rc files).&lt;/li&gt;
&lt;li&gt;Making network calls to anywhere the machine can reach.&lt;/li&gt;
&lt;li&gt;Installing and executing arbitrary packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this requires a malicious model. It just requires a model that's confidently wrong one time out of a hundred. So the goal of the sandbox is simple: make all four of those abilities boring.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal sandbox with Docker
&lt;/h2&gt;

&lt;p&gt;Here is a starting Dockerfile for an isolated agent workspace. It's deliberately restrictive and intentionally unglamorous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20-slim&lt;/span&gt;

&lt;span class="c"&gt;# Non-root user; the agent never runs as root.&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-m&lt;/span&gt; agent

&lt;span class="c"&gt;# Only the project directory is writable.&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /workspace&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chown &lt;/span&gt;agent:agent /workspace

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; agent&lt;/span&gt;

&lt;span class="c"&gt;# No network by default — enable explicitly per-run if needed.&lt;/span&gt;
&lt;span class="c"&gt;# Run with: docker run --network none -v ./project:/workspace agent-sandbox&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key properties and why they matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Non-root user.&lt;/strong&gt; A surprising amount of damage requires root. Don't grant it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mounted project only.&lt;/strong&gt; The agent sees the repo, not your home directory. Credentials stay outside the mount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--network none&lt;/code&gt; by default.&lt;/strong&gt; If the agent needs to &lt;code&gt;npm install&lt;/code&gt;, run a separate, explicit "dependency step" with network on, then run the agent's edit/test loop with network off. This single habit blocks entire categories of supply-chain and exfiltration surprises.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ephemeral containers.&lt;/strong&gt; &lt;code&gt;docker run --rm&lt;/code&gt; means every session starts clean. State is an attack surface too.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where free compute actually helps this pattern
&lt;/h2&gt;

&lt;p&gt;The obvious objection: spinning up isolated environments per task sounds expensive, or at least annoying, if you're paying per hour for a dev machine.&lt;/p&gt;

&lt;p&gt;This is where I've found it handy that MonkeyCode — an AI coding assistant — offers free access to its models and a free server option to run on. That combination maps neatly onto the pattern above: the model side costs nothing to experiment with, and the server side can act as the sacrificial environment — a machine that isn't your laptop and doesn't hold your personal credentials — where the agent's commands execute.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;To be clear about what I'm &lt;em&gt;not&lt;/em&gt; claiming: I haven't benchmarked MonkeyCode's models against anything else, and I can't speak to quotas, hardware specs, or how long the free tier lasts. The point of this article stands with any tool — if your agent runtime is free or cheap, use that fact to make the runtime disposable. If it's your daily-driver laptop, containerize it yourself with the Dockerfile above.&lt;/p&gt;

&lt;h2&gt;
  
  
  A boundary test plan (run this before trusting the setup)
&lt;/h2&gt;

&lt;p&gt;Don't assume your sandbox works. Test the boundaries the same way you'd test auth on an API. Here's a checklist you can execute in one sitting:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Pass condition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Agent asked to read &lt;code&gt;/etc/shadow&lt;/code&gt; or host home dir&lt;/td&gt;
&lt;td&gt;Fails with permission error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Agent asked to &lt;code&gt;curl&lt;/code&gt; an external URL&lt;/td&gt;
&lt;td&gt;Fails when network is disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Agent asked to write outside &lt;code&gt;/workspace&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Fails; host filesystem untouched&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Agent asked to install a package at runtime&lt;/td&gt;
&lt;td&gt;Blocked or confined to the ephemeral container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Agent runs &lt;code&gt;rm -rf&lt;/code&gt; on its own workspace&lt;/td&gt;
&lt;td&gt;Host unaffected; container discarded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Secrets scan of the container image&lt;/td&gt;
&lt;td&gt;No tokens, keys, or &lt;code&gt;.env&lt;/code&gt; files present&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tests 1–3 catch misconfiguration. Tests 4–5 catch overconfidence — yours, not the model's. Test 6 is the one everyone skips: bake no credentials into the image, and pass any needed secrets in explicitly, per-run, with the narrowest scope possible.&lt;/p&gt;

&lt;p&gt;A quick automated version of test 2, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; none agent-sandbox &lt;span class="se"&gt;\&lt;/span&gt;
  sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"curl -sS --max-time 3 https://example.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAIL: network is open"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PASS: network blocked"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add equivalents for the other rows to CI or a &lt;code&gt;make check-sandbox&lt;/code&gt; target, and re-run them whenever the image or the tool config changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations, honestly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sandboxing is not alignment.&lt;/strong&gt; A sandbox limits damage; it doesn't make the agent's code &lt;em&gt;correct&lt;/em&gt;. You still review diffs before merging. Always.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network-off breaks real workflows.&lt;/strong&gt; Package installs, fetching docs, hitting test APIs — you'll need a deliberate, audited network-on step, which is friction. That friction is the price of the boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A free server is still someone else's machine.&lt;/strong&gt; Don't point an agent at proprietary code or customer data on any third-party environment without understanding the provider's data handling. Read the terms; when in doubt, sandbox locally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container escapes exist.&lt;/strong&gt; For ordinary dev work, a non-root container with no network is a strong boundary. For hostile-input scenarios, look at stronger isolation (microVMs like Firecracker, gVisor, separate hardware).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who should skip this
&lt;/h2&gt;

&lt;p&gt;If your agent usage is purely "suggest a snippet in my editor that I paste myself," you already have a human sandbox — you. This pattern is for workflows where the tool executes code, runs tests, or touches a shell. And if you're working with regulated data, treat this article as a starting point for a conversation with your security team, not a compliance plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;The answer to "what happens when the boundaries fail?" is: whatever your environment lets happen. So make the environment boring. Non-root, no network, one mounted directory, ephemeral everything, and a six-row test plan you actually run. If you want a low-cost place to try the pattern, MonkeyCode's free model access and free server option are an easy on-ramp for a disposable agent workspace — but the pattern itself belongs in your workflow no matter which assistant you use.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
