Starlings.Tokenizers
0.3.2
dotnet add package Starlings.Tokenizers --version 0.3.2
NuGet\Install-Package Starlings.Tokenizers -Version 0.3.2
<PackageReference Include="Starlings.Tokenizers" Version="0.3.2" />
<PackageVersion Include="Starlings.Tokenizers" Version="0.3.2" />
<PackageReference Include="Starlings.Tokenizers" />
paket add Starlings.Tokenizers --version 0.3.2
#r "nuget: Starlings.Tokenizers, 0.3.2"
#:package Starlings.Tokenizers@0.3.2
#addin nuget:?package=Starlings.Tokenizers&version=0.3.2
#tool nuget:?package=Starlings.Tokenizers&version=0.3.2
Starlings.Tokenizers
Hugging Face tokenizer.json files in pure .NET, with the same token ids, offsets and decoded text as the Python and Rust tokenizers library, checked case by case.
using Starlings.Tokenizers;
Tokenizer tokenizer = Tokenizer.FromFile("tokenizer.json");
TokenEncoding encoding = tokenizer.Encode("Hello, world!");
string text = tokenizer.Decode(encoding.Ids.AsSpan(), skipSpecialTokens: true);
- Faithful. Every supported tokenizer has a profile: a pinned
tokenizer.json(full commit SHA and SHA-256) with reference outputs from huggingface/tokenizers for multilingual text, emoji, combining marks, control characters, pairs, truncation and padding. CI fails on any difference. - Explicit. A
tokenizer.jsonthat uses a component this library does not implement fails at load withUnsupportedTokenizerComponentException, naming the JSON path. Nothing is approximated, and unknown fields are rejected rather than ignored. - Plain .NET. No native code, no package dependencies,
net10.0. Instances are immutable and thread-safe. A 17 MB vocabulary loads in about 0.27 s, about half the time the Rust library takes on the same machine.
Part of Starling, .NET implementations of AI models with reproducible evidence of what works.
0.x. The public API can still change between minor versions. A profile's status is in its file under
profiles/; the Starling model profiles that use a profile pin the exact tokenizer version they were qualified with.
Install
dotnet add package Starlings.Tokenizers
Usage
using Starlings.Tokenizers;
Tokenizer tokenizer = Tokenizer.FromFile("tokenizer.json") // also FromStream, FromUtf8Json
.WithTruncation(new TruncationOptions(MaxLength: 512))
.WithPadding(new PaddingOptions(PadId: 1, PadToken: "<pad>")); // no FixedLength: pad to the batch's longest
TokenEncoding one = tokenizer.Encode("query: how much protein should a female eat");
TokenEncoding pair = tokenizer.Encode("What is the capital of France?", "Paris is the capital of France.");
IReadOnlyList<TokenEncoding> batch = tokenizer.EncodeBatch(["first text", "second, longer text"]);
int[] ids = [.. one.Ids]; // also Tokens, TypeIds, AttentionMask, SpecialTokensMask, SequenceIds
TokenOffset span = one.Offsets[1]; // UTF-16 code units: slice the C# string with these
TokenOffset scalars = one.ScalarOffsets[1]; // Unicode scalar values: the unit Python tokenizers reports
string decoded = tokenizer.Decode(one.Ids.AsSpan(), skipSpecialTokens: true);
int? eos = tokenizer.TokenToId("</s>");
WithTruncationandWithPaddingreturn new instances that share the loaded pipeline. Without them, the file's owntruncationandpaddingsections apply.Encode(text, addSpecialTokens: false)skips the post-processor's special tokens. Special tokens written in the input text are still matched as added tokens.- Input containing unpaired UTF-16 surrogates is rejected with
ArgumentException. tokenizer.Componentslists the pipeline stages the file uses, for examplemodel:BPE.
Supported tokenizers
A model is supported when its tokenizer.json uses only supported components. A profile is the evidence: one pinned file and the cases it matches.
| Profile | Model | Algorithm | Evidence |
|---|---|---|---|
xlmr-unigram-e5 |
intfloat/multilingual-e5-small |
SentencePiece Unigram | 49/49 cases exact, with truncation and padded batch |
gliner2-base-v1-unigram |
fastino/gliner2-base-v1 |
SentencePiece Unigram (DeBERTa-v3) | per-word and 10 whole-text cases; offsets, pairs and decode untested |
qwen2-bpe-kev |
jaredpalmer/kev-0.8b (Qwen2/Qwen3 regex) |
byte-level BPE | 137/137 cases exact, 0 mismatches in 1.15 M randomized encodes |
qwen35-bpe-chat |
Qwen/Qwen3.5-0.8B |
byte-level BPE | 137/137 cases exact, 0 mismatches in 1.15 M randomized encodes |
gemma-bpe-embeddinggemma2 |
google/embeddinggemma-2 |
SentencePiece-style BPE, byte fallback | 49/49 cases exact, 0 mismatches in 1.7 M randomized encodes |
All five are experimental. BERT-family WordPiece files (for example sentence-transformers/all-MiniLM-L6-v2 and BAAI/bge-small-en-v1.5) load and pass component-level reference cases, but have no profile yet. Other files may load and work too. Without a profile, matching the reference is untested, not promised.
The full list of components and options, and what fails at load, is in docs/supported-components.md. Not offered: pre-tokenized input, word ids, overflowing windows (truncation stride), incremental (streaming) decode, and chat templates.
Need a tokenizer that is not here? Open a tokenizer request with the error Tokenizer.FromFile gives you.
Documentation
| Page | Contents |
|---|---|
| Supported components | Every tokenizer.json component and option, byte fallback and regex details |
| Adding a tokenizer | From a new model's tokenizer.json to a released profile |
| Architecture | How the interpreter is built and where each stage lives |
| Performance | Load and encode measurements against the Rust library |
| Releasing | Versions, the tag-to-NuGet workflow, one-time setup |
| Changelog | What changed in each version |
llms.txt |
A compact guide for language models and coding assistants using this library |
Contributing
See CONTRIBUTING.md. Coding agents should read AGENTS.md first.
License
Copyright (c) 2026 StarlingHq. Licensed under either of
at your option. Use it in open-source or commercial software, modify it, and ship it without releasing your own code. Apache-2.0 adds an explicit patent grant. Unless you state otherwise, any contribution you submit for inclusion is dual-licensed the same way, with no additional terms.
Some files are ported or adopted from huggingface/tokenizers, SentencePiece and spm_precompiled (Apache-2.0), dotnet/machinelearning (MIT), darts-clone (BSD 2-Clause), serde_json and unicode-normalization-alignments (MIT OR Apache-2.0), and Unicode data (Unicode License V3). All of these are permissive, and none of them adds conditions beyond keeping their notices. The notices are in THIRD-PARTY-NOTICES.md, which ships inside the package, so distributing the package as-is satisfies them. File-by-file origins are in PROVENANCE.md. Each model's tokenizer.json keeps its owner's terms and is never included in the package.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (7)
Showing the top 5 NuGet packages that depend on Starlings.Tokenizers:
| Package | Downloads |
|---|---|
|
Starlings.Generation.OnnxGenAI
Text generation on ONNX Runtime GenAI 0.17.1 behind a Starling adapter: model loading with explicit provider selection (no silent fallback, TF32 off by default), runtime config overlays, reference-counted disposal, and an owned decode loop over pre-tokenized ids (greedy or seeded sampling, max new tokens, stop token ids and stop strings, streaming with UTF-8-safe incremental detokenization through the owned tokenizer Starlings.Tokenizers, cancellation between decode steps, usage accounting). References only Microsoft.ML.OnnxRuntimeGenAI.Managed: the application adds Microsoft.ML.OnnxRuntimeGenAI (CPU) or Microsoft.ML.OnnxRuntimeGenAI.Cuda. Maturity is per model profile (Stable, Preview or Experimental): see the README, generated from the model registry. |
|
|
Starlings.Models.Qwen35
Qwen/Qwen3.5-0.8B (revision 2fc06364) chat generation in-process on ONNX Runtime GenAI 0.17.1: the pinned chat template rendered in C# for text and tool-calling conversations (system, user, assistant and tool messages, tool definitions and calls, thinking switch; images rejected), a parser for the template's tool-call format (whole or streamed), prompt ids from the owned tokenizer (Starlings.Tokenizers profile qwen35-bpe-chat: no Microsoft.ML.Tokenizers, no GenAI tokenizer), and Starling's decode loop (greedy or seeded sampling, stop tokens and strings, streaming, cancellation between steps, usage). Ships the asset lock, not the weights. Profiles qwen3.5-0.8b/ortgenai-fp32x (CPU; CUDA with TF32 off) and ortgenai-fp16x (CUDA), Linux x64, Stable. The application adds Microsoft.ML.OnnxRuntimeGenAI or Microsoft.ML.OnnxRuntimeGenAI.Cuda. Maturity is per model profile (Stable, Preview or Experimental): see the README, generated from the model registry. |
|
|
Starlings.Models.EmbeddingGemma2
google/embeddinggemma-2 (revision 914f7f89) text and image embeddings on ONNX Runtime, from text through the owned tokenizer (Starlings.Tokenizers, profile gemma-bpe-embeddinggemma2: no Microsoft.ML.Tokenizers, no native tokenizer) or from token ids: right-padded batching, mean pooling over every token including the prompt, L2 normalization, Matryoshka sizes 768/512/256/128, explicit named prompts (never added silently), inputs above 8,192 tokens rejected. Images: image-only and interleaved text-and-image embeddings from already-decoded RGB (no native dependency; the upstream processor restated bit for bit, including PyTorch's uint8 antialiased bicubic resize), default budget 280 soft tokens, vision graph plus multimodal text graph; text-only input keeps the released text graph. Videos: video-only and interleaved text/image/video embeddings from decoded RGB frames at the checkpoint settings (1 fps, at most 32 frames, 140 soft tokens per frame, no timestamps; upstream sampling restated exactly; frames without timing rejected unless opted in), same graphs; decoding is the optional FFmpeg adapter. Audio is not supported. Ships the asset locks (Starling's ONNX graphs and the pinned tokenizer.json), not the weights; acquire them explicitly. Profiles embeddinggemma-2/onnx-fp32-cpu, onnx-fp32-cuda, image-fp32-cpu, image-fp32-cuda, video-fp32-cpu and video-fp32-cuda (Linux x64). Apache-2.0 weights; deployments must adhere to the Gemma Prohibited Use Policy. The application adds the ONNX Runtime native package. Maturity is per model profile (Stable, Preview or Experimental): see the README, generated from the model registry. |
|
|
Starlings.Models.E5
intfloat/multilingual-e5-small (revision 614241f6) sentence embeddings on ONNX Runtime, from text through the owned tokenizer (Starlings.Tokenizers: no Microsoft.ML.Tokenizers, no native tokenizer) or from token ids: right padding, mean pooling, L2 normalization. Ships the model's asset lock, not the weights; acquire them explicitly. Profiles multilingual-e5-small/onnx-fp32-cpu and onnx-fp32-cuda. The application adds the ONNX Runtime native package. Maturity is per model profile (Stable, Preview or Experimental): see the README, generated from the model registry. |
|
|
Starlings.Models.Gliner2
fastino/gliner2-base-v1 (revision f9634218, GLiNER2 2.0.0) English entity extraction with labels and a threshold on ONNX Runtime: GLiNER2's Python text semantics (normalization, word splitter, lower-casing) and schema prefix through the owned tokenizer (Starlings.Tokenizers: no Microsoft.ML.Tokenizers, no native tokenizer), one ONNX graph, GLiNER2's span decoding, offsets into the original text. Ships the asset lock, not the weights; acquire them explicitly. Profiles gliner2-base-v1/onnx-fp32-cpu and onnx-fp32-cuda. The application adds the ONNX Runtime native package. Maturity is per model profile (Stable, Preview or Experimental): see the README, generated from the model registry. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.3.2 | 88 | 10/21/2026 |
| 0.3.2-preview.1 | 41 | 10/21/2026 |
| 0.3.1 | 118 | 10/19/2026 |
| 0.3.1-preview.1 | 47 | 10/19/2026 |
| 0.3.0 | 799 | 10/17/2026 |
| 0.3.0-preview.1 | 1,774 | 10/13/2026 |