<?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: Jordan Huang</title>
    <description>The latest articles on DEV Community by Jordan Huang (@gitlab_3188).</description>
    <link>https://dev.to/gitlab_3188</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%2F4066558%2F3018daf5-9f41-49c5-89c9-a0dadd1551c2.png</url>
      <title>DEV Community: Jordan Huang</title>
      <link>https://dev.to/gitlab_3188</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gitlab_3188"/>
    <language>en</language>
    <item>
      <title>A Personal Scorecard for Evaluating New Coding Models (With the Scripts I Use)</title>
      <dc:creator>Jordan Huang</dc:creator>
      <pubDate>Mon, 10 Aug 2026 11:18:35 +0000</pubDate>
      <link>https://dev.to/gitlab_3188/a-personal-scorecard-for-evaluating-new-coding-models-with-the-scripts-i-use-3912</link>
      <guid>https://dev.to/gitlab_3188/a-personal-scorecard-for-evaluating-new-coding-models-with-the-scripts-i-use-3912</guid>
      <description>&lt;p&gt;Every model launch triggers the same ritual on my timeline: screenshots of impressive one-liners on one side, screenshots of embarrassing failures on the other, and a hundred hot takes in between. After my third cycle of switching daily-driver models based on screenshots, I admitted the uncomfortable part — I wasn't evaluating anything. I was adopting other people's anecdotes.&lt;/p&gt;

&lt;p&gt;So I built myself a scorecard: a small, frozen set of tasks, a clean room to run them in, and a written grading policy. New release lands, I spend a couple of hours running it through the scorecard, and I walk away with notes instead of feelings. Here's the full setup, the reasoning behind it, and the honest list of ways it can lie to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two ways casual testing fooled me
&lt;/h2&gt;

&lt;p&gt;Before the scorecard, my evaluation process was "open a chat, try a few prompts, form an opinion." That process has structural defects I couldn't prompt my way around.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You're sampling blind.&lt;/strong&gt; Three prompts is three draws from a distribution you can't see. Pick tasks the model has effectively memorized and it looks superhuman. Pick tasks outside its comfort zone and it looks useless. Both impressions are artifacts of your prompt choice, not properties of the model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your environment contaminates the result.&lt;/strong&gt; When I tested inside my working editor, the model silently benefited from my open files, my earlier corrections, and half-finished edits. I wasn't scoring the model — I was scoring the model wearing my project as a life-support system. Great for shipping, worthless for comparison.&lt;/p&gt;

&lt;p&gt;The fix isn't clever. It's the boring discipline of any experiment: same stimulus, isolated environment, more than one repetition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost and safety were the real blockers
&lt;/h2&gt;

&lt;p&gt;Two practical problems kept me from running proper evaluations for months.&lt;/p&gt;

&lt;p&gt;First, cost discipline fights measurement discipline. A serious run means repeating each task several times, and on a metered API every repetition is a small financial decision. I kept cutting trials to save money, which destroyed exactly the statistical confidence I was paying for.&lt;/p&gt;

&lt;p&gt;Second, I didn't want an agent executing generated commands on the machine that holds my SSH keys, cloud credentials, and browser sessions.&lt;/p&gt;

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

&lt;p&gt;What unblocked me was MonkeyCode, an open-source coding agent. Its free model access lets me point a fresh release at my scorecard without setting up billing, and its free server option means the agent loop runs in a throwaway remote environment instead of my laptop. Since the agent is open source, I can also confirm that trial runs don't share memory or leftovers — something I'd have to take on faith with a closed runner.&lt;/p&gt;

&lt;p&gt;None of that is load-bearing, though. Any agent harness you can inspect, plus any model endpoint you don't have to ration, works. The scorecard below doesn't care what executes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scorecard structure: eight tasks, repeated four times
&lt;/h2&gt;

&lt;p&gt;The scorecard has three pieces. Swap my placeholder tasks for sanitized fragments of your own work — that's the version that actually tells you something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;tasks.yml&lt;/code&gt;&lt;/strong&gt; — the frozen task list. Eight tasks split across three skill areas, each one sized to be small enough that a pass/fail verdict is unambiguous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fix-01&lt;/span&gt;
  &lt;span class="na"&gt;area&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bugfix&lt;/span&gt;
  &lt;span class="na"&gt;sandbox&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./sandboxes/order-pipeline&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;Orders placed between 23:59 and 00:01 are assigned to the wrong&lt;/span&gt;
    &lt;span class="s"&gt;fulfillment date. Find the defect, repair it, and add a regression&lt;/span&gt;
    &lt;span class="s"&gt;test that fails on the old code and passes on yours.&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test -- --grep boundary-date&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;feat-03&lt;/span&gt;
  &lt;span class="na"&gt;area&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;feature&lt;/span&gt;
  &lt;span class="na"&gt;sandbox&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./sandboxes/pastebin-lite&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;Add an expiry feature: pastes accept a TTL in minutes and return&lt;/span&gt;
    &lt;span class="s"&gt;HTTP 410 after expiry. Test the exact expiry boundary.&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo test expiry&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;explain-02&lt;/span&gt;
  &lt;span class="na"&gt;area&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;analysis&lt;/span&gt;
  &lt;span class="na"&gt;sandbox&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./sandboxes/worker-queue&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;Under burst load, queue latency spikes then never recovers.&lt;/span&gt;
    &lt;span class="s"&gt;Explain the mechanism in writing. Do not modify any file.&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;  &lt;span class="c1"&gt;# graded against rubric.md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;score.py&lt;/code&gt;&lt;/strong&gt; — the harness. Only two design decisions really matter: every repetition starts from a byte-identical copy of the sandbox, and the full conversation transcript gets saved so I can re-read failures months 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="kn"&gt;import&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;time&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;repetition&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;rep&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;workdir&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results/&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;id&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="s"&gt;/rep&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rep&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;workdir&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="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rmtree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workdir&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="nf"&gt;copytree&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;sandbox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;workdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;started&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="n"&gt;transcript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_agent&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;prompt&lt;/span&gt;&lt;span class="o"&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="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;workdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&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;started&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="k"&gt;if&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;verify&lt;/span&gt;&lt;span class="sh"&gt;"&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;manual&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;  &lt;span class="c1"&gt;# graded by hand against the rubric
&lt;/span&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&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="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;verify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;shell&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;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;workdir&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;outcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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="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;rep&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rep&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;outcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;elapsed_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;elapsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# 8 tasks x 4 reps = 32 runs per model. Not science. Enough for a decision.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;rubric.md&lt;/code&gt;&lt;/strong&gt; — grading rules for the analysis tasks, since they have no automated check. Each explanation gets 0–2 points on three dimensions: &lt;em&gt;identifies the true mechanism&lt;/em&gt;, &lt;em&gt;proposes a workable mitigation&lt;/em&gt;, and &lt;em&gt;invents nothing&lt;/em&gt;. Five of six points is a pass, and any fabricated log output or nonexistent config option zeroes that dimension instantly. A model that hallucinates evidence is more dangerous than one that admits confusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the failure pattern, not the percentage
&lt;/h2&gt;

&lt;p&gt;Thirty-two runs give you a grid of outcomes. The aggregate pass rate is the single least useful cell in that grid. What changes my behavior is the &lt;em&gt;geometry&lt;/em&gt; of the failures:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern in the grid&lt;/th&gt;
&lt;th&gt;Probable cause&lt;/th&gt;
&lt;th&gt;How I respond&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Strong on fix/feature, weak on analysis&lt;/td&gt;
&lt;td&gt;Retrieval strength, weak causal modeling&lt;/td&gt;
&lt;td&gt;Use for implementation, keep architecture decisions human&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rep 1 passes, reps 2–4 wobble&lt;/td&gt;
&lt;td&gt;Sampling instability at default settings&lt;/td&gt;
&lt;td&gt;Distrust any single demo of this model; add reps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passes my public sandboxes, fails my private ones&lt;/td&gt;
&lt;td&gt;Has seen the public code before&lt;/td&gt;
&lt;td&gt;Discount heavily for proprietary codebases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify step fails, transcript looks right&lt;/td&gt;
&lt;td&gt;My sandbox or check script is broken&lt;/td&gt;
&lt;td&gt;Fix the scorecard, not the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passes everything, takes forever&lt;/td&gt;
&lt;td&gt;Capability without latency&lt;/td&gt;
&lt;td&gt;Fine for overnight batch jobs, wrong for pairing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The fourth row is the one I re-learn constantly. "The model broke" and "my test harness broke" produce identical output until you open the transcript. Archive everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why reproducibility beats verdicts
&lt;/h2&gt;

&lt;p&gt;There's a reason I lean on open components end to end. Open weights can't be silently swapped between my repetitions. An open agent loop lets me prove exactly what context the model received. And an open scorecard means anyone who doubts my conclusion can rerun it instead of arguing with it. When the next open-weight model drops, the most valuable community contribution isn't another hot take — it's a task suite with transcripts attached.&lt;/p&gt;

&lt;p&gt;Opinions expire with the next release. A frozen task list doesn't, because the next model walks into the same room and faces the same eight tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the scorecard fails
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thirty-two runs is not a study.&lt;/strong&gt; It ranks models for my own workflow. Procurement or platform decisions need far more data plus human review of every failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small sandboxes generalize poorly.&lt;/strong&gt; A model that shines on a 1,500-line fixture may drown in a 500k-line monorepo. If that's your reality, build sandboxes from your actual code (scrubbed of secrets).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free tiers are borrowed, not owned.&lt;/strong&gt; Free model access and free server capacity can be throttled, re-priced, or withdrawn at any time. Use them for weekend evaluations, never wire them into CI, and read the current terms before assuming anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't bother with this at all&lt;/strong&gt; if stakeholders need an audit-grade benchmark, if your code legally cannot leave your network and you have no local harness, or if your real question is answerable by simply using the tool for a week. Daily lived experience is a legitimate instrument — it's just not a calibrated one.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Launch-week discourse is a machine for manufacturing confidence from other people's single prompts. A scorecard converts "who should I trust?" into "what did I measure?" — eight tasks, four repetitions, one written rubric. If the two blockers I described (metered trials, unsafe execution) are what's stopping you, MonkeyCode's free model access and free server option are one workable way to start this weekend. But the scorecard is the asset that outlives any vendor, and it plugs into whatever tooling you already have.&lt;/p&gt;

&lt;p&gt;If you maintain your own task list, I'd genuinely like to know what skill areas you test that mine misses — especially anything involving large multi-file refactors, which I still haven't found a good way to grade.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Giving an AI Coding Agent a Job Without Giving It Your Credentials</title>
      <dc:creator>Jordan Huang</dc:creator>
      <pubDate>Mon, 10 Aug 2026 08:56:46 +0000</pubDate>
      <link>https://dev.to/gitlab_3188/giving-an-ai-coding-agent-a-job-without-giving-it-your-credentials-10a4</link>
      <guid>https://dev.to/gitlab_3188/giving-an-ai-coding-agent-a-job-without-giving-it-your-credentials-10a4</guid>
      <description>&lt;p&gt;There's a conversation happening on DEV right now about what happens when AI agents get more tools and the boundaries around those tools fail. Most of the discussion is philosophical. I want to make it concrete: if you're going to let an AI coding agent run inside your CI pipeline — even on your own infrastructure — what does the actual sandbox look like, and how do you &lt;em&gt;prove&lt;/em&gt; it holds?&lt;/p&gt;

&lt;p&gt;This article walks through a repeatable harness: a decision table for what the agent is allowed to touch, a runnable sandbox script, and a canary test that fails loudly the moment a boundary leaks. Everything here runs on a plain Linux box.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem in one sentence
&lt;/h2&gt;

&lt;p&gt;An agent that can read your repo and execute shell commands is, from a security standpoint, an unprivileged remote user who happens to be very fast — so treat its environment like you'd treat an untrusted contributor's laptop.&lt;/p&gt;

&lt;p&gt;Concretely, the three failure modes I care about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Credential exfiltration&lt;/strong&gt; — the agent (or a prompt injected via a file/issue it reads) prints an env var into a place that gets committed or POSTed somewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network egress&lt;/strong&gt; — the agent downloads or uploads something you never approved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope creep in the repo itself&lt;/strong&gt; — the agent edits files outside the task you gave it, quietly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Decision table: what goes where
&lt;/h2&gt;

&lt;p&gt;Before any code, decide which capabilities the agent actually needs. This is the table I use as a starting point — adjust for your own tasks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Code-fix task&lt;/th&gt;
&lt;th&gt;Doc-generation task&lt;/th&gt;
&lt;th&gt;Dependency-upgrade task&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read repo files&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write repo files&lt;/td&gt;
&lt;td&gt;✅ (scoped paths)&lt;/td&gt;
&lt;td&gt;✅ (docs/ only)&lt;/td&gt;
&lt;td&gt;✅ (lockfiles, manifests)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execute tests/build&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network egress&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ (package registry only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets in env&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ (use a short-lived token if truly needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git push&lt;/td&gt;
&lt;td&gt;❌ (open MR instead)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern: &lt;strong&gt;network and secrets default to denied&lt;/strong&gt;, and writing is always path-scoped. The agent proposes, CI disposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the agent actually runs
&lt;/h2&gt;

&lt;p&gt;You need a machine to host the agent loop and a model endpoint. For experimentation, I used MonkeyCode here — it offers free access to coding models and a free server option, which made it cheap to iterate on the harness without burning a budget on my own mistakes. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Check the current product documentation for exactly which models and server limits apply, since availability details change; the sandboxing below is provider-agnostic anyway.&lt;/p&gt;

&lt;p&gt;The important part isn't where the model lives — it's that the &lt;em&gt;execution&lt;/em&gt; environment is locked down regardless. A generous free tier doesn't change the threat model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sandbox script
&lt;/h2&gt;

&lt;p&gt;Below is a minimal, reproducible wrapper using only standard tooling. It runs the agent's working directory read-only-except-scratch, strips the environment, and blocks network with &lt;code&gt;unshare&lt;/code&gt; (Linux namespaces — no Docker required for the demo, though Docker works too):&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;# agent-sandbox.sh — run a command against a repo with minimal privileges.&lt;/span&gt;
&lt;span class="c"&gt;# Usage: ./agent-sandbox.sh /path/to/repo "your-agent-command --flag"&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;REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;realpath&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="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;SCRATCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s1"&gt;'rm -rf "$SCRATCH"'&lt;/span&gt; EXIT

&lt;span class="c"&gt;# 1. Strip environment: no inherited secrets, no CI tokens.&lt;/span&gt;
&lt;span class="c"&gt;# 2. Drop network entirely with a private net namespace.&lt;/span&gt;
&lt;span class="c"&gt;# 3. Bind-mount the repo read-only; only $SCRATCH is writable.&lt;/span&gt;
&lt;span class="nb"&gt;env&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin:/bin &lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SCRATCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  unshare &lt;span class="nt"&gt;--net&lt;/span&gt; &lt;span class="nt"&gt;--mount&lt;/span&gt; &lt;span class="nt"&gt;--map-root-user&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"
    mount --bind '&lt;/span&gt;&lt;span class="nv"&gt;$SCRATCH&lt;/span&gt;&lt;span class="s2"&gt;' /tmp 2&amp;gt;/dev/null || true
    cd '&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;'
    &lt;/span&gt;&lt;span class="nv"&gt;$CMD&lt;/span&gt;&lt;span class="s2"&gt;
  "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;env -i&lt;/code&gt; is the single highest-value line. Most leaks I've seen discussed are just inherited environment variables.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unshare --net&lt;/code&gt; removes networking for the whole process tree. If your task legitimately needs a registry (the dependency-upgrade row above), replace this with an egress proxy allowlist, not open internet.&lt;/li&gt;
&lt;li&gt;For real CI, run this inside an ephemeral job container/VM as well — defense in depth. The script is a second wall, not the only wall.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prove it: the canary test
&lt;/h2&gt;

&lt;p&gt;A sandbox you haven't attacked is a rumor. Plant canaries and assert they never escape:&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;# canary-test.sh — boundary checks that must all pass before trusting the harness.&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;REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'console.log("hello")'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;/app.js"&lt;/span&gt;

&lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="c"&gt;# Test 1: a fake secret in the environment must not be readable.&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"CANARY-7f3d-not-a-real-key"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; ./agent-sandbox.sh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'env'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"CANARY-7f3d"&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;"FAIL: secret leaked into sandbox environment"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PASS: environment stripped"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Test 2: network must be unreachable.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; ./agent-sandbox.sh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'curl -sS --max-time 3 https://example.com'&lt;/span&gt; 2&amp;gt;/dev/null&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;"FAIL: network egress succeeded"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PASS: network blocked"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Test 3: repo must be unchanged after a hostile command.&lt;/span&gt;
&lt;span class="nv"&gt;BEFORE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;/app.js"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
./agent-sandbox.sh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'echo pwned &amp;gt;&amp;gt; app.js; git init -q . 2&amp;gt;/dev/null || true'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="nv"&gt;AFTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;/app.js"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BEFORE&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="nv"&gt;$AFTER&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;"FAIL: repo was modified"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PASS: repo intact (modifications confined to scratch)"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$fail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this in CI &lt;em&gt;before&lt;/em&gt; any agent job. If any check fails, the agent doesn't run. That ordering matters — most setups test the agent's output but never test the cage.&lt;/p&gt;

&lt;p&gt;One more canary worth adding once you allow limited egress for package installs: embed a unique fake token in a file the agent reads, then alert if that string ever appears in outbound requests or in the diff the agent produces. Cheap to build, catches both naive leaks and injection-driven ones.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Namespace-based sandboxing is not a hard security boundary against a determined adversary with a kernel exploit.&lt;/strong&gt; For genuinely hostile input, use a separate VM per job (most CI platforms already give you this if you don't cache runners).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt injection is not solved by sandboxing.&lt;/strong&gt; Sandbox limits &lt;em&gt;blast radius&lt;/em&gt;; it doesn't stop the agent from being manipulated into writing bad code within its allowed scope. Human review of the diff is still mandatory — the table above says "open MR instead of push" for exactly this reason.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't use this pattern at all&lt;/strong&gt; if your task requires the agent to touch production secrets, customer data, or signed release artifacts. Get a scoped, short-lived credential from your secrets manager and audit it, or keep that step manual.&lt;/li&gt;
&lt;li&gt;The free-tier setup I mentioned is fine for prototyping the harness; I haven't load-tested it against a large monorepo pipeline, and quota/availability details are documented by the provider, not guaranteed by this article.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The current debate about agent tool boundaries gets a lot more tractable once you write the boundaries down as a table, enforce them with a hundred lines of shell, and attack your own enforcement with canaries before trusting it. The agent platform matters less than the cage. If you want a zero-cost sandbox to try this harness yourself, MonkeyCode's free models and server are one way to get an agent loop running — then point the canary tests at it and see what holds.&lt;/p&gt;

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