~/satyajit

Flint: 125 tokens a second is what 2.5B active parameters buy at 273 GB/s

mdjsonmcp

2026-10-23 · 19 min · mixture-of-experts · agentic-coding · on-device · apple-silicon · quantization · kv-cache · inference · benchmarks

A 1:44 narrated explainer, drawn in code. Every number and picture in it is this article's own; the sources are below.

› transcript

Hi, I'm Pawl! Flint is Recursive's first model, a mixture of experts for coding on your own machine. Here is why it is fast. The idea: every new token streams its weights through memory. So speed is bandwidth divided by bytes, and Flint is built to read fewer bytes. A token enters attention, which reads the cache earlier tokens left. A router scores two hundred fifty six small experts and wakes only six. The rest are never loaded. The output head turns that into the next token. Recursive stores even the head in four bits. Each token touches two and a half billion parameters, out of almost forty billion. Thirty five layers only look back over a short window, so their cache stops growing. Fourteen layers see the whole context, so their cache grows with every token. Divide them and the ceiling is about one hundred eighty tokens a second. An M4 Pro moves two hundred seventy three gigabytes a second. Flint's four bit weights cost about one and a half gigabytes per token, plus the cache. Recursive reports about one hundred thirty one with its own engine. On another engine the same model is much slower, so part of the speed is the kernels. Fit Recursive's whole curve to that formula and the engine holds about two hundred gigabytes a second at every context length. Once the active body is small, the output head and the cache are what is left to shrink. Flint shrinks both. Six of two hundred fifty six experts, a four bit head, short windows. Speed is bandwidth over bytes. Every source is in the full article. I'm Pawl. Bye!

Why read this

Notabletop 60%

Counts Flint's 2.5B active from its headers, then fits Recursive's own throughput curve to one bandwidth model: about 200 GB/s at every context length.

  • Original analysis
  • Widely used
  • Concrete numbers to act on

Inference & servingNeeds a workstation GPUApache-2.0Practitioner model

How this was scored
Is it new?
1 of 3: An incremental tweak
Can I trust it?
2 of 3: Measures key facts from files, code or configs
Can I run it?
2 of 3: Open code or weights with real limits
Will I understand it?
2 of 3: Mechanism from first principles with figures
Can I act on it?
2 of 3: A concrete recipe, numbers or comparison
Will it last?
1 of 3: Relevant for months
Does it affect many?
2 of 3: A widely used model, tool or lab release
Only here?
2 of 3: A teardown or measurement few others did

Score 63 of 100, ranked 246 of 577 rated articles. Each question is answered 0–3 by hand, and a 3 is rare. How articles are scored

Richard Socher introduced Flint as Recursive's first model: "a fast local coding model built with our automated research system, the Eureka Machine", with "125+ tokens/sec on a MacBook Pro, 150+ on RTX Spark", "up to 2x faster than comparable models", and "built from scratch in under 4 months". Unsloth followed with Dynamic GGUFs, calling it "the strongest MoE model under 50B parameters" that runs "on 24GB RAM".

Four claims, then: a speed, a ranking, a provenance and a method. The speed one is the one I can check most completely, because decode speed on a laptop is arithmetic. Here is what I found, with every number labelled measured (I computed it from a published file), reported (Recursive's or Unsloth's figure, not re-run) or reasoned (my arithmetic on the other two). I did not run the model: the BF16 checkpoint needs a B300 or H200, and the 4-bit builds need a Mac or an NVIDIA GPU this machine does not have.

ClaimWhat the files say
39.8B total, 2.5B activeHolds. Measured 39,785,287,456 parameters in the headers; 2,515,488,544 active per token including the output head.
125+ tok/s on an M4 ProPlausible to the decimal. Recursive's published curve implies a steady ~200 GB/s, 73% of the chip's 273 GB/s, from 1K to 252K tokens of context (reasoned).
Up to 2x faster than comparable models2.00x against Qwen3.6 35B-A3B on the M4 Pro, with Flint on Recursive's own engine. Same engine on both sides (llama.cpp on RTX Spark), it is 1.33x (reasoned from reported numbers).
Best MoE under 50B on agentic codingAgainst three named MoE peers, on Recursive's chart. Leads five of six columns; loses LiveCodeBench v6 to Qwen 3.6 by 0.1 and wins SWE-bench Verified by 0.8 (reported).
Built from scratchNothing in the files contradicts it: a new tokenizer, and no row of its attention weights matches the closest Qwen shape (measured). That is not proof.
The Eureka Machine did itThree contributions are named. No logs, ablations or code for the system are published.
RecursiveSI/flint@2a247be · snapshot 2026-10-23
parameters
39.79B
repo size
79.59 GB
architecture
FlintForCausalLM
task
text-generation
library
transformers
license
apache-2.0
safetensors
15 shards
largest file
5.37 GB
files
37
downloads
420
likes
564
parameters by dtype
BF1639.79B

repo last modified 2026-10-21

The shape, read from the headers

A safetensors file starts with an 8-byte length and a JSON header listing every tensor's name, dtype and shape, so fifteen range requests give the model's anatomy without the 80 GB of weights.

Measured: 36,734 tensors, all BF16, 39,785,287,456 parameters, which is the 39.8B on the card. The config matches the card's specification table: 49 layers, the first 2 dense and the other 47 MoE; hidden size 2,048; 32 query heads and 4 key-value heads of dimension 128; 256 routed experts of width 512 per MoE layer, 6 selected per token, plus a shared expert of width 1,024; a 150,144-entry vocabulary with untied input and output matrices.

The attention is a hybrid. 35 layers use a sliding window of 513 tokens (the current token and 512 before it) with RoPE; 14 layers attend to the whole context with no positional encoding at all. Every layer has per-head QK RMSNorm and learned per-head attention sinks, which show up in the headers as a 32-value softmax_offset tensor per layer. The router uses a sigmoid score, like DeepSeek-V3's, and there is no bias-correction tensor beside it.

Where the parameters sit (measured, from the headers):

GroupParametersRead per token
Routed experts (47 layers x 256 x 3 matrices)37.85B6 of 256: 887M
Attention projections (49 layers)925Mall
Output head307.5Mall
Input embedding307.5Mone row
Shared experts, 2 dense MLPs, routers, norms396Mall

Add the "read per token" column and you get 2,515,488,544 active parameters with the output head and 2,207,993,632 without it. The card says "approximately 2.5B, including the output head" and "approximately 2.2B" for the body. Both hold to the parameter.

Two things in that table drive the rest of this article. The experts are 95% of the model and 35% of what each token touches; that is the point of an MoE. And the output head is 12% of the active parameters on its own, because the body is small and the vocabulary is not. Recursive's quantization story starts there.

Why active parameters set the speed

At batch size 1, one token is one forward pass of matrix-vector products: each weight is loaded, used for one multiply-add, and dropped. The chip can compute far faster than it can fetch, so it waits on memory, and the speed limit is

tokens/s≤memory bandwidthbytes of weights read per token+bytes of KV cache read per token\text{tokens/s} \le \frac{\text{memory bandwidth}}{\text{bytes of weights read per token} + \text{bytes of KV cache read per token}}

Total parameters decide whether the model fits. Active parameters decide how fast it runs. A 40B MoE that reads 2.5B per token runs like a 2.5B dense model, as long as all 40B are resident.

The weight term depends on the format. Recursive's Apple build, RecursiveSI/flint-int4, is MLX group-64 affine INT4: each group of 64 weights stores 4-bit codes plus a BF16 scale and a BF16 offset, 4.5 bits per weight. Its headers (measured) show the output head at 4 bits too (lm_head.weight is 1,024 bytes per row of 2,048 values), the embeddings at 8 bits and the router left in BF16. Summing what one token touches, with 6 of 256 experts counted per layer and one embedding row:

Group (INT4 build)MB read per token
Attention projections520
Routed experts499
Shared experts, dense MLPs, routers, norms, one embedding row259
Output head173
Total1,451

That is the "against common practice" choice in Recursive's post: most quantization recipes leave the output head in 16 bits. Left in BF16 it would be 615 MB, and every token would read 1.89 GB instead of 1.45 GB (reasoned), about 30% more. Recursive says it recovered the accuracy with an offline distillation stage on the model's own pre-sampled responses, with the 16-bit model as teacher. Its summary: "The final NVFP4 model scores within 0.7 points of the 16-bit model across our benchmarks." The chart below has both checkpoints: the six differences average 0.60 points (reasoned from reported), the largest single drop 1.2. The NVFP4 GGUF for NVIDIA quantizes the output head as well; its header lists output.weight in the NVFP4 type (measured).

The KV term grows with context. Each full-attention layer keeps a key and a value per token: 4 heads x 128 dims x 2 bytes x 2 = 2,048 bytes. Fourteen such layers make 28,672 bytes per token of context (reasoned from the config). The 35 sliding-window layers never hold more than 513 positions, about 36.8 MB in total however long the session gets. At 1K tokens of context the KV read is 66 MB, noise next to 1,451 MB of weights. At 128K it is 3.8 GB, more than twice the weights.

The calculator does the division for a few chips. Pick a format, a context length and an engine efficiency (the share of the chip's peak bandwidth the kernels achieve). The filled dots are Recursive's own numbers for its rec engine on an M4 Pro, read off the chart in the rec README; the hollow ones are llama.cpp on the same Mac.

Checking 125 tokens a second

Apple specifies the M4 Pro at 273 GB/s. At 1K context the INT4 build reads 1.517 GB per token, so the ceiling is 180 tok/s. Recursive's speed chart reports 131.22 tok/s with its MLX engine at 1K input context, which is 73% of that ceiling (reasoned). That is a believable number for a well-tuned kernel; nothing about it needs a trick.

The stronger check is the whole curve. The rec README plots decode throughput from 1K to 252K tokens of context on the same M4 Pro, 4-bit weights, five runs per context, prefill excluded. I read the nine points out of its SVG (reported) and multiplied each by the bytes my model says that token reads:

Contextrec tok/sGB read per tokenImplied GB/sllama.cpp tok/sImplied GB/s
1K131.21.5219988.0134
8K113.71.7219679.5137
32K82.42.4320058.9143
128K39.15.2520524.2127
252K22.68.892018.676

Across all nine points the implied bandwidth for rec stays between 194 and 208 GB/s (reasoned). One constant explains a curve that falls by a factor of almost six. That is what a memory-bound engine looks like: the throughput drops because the bytes per token grow, and for no other reason. It also says the KV cache is held in 16 bits, which matches the source: the cache in rec's cache.py is allocated as bfloat16.

llama.cpp is a different story. It reaches about 134 GB/s at short context and decays to 76 at 252K, so its long-context attention path, not bandwidth, becomes the bottleneck. The README's own summary, "1.4–2.6×" faster than llama.cpp, is the ratio of these two columns.

rec is where the Metal megakernel lives: engine/src/rec_mlx/kernels/megakernel.py, 1,337 lines, the kernel the post describes as fusing "the entire decode forward pass" on M4 and M5 chips. It supports three chips, M4 Pro, M5 Pro and M5 Max, and needs 48 GB of unified memory.

For RTX Spark the reported figure is 155.82 tok/s at 1K context with the NVFP4 checkpoint. NVFP4 stores 4-bit values with an 8-bit scale per 16, also 4.5 bits per weight, so the bytes per token are about the same 1.5 GB. Recursive does not state the Spark's bandwidth. Reporting puts the N1X at about 300 GB/s (LPDDR5X-9400 on a 256-bit bus); on that figure the engine runs at roughly 79% of peak (reasoned, on a bandwidth I could not confirm from Recursive).

A table of horizontal bars: decode tokens per second on an Apple M4 Pro with 48 GiB and on an RTX Spark, at 1K input context and averaged through 128K. Flint with MLX reads 131.22 and 68.89; Flint with llama.cpp 87.98 and 47.58; Qwen3.6 35B A3B 65.55 and 37.13; dense Qwen3.8 27B 13.01 and 10.11. On RTX Spark Flint NVFP4 reads 155.82 and 101.95, Flint llama.cpp 96.61 and 59.35, Qwen3.6 llama.cpp 72.65 and 53.49.
Decode throughput, short context and averaged through 128K. The M4 Pro peer rows do not say which engine they ran on (Recursive's announcement post, speed figure).

What "up to 2x" compares

The 2x is 131.22 against Qwen3.6 35B-A3B's 65.55 on the M4 Pro, which is 2.00x (reasoned). But the Flint row is Recursive's own engine and the chart does not label the peers' engine. On the RTX Spark rows, where both sides are named, Flint on llama.cpp does 96.61 and Qwen3.6 on llama.cpp does 72.65: 1.33x. Flint on llama.cpp on the Mac, 87.98, is 1.34x Qwen3.6's 65.55.

How much of that should the shape alone give? Qwen3.6 activates about 3B parameters per token to Flint's 2.5B, which on bytes alone is about 1.2x (reasoned, from the "A3B" in its name rather than a header count). So roughly: the smaller active set buys 1.2-1.3x, and Recursive's engine buys the rest of the 2x. The engine is open source under Apache-2.0, so that part is real and usable. It is just not a property of the model, and it only exists for three Apple chips.

The "5x+ faster than dense models with similar coding scores" is conservative on Recursive's own numbers: dense Qwen3.8 27B reads 13.01 tok/s on the same chart, a tenth of Flint's short-context figure. That is the dense penalty in its purest form: 27B parameters read per token instead of 2.5B.

The benchmark claim, and its class

"Best MoE under 50B" is a statement about a chart, so here is the chart.

Six bar-chart panels: Terminal-Bench 2.1, SWE-bench Pro v2, SWE-bench Verified, LiveCodeBench v6, IFBench and IFEval. Each compares Flint BF16 and Flint NVFP4 with three sparse MoE models (Qwen 3.5, Qwen 3.6, Laguna XS 2.1) and three dense models (Qwen 3.8, Muse Glimmer, Gemma 4). Flint BF16 scores 54.9, 89.7, 74.2, 80.3, 89.2 and 95.1.
Flint BF16 and NVFP4 against three MoE and three dense models. Daggers mark scores Recursive measured itself; the SWE-bench Pro v2 panel carries one on its title (RecursiveSI/flint model card, benchmark figure).

Read it with the class filter on, then off:

The 89.7 on SWE-bench Pro v2 deserves its own line, because the card puts it in the second paragraph. I cannot check it: the harness is mini-swe-agent, the timeout is up to five hours per task, and the score is pass@1 averaged over at least five attempts, but the task set and the v2 changes are not described on the card or the post. Treat it as Recursive's measurement under Recursive's settings.

A scatter plot of mean benchmark score against decode speed on an M4 Pro with 48 GiB, speed measured as normalized area under the curve through 128K context. Flint with MLX sits near 69 tokens per second and 81 percent, Flint with llama.cpp near 48 and 81, Qwen3.8 27B near 10 and 85, Qwen3.6 35B A3B near 37 and 72. A shaded region labelled frontier gain from Flint lies between the frontier with and without Flint.
Quality against speed on the M4 Pro. The y-axis is the six-benchmark mean, IFBench and IFEval included; the x-axis is throughput averaged through 128K tokens (Recursive's announcement post, Pareto figure).

The two Flint dots show the engine effect: same model, same quality, 68.89 versus 47.58 tok/s depending on whose kernels run it.

Built from scratch?

"From scratch" cannot be proven from released weights. It can be contradicted, so I looked for a contradiction.

The tokenizer is new. Flint's tokenizer.json is a byte-level BPE with 150,000 entries and 149,744 merges, plus 144 special tokens (<|begin_of_text|>, <tool_call>, <arg_key> and reserved slots up to 150,143). Against eight candidate tokenizers, seven of them distinct (measured), the share of Flint's vocabulary strings that also exist in the other one ranges from 55% (DeepSeek-V3) to 71% (MiniMax-M2), and the share with the same id is 0.2% or less everywhere. The longest identical run of merges at the start is two. Independent BPEs trained on similar web and code text share most common strings, so 55-71% is what unrelated tokenizers look like; a fork keeps ids and merge order. The pre-tokenizer is a hybrid too: DeepSeek-V3's digit and CJK splits in front of an o200k-style letter rule, matching none of them exactly.

The attention weights do not match the closest public shape. Flint's attention projections have exactly the shapes of Qwen3-30B-A3B's (hidden 2,048, 32 query heads, 4 KV heads, dimension 128), and its two dense MLP layers are 6,144 wide like that model's. Same shapes are where a copy would show. I range-read the key and value projections of layers 0, 2 and 10 from both checkpoints (measured): the flattened cosine similarity is between -0.002 and 0.001, and the best match between any of Flint's 512 rows and any of Qwen's 512 rows is about 0.10, which is what random 2,048-dimensional vectors give. A rotation of the whole hidden space would defeat this test, and I did not test the experts, which have different shapes from any Qwen model. Nothing points that way.

The design space is familiar. 256 experts of width 512 is Qwen3.6 35B-A3B's expert grid; the config keys (mlp_only_layers, decoder_sparse_step, shared_expert_intermediate_size) are the Hugging Face Qwen-MoE vocabulary; the learned sinks and sliding windows recall gpt-oss. Recursive's post says the architecture search started "from a baseline with 35 billion total parameters and 3 billion active parameters", which is the Qwen3.6 size class. A borrowed shape is not borrowed weights.

What I cannot check is the four months. The card lists pretraining, mid-training, supervised fine-tuning and reinforcement learning, and the quantized cards describe the data as web, code, licensed and synthetic. No token count, compute budget or data mix is published.

What the Eureka Machine is credited with

The Eureka Machine is Recursive's automated research loop. Its earlier post describes it as proposing an idea, implementing it, running the experiment, validating the result against reward hacks and variance, and choosing the next experiment, with results on NanoChat autoresearch, the NanoGPT speedrun and a GPU kernel benchmark. For Flint, the announcement names three contributions:

  1. The shape. Starting from a 35B-total, 3B-active baseline, it searched expert counts and widths and picked 40B total and 2.5B active as the best projected trade between speed and coding quality.
  2. The quantization recipe. The 4-bit output head, plus the offline self-distillation stage that "nearly halved the number of training steps compared with our quantization-aware training baseline". The thread says low-bit training "shrank Flint by 71%"; the BF16 safetensors total 79.58 GB and the NVFP4 GGUF is 22.86 GB, a 71.3% reduction (measured).
  3. The kernels. Low-bit projections, MoE, attention and prompt processing for Apple Silicon and RTX Spark, and the Metal megakernel.

Of those, the files let me confirm the outcomes: the shape is what the post says, the output head is 4-bit in both quantized releases, and the engine's throughput sits at a steady three quarters of peak bandwidth. What they do not let me confirm is the attribution. There are no search logs, no list of what was tried and rejected, no ablation of agent-found versus human-found choices, and the Eureka Machine itself is not released. Flint is consistent with the claim and silent on it.

Running it, and the 24 GB line

The Apache-2.0 licence is on every repo and in a LICENSE file beside the weights; the card notes that hosted API terms and data practices are separate from the weight licence. The rec engine is Apache-2.0 too. Transformers modeling code is not included yet, so the BF16 checkpoint runs through an SGLang kit on one B300 or H200.

For a laptop the choices are, by file size (measured from the Hub API):

BuildSizeFor
RecursiveSI/flint-int4 (MLX)22.57 GBrec on M4 Pro, M5 Pro, M5 Max; 48 GB required
RecursiveSI/flint-int4-gguf (Q4_1)25.99 GBllama.cpp with Metal; 48 GB required
RecursiveSI/flint-nvfp4-gguf22.86 GBllama.cpp with CUDA; 48 GB recommended
unsloth/flint-GGUF UD-Q4_K_XL25.05 GBllama.cpp, Unsloth Desktop
unsloth/flint-GGUF UD-Q3_K_XL18.49 GBthe 24 GB option
unsloth/flint-GGUF UD-IQ1_M11.35 GBthe smallest
unsloth/flint-GGUF@20468ed · snapshot 2026-10-23
repo size
283.20 GB
task
text-generation
license
apache-2.0
gguf files
12
largest file
49.95 GB
files
19
downloads
7.4K
likes
156
flintunsloth

repo last modified 2026-10-21

So "runs on 24 GB" means the 3-bit file, which Unsloth's own guide says "fits 24GB RAM setups at short contexts". That caveat is doing work: the full-attention KV cache adds 0.94 GB per 32K tokens (reasoned), and macOS keeps part of unified memory away from the GPU by default, so 24 GB is a short-context, single-app setup. The 125 and 150 figures are measured on 48 GiB and 64 GB machines with 4-bit weights, not on the 3-bit file. On a 24 GB GPU the 3-bit file fits in VRAM with almost four times the M4 Pro's bandwidth; once experts spill to system RAM, the slower link sets the pace, as Edge0 and FreeToken count.

What I make of it

The speed claim is the best-supported thing about Flint, and it is supported by arithmetic rather than by trust. A 2.5B-active MoE with a 4-bit output head reads about 1.45 GB per token; a 273 GB/s chip moves that 180 times a second at best; Recursive's engine gets 131, and holds the same 73% of peak as the context grows to 252K. The ranking claim is true on the chart as drawn, against three peers, with one column lost by a tenth of a point and the strongest coding numbers in the room belonging to a slower dense model. The provenance claim survives the checks I could run. The method claim is a description.

The interesting design lesson is the one the bandwidth model makes obvious: once the active body is 2.2B, the output head and the KV cache are what is left to attack. Flint quantizes one and starves the other with 35 sliding-window layers. Those two decisions do more for its laptop speed than any benchmark column.

Related reading on this site: Tiel-Coder-35B-A3B counts what a "4-bit" GGUF of a model in the same size class really weighs; GLM-5.3-Flash-MLX checks another "built for MacBook Pro" claim against its own memory tables; Qwen3.8-27B on a 12 GB card is the dense model that tops this chart, squeezed down; continuous batching on a DGX Spark covers the box the RTX Spark is a sibling of; Laguna S 2.1 is the larger sibling of one of the three peers; and Dream-RSI and RSI-top look at other automated-research loops and what they actually changed.

Cite this article

For attribution, please use the following reference or BibTeX:

Satyajit Ghana, "Flint: 125 tokens a second is what 2.5B active parameters buy at 273 GB/s", ai.thesatyajit.com, October 2026.

bibtex
@misc{ghana2026flint,
  author = {Satyajit Ghana},
  title  = {Flint: 125 tokens a second is what 2.5B active parameters buy at 273 GB/s},
  url    = {https://ai.thesatyajit.com/articles/flint},
  year   = {2026}
}
share