I pointed three coding CLIs at the same local model and ran twelve tasks through each one. The model was Qwen 35B, hosted on an RTX 4070 12GB via llama-server with --cpu-moe. The tasks were mundane: build a hello.py, add a CLI flag to an existing script, write a failing test then fix it, refactor a Python file to split a class into two. Nothing you would not do on a Tuesday.
The results were not what I expected from reading each tool's README.
The three tools, in one line each
- Aider: git-native pair-programming CLI (45k stars, Apache-2.0), most-used terminal option, mature and well-documented, handles repo-wide context through a repo map.
- Qwen Code CLI: QwenLM's official fork of Gemini CLI (Apache-2.0), positioned as the "native" agent for Qwen models. Tested v0.18.1.
- OpenCode: MIT, provider-agnostic, 170k+ stars in 2026, not owned by any of the companies buying up the rest of this list.
All three claim to work with local models via Ollama, LM Studio, or an OpenAI-compatible endpoint. Two of them do. The third has a specific requirement nobody documented up front.
The one non-obvious requirement: Qwen Code needs --jinja and 32k context
I tried Qwen Code with Ollama first. This is the shape the tool's own docs suggest. Here is what happened across five configurations of the same task ("create hello.py"):
| Try | Backend | Context | Result |
|---|---|---|---|
| 1 | Ollama 9b (ping only) | - | OK — text response |
| 2 | Ollama 9b (agent mode) | default | Fail — tool did not fire, model returned code as prose |
| 3 | Ollama 35B (agent mode) | default |
Fail — model emitted raw <tools> text, no file written |
| 4 | llama-server --jinja | 8192 | Fail — context overflow (19,374 > 8192) |
| 5 | llama-server --jinja | 32768 | OK — file created, task completed |
Only the last combination worked. Ollama's default template does not agree with what Qwen Code sends. The model spits raw <tools> markers as text instead of emitting a tool call. Switching to llama-server --jinja uses the model's own chat template and the tool call round-trips correctly.
The 8k-to-32k jump is the second surprise. The error was:
400: request (19374 tokens) exceeds the available context size (8192 tokens)
Nineteen thousand tokens. Before I typed a single character. That is the size of Qwen Code's system prompt plus tool definitions.
Aider's equivalent first prompt was about 1,400 tokens. Roughly a 13× difference. Qwen Code carries a lot more agent scaffolding by default. SubAgents, four approval modes (Plan / Default / Auto-Edit / YOLO), headless mode, background agent forks. Each of these needs to be described in the system prompt. It adds up.
Here is the launch command that actually works:
llama-server -m qwen35.gguf -ngl 99 --cpu-moe -c 32768 \
--jinja --alias qwen35 --host 0.0.0.0 --port 18080
--jinja is the load-bearing flag. Without it the tool loop breaks. -c 32768 is the second one. --cpu-moe is how a 35B model fits on 12GB VRAM. The MoE experts get offloaded to CPU RAM.
Aider and OpenCode both worked with Ollama out of the box. No template flags, no context size gymnastics. Aider used aider --model ollama/qwen3-coder. OpenCode used its models.dev config with a local endpoint.
The 12-task grid
I ran each tool through the same twelve tasks. I did not tune prompts per tool. Same wording, same fresh working directory, same model. Here is the shape of what happened:
| Task | Aider | Qwen Code | OpenCode |
|---|---|---|---|
| 1. hello.py from scratch | OK | OK | OK |
2. Add --verbose flag to existing script |
OK | OK | OK |
| 3. Write failing pytest for a stub function | OK | OK | OK |
| 4. Make the failing test pass | OK | OK | OK |
| 5. Split a 200-line class into two files | OK | OK | Partial* |
| 6. Rename a symbol across 4 files | OK | OK | OK |
| 7. Add type hints to an untyped function | OK | OK | OK |
8. Migrate a requests call to httpx
|
OK | Partial† | OK |
| 9. Write a Dockerfile for a Flask app | OK | OK | OK |
| 10. Debug an off-by-one in a for-loop | OK | Fail‡ | OK |
| 11. Add a Makefile target | OK | OK | OK |
| 12. Extract a magic number into a constant | OK | OK | OK |
*OpenCode split the class but left one method import unresolved. I fixed it in about 30 seconds.
†Qwen Code migrated the call but did not update the exception handler.
‡Qwen Code proposed the fix in prose but did not apply it. This happened when I was in Plan mode by accident.
Success rates: Aider 12/12, OpenCode 11/12 (1 partial), Qwen Code 10/12 (1 partial, 1 failed).
That is not a real benchmark. It is one afternoon on one machine with one model. But the failures were not random. Qwen Code's partial and fail both came from cases where the model needed to reason about existing code across multiple edits. Aider's repo map earns its keep here. It gives the model a much better mental picture of the codebase before the edit.
Time and token cost
The real cost story is less about success rate and more about how each tool spends the context window you gave it.
| Metric | Aider | Qwen Code | OpenCode |
|---|---|---|---|
| Avg tokens per task (system + first turn) | ~1,400 | ~19,400 | ~4,800 |
| Avg wall time per task | 44s | 71s | 52s |
| Config effort to first success | 5 min | 45 min | 10 min |
| Notable strengths | Repo map, git integration | Approval modes, SubAgents, headless | Provider-agnostic, quick setup |
Qwen Code's per-task time is inflated by the larger system prompt processing on every turn. When you are running locally on a 12GB card the difference matters, because the model has to re-read that 19k every time you send a new message. On cloud LLMs where prompt caching is on by default this evaporates. On llama-server without KV cache reuse across sessions, it does not.
Which one goes on the RTX 4070 rig
For local, on-a-single-card, all-my-code-stays-here: Aider. It is the smallest system prompt, the highest first-try success rate on my tasks, and it is the easiest to get working with Ollama or llama-server. If the reason you are running local is "I do not want my code leaving this machine," Aider is the lowest-friction way to get there.
If you want more agent scaffolding than Aider gives you (approval modes, headless runs for CI, background forks), Qwen Code is where those features live. You pay for it with the 19k-token overhead per turn and the setup complexity. On a cloud LLM this is a non-issue and Qwen Code looks great. On local hardware it costs you 20-30 seconds per task.
OpenCode is the "I want to swap providers freely" answer. Its provider-agnostic model config is the cleanest of the three. If you are going to move between local Qwen, Cloud Claude, and API Gemini depending on the task, OpenCode makes that swap a one-line config change.
Ollama's free tier for Qwen Code is gone in 2026
One footnote nobody mentions: Qwen Code CLI used to have a hosted free tier from QwenLM directly. It was retired on April 15, 2026. This matters not at all if you are running local, because you connect to your own llama-server and the retirement is invisible. If you were using the hosted endpoint, you need to either self-host or pay per token now.
For anyone reading this because they are trying to decide "cloud API or local for my coding assistant," the retirement moved the local option up the ranking. Cost of running Qwen 35B on your own hardware: your electricity bill. Cost of the equivalent number of tokens on any hosted API: not that.
What "agentic" actually means, honestly
One thing I want to say clearly because the tools' marketing does not: none of these three do what you might call open-ended goal pursuit. They do not sit in a loop, evaluate whether they hit the goal, and keep going if they missed. What they have is a tool-use loop within a single task. You give it a task. It calls tools until it decides the task is done. Then it stops.
Qwen Code's approval modes and budget controls make that single-task loop safer to run long. They do not make it a self-directed agent. Same for Aider's --yes-always mode. Same for OpenCode's daemon mode. All three are agents in the "uses tools to accomplish a task" sense. None of them are agents in the "pursues a goal indefinitely" sense. If your project depends on the second interpretation, you are looking at a different kind of harness.
This distinction saved me from a bad architecture choice, and I have not seen it stated plainly in the three tools' docs, so I am stating it plainly here.
The reason I started this comparison was that I use Claude Code as my daily driver on cloud, and I wanted to know what the local-only story looks like when I take Claude Code out of the loop. The mechanics of running a code agent well — tool call design, approval modes, when to hand off to a subagent — apply across all four tools, and I wrote them up here: Claude Code Mastery. If Claude Code is your baseline, this book is the "how to actually use it" playbook; the local-agent comparison above is what you fall back to when you cannot ship your code to a cloud provider.
Top comments (0)