Which AI Coding Agent Works Best with a Local LLM? Four Tools Tested on a DGX Spark
This blog post is an informal comparison of four AI coding agents running against a locally hosted LLM. If you followed my earlier posts on running a local model on a DGX Spark (here and here), the next question is the one my customers ask: which coding agent should I point at it? So on September 9, 2026 I ran the same task through all four and scored the output with an automated test.
TL;DR, OpenCode won. qwen-code tied it on quality but took longer. Claude Code got 11 of 12 checks but ran for over an hour. Codex produced nothing on the first run and a broken page on the second. Details and the config gotchas below.
What I tested
The model was Qwen3.8-Flash-Next (NVFP4) served by vLLM on a single DGX Spark, the same setup from my last post. The four agents:
| Agent | Version | Made by |
|---|---|---|
| OpenCode | 1.18.30 | open source |
| qwen-code | 0.23.2 | Alibaba (open source) |
| Claude Code | 2.1.267 | Anthropic |
| Codex CLI | 0.147.0 | OpenAI |
All four support pointing at an OpenAI-compatible endpoint, so they all talked to the same server at http://127.0.0.1:8888/v1 and the same model id, qwen3.8-flash-next. Nothing left the box.
The task was deliberately small: write a single-file stopwatch web page (index.html) with start, stop, reset, and lap buttons, a mm:ss.cc display, Space to toggle, laps saved to localStorage, no external resources. The prompt listed the exact element ids and ended with "Do not ask questions; make reasonable decisions and proceed." Each agent got 20 minutes, unattended, with approvals disabled.
I scored the result with a Playwright script that loads the page in a headless browser and runs 12 checks: the file exists, no external resources, all ids present, starts at 00:00.00, runs, stops, resumes, lap adds an <li>, laps survive a reload, reset clears everything, Space toggles, and nothing throws in the console. Pass or fail, no partial credit, no opinions from me.
The Numbers
| Agent | Score | Wall time | Requests to vLLM | Prompt tokens sent |
|---|---|---|---|---|
| OpenCode | 12/12 | 11.7 min | 34 | 1.9M |
| qwen-code | 12/12 | 16.4 min | 59 | 2.9M |
| Claude Code | 11/12 | 60+ min (I killed it) | n/a | n/a |
| Codex, run 1 | 0/12 | 9.7 min | 17 | 0.8M |
| Codex, run 2 | 6/12 | 20 min (hit the cap) | 47 | 3.3M |
The "prompt tokens" column is from vLLM's own counters, not the agent's estimate. It is the total the agent sent to the model over the whole run, and it is the number that matters on a local box because it is where your wall time goes. Codex sent 3.3 million tokens to produce a broken page. OpenCode sent 1.9 million to produce a working one.
One caveat on wall time: during the first three runs the server was also serving three of my Hermes agents, so everybody's clock was inflated. The Codex rerun had the server mostly to itself.
What each one did
OpenCode wrote the file, ran a quick check, and stopped. 34 requests. No drama. It also has the best config story: one JSON file at ~/.config/opencode/opencode.json defines the provider and model, and opencode run -m vllm/qwen3.8-flash-next "..." uses it.
qwen-code got the same 12/12 but took 59 requests to do it, because it kept reading the file back and checking its own work. That turned out to be a feature: the model garbled a variable name mid-file, and qwen-code caught it and fixed it. More on that below.
Claude Code produced a nearly correct page but then looped on verification for an hour. The one failing check was localStorage persistence, and the cause was a typo the model wrote: stORAGE_KEY instead of STORAGE_KEY. It never found it. I killed the run at 60 minutes. To be fair, on a bigger real-world task the week before (a GitHub issue in our AIShield repo) Claude Code did finish, in 29 minutes and 81 requests, and opened a usable draft PR.
Codex, run 1 was the strange one. The model wrote "I'll create index.html with all CSS and JavaScript inline" and then ended its turn. No tool call, no file. 17 requests of that. I logged it as 0/12 and moved on.
Codex, run 2 was after I fixed its config (see below) and reran the identical test. This time it behaved like an agent: 47 requests, a real bash command that wrote an 8,315 byte index.html, a node syntax check, some sed fixes, another check. Then it hit the 20 minute cap mid-loop. The page passed every static check and failed every behavioral one, because line 323 of the JavaScript reads:
element.addEventList...;
That is not a typo, it is the model giving up halfway through addEventListener and typing three dots. The browser sees Unexpected token '...' and the script never runs. Codex's repair attempts made it worse: it "fixed" DOM calls into createLIElement and querySelectorALL, and called fs.readfiletostring, none of which exist.
The identifier problem
This is the thing to know if you run Flash-Next (or in my opinion any of the current local models) behind a coding agent: it mangles identifiers. camelCase DOM APIs come out with the wrong letters capitalized, constants get a lowercase run in the middle, and occasionally the model just stops typing a name. Three of the four agents hit it:
- Claude Code:
stORAGE_KEY - Codex:
addEventList...,createLIElement,querySelectorALL - qwen-code: also mangled one, but read the file back, noticed, and fixed it
The agents that finish are the ones that verify their own output by actually running it, not the ones with the most polished prompts. qwen-code's habit of re-reading files looked wasteful in the request count and turned out to be exactly what the model needed.
Three config gotchas
- Codex and qwen-code did not default to the local model. Both were installed and on my PATH, but a bare
codexwent to OpenAI's cloud and a bareqwenhad no config at all. The earlier runs only worked because a wrapper script passed the endpoint every time. I fixed both: qwen-code reads~/.qwen/.env(OPENAI_BASE_URL,OPENAI_MODEL,OPENAI_API_KEY), and Codex reads~/.codex/config.tomlwithmodel,model_provider, and a[model_providers.<name>]block. One thing that cost me a retest: in the Codex file those two top-level keys have to sit ABOVE the first[section]header, or TOML quietly files them under that section and nothing changes. codex execandopencode runhang forever if stdin is open. If you launch them from a script or a scheduled task, add< /dev/null. I lost a 4 minute timeout to this before I figured it out.- Reasoning effort. Flash-Next's chat template only accepts
xhigh,medium, andlow. Claude Code sendshighby default and the server rejects it, so you have to pin effort tomediumin its config.
Should you use these with a local model?
Yes, with the right one. Here is what I recommend as of today:
- OpenCode for unattended and scripted work against a local model. Fastest, cheapest in tokens, one config file.
- qwen-code if you want a second opinion. Same score, slower, and its self-checking is worth the extra requests on a model that mangles names.
- Claude Code for bigger tasks where you can watch it. It did finish the real repo task. Do not leave it unattended on a small task with a verification loop.
- Codex I cannot recommend against a local model at this time. Two runs, zero working pages, and by far the most tokens sent.
Two runs each is not a large sample, and the models leapfrog each other monthly, so treat this as a snapshot from September 2026. The test harness is simple enough that you can rerun it against whatever you are using: one prompt, one Playwright script, count the tokens on the server side.
Disclaimer: this is what happened on one box with one model. Test in your own environment before you bet a project on it.
Need help building or securing a local AI capability? Email us at Hello At PatriotConsultingTech.com
Sources and references:
- Qwen3.8-Flash-Next on a single DGX Spark (the server recipe): https://github.com/MiaAI-Lab/Qwen3.8-Flash-Next-Single-DGX-Spark
- OpenCode: https://opencode.ai | qwen-code: https://github.com/QwenLM/qwen-code | Claude Code: https://claude.com/claude-code | Codex CLI: https://github.com/openai/codex
- All runs on one DGX Spark (GB10, 119.7 GB usable unified memory), vLLM 0.1.dev20073 with FlashInfer 0.6.17, September 9, 2026. Token counts from vLLM's
/metricsendpoint before and after each run.
About the author. Joe Stocker is the Founder and Chief Technical Officer of Patriot Consulting, a former Microsoft Security MVP (2020-2026), and author of the book "Securing Microsoft 365." In his spare time Joe volunteers with several Microsoft programs including Microsoft's Defending Democracy (AccountGuard) program, Microsoft Tech for Social Impact, and the Microsoft Software and Systems Academy (MSSA), which serves military service members desiring to transition into the civilian workspace.