Local models on Apple M5 Max — which one should write your code?

Apple M5 Max — M5 Max, 16-core CPU · 40-core GPU · Metal · 128 GB unified · MLX, llama.cpp Metal. 21 models in this tree. A row appears only when the run used the shared profile (temperature 0 on every trial, seed 42, one 16384-token slot, C compiled -std=gnu11). Aya-23 clamps that context to 8192. Older sweeps used different stacks, context sizes, and a 0.7-temperature retry, so they are not in this table. Their raw JSON is still on disk. Click any column header to sort. Generated 2026-10-01 17:20.

Where to look: this page ranks the models and prices them by what a working answer costs. Analysis covers behaviour under load, whether the code they write is fast, whether the wording of the prompt changes the answer, and self-repair. The failing samples are split by technology — C, Python, Bash, research — and models shows how to reproduce every number. Charts is the same data as pictures.

How many times does each test run? Coding suites (C, Python, Bash — easy, hard and brutal) and the research paper: 3 trials per task, all at temperature 0 with seed 42, so a miss is the same answer again. Framing, from the older sweep: 20 trials per wording. Decode speed: median of 3 repeated 2048-token generations — the tok/s column shows ±1 std across those runs (hover a cell for the exact count), as does the dot plot on the analysis page. Quality: 6 probes × 3 trials (temp 0, then 0.7×2). Concurrency: one pass per stream level (no repeats). Self-repair: one initial attempt, then up to 5 rounds of compiler feedback. Two writing tasks that are easy to confuse: tok/s is measured on a 1500-word essay about MIT (speed only, content not graded — each model's essay is on its detail page), while the research column is a different test: extracting NFS facts from RHEL 10 documentation. All raw data is downloadable as CSV files.

most accurate
108/126 coding tasks · 33.0 tok/s · 39.0 GB
fastest
83.1 tok/s decode · 104/126 coding tasks
lightest of the accurate tier
11.8 GB · 83.1 tok/s · 104/126 coding tasks
model type coding total flaky ↓ tok/s ± RAM GB quality ppl-w ↓ ppl-t ↓ C Py Bash C-hard Py-hard Sh-hard C-brutal Py-brutal Sh-brutal research
qwen3.8-flash-next 125B llama.cpp MetalMoE108/126033.0 ±039.0—3.16—48/4824/2415/246/99/93/9———3/3
gpt-oss-120b llama.cpp MetalMoE106/126261.6 ±151.7—15.44—42/4824/2412/249/99/98/9———2/3
gpt-oss-20b llama.cpp MetalMoE104/126383.1 ±111.8—25.008.2447/4824/2411/246/99/96/9———1/3
gemma-4-26b llama.cpp MetalMoE102/126060.7 ±016.6—1,12292.9942/4824/2412/246/99/96/9———3/3
qwen3.8-27b llama.cpp Metaldense102/126014.4 ±015.6—11.346.4745/4824/2412/246/99/93/9———3/3
nemotron-3-super 120B llama.cpp MetalMoE102/126020.4 ±070.5—3.95—45/4824/2415/243/99/93/9———3/3
laguna-s 2.1 117B llama.cpp MetalMoE101/126139.7 ±161.6———47/4824/2415/246/99/90/9———0/3
laguna-xs.2 llama.cpp MetalMoE100/126381.1 ±416.9—16.41—39/4824/2416/246/99/94/9———2/3
qwen3-coder-next 80B llama.cpp MetalMoE99/126054.6 ±145.6—27.23253,53342/4821/2415/246/96/96/9———3/3
qwen3.6-27b llama.cpp Metaldense99/126014.8 ±015.9—11.976.1336/4824/2418/246/99/96/9———0/3
qwen3.6-35b llama.cpp MetalMoE96/126063.1 ±117.9—11.504.1242/4821/2415/243/99/93/9———3/3
qwen3.5-35b llama.cpp MetalMoE96/126058.1 ±119.1—11.153.3836/4824/2415/246/99/93/9———3/3
devstral-2 24b llama.cpp Metaldense94/126123.5 ±516.3—9.553.4436/4824/2415/246/96/94/9———3/3
glm-4.7-flash llama.cpp MetalMoE94/126148.4 ±417.9—31.958.5842/4824/2415/243/97/90/9———3/3
mistral-small-4 119B llama.cpp MetalMoE91/126352.2 ±159.7———38/4824/2415/247/93/93/9———1/3
qwen3.5-122b-a10b llama.cpp MetalMoE90/126027.2 ±068.8—3.21—33/4824/2412/243/99/96/9———3/3
qwen3.5-27b llama.cpp Metaldense87/126013.9 ±018.7—3.69—33/4824/2412/240/99/96/9———3/3
qwen3-coder-30b llama.cpp MetalMoE86/126180.5 ±318.4—21.454.6136/4824/249/246/96/92/9———3/3
k2-horizon 36B-A4B llama.cpp MetalMoE86/126247.1 ±124.0—7.89—36/4824/2410/246/96/93/9———1/3
seed-oss 36b llama.cpp Metaldense79/126211.2 ±024.5—5.18—32/4824/2411/243/93/93/9———3/3
aya-23 35b llama.cpp Metaldense66/126010.8 ±037.9—15.314.8127/4821/2415/240/93/90/9———0/3

Dense vs mixture-of-experts

A dense model runs every parameter on every token; a mixture-of-experts model routes each token to a few of its experts, so only the active column does compute. That is why the 125B flash-next decodes like a 6B model and the whole top of the table is MoE — on memory-bandwidth-bound Apple silicon, active parameters are what you pay per token, and MoE buys a large total capacity at a small active cost. The last column, tok/s per active billion, is the efficiency of that trade; dense models are 1x by definition and omitted.

modeltypetotalactiveexpertscodingtok/stok/s per act-B
qwen3.8-flash-next 125BMoE125B6B512, top-10 +186%335.5
gpt-oss-120bMoE117B5.1B128, top-484%6212.1
gpt-oss-20bMoE21B3.6B32, top-483%8323.1
gemma-4-26bMoE25.2B3.8B128, top-8 +181%6116.0
qwen3.8-27bdense27B27B—81%14—
nemotron-3-super 120BMoE120B12B512, top-22 +181%201.7
laguna-s 2.1 117BMoE117B3B256, top-10 +1 shared80%4013.2
laguna-xs.2MoE33.4B3B256 +1 shared79%8127.0
qwen3-coder-next 80BMoE80B3B512, top-10 +179%5518.2
qwen3.6-27bdense27B27B—79%15—
qwen3.6-35bMoE35B3B256, top-8 +176%6321.0
qwen3.5-35bMoE35B3B256, top-8 +176%5819.4
devstral-2 24bdense24B24B—75%24—
glm-4.7-flashMoE30B3B64, top-4 +175%4816.1
mistral-small-4 119BMoE119B6B128, top-472%528.7
qwen3.5-122b-a10bMoE122B10B256, top-8 +171%272.7
qwen3.5-27bdense27B27B—69%14—
qwen3-coder-30bMoE30B3B128, top-868%8126.8
k2-horizon 36B-A4BMoE36B4B—68%4711.8
seed-oss 36bdense36B36B—63%11—
aya-23 35bdense35B35B—52%11—
harness check — not a contestant
kimi-k3 (referee) solved 44/44
A cloud model was given the same tasks to confirm they're all solvable and that no failure below is a harness artifact. It's kept out of the ranking because it got one attempt per task rather than 3 trials (44 samples vs 126), ran no research task, and authored the harness. Read it as a ceiling, not a score.

Green cells are strong, red weak — shaded by percentage so a column can be scanned without reading every number. MLX targets use mlx_lm.perplexity; the llama.cpp-fork GGUFs (qwen38flash, k2horizon, laguna) use llama-perplexity on WikiText-2 (50 chunks). Those two are not comparable. Ollama and mlx-vlm-only architectures show —. coder-next's wikitext figure is measured at sequence-length 128; the default 512 triggers an mlx-lm bug for hybrid-attention models.

What it costs to get working code

Correctness alone picks a model that is right and unusably slow; tok/s alone picks one that is fast and wrong. The number that decides it is the two divided: seconds of wall clock per solution that passes. Across the 41 coding tasks (research excluded), 3 trials each at temperature 0 — timed end to end, failures included, because a wrong answer costs you its generation time too.

modeltypeC minPython minBash mintotal minper attempt
laguna-xs.2MoE1.40.60.72.81.3
qwen3-coder-30bMoE1.80.80.73.31.6
k2-horizon 36B-A4BMoE2.31.01.04.32.1
qwen3-coder-next 80BMoE2.31.01.14.52.2
mistral-small-4 119BMoE2.61.11.14.72.3
qwen3.5-35bMoE2.61.01.24.82.4
glm-4.7-flashMoE2.41.21.34.92.4
gemma-4-26bMoE3.11.20.95.22.5
qwen3.6-35bMoE2.91.11.55.62.7
laguna-s 2.1 117BMoE4.11.51.36.93.3
nemotron-3-super 120BMoE6.22.82.511.45.6
qwen3.5-122b-a10bMoE7.42.32.512.25.9
qwen3.8-flash-next 125BMoE7.32.63.113.16.4
devstral-2 24bdense7.83.32.413.46.6
gpt-oss-120bMoE7.73.34.615.77.6
qwen3.8-27bdense8.65.44.018.18.8
gpt-oss-20bMoE8.92.47.919.29.4
aya-23 35bdense12.44.74.621.810.6
qwen3.6-27bdense12.44.84.721.910.7
qwen3.5-27bdense15.25.56.026.713.0
seed-oss 36bdense192.089.279.9361.1176.1

Those totals are everything the model spent, right or wrong. Dividing by the answers that actually worked gives the figure below. first try is trial 1 alone, the honest number if you paste the first thing you get. with retry re-asks only when the previous attempt failed and stops at the first pass, so unused retries cost nothing — what a loop around the model really costs.

modeltypefirst trysec/solutionwith retrysec/solutionretry gainrank
qwen3.8-flash-next 125BMoE35/417.7s35/4110.9s+01 frontier
laguna-xs.2MoE34/411.7s34/412.6s+02 frontier
gpt-oss-120bMoE34/419.3s35/4111.6s+13 beaten
gpt-oss-20bMoE33/4111.1s35/4119.1s+24 beaten
laguna-s 2.1 117BMoE33/414.4s34/415.6s+15 beaten
gemma-4-26bMoE33/413.3s33/414.8s+06 beaten
nemotron-3-super 120BMoE33/417.4s33/4110.2s+07 beaten
qwen3.8-27bdense33/4111.1s33/4116.5s+08 beaten
qwen3.6-27bdense33/4113.6s33/4120.1s+09 beaten
qwen3-coder-next 80BMoE32/412.9s32/414.2s+010 beaten
qwen3.5-35bMoE31/413.2s31/415.0s+011 beaten
mistral-small-4 119BMoE30/413.4s31/415.2s+112 beaten
glm-4.7-flashMoE31/413.2s31/415.6s+013 beaten
qwen3.6-35bMoE31/413.7s31/416.4s+014 beaten
devstral-2 24bdense31/418.9s31/4114.9s+015 beaten
k2-horizon 36B-A4BMoE29/413.1s29/415.1s+016 beaten
qwen3.5-122b-a10bMoE29/418.7s29/4115.2s+017 beaten
qwen3-coder-30bMoE27/412.5s28/414.2s+118 beaten
qwen3.5-27bdense28/4119.1s28/4134.5s+019 beaten
seed-oss 36bdense24/41302.0s26/41575.4s+220 beaten
aya-23 35bdense22/4120.1s22/4145.5s+021 beaten

Rank is the frontier first (most solutions, then cheapest), then everyone else. beaten means another model is at least as accurate and cheaper — drop it.

kimi-k3 (referee) is not in these tables: the cost here is generation wall-clock, and the referee is a hosted cloud model whose solutions were written in-session, not generated through the harness — there is no timing to report.