the-veil-12b

The first official model for the nl-veil harness.

A Gemma 4 12B derivative, fine-tuned on nl-veil's own tool surface. One 7.4 GB file, no adapters to stack, no config to reconcile — point your client at it and it works.


What it's for

nl-veil hands a model a tool belt — a JSON array of everything it can do this turn — and that belt changes constantly. The chat surface ships twenty tools; a scout gets fifteen; an assembler gets eight; a browser session bolts on twelve more. A model that memorises one belt is useless the moment it sees another.

Most local models never learn to read the array at all. Handed read_file, they answer Read. Handed web_search, they answer WebSearch. Handed stop_process, StopProcess. Every one of those is rejected as an unknown tool and the turn is simply lost — which reads as "small models can't do tool use" when the real problem is that the model is answering from memory instead of from the belt in front of it.

the-veil-12b is trained so the belt is the only thing that can produce the right answer. Every training example carries a different tool array, sampled across nine schemas plus random subsets of a 58-tool registry. Memorising any single belt cannot help; reading the supplied one always can.

Results

Measured on 94 held-out drills against the stock model it was tuned from:

stock the-veil-12b
general tool-use 18/30 25/30
tools it has never seen in training 18/24 23/24
invented tool names 13 4

That middle row is the one worth dwelling on. Those twenty-four drills use tools — journal, host_command, stage_delivery, browser_console, mcp_discover, osint_scan — that appear in no training example whatsoever. Scoring 23/24 on them means the model learned a policy, not a vocabulary: read the array you were handed, use its exact names. Point it at a tool belt invented tomorrow and it will use that too.

Plug it in

With nl-veil

ollama create the-veil-12b -f Modelfile

Then pick the-veil-12b in nl-veil's model dropdown. That's the whole setup — the harness already speaks Gemma 4's native tool protocol, and this model speaks it back.

With Ollama directly

ollama create the-veil-12b -f Modelfile
ollama run the-veil-12b

Tools go over /api/chat the ordinary way:

curl http://localhost:11434/api/chat -d '{
  "model": "the-veil-12b",
  "messages": [{"role":"user","content":"Read notes/todo.txt and tell me the first line."}],
  "tools": [{"type":"function","function":{
      "name":"read_file","description":"Read a text file.",
      "parameters":{"type":"object","properties":{"path":{"type":"string"}},"required":["path"]}}}],
  "stream": false
}'

examples/tool_call.py runs a full round trip — offer a belt, get a structured call, execute it, feed the result back, get the answer. Copy it as a starting point.

With llama.cpp

llama-cli -m the-veil-12b-Q4_K_M.gguf --jinja -p "your prompt"

--jinja is required: the tool protocol lives in the model's own chat template.

Getting the most out of it

Render the chat template yourself if you can. Tool-name accuracy is materially higher when the host renders Gemma 4's template and posts a raw completion than when a runtime's built-in renderer does it — we measured a ~17-drill swing on identical weights. nl-veil does this automatically when it detects the difference. If you're building your own client, it's the single highest-value thing you can do.

Give tools honest descriptions. The model reads them. A tool described as "Read a text file. A whole-file read is CLIPPED — pass start_line/end_line for a big file" gets used correctly far more often than one described as "reads files".

Keep the belt to what the turn needs. It handles twenty-plus tools fine, but precision rises as the belt narrows to what's actually relevant.

Limitations

Worth knowing before you wire it into anything real:

  • It is a tool router, not a reasoner. Multi-step inference, mathematics and open-ended analysis are ordinary-12B quality. It is tuned for knowing which tool, not for thinking hard about the answer.
  • Ground anything time-sensitive. Like any model it will produce fluent, confident, wrong specifics for current facts if it answers from weights instead of searching. Give it a search tool and it will generally reach for it.
  • Phrasing shifts its behaviour. Naming the action — "search the web for …", "read the file …" — is the most reliable way to get the call you want.

Specifications

architecture gemma4 — 48 layers, 3840 hidden, 16 heads, 262144 vocab
context 262144
quantisation Q4_K_M, 7.38 GB
method QLoRA rank 16 / alpha 32 on attention + MLP, merged into the base
tool protocol Gemma 4 native (<|tool_call>call:name{...}<tool_call|>)

Files

file purpose
the-veil-12b-Q4_K_M.gguf the model
Modelfile Ollama recipe — renderer, parser, stop token
examples/tool_call.py end-to-end tool-call round trip
NOTICE attribution required by Apache-2.0

Origins

Built on Gemma 4 12B, Google's open model family, whose architecture, tokenizer and pretrained weights make all of this possible. The tool-routing behaviour described here is ours; everything underneath it is Gemma's, and the quality of that foundation is why a 12B can do this at all.

Apache-2.0. See NOTICE for the full attribution chain.

The harness

This model exists to drive nl-veil — a single-binary hive-mind orchestration engine: server, CLI and desktop client in one process, with a tool surface that spans the filesystem, the live web, a real browser, and a shared associative memory. the-veil-12b is the first model tuned specifically for it.

If you build something with either, we'd like to hear about it.

Downloads last month
32
GGUF
Model size
12B params
Architecture
gemma4
Hardware compatibility
Log In to add your hardware

4-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support