SDODS
Guides

Local models

Run the agents on a model on your own machine — Ollama with qwen, gemma or llama — with no key, no cost and nothing leaving the laptop.

What you'll learn

How to point SDODS at a model running on your own machine, the one setting that decides whether it works at all, which jobs a small model can finish, and how to tell the difference between a model that is wrong and a setup that is broken.

Why

Agents in SDODS only ever write proposals a human reviews. That makes a local model a reasonable place to start: nothing it produces reaches your suite without a review, and nothing you send it reaches anyone else. Two situations make it the only option — source that may not be sent to a hosted provider, and a team that wants the agent features without a per-token bill.

brew install ollama            # or: curl -fsSL https://ollama.com/install.sh | sh
ollama serve &
ollama pull qwen2.5-coder:7b

sdods doctor                   # the "local models (ollama)" row should be green
sdods agent review -p demo-shop --adapter ollama --model qwen2.5-coder:7b

That is the whole setup. There is no key to create, and agents.budgetUsd stops meaning anything because nothing is billed.

The setting that decides everything: context

Ollama loads a model with a 4096-token context by default, whatever its weights allow — and it truncates a longer prompt silently. An agent prompt carries the tool schemas, so it passes 4096 on the first turn. The model then answers confidently from a fraction of the question, and nothing in the output says so. It looks like a stupid model. It is a truncated prompt.

ollama ps
# NAME           ...  CONTEXT
# llama3.1:8b         4096      ← the weights allow 131072

Set it, either per project or on the server:

sdods.project.yaml
agents:
  provider: ollama
  models:
    default: qwen2.5-coder:14b
    reviewer: llama3.1:8b # a cheaper role can use a cheaper model
  local:
    contextTokens: 16384 # → options.num_ctx
    requestTimeoutMs: 300000
    keepAlive: 10m
OLLAMA_CONTEXT_LENGTH=16384 ollama serve    # the same thing, server-wide

SDODS refuses to start a job whose prompt cannot fit, rather than letting it be truncated:

✖ The prompt for this job is about 11,200 tokens, but qwen2.5-coder:7b is running with a
  4,096-token context. Ollama would truncate it without saying so.
  → Set agents.contextTokens: 32768 in the project yaml, or start the server with
    OLLAMA_CONTEXT_LENGTH=32768 (this model supports up to 32,768).

Raise the context to what the job needs, not to the model's maximum. An oversized num_ctx on a laptop spills the KV cache out of memory and turns ten-second turns into minutes.

Which model

sdods doctor reports what is installed and how it is loaded. Two properties matter: the model must be able to call tools, and it should be a coding model.

ollama show qwen2.5-coder:7b     # capabilities: completion, tools
ModelSizeGood for
qwen2.5-coder:14b9 GBthe best small-model results for generate and heal
qwen2.5-coder:7b5 GBreview, heal, converting a recording
llama3.1:8b5 GBreview and reading; calls tools reliably
gemma46 GBreview; also does vision, if you want screenshots read

A model whose capabilities do not include tools cannot drive the agent loop at all — SDODS says so rather than letting it flail.

The small profile

SDODS shows a hosted model everything it has: 33–35 tools for a role, and 24 more when the role drives a browser. A 7–8B model cannot choose from a menu that long — past roughly twenty functions it stops calling anything and starts describing the call it would make. So a local model gets a different menu, chosen automatically:

fullsmall
Tools for the generator355 (step_find, feature_list, feature_read, feature_parse, feature_write)
Browser serverattached for planner, generator, healernot attached--browser adds it
Tool calls per turnunlimited1
First turnmodel's choicemust call a tool
System promptfull conventionsshort rules, plus 60 of the project's real step patterns
A call written as proseignoredexecuted

The profile is picked by resolveProfile: any ollama model, any OpenAI-compatible endpoint on a private address, any model whose name says 7b/8b/14b, any context under 16k, or any model that does not advertise tool calling. Override it per run or per project:

sdods agent generate -p rwa-bank --adapter ollama --profile small   # or full
sdods.project.yaml
agents:
  profile: auto # auto | full | small

Three of those rows came out of measurement rather than taste, on llama3.1:8b:

  • The browser is not "more tools", it is a different job. With the five generator tools the model called feature_write. Adding a single browser_* tool made it stop calling anything and describe a plan instead. A small model writes from the step vocabulary; give browser work to a larger one.
  • Grounding beats brevity. The longer prompt — the one carrying 60 real step patterns — got a tool call where the short prompt got prose.
  • Some models write the call instead of making it. step_find({"project":"rwa-bank",…}) as plain text, with the structured field empty. Under the small profile that is read out of the answer and executed once, and the run says so: recovered a step_find call the model wrote as text.

What to expect from the result

A real run of agent generate on a local 8B, through this profile, produced a proposal in two turns — a feature file with the right tags, sensible scenario titles, and steps that were close to the project's real patterns rather than exactly them (I navigate to the Contacts page where the pattern is I navigate to the {string} page).

That is the honest shape of the result, and it is why nothing is applied automatically. Read the diff, fix the two steps, accept:

sdods proposals show <id>
sdods proposals accept <id> --branch sdods/<id>

Other local servers## Other local servers

Anything that speaks the OpenAI protocol works through the openai-compatible adapter, which no longer demands a key for a local address:

# vLLM, LM Studio, llama.cpp …
sdods agent review -p demo-shop \
  --adapter openai-compatible \
  --base-url http://127.0.0.1:1234/v1 \
  --model qwen2.5-coder-14b

The difference is that the OpenAI protocol has no way to set the context size, so that path relies on the server being started with the right one. The ollama adapter uses the native API precisely so SDODS can set it and check it.

What a small model can and cannot do

Local 7–8B models are good at bounded, well-described work and bad at long open-ended plans. In practice:

Job7–8B14B+
agent reviewgoodgood
agent heal on a locatorusuallygood
record convert (a recorded spec)usuallygood
agent generate from a planpatchyusually
agent plan for a whole applicationnopatchy

Mix them: agents.models takes a model per role, so planning can use a hosted model while generation stays local, or the other way round.

Every job is still a proposal:

sdods proposals list
sdods proposals show <id>
sdods proposals accept <id> --branch sdods/<id>

When something looks wrong

SymptomCause
The answer ignores half the instructionsthe context is too small — check ollama ps, raise contextTokens
model 'x' not foundit is not pulled: ollama pull x
Cannot reach Ollama at http://127.0.0.1:11434the server is not running: ollama serve
The job stops with error_tool_argumentsthe model cannot form a tool call — use a coding model, or a larger one
Turns take minutesthe model is being reloaded between turns, or num_ctx is too large for the machine
sdods doctor shows no local rowno server answered on OLLAMA_HOST or 127.0.0.1:11434

Next steps

On this page