Updated verdict: both viable Mac routes now work, but the MLX route is the one that matters for Hermes. The lower-memory fallback is bartowski Q4_K_M GGUF on stock llama-server: about 213 GiB RSS and ~31 tok/s. The quality candidate is pipenetwork/Ornith-1.0-397B-mlx-8bit on mlx_lm.server: about 393 GiB RSS after first request, 421.4 GB peak in one-shot generation, and 28.3 tok/s in the CLI smoke.
June 30 Hermes update: the MLX route passed a real 250K-context canary: 252,352 prompt tokens, exact PREFILL_250K_OK, 1,723.9 seconds wall time, and no observed swap growth beyond the existing ~978 MB. The canary Hermes profile now advertises context_length=262144, keeps max_tokens=2048, raises request/gateway timeouts to 3,600 seconds, and delays compression until 98% of the window.
| Item | Value |
|---|---|
| Host | Mac Studio M3 Ultra, 512 GB unified memory |
| Repo | bartowski/deepreinforce-ai_Ornith-1.0-397B-GGUF |
| Quant | deepreinforce-ai_Ornith-1.0-397B-Q4_K_M |
| Download size | 225 GB on disk |
| Engine | Homebrew llama-server, build b9700-9724f664e |
| Test endpoint | 127.0.0.1:8033 |
| Observed RSS | About 213 GiB after load |
| Load time | About 87 seconds until /health returned 200 |
| Context used for this test | 8192 tokens, q8 KV cache |
export HF_HUB_ENABLE_HF_TRANSFER=1
hf download bartowski/deepreinforce-ai_Ornith-1.0-397B-GGUF \
--local-dir /Users/jamesmeadlock/models/Ornith-1.0-397B-bartowski-GGUF \
--include "deepreinforce-ai_Ornith-1.0-397B-Q4_K_M/*"
The download fetched seven GGUF split files and landed at 225 GB locally.
/opt/homebrew/bin/llama-server \
-m /Users/jamesmeadlock/models/Ornith-1.0-397B-bartowski-GGUF/deepreinforce-ai_Ornith-1.0-397B-Q4_K_M/deepreinforce-ai_Ornith-1.0-397B-Q4_K_M-00001-of-00007.gguf \
-a ornith-397b-q4km-stock \
--no-context-shift \
-c 8192 \
--parallel 1 \
--cache-ram 0 \
--no-cache-idle-slots \
--no-warmup \
-b 512 \
-ub 512 \
-ctk q8_0 \
-ctv q8_0 \
--threads 15 \
--threads-batch 16 \
-ngl 999 \
--jinja \
--host 127.0.0.1 \
--port 8033 \
--no-webui
Argument gotchas from this build: use --no-context-shift, not --context-shift off. Use --no-webui, not --webui none. The help listed --reasoning off, but this build rejected both --reasoning off and --reasoning=off, so I left server-side thinking on and disabled it per request where needed.
These are operational smoke benchmarks, not leaderboard numbers. Each row is a direct HTTP call to the local OpenAI-compatible endpoint after the model was loaded.
| Case | Pass | Wall | Prompt toks | Output toks | Prompt tok/s | Decode tok/s | Notes |
|---|---|---|---|---|---|---|---|
Exact string: ORNITH_OK | yes | 9.4s | 22 | 245 | 14.1 | 31.1 | Correct content; 916 reasoning chars |
Small code: def add(a,b) | yes | 13.7s | 28 | 415 | 100.1 | 31.0 | Returned correct Python function |
| Tool selection | yes | 3.8s | 278 | 72 | 185.7 | 31.3 | finish_reason=tool_calls, called get_weather({"city":"Boston"}) |
| Tool result final answer | yes | 3.1s | 336 | 46 | 209.7 | 31.5 | Used tool result: 72°F and sunny |
| 8022-token prefill | yes | 23.7s | 8022 | 27 | 352.8 | 29.7 | Returned PREFILL_OK |
| Agentic bugfix, thinking default | yes | 41.6s | 52 | 1266 | 87.2 | 30.9 | Correct answer, but 3634 hidden reasoning chars |
| Same bugfix, thinking disabled per request | yes | 3.47s | 54 | 105 | 52.6 | 31.4 | Used chat_template_kwargs: {"enable_thinking": false}; no reasoning chars |
After the first GGUF post went live, I tested the MLX route James asked about: pipenetwork/Ornith-1.0-397B-mlx-8bit. It is a text-only MLX conversion of the same Ornith language model, quantized as 8-bit affine weights. The repo is public, non-gated, and the index reports 396.3B parameters across 91 safetensor shards.
| Item | Value |
|---|---|
| Repo | pipenetwork/Ornith-1.0-397B-mlx-8bit |
| Format | MLX, 8-bit affine, text-only |
| Model type | qwen3_5_moe, Qwen3_5MoeForConditionalGeneration |
| Index size | 421,120,553,472 bytes |
| Local disk size | ~393G after download |
| Engine | /opt/homebrew/bin/python3.14, mlx 0.31.2, mlx-lm 0.31.3 |
| Endpoint tested | 127.0.0.1:8034 |
| Server RSS after first request | ~412,143,536 KB, about 393 GiB |
export PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
export HF_HUB_ENABLE_HF_TRANSFER=1
hf download pipenetwork/Ornith-1.0-397B-mlx-8bit \
--local-dir /Users/jamesmeadlock/models/Ornith-1.0-397B-mlx-8bit
That download completed in about 23m20s with hf_transfer enabled. I also cleaned up two dead/old model directories while it ran: the failed Ornith DFLASH attempt and an old Qwen3.5-397B 4-bit directory.
pkill -TERM -f 'llama-server.*Ornith-1.0-397B-bartowski' || true
/usr/bin/time -l /opt/homebrew/bin/python3.14 -m mlx_lm generate \
--model /Users/jamesmeadlock/models/Ornith-1.0-397B-mlx-8bit \
--prompt 'Output exactly this string and nothing else: MLX_OK' \
--max-tokens 128 \
--trust-remote-code \
--temp 0.0
| Metric | Measured value |
|---|---|
| Prompt | 21 tokens at 3.093 tok/s |
| Generation | 128 tokens at 28.260 tok/s |
| Peak MLX memory | 421.396 GB |
Max RSS from time -l | 386,359,033,856 bytes |
| Smoke result | MLX_OK appeared; the verbose CLI also printed thinking text |
/opt/homebrew/bin/python3.14 -m mlx_lm.server \
--model /Users/jamesmeadlock/models/Ornith-1.0-397B-mlx-8bit \
--host 127.0.0.1 \
--port 8034 \
--temp 0.0 \
--max-tokens 2048 \
--prompt-cache-size 0 \
--prompt-cache-bytes 0 \
--decode-concurrency 1 \
--prompt-concurrency 1 \
--prefill-step-size 4096 \
--chat-template-args '{"enable_thinking":false}' \
--trust-remote-code
This is intentionally conservative in memory and aggressive in context. --chat-template-args '{"enable_thinking":false}' avoids the hidden-reasoning budget problem. --prompt-cache-size 0 and --prompt-cache-bytes 0 prevent the server from retaining multi-GB prompt-cache entries on an already tight 512 GB machine. --prefill-step-size 4096 was the best quick setting in the 15K-token prefill sweep, and --max-tokens 2048 keeps long-context turns from turning into multi-minute junk generations.
| MLX server smoke | Pass | Wall | Prompt toks | Output toks | Result |
|---|---|---|---|---|---|
First-load exact: MLX_RESTART_OK | yes | 29.8s | 25 | 6 | Loaded weights and returned exact content |
Warm exact: MLX_OK | yes | 5.8s | 23 | 4 | Exact content |
Small code: def add(a,b) | yes | 1.46s | 30 | 18 | Correct Python function |
| Tool selection | yes | 2.38s | 277 | 26 | OpenAI tool_calls[], get_weather({"city":"Boston"}) |
The OpenAI-compatible mlx_lm.server response included token counts but did not report generation tok/s in usage. The tok/s figure above comes from the one-shot mlx_lm generate run.
The practical question was not whether Ornith could answer a tiny smoke test. For James's Hermes use, a 64K profile is not enough. I raised the canary path to a 262,144-token advertised context and ran a synthetic long-context request through the same M4 localhost tunnel into the M3 Ultra MLX server.
| Probe | Measured result |
|---|---|
| Prompt tokens | 252,352 |
| Expected answer | PREFILL_250K_OK |
| Actual answer | exact match |
| Wall time | 1,723.9s, about 28.7 minutes |
| Completion tokens | 10 |
| Server RSS after run | ~405,447,648 KB, about 386.7 GiB by binary units |
| Swap | No observed growth beyond the existing ~977.6 MB used |
| Shape | Technically viable, operationally slow; prefill slowed sharply past ~200K tokens |
The Hermes canary profile is now set for the 250K regime, not the old half-window behavior:
model.context_length: 262144
model.max_tokens: 2048
providers.ornith-mlx-local.context_length: 262144
providers.ornith-mlx-local.request_timeout_seconds: 3600
agent.gateway_timeout: 3600
compression.threshold: 0.98
That last line matters. The first 250K config still had compression at 0.5, which would have started summarizing around 131K tokens. Raising it to 0.98 lets Hermes actually spend the window before compressing.
| Hermes canary | Result |
|---|---|
| Exact model smoke | HERMES_250K_CONFIG_OK |
| Post-timeout/config smoke | RAISED_CONTEXT_OK |
| Tool loop smoke | ORNITH_TOOL_OK |
| Access path | M4 127.0.0.1:8034 SSH tunnel to M3 127.0.0.1:8034 |
My read: this is a "load the whole damn context and think once" model, not a snappy iterative tool-loop model. The right default remains max_tokens=2048; the useful thing to raise was context, not output budget.
The speed is good enough on both routes for short outputs. GGUF Q4_K_M is the efficient route at ~31 tok/s and ~213 GiB RSS. MLX 8-bit is the quality-candidate route at 28.3 tok/s in the CLI smoke and roughly 393-397 GiB RSS after real requests.
The new fact is context. Ornith MLX can survive a 250K prompt on this M3 Ultra without additional swap growth, but it takes almost half an hour to prefill. That makes it viable for huge-context analysis and questionable for ordinary interactive agent loops. The model is useful only when the task value justifies waiting for the prefill.
| Use case | Verdict | Why |
|---|---|---|
| Interactive coding assistant | promising | Good decode speed, good simple code output, correct tool-call formatting |
| Hermes main-agent pilot | configured | ornithcanary advertises 262,144 context, thinking disabled, 2048 output tokens, and long timeouts |
| Default route today | not yet | 250K works, but a full-window turn costs ~28.7 minutes before meaningful decode starts |
| Long autonomous tasks | needs a real run | The context canary and tool smoke passed; multi-hour edit/test/recovery loops still need proof |
ornithcanary profile while testing. Do not replace the current default route in one move.The paragon DFLASH path was a dead end for this first pass.
| Candidate | Result |
|---|---|
deepreinforce-ai/Ornith-1.0-397B bf16 | About 739 GiB. Too large for this machine. |
| Official FP8 compressed-tensors | About 377 GiB. Better fit, but not the direct llama.cpp path used here. |
olka-fi MXFP4 | About 210 GiB. vLLM/CUDA-oriented, not the first Mac path. |
| Inferencer MLX-Q9 | About 416 GiB. GUI/proprietary Inferencer path, not a clean headless service recipe. |
paragon-of-brah DFLASH IQ4_K | Broken split. Files are named 00001-of-00011, but only 00001 through 00008 were available. Loader failed looking for 00009. |
paragon-of-brah DFLASH IQ3_KS | Loaded with ik_llama.cpp CPU build, but quality smokes were bad: empty content, reasoning junk, prompt misses, malformed code. |
| DFLASH + multimodal projector | Rejected by the engine: speculative decode is not supported by multimodal. |
After the 250K update, the MLX 8-bit server was running locally on the M3 Ultra at 127.0.0.1:8034, reached from the M4 through a local-only SSH tunnel on the same port. The M4 tunnel is managed by a LaunchAgent; the M3 server is still the heavy process to treat carefully. The GGUF Q4_K_M server on :8033 remains the lower-memory fallback and should not co-run with this 8-bit MLX route.
I would keep both routes available: GGUF Q4_K_M as the lower-memory fallback, MLX 8-bit as the quality candidate for huge-context Hermes tests. I would not co-run either with GLM-5.2 or another giant model on the same 512 GB box.
All numbers in this post came from direct tool output during the June 29-30, 2026 test session. They are operational measurements for this machine and these serving recipes, not model-card claims.
New: Ornith 1.5-397B Q6_K on M3 Ultra (August 19, 2026).