Laya MPS on macOS
A memory-conscious local runtime and HTTP server for Apple GPU / MPS, with multiple memory modes and benchmark tooling.
git clone https://github.com/afshinm/laya-mps.git
cd laya-mps
./scripts/serve.shRequires Apple Silicon and a recent macOS. Memory and latency numbers are hardware-specific.
laya-mps runs Laya on your Mac's GPU through PyTorch's Metal Performance Shaders (MPS) backend, as a local HTTP server with a browser demo, and focuses on low memory use.
Note the default model: it serves laya-typed-decisions, the checkpoint fine-tuned for customer service, invoices, security incidents and agent traces (what that means). Use --checkpoint english for the general English model.
Requirements
- Apple Silicon Mac (M1 or newer), macOS 14+.
- Git and uv; uv installs Python 3.12 if needed.
- About 4 GB of free disk for the runtime, cache and ~843 MB model.
Start it
git clone https://github.com/afshinm/laya-mps.git
cd laya-mps
./scripts/serve.sh
The first run installs dependencies and downloads the model; later runs work offline. The server listens on 127.0.0.1:8000, with a Pong demo and a 60-second latency benchmark at /demo/.
Memory modes (project README, M5 Pro, 24 GiB)
| Setting | Peak process RAM | Median decision latency |
|---|---|---|
minimal | 0.74 GiB | 171 ms |
reduced (default) | 2.11 GiB | 32 ms |
full | 2.30 GiB | 32 ms |
All three settings run the full model in FP32 and matched exactly on 260/260 decisions. minimal streams layers from disk, which is why it is slower. Switch with ./scripts/serve.sh --memory minimal.
API
curl -sS http://127.0.0.1:8000/v1/decisions \
-H 'Content-Type: application/json' \
--data-raw '{
"state": "The export page returns HTTP 500. Our team cannot finish its work.",
"questions": {
"owner": {"type": "choice",
"instructions": "Which team should investigate this report?",
"criteria": {"billing": "Payments and invoices",
"engineering": "Software failures"}}
}
}'
- Endpoints:
GET /health,GET /v1/config,POST /v1/decisions,GET /docs,GET /demo/. - 1–16 questions per request;
choicetakes 2–26 labels,scoretakes 2–10levels. - Add
?metrics=truefor timing and memory, or?diagnostics=truefor tokens, temperatures and logits. - One inference runs at a time; a busy server answers
503withRetry-After: 1. - Not a drop-in Jev endpoint: it uses its own path, a
levelsfield for scores and its own limits. For a Jev-compatible API see Arbiter or upstream'slaya-serve.
CLI
uv run --locked laya-mps decide request.json evaluates a request without starting the server; laya-mps doctor checks GPU availability and model readiness.
Source: afshinm/laya-mps · MIT (model weights Apache 2.0).
Last verified against the project README: September 24, 2026.