Numbering note: this ships everything that was staged as 2.0.3 plus the cache completion work on top. Together it grew past a patch, so it lands as 2.1.0. If you are on 2.0.2, everything below is new.
Memory (#150)
- The MLX allocator cache is bounded by default. MLX's own cache limit
tracks the memory limit (about 0.75x RAM high water), so freed
transients accumulated for the process lifetime. That was the dominant
bloat mechanism on 96GB and larger machines. Now RAM-tiered (2 to 8
GiB) out of the box;
--mlx-cache-limitto override,offto opt out. Diagnosis by @mmmugh. - New
--memory-budgetflag (envMTPLX_MEMORY_BUDGET): one knob that scales the session cache budget and the allocator bound to fit a declared RAM envelope. - The per-session admission cap is re-clamped on machines under 96GB. The v2 auto-sizing rule silently raised the gate compared to v1.0.4's flat 8GiB, letting 64GB machines admit snapshots whose restore transients blow past physical RAM. Found by @ArthoPacini.
- The paged KV pool no longer grows past
--context-window. The geometric growth step used to allocate blocks no request could address at 100k+ contexts. - Fixed a q4 crash on the paged split-SDPA path under kv-quant (the accumulator was sized to the dequantized head dim instead of the packed storage dim). Reported by @ArthoPacini.
- The memory pressure responder is redesigned: edge-triggered with hysteresis, and it defers to an idle engine instead of tearing down the allocator mid-decode every 10 seconds.
- The SSD session cache writer has a byte-bounded backlog and an hourly write budget, which closes the disk-write half of #144.
Agent and chat sessions (#121, #159, #144 read side)
- Warm prefix reuse now survives every tool turn. Chat templates render the last assistant turn differently from earlier ones, so every tool turn used to break the token prefix and prefill skip decayed toward 24% as sessions grew. Fixed end to end: recurrent-state boundary records thread through every store, inherit across entries, and the near-prefix restore lane runs whenever it beats the exact match. In replay validation, skip stays at 83 to 87% through hostile history rewrites (previously 52% and falling). Telemetry from @mmmugh and other reporters on the thread shortened this one.
- Near-prefix restores on hybrid (recurrent attention) models no longer collapse to the oldest retained boundary. Retention was tail-biased, so after enough turns a follow-up that diverged late could restore at around token 2,048 and re-prefill 20k+ tokens, felt as 30 to 50 second waits in agent front-ends. Retention is now geometric by distance from the tail and contract-tested. Live measurement on a 21,785 token prompt: the follow-up reused 21,760 tokens and started in 0.4s, against 33.8s for the same prompt cold.
- Sessions restored after a daemon restart keep their boundary records across SSD generations, so a new session over a shared system prompt restores warm instead of silently going cold (#159). Live measurement: 99.9% of the prefix restored from SSD after a real restart, first token in 2.0s.
- Every response now reports the session cache hit in standard usage
fields:
usage.prompt_tokens_details.cached_tokens(OpenAI shape) andusage.cache_read_input_tokens(Anthropic shape). - Session bank entry caps raised from 8/16 to 24/48. Tool sessions store about 3 entries per turn; bytes still bound the memory.
Sampling (#156)
- Presence and frequency penalties were silent no-ops in the batched AR
lane (quickstart chat and
--scheduler-mode ar_batch): the sampler never saw token history. Fixed with exact parity against the serial lane. Small models that lean on repetition penalties are the visible beneficiaries. Report, diagnosis, and PR by @mmmugh, with a convergent PR by @SuperMarioYL.
Performance
- The model-owner thread is pinned to USER_INITIATED QoS: 8 to 10% faster
decode under heavy background load (Electron apps, compositing), and
exactly flat when the machine is idle.
MTPLX_GENERATION_QOSto override.
App
- Fixed the startup and update hang (#158). Runtime installs run off the main thread, every subprocess wait has a deadline watchdog (a wedged pip now surfaces as an error instead of freezing the app), and the python probe is bounded. The reporter's spin dump made this a fast find. A follow-up sweep watchdogged every remaining subprocess wait and closed two more main-thread beachball sites.
- The Hermes tile launches Hermes Desktop when it is installed, with the terminal flow as fallback, pinned to the MTPLX backend profile.
- Raw
<tool_call>XML no longer leaks into chats that have no tools configured, including the unclosed-tag shape small models emit (#160). Reported by @FilterJoe. - Public app builds now fail loudly if the runtime wheel or the bundled Python is missing instead of producing a hollow bundle.
CLI
mtplx start opencodeserves the same engine lane the app serves. The in-decode cache-trim cadence is aligned (256 to 1024, measured flat or better on every promoted 27B artifact) and the banner no longer prints the pre-resolution profile.
Models and backends
- New
qwen3_5_mtpnative backend: Qwen3.5 and 3.6 MoE MTP exports load and draft correctly (trunk shim, sidecar key remap, sanitize double-shift fix). This also fixesforge buildfor that model type (#147). From PR #142 by @PhilipJohnBasile. - New
hy_v3(Tencent Hy3) native backend, also from @PhilipJohnBasile. It activates automatically once mlx-lm shipsmodels/hy_v3in a release. - Hermes streams no longer show tool preambles. PR #153 by @shiftedx.
- Dependency ranges:
transformers <5.14, !=5.13.0(5.13.0 breaks mlx-lm imports) andmlx >=0.31,<0.33(0.32 verified byte-identical on the exactness gate).
Operators
MTPLX_COMPILED_VERIFY_MAX_CONTEXTis honored as a user env override on profiled daemons, matching the other compiled-verify knobs, so you can A/B the compiled verify window without patching site-packages.
Known issues and what is next
- Long generations at 30k+ context on 27B-class hybrids settle into a verify-cost plateau around 33 to 35 tok/s on M-series. That is kernel work and it is queued for the next performance release.
- Context-copy drafting (PR #151 by @lBroth) is planned as the headline of that release.
- Hermes Desktop opens every session with its own stock prompt of about 22k tokens (client-side, independent of the profile's system prompt, which the Hermes terminal path does honor). First turns there pay that prefill once per session. We are raising it upstream.
Credits
@mmmugh, @ArthoPacini, @gcstang, @PhilipJohnBasile, @shiftedx, @SuperMarioYL, @FilterJoe, @lBroth, and everyone who retested builds and sent diagnostics. A lot of this release is your work.
Get it. Download the current DMG, or
brew upgrade mtplx / pip install -U mtplx. Every published speed
number with its conditions is on the benchmarks page; the archive of every version is
on the releases page.