New model support on the 2080 Ti: an ordered roadmap¶
Repository scope note. This is the plan, and two of its three checkpoints no longer have a runtime here. Ternary-Bonsai-2-27B was served through the C++ front end and Xing4.0-29B-A4B through
--backend xing4; the front end was deleted with the multi-card cut, so only the Xing4 stage is still live. GLM-5.3-Flash never landed. The stages below are kept as the record of the plan and of the measurements taken while executing it, not as a description of the current checkout.
This is the engineering record and the plan behind issue #380, the repository's second roadmap. The old-hardware roadmap asks what capability the engine is missing — continuous batching, prefix caching, KV quantization, offload. This one asks which checkpoints to support next, and it is tracked in PocketLLM Execution Queue.
Three checkpoints, in this order:
| # | Checkpoint | Weights we would run | Issue |
|---|---|---|---|
| 1 | Ternary-Bonsai-2-27B | 5.5 GiB, PTQ1_0 ternary GGUF | #381 |
| 2 | Xing4.0-29B-A4B | 18.7 GiB, official IQ4_NL GGUF | #388 |
| 3 | GLM-5.3-Flash | 101.3 GiB, UD-Q2_K_XL GGUF | #394 |
The lens: what the card can actually execute¶
An RTX 2080 Ti is compute capability 7.5. It has FP16 tensor cores and INT8/DP4A. It has no BF16, no TF32, no FP8 and no FP4 — every modern checkpoint's release format is one of those four. So "which model does the release ship" is the wrong question here. The question that decides the cost of a new checkpoint is:
Is there a low-bit artifact whose packing something can consume, and what does it cost to teach our kernels to?
This is why the table above lists weights we would run and not the safetensors the authors published. It is also why the ordering below is not by model quality or by popularity: it is by how much of the existing engine each one reuses.
Two hardware facts bound all three stages:
/dev/shmis the scarce resource, not RAM. The box has ~1 TiB of memory but the resident expert banks live in/dev/shm, which is 700 GB and currently holds the DeepSeek-V4.1-Flash bank (491 GB) and the MiMo-V2.6-Flash bank (161 GB). A new multi-hundred-gigabyte bank means evicting one of those first — a real cost, and part of why the first two stages were chosen as single-card or nearly so.- A dump cross a PCIe 3.0 link is a floor, not a starting point. The MiMo-V2.6 record measured the expert copy at essentially the link's own rate; any checkpoint whose weights must stream from host memory a token inherits that floor. Stages 1 and 2 avoid it by fitting on the card.
Stage 1 — Ternary-Bonsai-2-27B¶
prism-ml/Ternary-Bonsai-2-27B-gguf, 2026-09-16. The model card's own claim is that it is "Derived
from Qwen3.8-27B, a 27B hybrid-attention causal language model (architecture unchanged)", and the
GGUF header confirms it field for field: general.architecture = qwen35 — the string our Qwen3.8-27B
runtime already dispatches on — 64 blocks with full_attention_interval = 4 (48 Gated DeltaNet + 16
GQA), hidden 5120, 24 query heads over 4 KV heads at head_dim 256, and a dense MLP of 17408.
That means the attention, the linear layers, the runtime, the server, the batching and the prefix cache
all exist and are validated in TP4 on /mnt/data2/Qwen3.8-27B-FP8. The stage's new work is the
artifact:
PTQ1_0 |
5.54 GiB, 1.75 bits/weight, trits packed densely — GGML type 143 |
PQ2_0 |
6.71 GiB, 2.13 bits/weight — GGML type 142 |
| Tensor mix | 402 ternary, 353 F32 (norms, ssm_a, conv1d, dt), 96 BF16 (ssm_alpha/beta) |
| Reference kernels | PrismML-Eng/llama.cpp, prism branch |
Every id here is read out of the file's own header, not from documentation. Two details matter and both are unusual:
- The type ids are fork-private. Upstream GGML assigns nothing near 142; our
pocketllm/loader/gguf/quant_types.pylists nine dense types and no ternary one. The failure mode to design against is a silent F16 upcast, which costs ten times the memory and makes a wrong kernel look right. token_embd.weightandoutput.weightare ternary too, andtoken_embdcarries an inverse Hadamard. The model card is explicit that there are "no high-precision escape hatches behind a low-bit label", and the header bears that out: the packing is end to end.
The Hadamard is the stage's real risk. prism.hadamard.* declares a normalized
Sylvester–Walsh–Hadamard transform, axis = input-last-dimension, block size 1024, with explicit sign
vectors of widths 5120, 6144 and 17408. It is the incoherence transform that makes a 1.75-bit weight
representable, so getting it subtly wrong produces fluent-looking nonsense rather than a crash — hence
the first task in the stage is to read the fork's source and write down the semantics, not to
reimplement from the name.
Why it is first: on this card it is the cheapest stage to build and the most differentiated to ship. It puts a 27B model with a 262144-token context in 5.5 GiB of weights, leaving roughly 16 GiB of a 22 GiB card for KV. The old-hardware roadmap's first differentiation claim is 极致量化 — "FP4/Q2 lets a 2080 Ti run a 70B"; this would give it a sharper example. And the quality number is the interesting one: the card reports 84.78 average over 14 thinking-mode benchmarks, 98.2% of the FP16 parent, against 72.59 for a conventional IQ2_XXS build at a larger size — and IQ2_XXS is a quant this repository already has hand-written kernels for.
The gate measurement has run since this was written: the upstream reference decodes at 30.7 tokens/s and prefills at 665 tokens/s on one card, and 262144 contexts fit in 15,836 MiB with a quantized KV cache. It passes, and it also shows the reference spending only a third of the card's bandwidth per decode step, which is the number the kernel task has to beat.
The loader task (#384) has run since as well. Both packs read end to end: 851 tensors whose byte counts tile the file exactly, the type histogram the release ships (402 quantized / 353 F32 / 96 BF16), and decoded rows equal to the same rows of the checkpoint's own F16 GGUF, bit for bit. The bytes are addressable and nothing runs them yet — the loader refuses a ternary tensor by name rather than upcasting it to F16, which is the failure mode the task existed to prevent.
The Hadamard transform (#385) has run too, and it is the
half of this stage that cannot fail loudly. src/loader/gguf/prism_hadamard.py now computes the rotation as
well as parsing it, and every case in tests/test_prism_hadamard_transform.py is checked against
scripts/prism_hadamard_oracle.cpp — the fork's own ggml_permute, ggml_mul and FWHT path — as a digest
of the fork's fp32 bytes, not as a tolerance. What that leaves unclaimed is parity: the activations are
synthetic, because the model does not run yet, so "the transform is the fork's" is proven and "the model
generates" is not.
The ternary dense GEMM (#386) has run as well, and it is the stage's first uncomfortable number. Both phases are correct — bit-exact in bf16 against their own reference arithmetic over the released weights, with the packing pinned by the decoder's own round-trip — and the decode half is where the format pays: the dense projections of one forward pass decode at 21.8 tok/s against 9.2 for the same shapes at FP8 width, at a tenth of the bytes. Prefill is the other way round: 600 tok/s of dense projections at a 512-token prompt, 1.27× slower than handing the same weights to cuBLAS as fp16, and both phases are behind what the gate measured the upstream whole model reaching on this card. The decode gap has a measured mechanism — a lane reads its own 28-byte block with seven 4-byte loads, and a reduction at that stride reaches 73 GiB/s of useful bytes where a dense one reaches 526 — so the fix is staged loads rather than a different unpack. The measurement and both gaps are written up in full.
What remains before the model generates is the runtime wiring (#387), and the kernel work the two gaps above name.
Stage 2 — Xing4.0-29B-A4B¶
XingChen-AGI/Xing4.0-29B-A4B, 2026-09-16, 58.1 GiB of safetensors with an official IQ4_NL GGUF at
18.7 GiB. This is the stage where the card stops being the constraint: 18.7 GiB fits one 2080 Ti, so the
smallest card in the fleet gets an architecture with the shape of a frontier model.
| Blocks | 40 (+1 NextN), hidden 3584, 32 query heads |
| Attention | MLA: q_lora_rank 768, kv_lora_rank 512, qk_nope 128, qk_rope 64, v_head_dim 128 |
| MoE | 64 experts, top-4, 1 shared, 2 leading dense blocks, expert_ffn 1024 |
| RoPE | YaRN, original_context_length 4096 |
| GGUF types | 243 × IQ4_NL, 327 BF16, 406 F32, 1 Q6_K |
MLA is familiar — DeepSeek-V4.1-Flash and GLM-5.2 both use it — but the ranks and head counts differ, so the mapping is a mapping and not a copy. Two things are genuinely new:
IQ4_NLis not in our loader.IQ4_XS, its k-quant sibling, is one of the nine types we support; the non-linear variant decodes through a 16-entry codebook rather than a scale-and-add, and it is 243 of this checkpoint's tensors.hc_*hyper-connections. Every block carrieshc_attn_fn.weightof shape[14336, 24],hc_attn_baseof 24 andhc_attn_scaleof 3, and the same for the FFN, withhyper_connection.count = 4,sinkhorn_iterations = 20. 14336 is 4 × 3584, so a 24-wide coefficient vector is produced per token from a 4×-hidden projection and then Sinkhorn-normalised. That is a matrix hyper-connection: it widens the residual topology every model in this repository has had as a single stream. It is the one part of the architecture with no precedent here, and the stage's first task is a go/no-go on it — read out of the checkpoint's own remote code, not guessed.
The stage is second because it is a genuinely new architecture family at a size that fits, and because it is the only one of the three where the card is not the interesting constraint.
The gate (#389) has run:
the audit reads the hyper-connection out of the checkpoint's own remote code
and out of the open llama.cpp port, and the two agree operation for operation, so the block is a port
rather than a research project and the stage is a go. The same page is where the description a
reimplementation is written from now lives, and it corrects this document's attention ranks — the only
reading of its Stage 2 table that did not survive the artifacts, since 192 is key_length_mla and its
halves are 128 and 64. Two of the audit's findings change the remaining tasks rather than annotating
them: IQ4_NL is smaller work than it looked (reader.GGML_TYPES already carries its geometry, so
what is missing is a codebook and a dispatch entry, and the format is upstream rather than
fork-private), and this GGUF leaves the whole attention path at BF16 — 2.117 GiB of the 3.761 GiB a
decode step reads, against 0.877 GiB for the routed experts. On a bandwidth-bound decode step the MLA
path, not the MoE, is where this checkpoint's time will go, which is the opposite of what MiMo-V2.6 and
V4.1 both measured and is the first prediction the stage can be judged against.
Stage 3 — GLM-5.3-Flash¶
zai-org/GLM-5.3-Flash, 2026-08-25, 305.8 GiB of FP8 safetensors with upstream GGUFs at
unsloth/GLM-5.3-Flash-GGUF — UD-IQ1_S at
86.7 GiB, UD-IQ2_XXS at 94.9, UD-Q2_K_XL at 101.3, UD-Q4_K_XL at 186.0. UD-Q2_K_XL is the target:
101 GiB fits TP2 on the NVLink pair, or a three-way split of the four cards, on the 2-bit path this
repository already has.
The architecture is why it is last. Forty-five layers alternate three linear_attention to one
deepseek_sparse_attention — 34 linear, 11 sparse, read out of the config's own layer_types. Both
halves exist in this repository and have never run together:
- linear attention is Qwen3.8-27B's 48 Gated DeltaNet layers, validated in TP4 with a server;
- sparse indexed attention is GLM-5.2's
glm-dsapath, with its indexer, itsindex_topkand its own measured record — in which the indexer's prefix tile was half collective traffic, which is why its default depth is zero.
Everything else is familiar: hidden 4096, 288 experts activated top-8 with one shared,
first_k_dense_replace 3, kv_lora_rank 512, q_lora_rank 1536. One declared value has to be treated
as a warning rather than a detail: qk_rope_head_dim = 0, i.e. no RoPE on the qk path, which no
model here has yet and which a copy-paste port from GLM-5.2 would get silently wrong.
Note what this stage is not: zai-org/GLM-5.3, the 703.7 GiB glm_moe_dsa release, is GLM-5.2's
trunk with a newer indexer (indexer_types, index_topk_pattern, index_skip_topk_offset,
index_share_for_mtp_iteration) and would be a separate, smaller piece of work.
What "supported" means here¶
The bar every model in the support matrix was already held to, restated so this roadmap can be judged against it:
- The released checkpoint generates tokens on this hardware from a real prompt — through the model's own tokenizer, not a list of synthetic ids. A synthetic prompt moves the router's draw and invalidates every bytes-moved figure, which is a mistake this repository has made and recorded.
- A comparable number: prefill and decode tokens a second at a stated context, taken as the benchmarking rules require — a real prompt, warm state, one configuration per process, differences taken interleaved inside one process with a null arm where the difference is small.
- Served behind the OpenAI-compatible endpoint, when the checkpoint is text-only.
- A guide under
docs/models/and a design record underdocs/architecture/, registered in the directory'sindex.mdand in themkdocs.ymlnav in the same commit —mkdocs build --stricttreats a missing registration as a failure, which is the point.
Out of scope for all three: vision and audio towers, which every one of these checkpoints bundles and this repository deliberately does not read; and any claim about model quality, which belongs to the authors' evaluations and not to an inference engine's measurements.
Ordering, and when to stop¶
The order is cost-of-reuse, and each stage has an explicit early gate rather than a hope:
| Stage | The gate | What a failure means |
|---|---|---|
| Bonsai | task ⅙ measures the upstream reference on this card | the ternary path is slower than the memory it saves → close the stage on the measurement |
| Xing4.0 | task ⅕ reads the hyper-connection out of the reference code | it is not a port → re-scope or drop before any kernel is written |
| GLM-5.3-Flash | task ⅕ identifies whether the linear layer is GDN | it is not → the stage grows a new attention kernel and the estimate changes |
Stage 1's gate has run: the reference measures 30.7 tokens/s of decode and 665 tokens/s of prefill on one card, which is a pass on both the memory and the speed axis. That page also pins the block format, the Hadamard and the kernel question, so the tasks after it start from a measured artifact rather than from a model card.
Stage 2's gate has run too, and it is also a pass: the audit writes the hyper-connection out as a forward pass a reimplementation can be built from and finds it agreed operation for operation by the two published implementations of it, which is what "it is a port" means here. It also re-reads this document's Stage 2 table against the artifacts and produces the per-token byte table that the stage's final task is measured against.
Xing4.0's third task has landed and is measured on sm_75:
the MLA attention is ported in both the expanded form the checkpoint's own code uses and the absorbed
form its released GGUF is shaped for, the two agree with the reference and with each other, and the
cost measurement found the thing worth knowing. The expected geometry held — 2.117 GiB of attention
weights per decode token against the MoE's 0.877 GiB, so the attention is not the bottleneck at the
contexts this card holds — but the way the absorbed score is naturally written re-reads the cache once
per head, and folding the head axis into the GEMM's M dimension took the 32K decode step from 2.991
to 0.516 ms per layer. Prefill takes the expanded form and decode the absorbed one; the gap is 3.2x at
2048 tokens and 20x at 32768.
Xing4.0's fourth task has landed too, and it is measured on the same
card: the matrix hyper-connection is ported as the
audit read it — four residual streams, a 4 + 4 + 16 coefficient split, a 20-iteration Sinkhorn, and a
residual that is rebuilt from post and comb rather than accumulated — and its forward pass is
held to the released code's own line for line. The finding is a dispatch count rather than an
arithmetic one: the block is 2.5% of a token's weight bytes and 300 kernel launches per call, 120 of
them the Sinkhorn's 20 iterations of (sum, add, divide) on each axis, which is 30.6 ms of GPU per
decode token for 0.09 ms of work. That is the second largest decode item in the stage after the MoE and
the most fixable, and it is recorded with the three ways out rather than fixed here.
A stage that dies at its gate is a result, and it goes in this document rather than the issue tree being quietly pruned. That is the same convention the old-hardware roadmap follows: it records what was measured and closed — the FP4 cross-layer prefetch, the score-split hybrid, the resident expert cache — and not only what shipped.
Evidence¶
Everything in this document is read from the artifacts rather than from documentation: the GGUF
metadata sections, config.json files, and the safetensors inventories, all via the Hugging Face API
and HTTP range requests. The specific reads:
prism-ml/Ternary-Bonsai-2-27B-gguf— metadata and tensor table of bothPTQ1_0(type 143) andPQ2_0(type 142); architecture stringqwen35,full_attention_interval 4, and theprism.hadamard.*block.XingChen-AGI/Xing4.0-29B-A4B-GGUF— metadata and tensor table ofxing4_0-29b-IQ4_NL.gguf; architecture stringxing4_0, MLA ranks, thehc_*tensors, and thehyper_connection.*keys.zai-org/GLM-5.3-Flash—layer_types(34 linear / 11 sparse), the indexer keys, and the quant inventory of its GGUF repository.zai-org/GLM-5.3andXiaomiMiMo/MiMo-V2.6-Pro-RL— configs read for the comparison in the issue tree; the Pro checkpoint is deliberately not a stage here, for the reasons in #380.
Related¶
- Feature roadmap for old hardware — the capability axis, and the other half of what this repository is for
- PocketLLM vs vLLM vs SGLang — the comparison that motivates serving a single card well rather than scaling out
- Qwen3.8-27B-FP8 design and measurements — the runtime stage 1 reuses
- GLM-5.2 design and measurements — the DSA path stage 3 reuses
- Benchmarking and reporting — how every number in these stages must be taken