Skip to content
Michael-A-KuykendallPublic

About

Pure Rust GGUF tokenizer: 100% llama.cpp parity, zero C/C++ FFI, zero unsafe, WASM-ready. Free forever.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

25 stars

Watchers

1 watching

Forks

Latest commit

Β 

History

76 Commits

Folders and files

shimmytok - Pure Rust tokenizer for GGUF models

Pure Rust tokenizer for GGUF models

100% llama.cpp compatible β€’ zero C++ β€’ just works

License: MIT Trans rights LGBTQ+ friendly Crates.io Rust πŸ’ Sponsor


shimmytok is free forever. MIT licensed, no strings attached.

πŸ’ If shimmytok helps you, consider sponsoring.

πŸ’ Support shimmytok

πŸš€ 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)


✨ What is shimmytok?

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.

Why does this matter?

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.

🎯 v0.8.0 Highlights

This release makes the batch engine portable and deterministic without breaking any Stability-guaranteed API:

  • βœ… Optional Rayon β€” parallel feature (default on) makes Rayon an optional dependency; --no-default-features and 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_batch returns the lowest failing input index, identical across both backends.
  • βœ… get_token β€” exact-match single-token lookup, like candle's TokenOutputStream.
  • βœ… llama.cpp tokenizer support β€” SPM, BPE, WPM validated token-for-token; SPM, BPE, WPM, RWKV, and UGM validated; 41 BPE pre-tokenization patterns.

Features

  • πŸ¦€ 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

Installation

[dependencies]
shimmytok = "0.8"

Quick Start

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)?);
}

Validated Models

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

Tokenizer Algorithms

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

BPE Pre-tokenization Patterns

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...

API Reference

Core Methods

// 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)?;

Metadata

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 & Advanced

// 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

Use Cases

  • 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

Performance

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.

Links

  • πŸ“– CHANGELOG β€” Version history
  • πŸ—ΊοΈ ROADMAP β€” Future plans
  • 🀝 CONTRIBUTING β€” How to contribute
  • πŸ”’ SECURITY β€” Vulnerability reporting
  • πŸ“š docs.rs β€” API documentation

Related Projects

  • llama.cpp β€” Reference C++ implementation
  • GGUF spec β€” File format documentation

License

Dual-licensed MIT OR Apache-2.0 β€” free forever, no strings attached.


Maintainer: Michael A. Kuykendall
Mission: Pure Rust tokenization for the LLM ecosystem

Support

This project is a safe space. Trans rights are human rights.

If you or someone you love needs support:

About

Pure Rust GGUF tokenizer: 100% llama.cpp parity, zero C/C++ FFI, zero unsafe, WASM-ready. Free forever.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

25 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages