jq-coder-0.6B / README.md
DominuZ's picture
Card: jqc 0.2.0 (cargo install, --write com confirmacao, sessao interativa)
627e0a2 verified
|
Raw
History Blame Contribute Delete
11.2 kB
---
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}
}
```