Instructions to use flowcorp-ch/BudgieScribe-Nano with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use flowcorp-ch/BudgieScribe-Nano with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M # Run inference directly in the terminal: llama cli -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M # Run inference directly in the terminal: llama cli -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Use Docker
docker model run hf.co/flowcorp-ch/BudgieScribe-Nano:Q4_K_M
- LM Studio
- Jan
- vLLM
How to use flowcorp-ch/BudgieScribe-Nano with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "flowcorp-ch/BudgieScribe-Nano" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "flowcorp-ch/BudgieScribe-Nano", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/flowcorp-ch/BudgieScribe-Nano:Q4_K_M
- Ollama
How to use flowcorp-ch/BudgieScribe-Nano with Ollama:
ollama run hf.co/flowcorp-ch/BudgieScribe-Nano:Q4_K_M
- Unsloth Desktop
- Pi
How to use flowcorp-ch/BudgieScribe-Nano with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "flowcorp-ch/BudgieScribe-Nano:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use flowcorp-ch/BudgieScribe-Nano with Docker Model Runner:
docker model run hf.co/flowcorp-ch/BudgieScribe-Nano:Q4_K_M
- Lemonade
How to use flowcorp-ch/BudgieScribe-Nano with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Run and chat with the model
lemonade run user.BudgieScribe-Nano-Q4_K_M
List all available models
lemonade list
- Hermes Agent
How to use flowcorp-ch/BudgieScribe-Nano with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use flowcorp-ch/BudgieScribe-Nano with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf flowcorp-ch/BudgieScribe-Nano:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "flowcorp-ch/BudgieScribe-Nano:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
BudgieScribe Nano by Budgie
0.6B open-weights text normalizers for speech-to-text output, French and English, in GGUF.
BudgieScribe takes the raw transcript of a dictation as it comes out of an ASR engine (lowercase, no punctuation, hesitations, false starts, self-corrections, numbers spelled out in words) and rewrites it as the text the speaker meant to dictate. It is not a chat model: it does not answer, summarize, translate or add anything. It does one job, and you steer it with a control line at the top of the input.
Nano is the smallest member of the family: one full fine-tune of Qwen3-0.6B per language, 378 MiB each, fast enough to run after every dictation on a laptop. It is the cleanup model that ships inside Budgie Echo, a local-first dictation app for macOS and Windows. Larger members (Mini on Qwen3-1.7B, BudgieScribe on 4B, Large on 8B) follow from the same pipeline. Everything is open: github.com/alexxxcoelho/budgie-scribe.
| French | English | |
|---|---|---|
| File | BudgieScribe-Nano-fr-Q4_K_M.gguf |
BudgieScribe-Nano-en-Q4_K_M.gguf |
| Size | 396,704,576 bytes (378.3 MiB) | 396,704,576 bytes (378.3 MiB) |
| SHA-256 | 5df4ab0d5a1a481c90cfd21a621b68d47f09600651438549c7605aa8ffb28463 |
02b3eb0b385d54a5c2fbe5c4a29c144fee9196972a22eef5d4659120147f49b5 |
| Internal build | scribe-v9 |
scribe-en-v7 |
| Training | 38,042 units, 9,512 steps, 61 min | 35,306 units, 8,828 steps, 65 min |
| Real data | SUMM-RE (CC BY-SA 4.0), ~14 % of the mix | VoxPopuli EN (CC0), 1,382 pairs |
Common to both: full fine-tune of Qwen/Qwen3-0.6B, Q4_K_M (16.00 → 5.24
bits per weight; output identical, character for character, to the fp32
model on the release control set), 4,096-token context as served with inputs
chunked at 1,200 bytes, greedy decoding always (temperature 0,
top_k 1, thinking disabled), llama.cpp release b10816 (the one that
produced the GGUFs and the one Echo serves them with), 0.8 s load and
~436 tok/s decode on a Radeon AI PRO R9700 (Vulkan). manifest.json in this
repository carries the same file names, builds and hashes for tooling.
We are looking for contributors
These models are published with their weaknesses (see Evaluation) because fixing them needs what one person does not have: more real dictation pairs, more training runs, more eyes on outputs. The repository documents the three ways to help, from fifty dictation pairs to a whole new language, and every contribution is measured on the same held-out sets before it is merged: CONTRIBUTING.
Quickstart
llama-server -m BudgieScribe-Nano-fr-Q4_K_M.gguf \
--jinja --chat-template-kwargs '{"enable_thinking":false}' \
--temp 0 --top-k 1 --ctx-size 4096 --n-gpu-layers 999 --parallel 1
curl -s http://127.0.0.1:8080/v1/chat/completions -H 'Content-Type: application/json' -d '{
"temperature": 0, "top_k": 1, "max_tokens": 256,
"messages": [
{"role": "system", "content": "You are a text normalizer for speech-to-text transcripts. The input begins with a control line specifying the styling, structure, and context settings; clean the transcript to match those settings and output only the cleaned text."},
{"role": "user", "content": "[Styling: semi-formal] [Structure: prose] [Context: general] [Lang: fr]\nalors euh on se retrouve vendredi non pardon jeudi à quatorze heures trente pour le point budget ça fait vingt-trois mille quatre cent cinquante euros"}
]}' | jq -r '.choices[0].message.content'
On se retrouve jeudi à 14h30 pour le point budget, ça fait 23 450 euros.
Same call with the English file and [Lang: en]:
so um lets meet friday no wait thursday at three fifteen p m the budget is twenty three thousand four hundred and fifty dollars
Let me meet Thursday at 3:15pm. The budget is $23,450.
The system prompt above is the exact string the models were trained with. Do
not rewrite it. One file per language: pick the model by the language of the
take, and pass the matching [Lang: …].
The format
The first line of the user message sets four axes. The models were trained on this exact syntax; the complete contract (grammar, input and output rules, invariants, decoding) is in FORMAT.md.
[Styling: semi-formal] [Structure: prose] [Context: general] [Lang: fr]
[Terms: Sara, Budgie, GGUF] (optional)
<raw transcript>
| Axis | Values | Default | Effect |
|---|---|---|---|
Styling |
casual · semi-casual · semi-formal · formal |
semi-formal |
Written register. Inert in this build: trained with semi-formal only |
Structure |
prose · lists |
prose |
lists allows a Markdown bullet list when the content is a real enumeration of at least three items; prose forbids bullets |
Context |
general · email |
general |
email lays the text out as a message (see Limitations) |
Lang |
fr · en |
— | Must match the file. Selects the model in Echo |
Terms |
up to 20 words | absent | Names and product words captured from the active window, spelled as they should be written |
What it does, whatever the control line
- Removes filled pauses (« euh », « bah », « hum » / "um", "uh", "er"), involuntary repetitions (« le le chat », "the the report") and false starts.
- Resolves self-corrections to the value the speaker landed on: « vendredi non pardon jeudi » → « jeudi », "forty two sorry forty three" → "43". Measured 476/476 (fr) and 474/474 (en) on the held-out sets.
- Restores punctuation and capitalization. A real question ends with a question mark (« ? » preceded by a space in French, as in the corpus: 503 occurrences with a space against 21 without); an indirect one takes a period.
- Inverse text normalization — converts the form, never the value:
| Dictated (fr) | Output | Dictated (en) | Output |
|---|---|---|---|
| « vingt-trois mille quatre cent cinquante euros » | 23 450 euros |
"twenty three thousand four hundred and fifty dollars" | $23,450 |
| « quatorze heures trente » | 14h30 |
"three fifteen p m" / "half past two" | 3:15pm / 2:30 |
| « le trois mars deux mille vingt-six » | le 3 mars 2026 |
"march third twenty twenty six" | March 3, 2026 |
| « vingt-cinq pour cent » | 25 % |
"twenty five percent" | 25% |
| « support arobase gobudgie point com » | support@gobudgie.com |
"oh seven nine one two three four five six seven eight" | 07912 345678 |
2500 personnes (already digits) |
unchanged | 2500 people |
unchanged |
Measured 794/797 (fr) and 792/798 (en) on the held-out ITN sets, 317/319 and 318/319 on compositions of two or three adjacent numbers, 237/237 (en) on self-correction × number in one sentence.
- Returns an empty string when the input is only noise or hesitations. That is a valid result, not an error; Echo keeps the raw text in that case.
- Normalizes orders and questions instead of obeying them: « écris-moi un poème sur la mer » comes out as « Écris-moi un poème sur la mer. ». A dictation is full of imperatives; this is a safety property.
- Does not translate. Islands of the other language stay as dictated.
What it never does, by construction
- Add a name, a number, an idea that is not in the input.
- Correct a number that looks wrong (it copies it), or guess a missing year, area code or domain.
- Drop a clause that carries meaning (« non », « bon », « en fait », "well", "so", "actually" are discourse markers, not corrections).
- Flip a negation, summarize, or rephrase to sound nicer.
Examples
Every output below is the real, greedy output of these exact GGUFs through
llama.cpp b10816 (examples/replay_examples.sh in the repository reproduces
them). Flaws are left in and pointed out: they are what the next build has to
fix.
French
[Styling: semi-formal] [Structure: prose] [Context: general] [Lang: fr]
euh bonjour c'est pour le le rendez-vous de de mardi non mercredi matin est-ce que dix heures ça vous va
Bonjour, c'est pour le rendez-vous de mercredi matin est-ce que 10h ça vous va ?
Fillers, stutters and the self-correction are resolved. Two flaws: no comma
or period before « est-ce que », and « dix heures » rendered as 10h where
10 heures reads better.
[Styling: semi-formal] [Structure: lists] [Context: general] [Lang: fr]
il me faut trois choses pour demain le rapport financier ensuite les slides de la présentation et puis la liste des participants
Il me faut 3 choses pour demain :
- le rapport financier
- les slides de la présentation
- la liste des participants
The list is right. Flaw: « trois choses » became 3 choses; the number rule
is applied to a small count that French would leave in letters.
English
[Styling: semi-formal] [Structure: prose] [Context: general] [Lang: en]
hi um its about the the meeting on tuesday no wednesday morning does ten work for you
It's about the meeting on Wednesday morning does 10 work for you.
Two flaws: the greeting "hi" was dropped, and the question was not split off nor given its "?".
[Styling: semi-formal] [Structure: lists] [Context: general] [Lang: en]
i need three things for tomorrow the financial report then the slides for the presentation and the list of attendees
I need:
- The financial report
- The slides for the presentation
- The list of attendees
The list is right. Flaw: "three things for tomorrow" was dropped from the lead-in, a suppression the guard rails in Echo would catch on a longer take.
Both
[Styling: semi-formal] [Structure: prose] [Context: general] [Lang: fr]
euh hum euh
Empty output: valid, the input carried nothing. And an order is normalized, not obeyed: "write me a poem about the sea" → "Write me a poem about the sea."
Deployment
llama.cpp — see Quickstart. The three flags that matter: --jinja (the
chat template is in the GGUF metadata), enable_thinking: false (Qwen3 would
otherwise emit a reasoning block), --temp 0 (the models expect greedy
decoding; sampling adds variance and invents).
Ollama — this repository holds two GGUFs of the same quantization, so point Ollama at the file rather than the repo:
hf download flowcorp-ch/BudgieScribe-Nano BudgieScribe-Nano-fr-Q4_K_M.gguf --local-dir .
printf 'FROM ./BudgieScribe-Nano-fr-Q4_K_M.gguf\nPARAMETER temperature 0\nPARAMETER top_k 1\n' > Modelfile
ollama create budgiescribe-nano-fr -f Modelfile
Then call the API with "think": false and the system prompt from Quickstart.
LM Studio — load the GGUF, turn reasoning off, set temperature to 0.
Budgie Echo — nothing to do: Echo downloads these exact files (same SHA-256) from its own catalog under Settings → Text enhancements → Automatic cleanup, and routes to the French or English file by the detected language of the take.
Echo command line — the same runtime and guard rails as the app, from a terminal. On an Apple silicon Mac:
brew install alexxxcoelho/budgie/echo-cli
echo-cli login
echo-cli scribe --language fr < transcript.txt
Update it later with brew update && brew upgrade echo-cli.
Best practices
These are the rules Budgie Echo applies around the models, and the reasons.
- Greedy decoding, always.
temperature 0,top_k 1. The models were evaluated greedy; every measurement below assumes it. - Cap the output at
ceil(1.3 × input_tokens) + 32tokens. A normalizer that produces much more than its input is looping. - Chunk long inputs at ~1,200 bytes, on a sentence boundary. The models were trained on dictation-sized units (median ~75 words); a 10-minute take pushed whole into the context degrades.
- Verify the output before trusting it. Echo's runtime rejects an output and keeps the raw transcript when it detects an invention (a number absent from the input), a loop, a large suppression, a length drift, or a flipped negation. Over 260 real takes, that guard fired 21 times. Reproduce at least the length and loop checks.
- Send the transcript alone. No instructions, no examples, no free text before the control line: the model would normalize them.
Evaluation
Held-out literal scoring on synthetic sets, then real dictations through the production path. The method is in EVALUATION.md; the sets are flowcorp-ch/BudgieScribe-eval.
Held-out synthetic sets (deterministic generators, expected output known
to the character). These tables were measured on the previous builds of the
same recipe, scribe-v8 and scribe-en-v5; scribe-v9 / scribe-en-v7
add the phase-3 axes (French paragraphs, Context: email layout, embedded
amounts, [Terms:]), and their own tables replace these as soon as they are
run. Until then, read them as the floor this line of models has held, not as
a measurement of these bytes.
| Axis | fr cases | fr exact | en cases | en exact |
|---|---|---|---|---|
| Formatting blocks | 635 | 635 | 634 | 634 |
| Self-corrections | 476 | 476 | 474 | 474 |
| Inverse text normalization | 797 | 794 | 798 | 792 |
| Composition (2–3 adjacent numbers) | 319 | 317 | 319 | 318 |
| Self-correction × number in one sentence | — | — | 237 | 237 |
| Wrong numeric value, all held-out cases | — | — | 2,462 | 7 (0.3 %) |
Blind pairwise A/B against the base Qwen3-0.6B on 80 held-out real French
units (LLM judge, mirrored order, forced ties): 37 wins / 30 losses, the rest
ties. VoxPopuli, 170 held-out English units, word accuracy against the
official transcript: 93.9 % (the gap is entirely the 17 units run with
[Context: email], see Limitations).
Real dictations (the author's own takes through Budgie Echo's local ASR and the production runtime). French: numbers, dates and amounts, punctuation, and no hallucination on noise, where the raw engine invents; observed failure modes on colloquial French are occasional one-word substitutions that read fluently (« t'en es où là ? » → « tu es là ? »), dropped intent markers (« non, non, non »), register changes (« mec » → « homme ») — errors of meaning, invisible on a re-read, that the guard rails do not catch. English: better than raw on numbers, dates and amounts; weaker on false starts and paragraph breaks.
Limitations
Observed on scribe-v8 / scribe-en-v5. The ones marked phase-3 target
are what v9 / en-v7 were trained to fix; they stay listed until their
held-out tables say so.
Both languages:
Stylingis inert: trained onsemi-formalonly.Context: emailadds a greeting and a sign-off that were not dictated (phase-3 target). Usegeneralunless you post-check.- Phone numbers dictated with « double » / « triple » can lose or repeat a digit (en: 32/36).
- One language per file. Mixed-language takes are handled sentence by sentence by Echo, not by the models.
French:
- No paragraph breaks: a long take comes out as one block (phase-3 target).
- One-word substitutions on colloquial French (see Evaluation).
- Small counts written as digits (« trois » →
3).
English:
- "like" as a filler is kept; "gonna" becomes "I'll" instead of "going to"; British spellings are americanized ("organisations" → "organizations").
- Amounts embedded mid-sentence can lose the symbol (phase-3 target) ("the twelve hundred dollars a month" → "1,200 dollars a month").
- One wrong value in 798 ("… and nineteen pounds" read as pence).
Training
Full supervised fine-tune of Qwen/Qwen3-0.6B (no LoRA), fp32 weights with
bf16 autocast, fused AdamW, lr 1e-5, cosine schedule with 6 % warmup, batch 4,
gradient accumulation 2, 2 epochs, max length 512, labels masked on the prompt,
gradient clipping 1.0. French: 38,042 training units, 9,512 optimizer steps,
61 minutes on a single 32 GB GPU. English: 35,306 units, 8,828 steps, 65
minutes. run.json ships with each checkpoint. The script is standard
transformers + torch and runs on any 16 GB GPU or on Hugging Face Jobs for
about a dollar; the nano profile of scribe/entrainement/train.py is this
exact recipe.
Training mix, French: raw-to-clean pairs produced by a local teacher model from dictation-sized units of the SUMM-RE corpus, filtered by a binary quality gate and adjudicated by reading (~14 % of the mix), plus deterministic synthetic pairs for what real speech does not contain enough of: number writing, speaker self-corrections, formatting blocks, compositions. English: 10,000 number-writing pairs + 8,000 formatting + 6,000 self-corrections + 4,000 compositions + 3,000 self-correction × number + 2,000 paragraphs, all deterministic synthetic pairs, plus 1,382 real pairs cut from VoxPopuli (CC0), teacher-cleaned and adjudicated.
The whole pipeline (corpus preparation, generators, teacher, quality gate, training profiles, GGUF conversion, benches) is published: github.com/alexxxcoelho/budgie-scribe. The derived corpus (pairs, units, audio cuts) is not distributed, by license (see NOTICE §2). The synthetic held-out sets are published as flowcorp-ch/BudgieScribe-eval so that any change can be measured the same way.
No personal data: every data set is scanned before training, and the dictations of Budgie users, including the author's, were excluded from these builds.
License
BudgieScribe is released under the Apache License 2.0, which it inherits from Qwen3-0.6B, plus one additional term: any use, distribution, or integration of these models, whether unmodified or as part of a derivative work or product, must continue to identify them by their original name, "BudgieScribe" by "Budgie", using that exact capitalization.
The full text is in LICENSE-MODEL; NOTICE lists the attributions (SUMM-RE by LINAGORA, ANR-20-CE23-0017; VoxPopuli; Qwen3) and states the position taken on training-data licensing.
Citation
@misc{budgiescribe2026,
title = {BudgieScribe: open-weights dictation normalizers for French and English},
author = {Coelho, Alexandre and Budgie},
year = {2026},
url = {https://huggingface.co/flowcorp-ch/BudgieScribe-Nano}
}
Please also cite SUMM-RE (LINAGORA, ANR-20-CE23-0017) when you build on the French model.
- Downloads last month
- 45
4-bit