Benchmarking local coding agents

I run local models to do real work, so I care about completed, verifiable artifacts. The model matters. So do the harness, its configuration, and the way the result gets graded.

Evidence
August 2026 local evaluations
Tasks
Coding & tool-using agents
Priority
Reliable completed work

What I found

  1. An extractor bug executed an unfinished draft from the reasoning trace: the recorded score was 17/100; re-scoring the identical final-answer bytes produced 97/100.

  2. Three runs of one Qwen configuration on four hard tasks scored 392/400, 359/400 and 389/400, a mean of 380/400, with two runaway fuzz subprocesses interrupted.

  3. Without a thinking-budget proxy, GLM-5.3-Flash reasoned for 65,536 tokens and scored 4/100; with an 8K thinking budget, its three runs averaged 372 of 400.

  4. On Ornith-1.5-35B-A3B, refusal ablation that left the token embedding alone kept the coding suite at 489/500; adding the embedding edit dropped it to 400/500.

The central idea

Before interpreting a low score as a model failure, check what was actually executed. Before choosing a model from a high score, repeat the task and record how much help it needed.

  1. 01Fix the task
  2. 02Record the config
  3. 03Inspect the artifact
  4. 04Repeat the run
  5. 05Explain the limits
Evaluation discipline distilled from my local tests
Contents
  1. What I found
  2. The same answer went from 17 to 97
  3. A good run is not a reliability estimate
  4. The suite, the runners and the numbers are public
  5. Do not let a harness limit become a model verdict
  6. The serving setup is part of the experiment
  7. Abliteration and fine-tuning need separate tests
  8. What belongs beside every result
  9. Sources & scope

The same answer went from 17 to 97

In an August 26 coding evaluation, a model returned unfenced Python after being told to output only code. The extractor expected a Markdown code fence. When it found none, it searched the reasoning trace instead and executed an unfinished draft.

The recorded score was 17/100. Re-scoring the identical final-answer bytes through the corrected extractor produced 97/100. The model had not improved; the evaluation had finally executed the intended answer.

The clue was a mismatch: every functional criterion was zero while the text-based code-quality criterion still earned partial credit. I now treat that pattern as a reason to inspect the extracted artifact before making a claim about capability.

A good run is not a reliability estimate

An August 27 comparison used the same Prime agent harness and four hard tasks: a POSIX regex engine, replicated text, an asynchronous DAG orchestrator, and a streaming JSON parser. Three runs of one Qwen configuration produced the scores below.

Even this small table is more useful than displaying only the best result. It also needs its intervention record: two runaway fuzz subprocesses were interrupted across these runs; the agent adapted and completed those tasks. “No derailments” would not mean “no human assistance.”

Historical local run · Qwen3.8-Flash-Next-Uncensored FP8 + MTP4 · August 27, 2026
RunScore across four tasksInterpretation
1392/400Observed result
2359/400Observed result
3389/400Observed result
Mean380/400Three runs, not a general capability rating

The suite, the runners and the numbers are public

The task set, the direct-API and harness-assisted runners, and 82 result records are on GitHub as coding-agent-bench, together with the four harness failures described on this page and how the scoring was fixed. The table below is the same four-task, three-run protocol applied to the other local configurations I ran on the two-GPU workstation between August and September 2026. Each row is three complete runs; the interpretation column carries what the score alone would hide.

The five-task direct-API suite in the same repository is a different measurement and its scores are out of 500: Ornith-1.5-35B in bf16 scored 489, a Qwen3.8-27B MTPLX build 483, Claude Opus 4.6 483, and DeepSeek V4-Flash 459 to 481 depending on the serving stack. Those numbers should not be placed in the table below.

Four hard tasks, same agent harness, three runs each · two RTX PRO 6000 · August–September 2026
Model and serving pathRuns (/400)MeanWhat the mean hides
Qwen3.8-Flash-Next, FP8, TP2, MTP depth 4392 / 359 / 389380Zero degenerate generations; two runaway test subprocesses were interrupted and the agent adapted
GLM-5.3-Flash TR3-4bpw, 8K thinking budget389 / 359 / 369372Needed a thinking-budget proxy; without one it reasoned for 65,536 tokens and scored 4/100
DeepSeek V4-Flash (abliterated), DSpark drafts287 / 197 / 382289Three degenerate generations in twelve tasks; spec decoding and the ablation were not isolated
Qwen3.8-Flash-Next, NVFP4, one GPU274 / 359 / 268300Parity on two tasks, a consistent partial on one, a collapse on the JSON parser in two runs

Do not let a harness limit become a model verdict

A timeout, output-length limit, malformed tool exchange, and incorrect implementation are different events. I keep inconclusive runs visible and separate from completed-task scores. They still matter operationally—someone waiting for an answer experienced an unfinished task—but they are not interchangeable evidence of reasoning failure.

Some older comparison tables assigned a low floor to interrupted or missing-artifact runs. I would not reuse those totals as a clean model ranking. The statuses, final files, and intervention notes need to travel with the score.

The serving setup is part of the experiment

I record precision or quantization, the serving engine, sampling settings, context and thinking budgets, tool parser, and whether speculative decoding is enabled. Changing any of these can change the experiment. A speed comparison also needs the same workload and hardware constraints.

For my own work, the best setup can depend on what else is running. A configuration that leaves room for rendering may be more useful that evening than the one with the best isolated coding result. Completed work and resource coexistence are product criteria, not just infrastructure details.

Abliteration and fine-tuning need separate tests

I work with fine-tuning, LoRAs, and abliteration as part of model adaptation. Changing refusal behavior is not the same as improving reasoning, tool use, or instruction following. A model that responds more often can still produce worse answers.

I therefore treat behavior and task performance as separate evaluation axes and compare adaptations with their base model under matched conditions. A label on a model upload is not evidence that an adaptation worked. Neither is a single successful demonstration.

This is also why I value open-weight models and inspectable tools: they let me investigate the cause of a change instead of treating every result as an opaque property of a product name.

Measured on Ornith-1.5-35B-A3B, a 35B mixture-of-experts model with 3B active parameters: per-layer refusal directions on all forty layers, with the token embedding left alone, took refusals from ten or eleven of twelve prompts to zero with no false refusals on the matched benign set, and the five-task coding suite stayed at 489/500, identical task for task. The same directions applied with the token-embedding edit from the original recipe also removed the refusals but dropped the suite to 400/500, with the recursive-descent parser collapsing from 98 to 13; reducing the scale did not rescue it. The only community “abliterated” upload of that model at the time turned out to be a no-op.

What belongs beside every result

My minimum useful evaluation record includes:

  • The task, input set, final artifact, and exact grading procedure.
  • The model and serving configuration, with the date of the run.
  • Repeated results and completion statuses—not just the best score.
  • Human interventions, skipped checks, timeouts, and resource constraints.
  • The decision the evidence supports, and the claims it cannot support.

Questions about this note? Get in touch.

sipratt@gmail.com