AI Adapters¶
teststop generates scenarios by calling an AI backend. The default is ollama (free, local, unlimited). Cloud CLIs (claude, copilot) are opt-in.
How Adapters Work¶
The AIAdapter interface:
type AIAdapter interface {
GenerateScenarios(mandate string) ([]scenario.Scenario, error)
Prompt(input string) ([]byte, error)
Name() string
}
teststop passes the full composed mandate as a single prompt and parses the JSON array response. All adapters share the same JSON parser (ParseScenariosFromJSON) which strips markdown fences and rejects hollow batches.
Auto-Detection¶
TESTSTOP_CLI=auto (the default) tries backends in this order:
| Priority | Backend | Detection |
|---|---|---|
| 1 | ollama | localhost:11434 responds within 2s |
| 2 | claude | claude found on PATH |
| 3 | copilot | copilot found on PATH |
The TESTSTOP_CLI env var overrides auto-detection:
TESTSTOP_CLI | Behavior |
|---|---|
auto (default) | ollama → claude → copilot |
ollama | Use ollama only; error if not reachable |
claude | Use Claude CLI only; error if not found |
copilot | Use GitHub Copilot CLI only; error if not found |
# Use local model (default when ollama is running)
teststop run
# Force Claude (opt-in — uses account quota)
TESTSTOP_CLI=claude teststop run
# Force a specific ollama model
TESTSTOP_MODEL=qwen3:4b teststop run
Quality tradeoff: Local models (ollama) produce valid, useful scenarios at the cost of some specificity and edge-case creativity versus cloud models. For production use where quota is not a concern, TESTSTOP_CLI=claude gives higher-quality output. For development iteration and free CI runners, ollama is the right default.
Ollama (default)¶
Calls the ollama HTTP API at localhost:11434. No subprocess, no API key, no quota.
Default model: qwen3.6:latest (36B, Q4_K_M — high-quality, ~3–4 min per run)
Model selection:
# Use a smaller, faster model
TESTSTOP_MODEL=qwen3:4b teststop run
# Use gemma4
TESTSTOP_MODEL=gemma4:latest teststop run
| Model | Size | Speed | Scenario Count | Quality |
|---|---|---|---|---|
qwen3.6:latest | 23 GB | ~3–4 min | 29–31 | Best local quality (recommended) |
gemma4:latest | 9.6 GB | ~8 min | 52 | Excellent — most thorough |
qwen3:4b | 2.5 GB | — | — | Not viable — model reasons without generating JSON |
llama3.2:latest | 2 GB | — | — | Untested; likely similar to qwen3:4b limitation |
Minimum viable size: ~10B+ parameters. Sub-10B models typically lack the instruction-following capacity to generate 30-item JSON arrays reliably. Use
qwen3.6:latest(faster) orgemma4:latest(more thorough) for reliable output.
Timeout: 10 minutes (local inference is slower than cloud)
Request shape:
{
"model": "qwen3.6:latest",
"prompt": "<mandate + JSON-only constraint>",
"stream": false,
"think": false,
"options": {"num_ctx": 32768}
}
think: false disables the reasoning chain for qwen3 models. Even if the server ignores this (older ollama builds), the adapter strips <think>...</think> blocks automatically before parsing.
Quick-start:
# Install ollama and pull a model
brew install ollama
ollama pull qwen3:4b # 2.5 GB, fast
ollama serve # starts the server
# teststop auto-detects it
teststop run
Claude CLI¶
Uses the official Claude Code CLI. Requires an active Claude subscription — runs consume account quota shared with all Claude Code agents.
Command executed:
claude -p "<mandate text>" --output-format json
# With model override:
claude -p "<mandate text>" --output-format json --model claude-sonnet-4-6
Model selection:
Timeout: 5 minutes
GitHub Copilot CLI¶
Uses the GitHub Copilot CLI.
Command executed:
Timeout: 5 minutes
JSON Parsing¶
All adapters use the same parser (ParseScenariosFromJSON):
- Strip leading/trailing markdown fences (
```json…```) - Unmarshal into
[]scenario.Scenario - Reject hollow batches (every object missing
scenario_idandtitle) — catches event-stream format mismatches and empty-struct slippage
Troubleshooting¶
- "no AI backend found"
- Start ollama (
ollama serve), or installclaude/copilotand add to PATH. - ollama: HTTP request failed
- ollama is not running. Start it with
ollama serve. - "model not found"
- Pull the model first:
ollama pull qwen3.6:latest - "all N parsed scenarios are hollow"
- The model returned a non-scenario JSON structure. Check that the model is responding to the prompt (run
ollama run qwen3:4b "say hello"to verify). - "failed to parse scenarios JSON"
- The AI returned non-JSON output. With cloud adapters, authenticate first:
claude authorcopilot auth. With ollama, try a model with a larger context:TESTSTOP_MODEL=qwen3.6:latest teststop run. - Timeout
- For large projects, try
--depth lightto reduce mandate size. With ollama and qwen3.6:latest, a normal-depth run takes ~3–4 minutes.