Coding with local models

PounceCode runs against Ollama, vLLM, LM Studio or anything else that speaks the OpenAI shape — on your laptop, on a box under your desk, or on a GPU server you reach over the network. The code never leaves your control and the marginal cost of a turn is electricity.

This is not a checkbox feature. The plan-and-step loop was tuned until a 27B model running locally could carry a five-step feature end to end, and the app's benchmark suite is run against local models precisely because they find the rough edges a frontier model papers over.

Setting it up

zsh
1 2 3 4 5 6 7 8
# 1. get a model. 14B is the floor for agentic work; 27B+ is comfortable $ ollama pull qwen2.5-coder:32b # 2. point PounceCode at it $ pounce --setup # choose Ollama, give the endpoint # 3. use it $ pounce --profile local "add a test for the remove path"
The AI Provider settings page listing two profiles, one Anthropic and one Ollama, each with its model and per-1K rates.
A local profile sits alongside a hosted one and costs nothing per token. Switch between them mid-conversation.

In the desktop app the same thing lives in Settings → AI → add a profile. Ollama's default endpoint is http://localhost:11434; a machine on your network works just as well, which is the usual arrangement — a laptop driving a GPU box.

The context-length trap

This is the single most common reason local coding agents appear stupid, and it has nothing to do with the model.

Ollama defaults to a 4096-token context, regardless of what the model supports. A coding agent's system prompt, tool definitions and a couple of file reads exceed that immediately. The model then loses the beginning of its own instructions mid-task and starts behaving erratically — forgetting the working folder, re-reading files it just read, ignoring the plan.

Raise it. A Modelfile is the durable fix:

Modelfile
1 2 3 4 5
FROM qwen2.5-coder:32b PARAMETER num_ctx 32768 # then: # ollama create qwen-coder-32k -f Modelfile

PounceCode reads the real window from the endpoint rather than assuming, so once you have raised it the ctx readout on the status bar reflects what you actually configured. If that number looks small, this is why.

Watch your memory. Context costs VRAM, and a long window on a large model will push layers onto the CPU and slow everything down dramatically. 32k on a 32B model wants a lot of headroom. If generation suddenly crawls, that is usually what happened.

Choosing a model

Agentic coding asks for something most benchmarks do not measure: the model must call tools correctly, many times, and keep track of what it has already done. Raw code quality matters less than reliability.

SizeWhat to expect
7B and belowChat and completion, not agentic work. It will produce plausible tool calls with the wrong arguments and cannot recover.
14BThe floor, and an unforgiving one. In our own testing a 14B coder model would draft a reasonable plan and then fail to execute it — the gap between planning and doing is where models this size break.
27B–32BThe sweet spot for a single workstation. This is the size at which multi-step features complete reliably: read, write, test, commit, without hand-holding.
70B+Comfortable, if you have the hardware for it at a usable context length.

Prefer models trained for tool use. Qwen's coder line is the most reliable family we have measured for this; instruction-tuned general models of the same size are usually worse at the tool-calling part even when they write better code.

What PounceCode does differently for small models

Most of the work behind local-model support is not in the model. It is in not handing the model an impossible job.

It shows fewer tools

Handing a model ninety tool definitions is how it picks the wrong one. Sub-flagship models get a bootstrap set of around 28 tools instead of 81, with the rest behind named groups it can load on request. The prompt states that the list is deliberately partial, so it asks rather than concluding the thing is impossible.

Each step gets its own context

The outer loop holds the plan and does no work; each step runs its own inner loop and never sees the plan. What crosses between them is a summary, not a transcript. That boundary is the mechanism — it is what keeps step five as coherent as step one on a model with a modest window.

It probes the machine first

At startup PounceCode checks which executables are actually present and working, and tells the model. Without it, a local model burns half its round budget discovering that this machine has python3 but not python, and no pytest.

It states the working folder

Always, explicitly, and again whenever it changes. A model that is not told where it is writes to /tmp and reports success. A strong model guesses right often enough to hide the bug; a local model does not, which is how it got found.

What it can do at 27B

A finished five-step run in PounceCode on qwen3.8-27b: every step struck through with a note on what it did, 7 tests passing, a commit hash, and 'Pounced for 1m 59s'.
A five-step feature carried end to end by a 27B model running locally: code, a test per command, the suite run, and a commit. The status bar shows the model and the context used.

From the benchmark suite, run against a 27B model on a single GPU. Every check reads the disk or runs a subprocess — none of them read the model's reply, because the failure being hunted is a model reporting success it did not achieve.

ScenarioResult
Build a SQLite inventory CLI, with testsFive nested steps, 5 passing tests, 2 git commits
Debug a failing testReads, locates, fixes, re-runs
Multi-step feature with acceptance criteriaCompletes and reports with evidence
Overall131 of 135 checks, 38 of 39 runs fully clean
Tuning for a small model improves the harness for every model. The failures live in the seams between components, and a 27B model cannot paper over an ambiguity the way a frontier model can. Every bug it surfaced — the working folder never being stated, reads and writes disagreeing about "here", git running in the wrong directory — was a real bug that also affected the big models, silently.

What "good" looks like on a local model

Asked to document a command-line interface, this 27B checked first, found there wasn't one, and said so — rather than writing a plausible page of commands that do not exist. That is the behaviour worth testing for, and it is not the one benchmarks usually measure.

A PounceCode conversation on qwen3.8-27b: the model reports that inventory.py has no CLI, explains it grepped to confirm, says it documented the actual state instead, and offers to scaffold a real CLI if wanted.
"So instead of inventing commands that don't exist, I created CLI.md documenting the current state." Running entirely on a local GPU.

What a local run costs

The same panel the hosted models fill in with money. A six-step feature here moved 643,000 tokens — 85% of them served from cache — and the line where the cost would be says there are no rates configured, because there is nothing to charge.

The tokens and cost panel on a local model: 637,252 input, 6,114 output, 643,366 total, 540,800 cache hits, an 85% hit rate, and the note 'No cost rates configured for this profile.'
Tokens still matter on a local model — they are time and VRAM — which is why the counters stay whether or not anyone is billing you.

Mixing local and hosted

Profiles are switchable mid-conversation, so the two are not an either/or. A common arrangement is a strong hosted model to draft the plan and a local model to execute the steps — the planner profile is configurable separately for exactly this. Another is local by default, escalating to a hosted model when something is genuinely hard.

When it goes wrong

SymptomUsually
Forgets instructions mid-task; repeats workContext too small. See the trap above.
Plans well, then does nothing usefulModel too small for agentic execution. Go up a size.
Calls tools with malformed argumentsModel not trained for tool use. Try a coder-tuned model.
Suddenly very slowContext length pushed the model out of VRAM onto the CPU.
Writes files somewhere unexpectedCheck the working folder on the status bar — it shows where writes actually land.
ctx shows a dashThe endpoint did not report a window and the model is unknown. It will learn the real limit from the first overflow error.