Skip to content

Engineering

No server to start. The model answers from inside the app.

Runlix runs models in its own process: nothing to launch first, six model families that work natively, and speed measured against mlx-lm with the date of the measurement next to it.

Updated 2026-09-13Measured 2026-09-07

You open the app and ask a question. That is the whole sequence.

Nothing to start first No background service, no terminal window, nothing listening on a port unless you switch it on.
No Python, anywhere Not in the inference path and not in the app: 229 MB installed, 80 MB to download, and the build fails if an interpreter ever finds its way back in.
Six model families, natively And for the rest, a straight answer before you download: not yet, or not at all.
86–93% of mlx-lm Measured 7 September 2026. The four ratios are further down, with the day next to them.

This sounds like a small thing until the day it isn't. Most ways of running a model on your own Mac put a separate program in the middle: the app you click talks over the network to an engine someone else wrote, which is itself running on a language runtime with its own versions and its own ways of breaking. When that arrangement fails, the thing that stopped working is not the thing you installed, and the error message belongs to a program you never chose.

Runlix loads the model into itself. Quit the app and nothing is left running.

Will my model actually run?

Six model families work natively:

  • phi3
  • llama
  • qwen2
  • qwen3
  • gemma3_text
  • deepseek_v2

In practice that covers most of what people download — and it includes models whose names say nothing about it, because Mistral models are built on the llama shape and run natively too. Runlix tells you which family it recognised rather than leaving you to guess.

For a model outside those six the answer is not yet, and it comes with its reason. If mlx-lm knows the family, it is one the engine can learn, and the list grows one verified family at a time. If nobody knows it, Runlix says that too. There is no second, slower engine hiding behind the first: what you run is what you get.

And you find out before the download, not after. Downloading eight gigabytes to discover the model will not load is the ordinary experience of running AI locally, and it is the one thing here that was designed away: Runlix reads the model's own description on Hugging Face first and gives you a verdict with the reason written next to it. That is covered on the models page.

How this differs from the usual arrangement

If you have run models locally before, you have almost certainly used a setup with two halves: a background service that holds the model, and a window that talks to it. That design has real advantages, and they are worth naming honestly — the service keeps running when you close the window, several apps can share one loaded model, and a crash in the model does not take your interface down with it.

A service plus a window

  • The service keeps running when you close the window.
  • Several apps can share one loaded model.
  • A crash in the model does not take your interface down.
  • Something separate to install and keep updated.
  • A port, which something else on your Mac may already want.
  • When an answer never arrives, which half is stuck is yours to work out.
  • Often Python underneath: a second software environment with its own versions and its own ways of breaking on a Tuesday.

Runlix

  • One thing to install, one thing to quit.
  • One place a failure can come from — never the question of which half.
  • No port open unless you ask for one.
  • No second software environment to maintain.
  • Nothing is left running when you quit.
  • You cannot share a loaded model between applications.
  • A crash in the model takes the app with it.

Neither answer is universally right. This one is right if you want the model to feel like part of an application rather than like infrastructure you maintain.

How fast, compared to what

Speed on its own is a number without a meaning. The honest way to state it is as a ratio against a reference everybody can run — mlx-lm, the library Apple's own examples use — with the day the measurement was taken written next to it, because a number in a marketing page has nobody maintaining it.

Greedy generation 89% 253 tok/s · reference 284 tok/s
Temperature 0.8 93% 229 tok/s · reference 246 tok/s
Repetition penalty 1.1 93% 228 tok/s · reference 246 tok/s
4096-token prompt 86% 1865 ms · reference 1609 ms

Reference: mlx-lm = 100%. Measured 7 September 2026, Llama-3.2-1B at 4 bit. Peak memory on the 4096-token prompt: 1115 MB.

Runlix is behind the reference on every row, and that is stated rather than hidden. Between 86% and 93% of a library that has had years of attention, in exchange for the model living inside the application instead of behind a network port. If raw tokens per second is the only thing you care about, the reference is right there and you can run it.

What it does to your Mac

You can keep more than one model loaded at once, and switch between them without waiting for a reload each time. When there is no room left, the one you have not used for longest makes way — never the one that is answering you at that moment.

The limit is not the RAM printed on the box. It is how much of it the graphics system says it is willing to hand over, which the app asks for rather than assuming.

23347 MB What a 24 GB Mac actually offered, asked rather than assumed.
1.68× What a long question costs beyond the model's own weights. Measured on a 1B model, rounded up to double for safety.
1 Models kept loaded when the machine will not say what its ceiling is — rather than guessing a number.

What this means day to day: on a Mac with plenty of memory you can leave a small fast model and a larger careful one both loaded, and move between them in a conversation without a pause. On a machine with less to spare, the app quietly makes room and reloads when you come back — slower, but never a refusal and never a crash for running out.

What it refuses to do, and what it costs you

It refuses rather than guesses

Some models describe themselves in ways this engine does not implement. When that happens the model fails to load, with the reason named, instead of loading anyway.

That refusal is the feature. An inference engine that is almost right does not crash — it produces fluent, confident, wrong text, and you find out weeks later or never. Given the choice between an error today and a plausible mistake you may never catch, this errs today.

Two limits to know before you start: models in MLX format only — no GGUF, a decision and not an unfinished corner — and no vision models. Both are checked against Hugging Face before you spend the download.

And if it crashes, it takes the app

Running the model inside the application is a trade, and this is the side you pay: a crash in the model code takes the application with it. There is no server in between to absorb it.

It was chosen deliberately, and the way out is kept ready: the engine is separated from the app by a boundary designed so it can be moved back into its own process on the day that trade stops being worth it.

Saying it plainly is part of the point. You are choosing an arrangement, not being sold a free lunch.

If you want to check any of this

None of the above asks to be believed.

Correctness

mlx-lm is used to generate the exact sequence of tokens a model should produce for a given question; the engine has to reproduce it, and the build fails if it does not. Where the reference itself is genuinely undecided between two words, the test records the margin instead of demanding agreement on a coin flip.

The list of six

Not a claim in a brochure. Each family is recorded alongside the version of mlx-lm it was translated from and the date it was last verified, and the build fails if a family is declared supported without both.

The speed numbers

Every ratio above carries the day it was taken and the model it was taken on. Re-run them when you like; the reference is a public library.

The third-party code

Apple's MLX interface ships inside the project exactly as published, with its fingerprint verified before every build. Corrections are kept as separate patches, and the build stops and names the patch if one no longer fits — so a change cannot quietly disappear at the next update.

The engineering behind these checks — why a misspelled function name across a language boundary is not a compile error, and how a correct name with the wrong type turned a 23 GB memory ceiling into 2.8 GB without ever crashing — is written up in the notes, which is where that kind of thing belongs.