shimmytok is free forever. MIT licensed, no strings attached.
π If shimmytok helps you, consider sponsoring.
π If shimmytok helps you, consider sponsoring β 100% of support goes to keeping it free forever.
- $5/month: Coffee tier β β Eternal gratitude + sponsor badge
- $25/month: Bug prioritizer π β Priority support + name in SPONSORS.md
- $100/month: Corporate backer π’ β Logo placement + monthly office hours
- $500/month: Infrastructure partner π β Direct support + roadmap input
π― Become a Sponsor | See our amazing sponsors π
Thank you to our sponsors: ZephyrCloudIO (Corporate backer) Β· alistairheath (Coffee tier)
shimmytok is a pure Rust tokenizer library that reads tokenizers directly from GGUF model files. No Python, no C++, no separate tokenizer files β just point it at your .gguf and go.
When you download a GGUF model, the tokenizer is embedded inside. Most Rust projects either:
- Bind to C++ (llama.cpp FFI) β adds build complexity
- Use separate tokenizer files β requires extra downloads
- Roll their own β risk of incompatibility
shimmytok extracts and runs the tokenizer directly from your GGUF file, producing identical output to llama.cpp.
This release makes the batch engine portable and deterministic without breaking any Stability-guaranteed API:
- β
Optional Rayon β
parallelfeature (default on) makes Rayon an optional dependency;--no-default-featuresand WASM/WASI build with a sequential backend and identical, deterministic results. - β
Immutable, lock-free BPE β regexes and merge ranks prepared once at
construction; no per-encode
Mutex. - β
Deterministic batch errors β
encode_batchreturns the lowest failing input index, identical across both backends. - β
get_tokenβ exact-match single-token lookup, like candle'sTokenOutputStream. - β llama.cpp tokenizer support β SPM, BPE, WPM validated token-for-token; SPM, BPE, WPM, RWKV, and UGM validated; 41 BPE pre-tokenization patterns.
- π¦ Pure Rust β No C++ dependencies, compiles anywhere
- π¦ Load from GGUF β Tokenizer embedded in model file
- β Validated β SPM, BPE, WPM, RWKV, and UGM tested token-for-token against llama.cpp
- β‘ Fast β Batch encoding with optional Rayon parallelism for large workloads
- π Streaming β Token-by-token decoding for LLM output
- π Safe β Zero unsafe code in critical paths
[dependencies]
shimmytok = "0.8"use shimmytok::Tokenizer;
// Load tokenizer from any GGUF model
let tokenizer = Tokenizer::from_gguf_file("llama-3.gguf")?;
// Encode text to tokens
let tokens = tokenizer.encode("Hello, world!", true)?;
println!("Tokens: {:?}", tokens);
// Decode back to text
let text = tokenizer.decode(&tokens, true)?;
println!("Text: {}", text);
// Stream tokens one at a time (for LLM generation)
for token_id in tokens {
print!("{}", tokenizer.decode_single(token_id, false)?);
}All models produce exact token match with llama-tokenize:
| Model | Tokenizer | Status |
|---|---|---|
| llama-spm | SentencePiece | β Match |
| gpt-2 | BPE | β Match |
| qwen2 | BPE | β Match |
| starcoder | BPE | β Match |
| deepseek-coder | BPE | β Match |
| deepseek-llm | BPE | β Match |
| falcon | BPE | β Match |
| command-r | BPE | β Match |
| refact | BPE | β Match |
| bert-bge | WordPiece | β Match |
shimmytok implements all tokenizer types from llama.cpp:
| Type | Algorithm | Models |
|---|---|---|
| SPM | SentencePiece with resegment | LLaMA, Mistral, Gemma |
| BPE | Byte-Pair Encoding + regex pre-tokenization | GPT-2, Qwen, StarCoder, DeepSeek |
| WPM | WordPiece (BERT-style) | BERT, BGE embeddings |
| UGM | Unigram (Viterbi DP) | T5, mT5 |
| RWKV | Trie-based greedy | RWKV World |
shimmytok supports 41 different regex patterns for BPE pre-tokenization, covering:
- GPT-2/GPT-3/GPT-4 style
- Llama-3 style
- Qwen/Qwen2 style
- DeepSeek (coder + LLM variants)
- StarCoder/StarCoder2
- Falcon, Command-R, DBRX
- And many more...
// Load from GGUF file
let tokenizer = Tokenizer::from_gguf_file("model.gguf")?;
// Encode text β tokens
let tokens = tokenizer.encode("Hello", true)?; // true = add BOS/EOS
// Decode tokens β text
let text = tokenizer.decode(&tokens, true)?; // true = skip special tokens
// Streaming decode (for LLM generation)
let piece = tokenizer.decode_single(token_id, false)?;tokenizer.vocab_size() // β usize
tokenizer.bos_token() // β TokenId
tokenizer.eos_token() // β TokenId
tokenizer.model_type() // β &str ("llama", "gpt2", etc.)
tokenizer.pre_type() // β Option<&str> (pre-tokenization pattern)// Batch encoding β always available; large native batches run in parallel
let batch = tokenizer.encode_batch(&["text1", "text2"], true)?;
// Exact-match single-token lookup (like candle's TokenOutputStream)
let maybe_id = tokenizer.get_token("<|endoftext|>"); // β Option<TokenId>
// Token introspection
tokenizer.token_to_piece(token_id)? // β Result<String, Error>
tokenizer.token_type(token_id) // β TokenType
tokenizer.is_special_token(token_id) // β bool- LLM Inference Engines β Pure Rust inference without C++ bindings
- WASM Applications β Run tokenization in the browser
- Embedded Systems β No C++ toolchain required
- CLI Tools β Inspect and debug GGUF tokenizers
- Research β Understand tokenization without black boxes
shimmytok prioritizes correctness over speed, but it's still fast:
- Immutable per-model BPE state (regexes and merge ranks prepared once, no per-encode locks)
- Batch encoding that dispatches to Rayon only when the workload is large enough
to outweigh scheduling overhead (measured crossover β see
benches/tokenization.rs); smaller batches,--no-default-features, and WASM/WASI run sequentially - Efficient trie structures for UGM/RWKV
Batch results are always deterministic and order-preserving regardless of backend. For most use cases, tokenization is not the bottleneck β inference is.
- π CHANGELOG β Version history
- πΊοΈ ROADMAP β Future plans
- π€ CONTRIBUTING β How to contribute
- π SECURITY β Vulnerability reporting
- π docs.rs β API documentation
Dual-licensed MIT OR Apache-2.0 β free forever, no strings attached.
Maintainer: Michael A. Kuykendall
Mission: Pure Rust tokenization for the LLM ecosystem
This project is a safe space. Trans rights are human rights.
If you or someone you love needs support:
- The Trevor Project β 24/7 for LGBTQ+ young people. Call 1-866-488-7386 or text START to 678-678
- Trans Lifeline β peer support run by and for trans people. US: 877-565-8860
- 988 Suicide & Crisis Lifeline β call or text 988
