Overview
Simplicio 27B is a LoRA fine-tune of Qwen3.8-27B by Wesley Simplicio at SimpleTI. It was trained to answer a code-change request in five tagged phases (<orient>, <plan>, <patch>, <validate>, <deliver>). The <patch> phase holds SEARCH/REPLACE blocks that touch only the lines that change.
- Base model: Qwen3.8-27B, 27.36B parameters, 64 layers that alternate linear attention (DeltaNet) and full attention in a 3:1 pattern.
- Files on Hugging Face: the LoRA adapter in
lora/ (0.64 GB), the merged BF16 checkpoint (18 shards, 55.6 GB), and a GGUF Q4_K_M (16.8 GB) with the base model's vision projector (0.93 GB). Image input is inherited from the base model and has not been evaluated.
- Status: research release. It has not been scored on a reproducible benchmark yet. See Benchmarks.
Benchmarks
No benchmark result is published in this README yet. Numbers that were not produced by a reproducible run have been removed.
In accordance with the pre-registered protocol (ADR 0001):
- Pre-registration: The evaluation protocol is specified in
PREREG_eval.md with SHA-256 locked in PREREG_sha256.txt.
- Audit template: Release evaluations are published in
RELEASE_EVAL.md with two-sided 95% Wilson confidence intervals.
- Harness: The benchmark harness is in
benchmarks/harness/. It runs 40 SEARCH/REPLACE tasks against any OpenAI-compatible endpoint. A task passes only when the hidden pytest tests pass on the patched code. A result will be published here only together with its commit, the model file and its checksum, the prompt hash, the decoding settings, and the per-task output.
- Quantized builds (FP8, GGUF, AWQ, MLX) are verified against the unquantized baseline via with Wilson 95% bounds.
Not evaluated: SWE-bench, Aider, Terminal-Bench, the Artificial Analysis indices, and image input.
Quick start
Ollama
ollama run wesleysimplicio/simplicio-27b --think=false
If Ollama is not installed, get it from ollama.com/download. The latest tag is built from the root Modelfile and needs Ollama 0.30.0 or newer. The Modelfile uses the Q4_K_M GGUF and leaves the base model's vision projector out on purpose: Simplicio is used for text only. The published tag's manifest lists a projector layer too, so the two do not match yet. Image input has not been evaluated. It sets:
RENDERER qwen3.5 and PARSER qwen3.5: Ollama's built-in Qwen 3.5 prompt format. Tool calls come back in message.tool_calls and reasoning in message.thinking.
num_ctx 40960: a 40,960-token context, the same as vLLM (deploy/context.env).
- Qwen's recommended sampling for Qwen3.8-27B in non-thinking mode:
temperature 0.7, top_p 0.8, top_k 20, min_p 0, presence_penalty 1.5, repeat_penalty 1. The benchmark harness uses greedy decoding, so to match it send . The tag stops only at ; add inside to also stop at the end of the answer.
Thinking. The training data has no <think> blocks, so run with thinking off. Ollama turns thinking on by default for models that support it, so turn it off on every request:
Table with columns: Client, Thinking off| Client | Thinking off |
|---|
ollama run | --think=false, or /set nothink inside a session |
/api/chat | "think": false |
/v1/chat/completions | "reasoning_effort": "none" |
With thinking on, the model reasons first and the reasoning goes to message.thinking. That mode has not been evaluated.
Prompt format. Training used this system prompt and user message. Ollama adds the system prompt by itself; with vLLM or transformers, send it as the system message:
system: Voce e o Simplicio 27B, treinado para executar tarefas de desenvolvimento seguindo rigorosamente os 50 pontos do Simplicio-Loop: Orientacao, Planejamento, Edicao Cirurgica por Diff, Validacao e Entrega Verificada sem alucinacao.user: Contexto: <files, stack and bug report> Tarefa: <the change to make>
Not evaluated. The Q4_K_M file has not been scored. Image input has not been evaluated. Training was text-only. The training data has no tool calls, so tool calling is whatever the base model does.
pip install vllm==0.31.0git clone https://github.com/simpletibr/simplicio-27bcd simplicio-27b./deploy/serve_vllm.sh wesleysimplicio/Simplicio-27B 8000
This serves the merged BF16 checkpoint. The weights alone take 55.6 GB. deploy/serve_vllm.sh is the only serve command, and the Colab notebook runs it too. It sets:
--max-model-len 40960, defined once in deploy/context.env: the total context window.
- No
--chat-template: vLLM uses the model's own chat_template.jinja.
--default-chat-template-kwargs '{"enable_thinking": false}': thinking is off by default because the training data has no <think> blocks. A request can turn it on with "chat_template_kwargs": {"enable_thinking": true}.
--enable-auto-tool-choice --tool-call-parser qwen3_coder --reasoning-parser qwen3: vLLM's built-in parsers for Qwen's native <tool_call><function=…> format.
--enable-force-include-usage: every response carries .
vllm serve has no stop flag. <|im_end|> already ends generation through generation_config.json; to end at </deliver>, send "stop": ["</deliver>"] in the request.
notebooks/Simplicio_27B_Serve_Colab.ipynb runs the same script on a Colab G4 (RTX PRO 6000, 96 GB) behind the completion gate and a Cloudflare tunnel.
OpenCode
Add the vLLM server to opencode.json as an OpenAI-compatible provider:
{ "$schema": "https://opencode.ai/config.json", "provider": { "simplicio": { "npm": "@ai-sdk/openai-compatible", "name": "Simplicio 27B", "options": { "baseURL": "http://localhost:8000/v1" }, "models": { "simplicio-27b": { "name": "Simplicio 27B" } } } }}
opencode -m simplicio/simplicio-27b
OpenCode works through tool calls, so point it at the vLLM server. OpenCode has not been tested against the Ollama tag.
The Hugging Face repository root is a plain Transformers checkpoint: the merged BF16 weights (55.6 GB). do_sample=False is greedy decoding, the setting the benchmark harness uses; without it, generate uses the sampling defaults in generation_config.json, the same values as the Ollama Modelfile.
import torchfrom transformers import AutoModelForImageTextToText, AutoTokenizer repo = "wesleysimplicio/Simplicio-27B"tokenizer = AutoTokenizer.from_pretrained(repo)model = AutoModelForImageTextToText.from_pretrained(repo, dtype=torch.bfloat16, device_map="auto") messages = [{"role": "user", "content": "In api/schemas/user.py, accept tax_id with punctuation such as 123.456.789-00."}]inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, enable_thinking=False, return_tensors="pt").to(model.device)output = model.generate(**inputs, max_new_tokens=1024, do_sample=False)print(tokenizer.decode(output[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))
The LoRA adapter is in lora/. To apply it to your own copy of the base model, load the base with AutoModelForImageTextToText, the class whose module names (model.language_model.layers.*) match the adapter:
import torchfrom peft import PeftModelfrom transformers import AutoModelForImageTextToText base = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen3.8-27B", dtype=torch.bfloat16, device_map="auto")model = PeftModel.from_pretrained(base, "wesleysimplicio/Simplicio-27B", subfolder="lora")
Each phase is a list of numbered points. This example is shortened and translated from the first training example:
<simplicio_loop><orient>[Point 1: Root] Root confirmed at /workspace/api-gateway (pyproject.toml found).[Point 3: Type signatures] UserCreate.tax_id: str = Field(..., min_length=11, max_length=14).…</orient><plan>[Point 11: Atomic steps] Step 1: add a field_validator to the schema. Step 2: run tests/test_users.py.…</plan><patch><<<< SEARCH tax_id: str = Field(..., min_length=11, max_length=14)==== tax_id: str = Field(..., min_length=11, max_length=11) @field_validator("tax_id", mode="before") @classmethod def sanitize_tax_id(cls, v: str) -> str: cleaned = re.sub(r"\D", "", v) if len(cleaned) != 11: raise ValueError("tax_id must have exactly 11 digits") return cleaned>>>> REPLACE</patch><validate>[Point 32: Targeted tests] pytest tests/test_users.py -k "tax_id" -> 2 passed…</validate><deliver>…</deliver></simplicio_loop>
The SEARCH/REPLACE markers are four characters long (<<<<, ====, >>>>), not the seven that Git and Aider use. To apply a patch, find the SEARCH text verbatim in the file and replace it.
Training
The published adapter was produced by notebooks/Simplicio_27B_Training_Colab.ipynb. The settings below come from that notebook and the published lora/adapter_config.json.
Table with columns: Setting, Value| Setting | Value |
|---|
| Method | QLoRA with Unsloth; base loaded in 4-bit |
| LoRA | r 32, alpha 32, dropout 0. q, k, v, o projections on the 16 full-attention layers (3, 7, …, 63); gate, up, down projections on all 64 layers. The linear_attn projections of the 48 DeltaNet layers and the vision tower were not adapted (512 LoRA tensors in the published adapter) |
| Steps | 120 steps, batch size 1, gradient accumulation 8 |
| Optimizer | AdamW 8-bit, learning rate 2e-4, cosine schedule, 10 warmup steps, weight decay 0.01 |
| Sequence length | 4,096 |
| Loss | whole sequence, prompt included |
| Data | 101 examples in Portuguese: 1 written by hand and 100 generated from a short list of stack and task templates |
An earlier script, train_simplicio_27b.py, was removed because its defaults do not reproduce the published adapter: 150 steps, the bottom 48 layers frozen, and the 10 phase tags added as special tokens. The published adapter used none of these, and its tokenizer has no added tokens. generate_dataset.py writes data/simplicio_loop_50pts_train.jsonl (80 examples) and data/simplicio_loop_50pts_val.jsonl (15 examples).
Limitations
- No functional correctness of the patches has been measured yet.
- The training set is small (101 examples), templated and in Portuguese. Whether outputs follow the five-phase format was not measured.
- In the training examples,
<validate> and <deliver> contain written-out results such as "2 passed" or "COMMIT_READY". The model writes these without running anything. Treat them as claims and run your own tests.
- It has not been compared with the base model under the same protocol, and it has not been run on public benchmarks.
- No checkpoint has been evaluated yet. The BF16 weights, the Q4_K_M GGUF, the Ollama template and parameters, and the 4-bit base + LoRA path are all unmeasured.
- Decoding: the benchmark harness is greedy (temperature 0). The sampling defaults in the Hugging Face
generation_config.json and in the Ollama tag are not greedy and have not been measured.
- Aider: the patch markers differ from Aider's edit format, and Aider has not been tested.
- Vision: the Hugging Face repository ships the base model's vision projector as a separate file. The Modelfile leaves it out, but the published Ollama manifest lists it. Training was text-only, and image input has not been evaluated.
Repository
Table with columns: Path, Contents| Path | Contents |
|---|
scripts/hf_publish.py | Syncs the Hugging Face repo with this one: file allowlist, adapter in lora/, one commit that only adds and updates files, never deletes on the Hub; dry-run by default, --publish needs HF_TOKEN |
lora/ | Where the LoRA adapter goes (adapter_config.json, adapter_model.safetensors); the weights are not in git |
notebooks/Simplicio_27B_Training_Colab.ipynb | Training run that produced the adapter |
|
Development
make check needs python3, ruff, shellcheck, php and make on the PATH.
make check # unittest, ruff F/E9, shellcheck, php -l, vLLM argsgit config core.hooksPath .githooks # once per clone: run make check before every push
The last step parses the exact vllm serve argv from deploy/serve_vllm.sh with vLLM's own CLI parser, so it needs vllm==0.31.0 importable. Without vLLM installed it fails with exit code 1 on purpose: a flag that vLLM does not accept must not pass the gate unnoticed. On a machine without vLLM, export SIMPLICIO_SKIP_VLLM_ARGS=1 to skip only that check (it prints SKIP: vllm not importable; argv extracted, not validated); the other four steps still run. There is no CI: all checks run locally. Commit subjects are one plain sentence, without a type: prefix. Colab notebooks live in notebooks/; tests/test_layout.py fails on a notebook at the repository root or on a blob/main link to a missing file.
Agent integration (MCP)
Simplicio 27B provides a native Model Context Protocol (MCP) server over stdio in scripts/mcp_server.py with zero external dependencies.
apply_surgical_diff: Atomically applies SEARCH/REPLACE diff blocks to target files with rollback on mismatch.
validate_patch: Validates diff block structure and syntax offline without modifying files.
format_prompt: Renders structured prompts conforming to the Simplicio-Loop (<orient>, <plan>, <patch>, <validate>, <deliver>).
The server natively accepts both standard diff formats:
- Aider standard (7-char):
<<<<<<< SEARCH, =======, >>>>>>> REPLACE
- Simplicio compact (4-char):
<<<<, ====, >>>>
MCP configuration
Add to your MCP client configuration (Claude Desktop, Claude Code, Cursor):
{ "mcpServers": { "simplicio": { "command": "python3", "args": ["scripts/mcp_server.py"] } }}
Citation
@misc{simplicio27b2026, author = {Simplicio, Wesley}, title = {Simplicio 27B: a Qwen3.8-27B fine-tune for SEARCH/REPLACE code patches}, year = {2026}, publisher = {SimpleTI}, howpublished = {\url{https://huggingface.co/wesleysimplicio/Simplicio-27B}}}
Links