<?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: Giuseppe Sirigu</title>
    <description>The latest articles on DEV Community by Giuseppe Sirigu (@gsirigu).</description>
    <link>https://dev.to/gsirigu</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%2F4147401%2Fda4ea757-adf0-412c-b025-87f215fdbd4b.jpg</url>
      <title>DEV Community: Giuseppe Sirigu</title>
      <link>https://dev.to/gsirigu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gsirigu"/>
    <language>en</language>
    <item>
      <title>I ran six coding agents on seven local models, 30 times each</title>
      <dc:creator>Giuseppe Sirigu</dc:creator>
      <pubDate>Thu, 01 Oct 2026 16:00:55 +0000</pubDate>
      <link>https://dev.to/gsirigu/i-ran-six-coding-agents-on-seven-local-models-30-times-each-2m82</link>
      <guid>https://dev.to/gsirigu/i-ran-six-coding-agents-on-seven-local-models-30-times-each-2m82</guid>
      <description>&lt;p&gt;Last week I posted a small benchmark on whether coding agents still work when the model you run yourself is shaky at tool calls. It used three runs per task, a handful of models, and a harness I kept private. Fair criticism followed, so here's the bigger, stricter version.&lt;/p&gt;

&lt;p&gt;Seven models running locally, including the current ones people actually pick today. Six agents. Thirty runs per agent per model. Tiers decided before the first run. And the whole thing - harness, raw results, failed-run transcripts - is &lt;a href="https://github.com/giuseppe-sirigu/polyglot-benchmarks" rel="noopener noreferrer"&gt;public on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Disclosure up front: I build &lt;a href="https://www.usepolyglot.dev" rel="noopener noreferrer"&gt;Polyglot&lt;/a&gt;, one of the six agents. That's exactly why everything is public.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;Each cell is how many of 30 runs completed the task, checked automatically against the files the agent left behind.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Polyglot&lt;/th&gt;
&lt;th&gt;pi&lt;/th&gt;
&lt;th&gt;goose&lt;/th&gt;
&lt;th&gt;goose + toolshim&lt;/th&gt;
&lt;th&gt;Hermes&lt;/th&gt;
&lt;th&gt;opencode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.8-27B&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss 20B&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Devstral Small 2 24B&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen3-coder 30B&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen2.5-coder 32B&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen2.5-coder 14B&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen2.5-coder 7B&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I set three tiers before running anything: &lt;strong&gt;works reliably&lt;/strong&gt; is 26 or more out of 30, &lt;strong&gt;works sometimes&lt;/strong&gt; is 12 to 25, and &lt;strong&gt;fails&lt;/strong&gt; is under 12. Thirty runs is enough to tell those apart, but not to rank agents inside a tier - 28 out of 30 is consistent with anything from 79% to 98%. So a 30 next to a 28 is a tie, not a win.&lt;/p&gt;

&lt;p&gt;Read that way, Polyglot is the only agent that doesn't fail on any of the seven models. Its weakest cells are qwen2.5-coder 32B and 7B, both "works sometimes" - and the 7B sits right on the line at 12.&lt;/p&gt;

&lt;h2&gt;
  
  
  The newest models don't separate the agents
&lt;/h2&gt;

&lt;p&gt;On Qwen3.8-27B every agent works reliably. On qwen3-coder four of the six do, on Devstral three, and the rest still work sometimes. These models are good at emitting tool calls through the native channel most agents listen on, so the agents mostly differ in how they plan and edit, not in whether they work at all.&lt;/p&gt;

&lt;p&gt;If you run one of these models, pick your agent on other grounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it breaks
&lt;/h2&gt;

&lt;p&gt;It breaks on models that write their tool calls as plain text instead of through the native channel. All three qwen2.5-coder sizes do this through Ollama. On those, pi, Hermes and opencode made no tool call in any of the 30 runs: the model writes a perfectly reasonable &lt;code&gt;{"name": "edit_file", ...}&lt;/code&gt; into its reply, the agent treats the whole reply as a final answer, and the task ends with nothing done. goose makes some calls but completes no task.&lt;/p&gt;

&lt;p&gt;goose's toolshim is the honest exception. It routes the model's text through a second, small model whose job is to turn it into a proper tool call, and it works: on qwen2.5-coder 32B it scored 28, ahead of Polyglot's 24. The same second model hurts on gpt-oss, where it dropped goose from 18 to 5. Polyglot does the same job with a parser instead of a second model, which is why it holds up on both.&lt;/p&gt;

&lt;p&gt;gpt-oss is the other model that separates the field. It's strong, but it emits tool calls in its own trained format, and goose, Hermes and opencode land in "works sometimes" on it while Polyglot and pi stay reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smaller prompts, too
&lt;/h2&gt;

&lt;p&gt;I also measured what each agent sends to the model, from Ollama's own request log so every agent is counted the same way. Polyglot opens each task with about 1.2k tokens of fixed prompt and pi with 1.2-1.6k. Hermes starts at 3.9-4.7k, and goose and opencode at 5.5-7.6k. Across a whole task, Polyglot used several times fewer prompt tokens per completed task than goose, Hermes and opencode. pi reuses Ollama's prompt cache better than Polyglot does - something for me to fix, not to advertise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong the first time
&lt;/h2&gt;

&lt;p&gt;My earlier numbers for goose, Hermes and opencode were wrong, and not in their favour. Ollama defaults to a 4,096-token context and silently cuts anything longer. Those three agents send several thousand tokens of instructions, so on my first runs they were working from a prompt with most of their instructions missing.&lt;/p&gt;

&lt;p&gt;Every model in this grid now runs with a 32k context, and the harness refuses to start below 16k. After each agent's runs, it scans Ollama's log for truncated prompts and marks the results invalid if it finds any. If you benchmark agents on Ollama yourself, check this first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Polyglot lost runs
&lt;/h2&gt;

&lt;p&gt;I read every one of Polyglot's failed transcripts. Outside the 7B, it missed 13 of 150 runs. In up to 5 of those, my parser was at fault: a model stuttering an empty tag before the real one, or running past a broken closing tag into an invented next turn. Those are fixed in Polyglot 0.13.2, along with every other format I found in the reruns. The rest were the model's own mistakes - a wrong edit, a misread file, an answer it made up.&lt;/p&gt;

&lt;p&gt;The Polyglot column above is a pre-release build of 0.13.2, the first of three I ran. The two later builds scored 173 and 172 out of 210 against this one's 179 - the same tiers, with the spread coming from the models, not the code. gpt-oss scored 30, 27 and 25 across the three builds without a single parsing error among its misses. That's what run-to-run noise looks like at 30 runs, and it's why I report tiers.&lt;/p&gt;

&lt;p&gt;From here on, Polyglot's column comes from the current npm release, run once, whatever it scores. No rerunning a build to replace a number I don't like, and every run stays in the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Methodology
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tasks.&lt;/strong&gt; Six small coding jobs: add a CLI subcommand, fix an off-by-one, answer a question from a file without editing it, remove dead code, rename a function across two files, and trace a runtime error to its cause. Each runs in a fresh directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Models.&lt;/strong&gt; All local, through Ollama, on one RTX 5080 16GB, each with a 32k context: Qwen3.8-27B, gpt-oss 20B, Devstral Small 2 24B, qwen3-coder 30B, and qwen2.5-coder 7B, 14B and 32B.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents.&lt;/strong&gt; Polyglot, pi 0.85.1, goose 1.52.0 (with and without its toolshim, using llama3.2 3B as the interpreter), Hermes Agent 0.19.0 and opencode 1.18.32, each run headless with tools auto-approved and an isolated config.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoring.&lt;/strong&gt; The same automated check for every agent: the files must end up right and a verify command must pass. Five trials of each task, so 30 runs per cell, 600 seconds per run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://github.com/giuseppe-sirigu/polyglot-benchmarks" rel="noopener noreferrer"&gt;README&lt;/a&gt; has the commands to reproduce it, and &lt;a href="https://github.com/giuseppe-sirigu/polyglot-benchmarks/blob/main/results/GRID.md" rel="noopener noreferrer"&gt;&lt;code&gt;results/GRID.md&lt;/code&gt;&lt;/a&gt; links every cell to its raw file. If you think I got something wrong, open an issue on the run in question - I'd rather fix the benchmark than defend it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Polyglot is free and open source: &lt;code&gt;npm install -g @usepolyglot/cli&lt;/code&gt;, point it at whatever's already running on your GPU, and see whether your agent is doing the work or just describing it. Repo: &lt;a href="https://github.com/giuseppe-sirigu/polyglot" rel="noopener noreferrer"&gt;https://github.com/giuseppe-sirigu/polyglot&lt;/a&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>opensource</category>
      <category>selfhosted</category>
    </item>
  </channel>
</rss>
