The catalogue rows carry the figures measured on a Mac (the MLX build of
qwen3.6:35b-a3b is 23,105,798,956 bytes, about 37 KB held per context token,
about 3 GB of runner overhead, about 5 GB more for a moment while a long
prompt is processed). A model's need is now its peak. Rows that were not
measured use the same per-token and overhead figures and say `estimated`.
qwen3.6:35b-a3b gets the tested entry for an Apple M5 Pro with 48 GB and
OpenCode, with its measured 67.7 tokens per second, so that row may say
"Tested on a Mac like this".
The ranking changes with it: a pair tested on a Mac like this one comes
first, then speed (ok, unknown, slow), then model rank, harness rank and the
larger context. The fit grade decides whether a row is listed and what it
says, it no longer sorts, so a model is offered at the largest context it
fits at. recommend() takes the budget the runtime measured
(`budgetSource: measured`), and modelFitsBudget() judges one model against it.
Candidate rows now always carry `needSource`, `harnesses`, `installBytes`,
`installGb` and, where one applies, `tag`. `kvBytesPerToken` and the prompt
cache tiers are gone.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The core of the read-only recommendation: what this Mac is, what the catalogue
knows, and which model fits. Nothing is downloaded, installed or written.
- hardware.ts: one bounded async spawn of /usr/sbin/sysctl with seven keys,
without -n, parsed as "key: value" lines by the pure parseSysctl(). Free disk
of the data dir through statfs behind the bounded path probe. Fallbacks from
node:os, a 60 s cache, never throws, never system_profiler. A wired limit of
0 means "not set".
- local-model-catalog.ts: seven models, three harness rows (pi gated) and the
chips table as a compiled constant, validated by a Zod schema on first use.
No override file. Model ids are name:tag in lowercase without a slash; every
model carries paramsB and an (empty) tested list. Chip names match on the
end of the chip string, so 'M4' is not the chip of 'Apple M4 Pro'.
- recommend.ts: device budget (the wired limit when above 0, else 2/3 of
memory below 36 GB and 3/4 from 36 GB, less the reserve), need = weights +
KV cache + 1 GiB + prompt cache, fit good up to 0.85 and tight up to 0.98,
speed ok, unknown or slow (a chip in no chips row is unknown), and the
ranking. Verdicts ok, limited (best model under 12 billion parameters) and
none with its reason. "Recommended" only for a pick with a tested entry for
this Mac, which no row has today.
- types/local-model.ts: comments brought in line with the code (chip matching,
budgetShare rounding, a budget of 0 on an Intel Mac).
- cli-registry-no-id-branching.test.ts: the guard also catches a comparison of
a `cli` field with a CLI id (plus one stray blank line Prettier refused).
Tests: test/local-model-format.test.ts, test/local-model-hardware.test.ts
(the captured output of two real Macs), test/local-model-catalog.test.ts,
test/local-model-recommend.test.ts.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>