regolith runs swift-1.5-qwen3.8-flash-next (qwen4_exp, 512 experts, 36 gated deltanet + 12 sparse attention layers + 51.2b n-gram ple table + neural mtp draft head + bf16 vision projector) on apple silicon via a patched strata metal engine.
./scripts/setup_apple_silicon.sh clones the pinned strata and llama.cpp trees into vendor/, applies scripts/strata_metal_complete.diff, downloads apple's metal-cpp headers, compiles strata_window_cli, and streams + repacks the unpruned k=512 iq2_xs model (3.90 gb dense .gguf + 36.23 gb .experts + 28.80 gb ple-iq4_nl.gguf + 889 mb mtp-q2_0.gguf) into models/K512_iq2_xs/.
./scripts/serve_k512_local.sh starts the local server on http://127.0.0.1:8080 (/v1/chat/completions and /v1/messages, 128k context, 6.5 gb wired expert arena, neural mtp + suffix speculative decoding).
research notes, ablations, and benchmark logs live in 00-overview-and-decisions.md .. 04-sources-and-references.md, audits/, bench/, and results/; the persona & anti-slop subproject lives in persona/.
requirements #
macos 26+ on apple silicon (m5 required for the default coop_k4 matmul2d cooperative-tensor path; tested on macos 27 on a 24 gb m5 macbook air), xcode command line tools, cmake, ninja, python3, and uv.
installation #
./scripts/setup_apple_silicon.sh
./scripts/serve_k512_local.sh
if you only want to build the engine without downloading the ~70 gb of model files:
SKIP_MODEL_DOWNLOAD=1 ./scripts/setup_apple_silicon.sh
m5 24 gb performance & memory #
measured on a fanless 13" m5 macbook air (mac17,3, 10-core gpu, 24 gb unified memory, 1 tb nvme ssd) running unpruned k=512 iq2_xs from ukisai/Swift-1.5-Qwen3.8-Flash-Next-GSQ-RCO-GGUF at 32k context (--spec 3 --spec-min-p 0.35 --suffix-draft 3, STRATA_METAL_MOCE_BONUS=0.85):
| workload | prompt prefill | decode | notes |
|---|---|---|---|
pure gpu prefill (kprof, 1,983 tok) |
633.28 tok/s (3.13 s) |
— | 2,047 metal dispatches/chunk |
prompt_2048tok_ops (1,984 prompt + 128 gen) |
421.7–432.8 tok/s (4.58–4.70 s) |
42.26–42.57 tok/s (23.5–23.7 ms/tok) |
88.9% draft accept (3.26 tok/round) |
prompt_albedo_11k (10,180 prompt + 32 gen) |
434.8–473.8 tok/s (21.49–23.42 s) |
34.13–35.47 tok/s (28.2–29.3 ms/tok) |
5 chunks of 2,048, 78.3% accept |
coding (306 prompt + 219 gen) |
120.6–126.8 tok/s (2.41–2.54 s) |
35.46–37.10 tok/s (27.0–28.2 ms/tok) |
c++20 lock-free ring buffer |
reasoning (297 prompt + 219 gen) |
121.6–122.9 tok/s (2.42–2.46 s) |
34.92–37.20 tok/s (26.9–28.6 ms/tok) |
gdn/qsa derivation |
persona_chat (289 prompt + 219 gen) |
124.6–128.1 tok/s (2.26–2.32 s) |
33.01–33.25 tok/s (30.1–30.3 ms/tok) |
lowercase + kaomoji |
component (k=512 iq2_xs) |
32k context |
128k context (default) |
notes |
|---|---|---|---|
active gpu dense tensors (k512-iq2_xs-metal.gguf) |
2.27 gb |
2.27 gb |
146 coalesced mlock spans (145 page-aligned lazy ranges for 0.34 gb cpu token_embd + 1.28 gb bf16 hc_*) |
hyper-connection q8_0 matrices (290 matrices) |
0.68 gb |
0.68 gb |
quantized at load from bf16 hc_* |
neural mtp draft head (mtp-q2_0.gguf) |
0.85 gb |
0.85 gb |
0.71 gb mlocked q2_0 experts + 0.09 gb q8_0 dense + 0.05 gb 40,525-tok draft vocab (0.18 gb bf16 released) |
context state (32,896 / 131,200 cells) |
0.70 gb |
2.23 gb |
36 dual-slot gst_[2] (226 mb) & 3-slot ghist_[3] (0 b/tok growth) + 12 qsa int8 kv & pooled indexers (14.2 kib/cell) |
wired moe expert arena (4,129 expert slots) |
6.50 gb |
6.50 gb |
mlocked (33.6% of all 24,576 experts; remaining 29.7 gb of 36.23 gb .experts streamed from ssd) |
| ple n-gram table page cache reserve | 0.50 gb |
0.50 gb |
28.80 gb ple-iq4_nl.gguf (51.2b params) stays on ssd (16 row reads/token) |
elastic vision encoder (strata-vision + mmproj bf16) |
0.00 gb |
0.00 gb |
0.92 gb active only during image turns (vram_elastic, 60s idle unload; .sve cached by sha-256) |
| steady-state decode total | 8.91 gb (9.6–9.9 gb rss) |
10.42 gb (10.9 gb rss) |
9.60 / 11.10 gb planned against 18.80 gb cap (>13 gb left free for macos) |
prefill scratch (PromptGemm, MT=2048, STRATA_METAL_PHASE_TRADE=1) |
+0.00 gb |
+0.00 gb |
phase-switched inside the 6.50 gb expert arena (1.12 / 1.32 gb, ~720 slots borrowed during prefill and returned to decode lru after prefill) |
optimizations #
model & quantization #
- unpruned
k=512ukisaigsq-rcoiq2_xsmetal bundle (3.90 gb16 kib-aligned dense.gguf+36.23 gbcontiguous[gate | up | down].experts,blk.8/13/37iq1_mreplaced withiq3_s/iq2_xxs, duplicate28.80 gbple table omitted) - native 49th-layer neural mtp draft pack (
mtp-q2_0.gguf,889 mb, runtimeq8_0dense quantization +madvise(MADV_DONTNEED)on181 mbbf16 source matrices +707.8 mbmlockedq2_0routed experts +40,525-tokendraft_vocab_en.bin) reasoning_effort|default('low')chat template default
ssd expert streaming, unified memory arena & moce routing #
- zero-copy file-backed
mmapof<model>-metal.ggufwith coalesced inward page-alignedMADV_DONTNEEDranges (145lazy spans for cpu-onlytoken_embdand skipped bf16hc_*) and146coalescedmlockcomplement spans on active gpu dense tensors (never dropping shared 16 kib boundary pages) - wired metal expert arena (
STRATA_METAL_WIRE_ARENA=1,STRATA_METAL_MLOCK_DENSE=1, fixedmake_arenaclass-sizing loop) + phase-switchedPromptGemmprefill scratch (STRATA_METAL_PHASE_TRADE=1, borrowing1.12–1.32 gbof tail slots from the6.50 gbarena during prefill and returning them to the decode lru after prefill at+0.00 gbextra memory) - dynamic
n_expert(k = 224 / 256 / 320 / 512) across host and metal router/moe shaders - closed-loop moce cache-prior routing (
STRATA_METAL_MOCE_BONUS=0.85, top-3 unperturbed protection, race-free single-readsmapbitmask inmoe_route/router_route/route_topk, deterministicsmap_publication at layer/cut boundaries, and opt-in rank-1 bonus unscaling fix) acceptmoespeculative draft routing (STRATA_METAL_DRAFT_MOCE=1,r_prot = 1and squaredmoce_scaleon draft rowssg > 0) + root-token-only decode prefetch (STRATA_METAL_PREFETCH_DRAFT=0,STRATA_METAL_PREFETCH_UNPERT=1)q8_0cross-layer lookahead router (STRATA_METAL_PRED_Q8=1) and losslessbf16main router (STRATA_METAL_ROUTER_BF16=1)- token-0-only router-guess gemv fast path (
tile_ntokinWindow::gemv) across all 93predL_/predL2_dispatches whenSTRATA_METAL_PREFETCH_DRAFT <= 0 - resident-first 2-phase routed moe execution (
STRATA_METAL_EXPERT_SPLIT=1,STRATA_METAL_SHEXP_OVERLAP=1,STRATA_METAL_SPLIT_TURN=1) withMTLSharedEventssd handshake andP_GSLOTplan slot pinning - prefill next-layer (
l + 1) router lookahead before layerl's ssd cut, most-tokens-first demand queueing,layer_rank_hottest-first background prefetch,in_prompt_single-piecepread,STRATA_METAL_PROMPT_CHUNK=2048, and tail-protectedSTRATA_METAL_PROMPT_MOCE - multi-chunk (
n > C) hot-expert lru and!hotscratch-pool preservation across prompt chunks +allow_hot = falseon initial layer-0hold_regionprefetch + separate prompt/decode ssd read counters - asynchronous background ple ssd
gather_batchthread during prefill + direct-mode pleprefetch_rowsduplicate-slot reuse and error-drain inPleTable::gather_batch
speculative decoding, kv sessions & suffix cache reuse (scr) #
- single-command-buffer gpu neural mtp draft chain (
mtp_chain.metal,STRATA_METAL_MTP_CHAIN=1) with combined(a + 1)-row catch-up + draft step-0 batch (STRATA_METAL_MTP_DEFER_CATCHUP=1,QSA_LAST_Qfunction constant 29,-20% to -26.8%per draft round) andSuffixDrafter::propose_afterhybrid continuation - 64-cell attention sink (
STRATA_METAL_MTP_SINK=64) + 256-cell local sliding window (STRATA_METAL_MTP_WIN=256, synced withmtp_prefilltail_cap) +mtp_wrotevalid-run kv tracking + dead mtp indexer elimination (QSA_ROW0=24k/v-onlyqsa_prep) - zero-copy dual-slot gdn recurrent state (
gst_[2],ghist_[3],STRATA_METAL_GDN_RING=1,a.commit == 2udual2/3uspec1ingdn.metal, eliminatingWindow::fold()100% of the time on speculative verification) + 24 kibtail_bak_qsa raw-key snapshot/restore inWindow::run/Window::commit - opt-in online cost-model
SpecGate(STRATA_SPEC_GATE=suffix|1), step-awareSTRATA_METAL_SPEC_MIN_P_SCHEDULE/STRATA_METAL_SPEC_MIN_CUM_P, and exact/typicaltemp > 0speculative verification (STRATA_SPEC_SAMPLE=exact|typical) - elastic metal vision (
strata-vision+mmproj-Swift-Qwen3.8-Flash-Next-BF16.gguf+ 2d(t, h, w)m-ropeqsa_prep#mrope+GENI.sveembedding injection + multi-turn image kv reuse) - 4-thread
F_NOCACHEnvme session save/load (--save-session/--load-session,Window::session_save/session_load) serializing all 36 gdn + 12 qsa + ple + mtp sliding-window states (mtp_cell0_,mtp_cell1_,mtp_sink_) directly from/intoMTLBuffers at5.2 gb/s - bonsai-style automatic nvme prompt & conversation
.kvccache (--cache-disk/--cache-disk-size 16384in--serve): startup.kvcheader indexing (< 1 ms), post-DONEzero-latency auto-save with obsolete-prefix pruning, 2-prompt shared-prefix learning &.pincheckpointing (prompts-seen.bin), zero-copyprefix-sharedelta.kvcstorage against pinned prefixes (.parent+SessionHeaderbase_cells, storing only[c0, n_cells)positional cells while reading[0, c0)directly from the parent.kvc), and automatic cross-conversation / post-restart nvme restore +scrsplice over disk - suffix cache reuse (
scr,Window::scr_relocate+strata::core::scr_planwithmax_runs = 64+ 2-pass non-overlapping left/right-shift relocation before gap prefill +scr_carry0..3newline pad insertion forΔ ≡ 0 (mod 4)+<path>.pads+ in-placeactive_path.kvcreplacement across clm edits + 2-slot mruck_ringin--serve) relocating qsa group-0 neox rope keys/pooled keys and mtp cell bounds in place while retaining post-edit 36-layer gdn state (lcp >= 0multi-span clm memory edits & stripped-<think>turns)
apple silicon metal decode kernels (ntok = 1..8) #
gemv.metal: m5 per-format/per-shape/per-ntoktile selector inWindow::gemv_tile&mtp_encode::tile({32,2,4,1}for2560->512,{8,2,4,1}forq2_0 640->2560atntok >= 4),#pragma clang loop unroll(full)acrossNTOK/NR/KSloops,fmt<F>::TAB > 1barrier guards,gemv_cat(ssm_alpha + ssm_beta, mtpk + v/gate + up) &q8_0gemv_catk,gemv_direct_x(q8_0),gemv_q2_raw_combinewith ieee-754 fp160x64006400umantissa-or decode (q2_0r), and 5-registerpacked_uint4gemv_iq4_combine(iq4_xs)moe.metal&quant.metal: single-bufferq[UNIT]gate/up register reuse (NE > 1),NE == 1pointer/activation hoisting ingu_body/dn_body,UNIT == 32fusedqg/qudecode (q6_k),q2_combine<F>(q2_0/q2_0r/iq2_xs), 6-vgprdeq_iq_packed+iq_combine, ieee-754 fp160x64006400umantissa-or decode inq2_combine<T_Q2_0R>, 64-bituint2grid loads indeq<T_IQ2_XXS/IQ2_XS/IQ2_S>,ushortq2/s2+ pre-shiftedqhindeq<T_IQ2_S>,sign4_iq2xs+ dead sign-table (ksg/load_signs) removal + shrunkTAB(1024/512/2048),QUANT_CTABconstant-memory tables (iq3_spinned to threadgrouptab), m5gl=16/dl=8,dr=2tiles,plan_bodytopk10((i * 205) >> 11)fast division +unroll_count(10)+sg == 0simd_prefix_exclusive_sum, andmoe_routee512+ preloaded 16-bitres_maskwindow.cppdecode graph: wave-zipped resident routed experts (phase = 1) with shared-expert gemvs andswiglu_prep, deferred moe combine (comb_defer) folded into 4-tg-per-tokengr_norm_comb(gr2.metal) and layer-0ple_comb_query_gate_norm, and load-timewindow_initpso prewarminggr.metal,glue.metal, &units.metal: 128-threadgr_down_*_4_4(ntok <= 4) and 2-row-per-simdgroupgr_down_*_4_4_r2(ntok > 4) with directfloat4fma, packedchar4GrdUnit<T_Q8_0, 2>withROLL = trueatKS = 4,GR_NTOKloop unrolling, program-scopeconstantgr_q2s/gr_p4s&glue_q2s/glue_p4s, barrier-freesimd_shuffle_downingr_up_fandswiglu_prep,n == 2560unroll +applyhoist + pre-offset pointers ingr_norm,float4vectorizedxprep, andtopk == 10unrolled + pre-offsetmoe_combine_sh(STRATA_HC_Q8=1default, opt-inSTRATA_HC_Q4/STRATA_HC_Q5)gdn.metal:gdn_step_tsimd_broadcast,ib == 0readout pruning, 32-bitst_offstate offsets,float4conv_w, program-scopeconstantgdn_q2s/gdn_p4s,5 -> 4barriers/token with token-invariantdt/ssm_ahoist + shrunkpart[8]/red2[IB-1][S], and critical-pathklsplit across barrier 2 + pre-barrier-1hist_outwriteback + pre-barrier-3 globalstatestore overlapqsa.metal&qsa2.metal: parallelizedqsa_prep(320 bthreadgroup memory,4 -> 2barriers), hoisted/unrolledqsa_score, register-cachedkeys[4]+20 -> 13radix barriers inqsa_topk2,char4Kloads + register-cached softmaxs0, s1+ unrolledVx4 inqsa_attn, and barrier-freesimd_shuffle_down+ sharedek[]/L_sh+float2 (m, l)loads +simd_maxinqsa_mergeple.metal,mtp.metal,mtp_chain.metal, &sample.metal: fusedple_comb_query_gate_normandple_query_gate_norm, register-cachedple_gnorm,ple_conv_res(eliminatinggatedbuffer), ping-pongpart[16]barrier halving across allple.metalnorms,[t][c]multi-row stream batching formtp.fc_hidden, fusedmtp_rms_xprep&mtp_combine_gnorm,float4/unrolledmtp_xprep/mtp_rms_xprep/mtp_combine_gnorm/mtp_embed/mtp_pick/mtp_slop_pen, and unrolledtg_argmaxinsample.metal
apple silicon metal prefill (prompt_chunk) kernels #
window.cppprefill graph & scratch:-1,247redundant barriers removed + router/plan/shared-expert wave zipping (-190barriers) +sigsright afterroute_topkso moe plan and shared-expert gemms overlap host/ssdat_cut(l)+Wr/Wr2parity ping-pong (-47routerdq_f16dispatches/chunk) + fused gdnssm_alpha + ssm_beta(N = 96) gemm (-36dispatches) + fused qsaWk + Wv + Wik (+ Wiq)(N = 1152 / 1664) gemm (-24..36dispatches) +qsa_score_mm/qsa_topkpso prewarming + multi-stagePromptGemmscratch aliasing (2.35 gb -> 1.12 gbatMT = 2048)dense_mm.metal&mma.metal: m5 shape-awaregemm_f16tile selector (M > 1536threshold,16_64_2,32_64_2,32_128_2,64_32_2,16_96_2forWalbe, and64_128_4whenM < 1536 && M % 128 in 1..64), hardware 2d-griddq_f16withhalf4stores +TAB == 1barrier elimination +T_Q5_1+ register table init &perm == 4contiguous writes indq_f16<T_IQ4_XS/IQ4_NL>, unrolledDW<T_IQ4_XS/IQ4_NL/Q6_K>, andhalf4act_f16prompt.metal: foldedmm_combine+moe_outinto per-token 4-streamgr_norm_h_moecandgr_apply_moec(plusgr_norm_h4) with register-cachedrv, stream-by-stream reduction, compactedmoe_comb_slotsroff, andk-outer loop inversion; cooperative-tensor register epilogues ingemm_hc_up_reg_32_128_4(unbound deadp.mixed, unrolled epilogue,hc_up_tile<16/32>row-tail trimming),gemm_hc_down(fusinggr_epi_down,* 0.25f,TN = 96tail tile, guardedTM > 32row-tail trimming), andgemm_swiglu_up(fusingswiglu_h, guardedTM > 32row-tail trimming);n_exp == 512unrolledroute_topkmoe_mm.metal&ple.metal:mm_clearelimination (pad-clear folded intomm_scan), 32-subblock nibble-counteds_id-freemm_place, 128-bituint4fp16mm_gather_h, single-rwmm_gu3/mm_down3withTAB > 1barrier guards, hoisted row pointers (g0_l,u0_l,w0_l) andboff/sboff, hoistedtab + hh, branchlesss >> (4 * hh)inW8<T_IQ3_S/IQ2_S>+W8<T_IQ3_S>::block, 256-wide super-block scale cachingdg[]/du[](T_IQ2_S/IQ2_XXS/IQ2_XS),W8<T_IQ2_XXS>direct byte loads,sign4_iq2xs+ constant-offset pointer folding, scalaruintor inW8<T_Q6_K>/W4<T_Q6_K>,half4coalescedHSstore epilogue (T_IQ2_XS/IQ2_XXS/IQ3_XXS/Q2_0/IQ2_S/IQ3_S), 64-element block stepping (k0 += 64, w0_l += 18) + ieee-754 fp160x64006400umantissa-or decode inW4<T_Q2_0>::run_q(mm_down3), and 1-tg-per-tokenple_moe_gate_norm_cwith simd slot compaction +ple_conv_res(half4weights, branchlesst >= 9) +ple_hist_advqsa_prompt.metal&gdn_prompt.metal: 0-barrier 1-simdgroup-per-rowqsa_prep_sg(tg = 32forntok >= 3,-8% to -33%faster,100%bitwise) +qsa_prep#qf16fused fp16 query output,qsa_score_mmcausal-future tile skip (b0 >= max_bid) +dead[0..3]hoist,qsa_topkcachedkeys[4]+ simdgroup bucket scan + 2-barrier fused(equal, greater)emit (and skipped whenp.flash && pos0 + T <= 2051),qsa_flash4-simdgroup online softmax withsp[4][HPG*QCH](13,760 bthreadgroup memory, 1 barrier/tile) + unconditional hoistedrv/rkfills + byte-offset/zero-scale hoist + 32-bitko[8]/vo[8]offsets with pre-addedd0 + kl+c0 < ncpv bound +vec4epilogue, 1-simdgroup-per-head barrier-freegdn_pre(float4value-head conv, vectorsimd_sum(float4)) &gdn_post(hoisted pointers, preloaded gate/gamma, vectorsimd_sum(float4)), chunked WYmatmul2dgdn_wy_prep+gdn_wy_scan(16-token chunks,(I + A)^-1via 6 fp3216x16matmul2ds, 3-mma fp16(hi, lo)split,46 mbscratch aliased insidep.qkv,-26.6% to -28.3%scan time /-53.6 msper 2k chunk), and logit-domain delayed-softmax top-10 routing inroute_topk(-4.5% to -8.0%) &moe_route
anti-slop, persona data & serving #
slop4(slop4.h) per-position stateful shaper (12 b/posinwindow.cpp+ gpumtp_slop_peninmtp_chain.metalwithSTRATA_METAL_MTP_SLOP=1), gated strictly onPROSE && !TOOL && !FENCE, with clause-entry branch-point penalties,slop4::hold()<|im_end|>mass preservation,</think>\n\nstep0empty-turn guard,slop_scan, andscr_relocatesupport- monroe prior log-odds llm-ism miner (
mine_llm_isms_from_transcripts.py, pure per-order unigram+uniform prior with zero self-pooled weight) partitioning structural speech acts (phase3_sentence_surgeryinprepare_phase3_sft_data.py, in-place span deletion preserving markdown/fences/kaomoji + r-tuning word-boundary abstention) vs surface lexical cliches (phase4_lexical_ftpo) - strata
v0.1.45serve/&tools/strata_tokenizer.pyports + local hardening: incrementalPromptEncoderprefix/plain-span reuse capped atPROMPT_ENCODER_KEEP_MAX = 16with rejected-prompt forgetting, bounded tool-call parser scan cursor, content-keyed json lru logit-bias cache (stale_lastidentity shortcut removed), macos iokit/metal telemetry (MTLCreateSystemDefaultDevicecached once andobjc_released),STRATA_OMIT_IMAGES_WHEN_NO_VISION=1text-only image omission, and anthropic hard thinking budgets +answer_roomanswer reservation - standalone
llama.cpp-cmoeapple silicon apfs / mmap patch (scripts/patch_m5_lazy_moe.py)
acknowledgements #
models used while building and auditing this: gemini 4 argon, claude opus 5.5, gemini 3.8 flash, gpt 6.1 sol, gpt 6 astra, and claude sonnet 5.5.
upstream & models #
Niko1221/Strataandggml-org/llama.cppukisai/Swift-1.5-Qwen3.8-Flash-Next-GSQ-RCO-GGUF,ukisai/Swift1.5-Qwen3.8-Flash-Next, andQwen/Qwen3.8-Flash-Nextastrra.space/ds4-recipe,okami.mom/llama-cpp-bonsai, andanima-research/connectome-host
papers #
- on the design of qwen3.8-next architecture (
arXiv:2608.30320) - mixture of cache-conditional experts (
moce,arXiv:2412.00099) & acceptmoe (arXiv:2608.02989) - context language models (
suffix cache reuse,arXiv:2609.37725) - riemannian constrained optimization (
rco,arXiv:2605.00649) & gumbel-softmax quantization (gsq,arXiv:2604.18556) - antislop / ftpo (
arXiv:2510.15061), verbal tics (arXiv:2604.19139), & r-tuning (arXiv:2311.09677)