--- license: cc-by-4.0 language: - en - pt base_model: Qwen/Qwen3-0.6B-Base pipeline_tag: text-generation library_name: gguf inference: false quantized_by: Edelmar Schneider tags: - jq - json - text-to-jq - natural-language-to-code - code-generation - text-to-code - gguf - qwen3 - ollama - llama.cpp - offline - privacy - structured-data - portuguese metrics: - pass@1 model-index: - name: jq-coder-0.6B results: - task: type: text-generation name: Natural language to jq dataset: type: DominuZ/jq-bench name: jq-bench (human slice, 30 real StackOverflow tasks) split: test metrics: - type: pass@1 name: pass@1 strict (execution-verified) value: 0.333 verified: false - type: pass@1 name: pass@1 task-solved (execution-verified) value: 0.367 verified: false - task: type: text-generation name: Natural language to jq dataset: type: gauthierpiarrette/nl2jq-bench name: nl2jq-bench v1.0.0 (external, frozen, 400 items) split: test metrics: - type: pass@1 name: pass@1 (execution-verified, one-shot) value: 0.305 verified: false --- # jq-coder-0.6B — Natural Language to jq, 100% Offline (GGUF) *Part of the **jq-coder** project — [all artifacts](https://huggingface.co/collections/DominuZ/jq-coder-natural-language-to-jq-offline-6a582d4af58d35f838b45d80) · [`jqc` CLI (prebuilt binaries)](https://github.com/EdelmarSchneider/jq-coder-cli) · [jq-bench benchmark](https://huggingface.co/datasets/DominuZ/jq-bench)* **Convert natural language to jq filters without your JSON ever leaving your machine.** jq-coder is a 0.6B full fine-tune of Qwen3-0.6B-Base that turns a plain-language request plus a JSON sample into an executable [`jq`](https://jqlang.org/) filter, on CPU, in a fraction of a second. An offline jq filter generator, built for the JSON you can't send to a cloud API: production payloads, logs with PII, anything under NDA. To our knowledge it is the **first NL→jq model with GGUF builds on Hugging Face**. It ships with [**jq-bench**](https://huggingface.co/datasets/DominuZ/jq-bench), an execution-verified benchmark built from real StackOverflow questions — and, as a bonus, it also understands requests in Brazilian Portuguese (the only NL→jq model that does). ## Model overview | | | |---|---| | Parameters | 0.6B (full fine-tune of Qwen3-0.6B-Base) | | Recommended file | `jq-coder-v14-release-Q8_0.gguf` (~640 MB) | | Runs on | CPU-only is fine; any llama.cpp-compatible runtime | | Context | 4k used in practice (request + JSON sample) | | Languages | English + Brazilian Portuguese | | Output | one executable jq filter, nothing else | ## Quickstart — 10 seconds with Ollama ```bash ollama run D0minuZ/jq-coder ``` The [Ollama library build](https://ollama.com/D0minuZ/jq-coder) ships the system prompt and `temperature 0` preconfigured — just type your request (+ a JSON sample). Running straight from this repo also works: `ollama run hf.co/DominuZ/jq-coder-0.6B:Q8_0`. ## Or the `jqc` CLI — one binary, batteries included `cargo install jqc`, or prebuilt binaries for Windows, Linux and macOS (Apple Silicon) on the [Releases page](https://github.com/EdelmarSchneider/jq-coder-cli/releases). It embeds llama.cpp and runs the generated filter for you; the model downloads on first use. ```bash jqc "get the id of every order" orders.json ``` Since v0.2.0 it can also **write the result back into the file** (`--write`: shows a diff, asks first, keeps a `.bak`, writes atomically) and offers an **interactive session** (`jqc orders.json`): chain requests against a working buffer with apply/undo, and the file on disk only changes when you confirm `:w`. ## Or llama.cpp / LM Studio ```bash llama-server -m jq-coder-v14-release-Q8_0.gguf --port 8091 -ngl 99 ``` ```bash curl -s http://127.0.0.1:8091/v1/chat/completions -d '{ "messages": [ {"role": "system", "content": "You translate natural-language requests into jq filters. Reply with only the jq filter."}, {"role": "user", "content": "get the id of every order\n\nJSON sample:\n{\"orders\": [{\"id\": 1, \"status\": \"done\"}]}"} ], "temperature": 0 }' ``` In [LM Studio](https://lmstudio.ai/), open this repo via "Use this model". ## Files | File | Size | Verdict | |---|---|---| | [jq-coder-v14-release-Q8_0.gguf](https://huggingface.co/DominuZ/jq-coder-0.6B/resolve/main/jq-coder-v14-release-Q8_0.gguf) | ~640 MB | **Recommended** — matches f16 on every metric (measured, not assumed) | | [jq-coder-v14-release-f16.gguf](https://huggingface.co/DominuZ/jq-coder-0.6B/resolve/main/jq-coder-v14-release-f16.gguf) | ~1.2 GB | Reference precision | | jq-coder-v13-release-{Q8_0,f16}.gguf | | Legacy (previous release, kept for pinned revisions) | Q4_K_M was measured and **rejected**: it preserves in-distribution accuracy but breaks exactly the hard compositions. Small models do not survive aggressive quantization unharmed — we measured instead of assuming, and we don't publish what failed the gate. ## Prompt format ChatML (the chat template is embedded in the GGUF). The contract has two parts: - **system**: `You translate natural-language requests into jq filters. Reply with only the jq filter.` - **user**: the request, then a blank line, then `JSON sample:` and a sample of the JSON you want to query. **The JSON sample is mandatory.** The model was trained to read field names and shapes from it — without a sample it will hallucinate fields. A truncated sample is fine as long as it shows the structure you are asking about. ## Examples All examples below were run against the published Q8_0 GGUF and verified by executing the generated filter with real jq. Input JSON: ```json {"orders": [{"id": 1, "status": "done", "total": 120.5}, {"id": 2, "status": "pending", "total": 40.0}]} ``` | Request | Generated filter | |---|---| | get the id of every order | `.orders[] \| .id` | | keep only the orders whose status is done | `[.orders[] \| select(.status == "done")]` | | some o total de todos os pedidos | `[.orders[].total] \| add` | | remova o campo total de cada pedido | `del(.orders[].total)` | The model conditions on the JSON sample, so the same request over a differently shaped document correctly yields a different filter. **Bonus — Brazilian Portuguese**: the model was trained bilingually (EN/PT-BR 50/50), so requests like "some o total de todos os pedidos" work out of the box, as shown above. English remains the primary interface and documentation language. ## How it was trained **Reverse generation with ground truth by execution** — the training data was never written by an LLM guessing jq: 1. A grammar of **148 program families**, anchored in real-world usage (top-voted StackOverflow `[jq]` questions, the llm-jq / jiq / gpt-jq corpora, the official jq manual), samples candidate programs. 2. Each program is **executed with real jq 1.8** against families of synthetic JSON documents — the output is the ground truth, for free. 3. Three quality guards filter the pairs: **(G1)** non-degeneracy (exit 0, non-empty, non-constant output across distinct documents), **(G2)** coverage anchored in real corpora, **(G3)** NL↔program consistency via round-trip with an independent second model. 4. Only then does a teacher LLM write the natural-language request (the cheap, safe part). Teachers are locally served open-weights models (Apache 2.0, distillation permitted). Result: **36,879 verified pairs**, bilingual EN/PT-BR 50/50, full fine-tune (not LoRA) of Qwen3-0.6B-Base. ## Evaluation All metrics are computed **by execution**: the generated filter runs against held-out JSON documents and the canonical output (`jq -cS`) is diffed against gold. No LLM-as-judge anywhere. ### jq-bench (ours — human slice of 30 real StackOverflow tasks) | Artifact (v14) | human slice, strict | human slice, task-solved¹ | in-distribution (400) | |---|---|---|---| | f16 | 10/30 | 11/30 | 394/400 | | **Q8_0 (recommended)** | **10/30** | **11/30** | **394/400** | ¹ *strict* = byte-identical to gold after canonicalization; *task-solved* additionally accepts equivalent output shapes (stream vs. array wrapper, etc.). ### nl2jq-bench (external, frozen, 400 items) On [nl2jq-bench v1.0.0](https://huggingface.co/datasets/gauthierpiarrette/nl2jq-bench) — an independent frozen benchmark by another author, evaluated one-shot with greedy decoding per its protocol — v14 scores **pass@1 0.305, valid@1 0.778** (tiers: T1 0.53 · T2 0.38 · T3 0.28 · T4 0.24 · T5 0.083). The T5 gap is honest and diagnosed: that tier is built from constructs (`reduce`, `foreach`, recursive `..`, update-assignment) that our v14 training grammar does not cover yet — they are the target of the next data iteration. Two internal diagnostics of ~200 realistic probes each (execution-verified, authored independently of the training pipeline) track progress across data iterations: the v14 iteration scores **63.7%** on the older set (v13: 52.5%; v12: 31.4%) and **50.0%** on a fresh, fully independent set (v13: 32.0%). The human slice remains the canonical metric. ## Honest limitations - **Long compositions still fail** (~2/3 of the human slice): array subtraction (`. - [...]`), `to_entries` with object reconstruction + `tonumber`, compound merges with `del`, recursive descent (`..`). The model interpolates between neighboring compositions it saw in training; requests far from everything it saw come out wrong or hallucinated. (v14 added `any`/`all`, filtered aggregations and conditional field derivation — those now work in typical shapes but still break inside longer chains.) - Aggregations under nested fields can come out as listings instead of sums. - The request must mention fields by their real names in the JSON; the JSON sample in the prompt is mandatory. - English and Brazilian Portuguese only. - It generates **filters**, not shell invocations: no `-r`/`-s`/`--arg` handling. Always review generated filters before running them against data you care about — especially destructive ones (`del`, assignments). ## License and attribution - **Model weights: CC BY 4.0.** Commercial use welcome. If you share the weights or a derivative (re-hosts, quantizations, further fine-tunes), credit **Edelmar Schneider**, link back to this page, and indicate changes. The base model, [Qwen/Qwen3-0.6B-Base](https://huggingface.co/Qwen/Qwen3-0.6B-Base), is Apache 2.0 and its notices are retained. - **jq-bench** (evaluation dataset): CC BY-SA 4.0, with per-item attribution (StackOverflow URL / author / votes). If this model or benchmark is useful in your work, please cite: ```bibtex @misc{jqcoder2026, title = {jq-coder: a 0.6B offline natural-language-to-jq model and jq-bench}, author = {Edelmar Schneider}, year = {2026}, url = {https://huggingface.co/DominuZ/jq-coder-0.6B} } ```