<?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: Avery Wang</title>
    <description>The latest articles on DEV Community by Avery Wang (@apppro_5726).</description>
    <link>https://dev.to/apppro_5726</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%2F4066151%2Fd488ee67-914e-4031-8445-1442aec4f783.png</url>
      <title>DEV Community: Avery Wang</title>
      <link>https://dev.to/apppro_5726</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/apppro_5726"/>
    <language>en</language>
    <item>
      <title>A New MiniMax Model Dropped: How to Evaluate It on Your Own Code Before Believing the Benchmarks</title>
      <dc:creator>Avery Wang</dc:creator>
      <pubDate>Mon, 10 Aug 2026 11:03:35 +0000</pubDate>
      <link>https://dev.to/apppro_5726/a-new-minimax-model-dropped-how-to-evaluate-it-on-your-own-code-before-believing-the-benchmarks-ioi</link>
      <guid>https://dev.to/apppro_5726/a-new-minimax-model-dropped-how-to-evaluate-it-on-your-own-code-before-believing-the-benchmarks-ioi</guid>
      <description>&lt;p&gt;Every few weeks a new open-weight model lands — most recently another release from MiniMax — and the timeline fills with leaderboard screenshots within hours. The problem: public benchmarks measure how a model performs on &lt;em&gt;someone else's&lt;/em&gt; tasks. The only number that matters for your work is how it behaves on &lt;em&gt;your&lt;/em&gt; repos, &lt;em&gt;your&lt;/em&gt; prompts, and &lt;em&gt;your&lt;/em&gt; failure modes.&lt;/p&gt;

&lt;p&gt;This post is a practical, reproducible workflow for running a newly released model against your own coding tasks in an afternoon, using only free tooling. No vendor credits, no GPU bill, no cherry-picked demos.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow at a glance
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Freeze 10–20 real tasks from your recent work (bug fixes, small features, refactors, test writing).&lt;/li&gt;
&lt;li&gt;Run each task against the new model and one baseline model you already trust.&lt;/li&gt;
&lt;li&gt;Score outputs with a fixed rubric — not vibes.&lt;/li&gt;
&lt;li&gt;Record everything so the comparison is repeatable when the next model drops.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 1: Build a task set from your actual work
&lt;/h3&gt;

&lt;p&gt;Don't use synthetic prompts like "write a fizzbuzz." Pull real tickets or commits. A good task file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task-007"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bugfix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"context_files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/auth/session.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/auth/token.ts"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Refreshing an expired token intermittently logs the user out. Find the race condition and fix it."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"acceptance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Existing test suite passes; new regression test covers the race; no API surface changes."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ten tasks is enough to see patterns. Twenty starts to be meaningful. The acceptance criteria matter more than the prompt — they're what you score against.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Run models without paying for the experiment
&lt;/h3&gt;

&lt;p&gt;Evaluation is exactly where free tiers shine: you need breadth (several models, several runs), not sustained throughput. Two things make this cheap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free model access&lt;/strong&gt; so you can swap the candidate model and a baseline without juggling API keys and billing across three providers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A free server option&lt;/strong&gt; so the harness itself — the runner script, result store, scoring — runs somewhere persistent instead of your laptop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/em&gt; MonkeyCode is one place that offers both — free access to models and a free server option you can use to host the runner — and its open-source posture means the harness you build isn't locked to one vendor's plumbing. Whatever you use, the point is the same: the eval infrastructure should cost nothing, so you spend your attention on the scoring, not the setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Score with a rubric, not a vibe
&lt;/h3&gt;

&lt;p&gt;Here's a minimal runner sketch (Python, pseudocode-adjacent but runnable with any OpenAI-compatible endpoint):&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="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;time&lt;/span&gt;

&lt;span class="n"&gt;RUBRIC&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;compiles_or_parses&lt;/span&gt;&lt;span class="sh"&gt;"&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="c1"&gt;# hard gate
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;acceptance_met&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# did it satisfy the stated criteria?
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no_unrelated_changes&lt;/span&gt;&lt;span class="sh"&gt;"&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="c1"&gt;# diff discipline
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;explanation_honest&lt;/span&gt;&lt;span class="sh"&gt;"&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="c1"&gt;# admits uncertainty vs. hallucinates confidence
&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;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&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;task&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&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="n"&gt;p&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context_files&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&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="o"&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;messages&lt;/span&gt;&lt;span class="o"&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;system&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a careful senior engineer. Minimal diffs.&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Files:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Task: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&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;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;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;resp&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="sh"&gt;"&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="c1"&gt;# Score manually against RUBRIC, or semi-automate the compile gate.
# Save raw outputs + scores as JSONL so the whole run is reproducible.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two rules that save you from fooling yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Score blind where possible.&lt;/strong&gt; Shuffle outputs so you don't know which model wrote which until after scoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run each task at least twice.&lt;/strong&gt; A single sample tells you almost nothing about variance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Decision table
&lt;/h3&gt;

&lt;p&gt;After scoring, the decision usually falls into one of these buckets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Result pattern&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New model wins on &lt;code&gt;bugfix&lt;/code&gt; and &lt;code&gt;refactor&lt;/code&gt;, ties elsewhere&lt;/td&gt;
&lt;td&gt;Genuine candidate for daily driver&lt;/td&gt;
&lt;td&gt;Trial it on one real project for a week&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wins on generation, loses on &lt;code&gt;no_unrelated_changes&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Eager rewriter — risky for large diffs&lt;/td&gt;
&lt;td&gt;Use for greenfield/snippets only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passes compile gate but fails &lt;code&gt;explanation_honest&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Confident hallucinator&lt;/td&gt;
&lt;td&gt;Keep away from code review duties&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ties your baseline everywhere&lt;/td&gt;
&lt;td&gt;No switching cost justified&lt;/td&gt;
&lt;td&gt;Stay put, rerun eval on the next release&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Limitations and who shouldn't do this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;N=10–20 tasks is directional, not statistical.&lt;/strong&gt; It's enough to reject a model or justify a deeper trial — not enough to crown a winner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free tiers change.&lt;/strong&gt; Rate limits, model availability, and server quotas shift over time; design the harness so results are stored durably and runs can be resumed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If your work is confidential code&lt;/strong&gt;, don't paste proprietary files into any hosted eval path. Sanitize tasks or use synthetic-but-representative code instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you need latency/throughput numbers for production sizing&lt;/strong&gt;, this workflow won't give them — free access is for correctness and behavior evaluation, not load testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;The half-life of "best model" discourse is about two weeks. A personal eval harness has a much longer shelf life: every new release — MiniMax today, someone else next month — becomes a 30-minute rerun instead of a leap of faith. If you want the free model access and free server to host yours, MonkeyCode is a reasonable place to start; the harness above is plain Python and ports anywhere.&lt;/p&gt;

&lt;p&gt;Build the harness once. Let every future launch come to you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>llm</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your AI Coding Assistant Writes Shell Commands. Do You Actually Test Them Before They Run?</title>
      <dc:creator>Avery Wang</dc:creator>
      <pubDate>Mon, 10 Aug 2026 08:40:06 +0000</pubDate>
      <link>https://dev.to/apppro_5726/your-ai-coding-assistant-writes-shell-commands-do-you-actually-test-them-before-they-run-1h3e</link>
      <guid>https://dev.to/apppro_5726/your-ai-coding-assistant-writes-shell-commands-do-you-actually-test-them-before-they-run-1h3e</guid>
      <description>&lt;p&gt;There's a popular conversation going around DEV right now about giving AI agents more tools and what happens when the boundaries fail. Most of those posts talk about the problem abstractly: prompt injection, over-permissioned agents, runaway automation. I want to get concrete about the smallest, most common version of it.&lt;/p&gt;

&lt;p&gt;Almost every AI-assisted coding workflow ends with the model suggesting a shell command. A migration. A cleanup script. A &lt;code&gt;find ... -delete&lt;/code&gt;. And the failure mode isn't usually malicious — it's &lt;em&gt;plausible-looking but wrong&lt;/em&gt;. The command is syntactically valid, confidently phrased, and subtly destructive on your actual filesystem layout.&lt;/p&gt;

&lt;p&gt;So I built a tiny habit: every destructive or irreversible command an AI assistant suggests goes through a dry-run harness before it touches a real directory. Here's the harness, the test plan, and where this approach breaks down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea: assert before you execute
&lt;/h2&gt;

&lt;p&gt;The trick is to stop treating AI output as a command and start treating it as a &lt;em&gt;proposal&lt;/em&gt; that must pass assertions. For file operations, most commands have a dry-run or list-equivalent mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rm -rf path&lt;/code&gt; → first &lt;code&gt;find path -type f | head&lt;/code&gt; and check the count and scope&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mv&lt;/code&gt;/&lt;code&gt;cp&lt;/code&gt; batches → run with &lt;code&gt;-n&lt;/code&gt; (no-clobber) and echo first&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git clean -fd&lt;/code&gt; → always &lt;code&gt;git clean -nd&lt;/code&gt; first&lt;/li&gt;
&lt;li&gt;SQL migrations → run inside a transaction you roll back&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrapped this into a small shell script I keep in &lt;code&gt;~/bin/ai-guard.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# ai-guard.sh — inspect a proposed command before running it.&lt;/span&gt;
&lt;span class="c"&gt;# Usage: ai-guard.sh &amp;lt;sandbox_dir&amp;gt; -- &amp;lt;command...&amp;gt;&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;SANDBOX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"--"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;shift

&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SANDBOX&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Sandbox dir '&lt;/span&gt;&lt;span class="nv"&gt;$SANDBOX&lt;/span&gt;&lt;span class="s2"&gt;' does not exist. Refusing."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Rule 1: never let the command reference anything outside the sandbox.&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;arg &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    /&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;..&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"BLOCKED: argument '&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;' escapes the sandbox."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
      &lt;span class="nb"&gt;exit &lt;/span&gt;2 &lt;span class="p"&gt;;;&lt;/span&gt;
  &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Rule 2: snapshot file list before, run inside sandbox, diff after.&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SANDBOX&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/before.txt

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;&amp;gt;&amp;gt; Running inside &lt;/span&gt;&lt;span class="nv"&gt;$SANDBOX&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true

&lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/after.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;&amp;gt;&amp;gt; Files changed:"&lt;/span&gt;
diff /tmp/before.txt /tmp/after.txt &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow: I create a throwaway copy of the directory structure the command is meant to operate on (just the layout plus a few sentinel files — &lt;code&gt;cp -r --parents&lt;/code&gt; or a small fixture script works), run the AI's proposed command through the guard, and read the diff. Only if the diff matches my intent do I run the real thing — and even then, with the dry-run variant first.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete failure this catches
&lt;/h2&gt;

&lt;p&gt;Last month an assistant suggested this to clean up nested build output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"dist"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; +
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks fine. But run in my actual repo root, it also matched &lt;code&gt;packages/e2e/fixtures/dist&lt;/code&gt; — a checked-in fixture directory, not a build artifact. The sandbox harness flagged it immediately because my fixture copy included that directory and the diff showed deletions I didn't intend. The fix was adding &lt;code&gt;-not -path "*/fixtures/*"&lt;/code&gt;, which I would never have thought to check if I'd just pasted the command into my terminal.&lt;/p&gt;

&lt;p&gt;That's the pattern worth internalizing: &lt;strong&gt;the AI's command was correct for the repo it imagined, not the repo I have.&lt;/strong&gt; A sandbox diff forces the mismatch to the surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the free-tier tooling fits
&lt;/h2&gt;

&lt;p&gt;One practical note: this habit multiplies how often you iterate with the model. I rarely accept the first suggested command — I ask for a safer variant, a dry-run version, or an explanation of edge cases, and each of those is another round trip. Iterating like that on a paid meter adds friction, which is honestly why people skip it. I've been running this loop with MonkeyCode, which offers free model access plus a free server option, so the extra "give me the dry-run version first" prompts don't cost anything. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The harness above doesn't depend on any specific tool, though — it works the same whether the command came from an assistant, a teammate, or a Stack Overflow answer from 2014.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test plan you can steal
&lt;/h2&gt;

&lt;p&gt;If you want to adopt this, here's the minimal checklist I run for any AI-suggested command that deletes, moves, overwrites, or migrates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scope check:&lt;/strong&gt; Does the command reference absolute paths or &lt;code&gt;..&lt;/code&gt;? If yes, rewrite before anything else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixture replay:&lt;/strong&gt; Rebuild the target structure in &lt;code&gt;/tmp&lt;/code&gt; with sentinel files, including edge cases (fixtures, symlinks, dotfiles).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dry-run first:&lt;/strong&gt; Use &lt;code&gt;-n&lt;/code&gt;, &lt;code&gt;--dry-run&lt;/code&gt;, &lt;code&gt;git clean -nd&lt;/code&gt;, or &lt;code&gt;EXPLAIN&lt;/code&gt;/&lt;code&gt;BEGIN; ... ROLLBACK;&lt;/code&gt; equivalents. No dry-run mode exists? That's itself a red flag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diff review:&lt;/strong&gt; Compare before/after file lists. Any unexpected path in the diff = stop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reversibility question:&lt;/strong&gt; If the command is wrong on the real run, what's my recovery? No answer (no backup, no VCS) = don't run it yet.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;This harness is a &lt;em&gt;safety net, not a validator&lt;/em&gt;. It tells you what a command did to files; it can't tell you whether a migration produced semantically correct data.&lt;/li&gt;
&lt;li&gt;It doesn't help with commands whose damage is non-local: API calls, CI triggers, package publishes, anything touching shared state. Those need environment-level isolation (a staging project, a scoped token), not a directory sandbox.&lt;/li&gt;
&lt;li&gt;Path-based blocking is naive. A determinedly weird command can do damage without a suspicious-looking argument. Treat the guard as a tripwire, not a proof.&lt;/li&gt;
&lt;li&gt;It adds a minute or two per command. That's the point — but it means you'll be tempted to skip it "just this once" for commands that look simple. In my experience the simple-looking ones are exactly where the fixtures get deleted.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;If your AI assistant never generates shell/SQL/infra commands for you — say you only use it for in-editor completions — this harness is overhead. And if your team already has a proper ephemeral-environment setup (devcontainers per task, preview environments, disposable VMs), use that instead; it's strictly stronger than my little script.&lt;/p&gt;

&lt;p&gt;But if you're a solo dev or on a small team and you've been copy-pasting suggested commands straight into your terminal: build the fixture habit before the day an assistant confidently deletes something with no &lt;code&gt;git&lt;/code&gt; history behind it. If you're already iterating with a model daily, try routing that iteration through a free tier — MonkeyCode's free models and free server are one option — and spend the saved budget on being more paranoid, not less.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>productivity</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
