Configuration¶
Everything on this page was read from the source. When a default here disagrees with older docs, the code wins, and the disagreement is marked TODO-VERIFY.
Server: proxy/server.py¶
All settings are environment variables read once at startup. Restart the server to change them.
Model and network¶
| Variable | Default | What the code does |
|---|---|---|
MLX_MODEL |
divinetribe/gemma-4-31b-it-abliterated-4bit-mlx |
Hugging Face ID or local folder passed to mlx_lm.utils.load(). Downloaded on first use if it is an ID. Reported as model by /health. |
MLX_PORT |
4000 |
Port to listen on. The server always binds 127.0.0.1, never all interfaces. |
Memory and speed¶
| Variable | Default | What the code does |
|---|---|---|
MLX_PREFILL_SIZE |
512 |
Tokens per prefill chunk (prefill_step_size). It used to be 8192; the code comment records 34.2 GB peak at 8192 vs 20.9 GB at 1024 on a 21.4k-token prompt with Gemma 4 31B 4-bit, and notes small chunks were not slower. |
MLX_CACHE_LIMIT_GB |
3 |
Cap on MLX's buffer recycle pool via mx.set_cache_limit. 0 disables the cap. Empty means the default. |
MLX_KV_BITS |
0 (full precision) |
KV cache quantization bits. When set, the server also passes kv_group_size=64. Forced back to 0 when the model path contains gemma, because mlx-lm cannot quantize Gemma's RotatingKVCache. |
MLX_KV_QUANT_START |
256 |
Token position where KV quantization begins (quantized_kv_start). Only used when MLX_KV_BITS is non-zero. |
MLX_KV_BITS=4 and tool calls
Issue #42 measured MLX_KV_BITS=4 on Hermes 4 14B passing 3 to 10 of 14 tool-call tests, against 12 to 13 at 0, with tool calls coming back with empty arguments partway through a session. Use 4-bit KV only when you need the memory. Claude Chat.command and Claude Agentico.command default to it (with MLX_KV_QUANT_START=0) to fit 16 GB.
TODO-VERIFY: defaults in older docs
docs/FULL-GUIDE.md lists the defaults as MLX_KV_BITS=8 and MLX_KV_QUANT_START=1024. The code defaults are 0 and 256. This page follows the code.
MLX_PORT, MLX_PREFILL_SIZE, MLX_KV_BITS, MLX_KV_QUANT_START, MLX_MAX_TOKENS and MLX_TOOL_RETRIES are read with a helper that treats an empty value as "use the default". MLX_CACHE_LIMIT_GB does the same. A non-numeric value stops the server at startup.
Generation¶
| Variable | Default | What the code does |
|---|---|---|
MLX_MAX_TOKENS |
8192 |
Output token limit when the request has no max_tokens. |
MLX_SUPPRESS_THINKING |
1 |
Only when the model path contains gemma: appends an empty <|channel>thought\n<channel|> block to the prompt so Gemma 4 skips its reasoning chain. Anything other than exactly 1 turns it off. |
MLX_TOOL_RETRIES |
2 |
How many times to re-prompt when the reply looks like a tool call but none could be parsed. Each retry runs on a fresh, throwaway KV cache. |
Temperature is not an environment variable. The server uses the request's temperature, defaulting to 0.2.
Prompt modes¶
| Variable | Default | What the code does |
|---|---|---|
MLX_CODE_MODE |
on | Any value except 0 keeps it on. When a request includes any of Bash, Read, Edit, Write, Grep, Glob or Skill, the server replaces Claude Code's system prompt with a short coding prompt, keeps only those seven tools and strips their descriptions down to names and parameter types. See How it works. |
MLX_BROWSER_MODE |
off | Exactly 1 turns it on. Takes priority over code mode. For requests that include Chrome DevTools MCP tools, replaces the system prompt with a browser prompt and keeps only nine mcp__chrome-devtools__* tools (no screenshots). Requests without those tools pass through untouched. |
MLX_APPEND_SYSTEM_PROMPT_FILE |
unset | Path to a text file. Its contents are appended to the system prompt after code or browser mode has run, separated by ---. Read on every request. Narrative Gemma.command uses it for its narration rules. |
Streaming and debugging¶
| Variable | Default | What the code does |
|---|---|---|
MLX_LIVE_STREAM |
on | For stream: true requests with no tools, tokens are sent as they are generated. 0 or false (any case) turns that off. Requests with tools are always generated in full first, parsed, then replayed as server-sent events. |
MLX_DEBUG_REQUEST |
unset | Any non-empty value logs the role and block types of the last six messages of each request. |
MLX_DEBUG_RESPONSE |
unset | Any non-empty value logs the tool schemas used for input filtering and the first 1500 characters of each response JSON. |
Request fields the server honors¶
| Field | Behavior |
|---|---|
system |
String or list of text blocks. Replaced in code mode and browser mode. |
messages |
Text, tool_use and tool_result blocks are converted. Image and document blocks inside a tool_result become the text [image omitted] or [document omitted]. tool_result with is_error: true gets an Error: prefix. |
tools |
Converted to the Hugging Face function format and passed to the model's chat template. If the template rejects them, they are written into the system prompt as text instead. A request with no tools never gets tool_use back. |
max_tokens |
Defaults to MLX_MAX_TOKENS. |
temperature |
Defaults to 0.2. |
stop_sequences |
Generation stops at the earliest match, the text is cut there, and stop_reason is stop_sequence. |
stream |
Server-sent events in the Anthropic format. |
model |
Not used to pick a model. Echoed back in the response (default claude-sonnet-4-6). |
HTTP endpoints¶
| Method and path | Response |
|---|---|
POST /v1/messages (also /messages) |
Anthropic Messages response, JSON or SSE. Errors are {"type": "error", "error": {...}}: 400 invalid_request_error for a body that is not a JSON object, 500 api_error if generation throws. |
POST /v1/messages/count_tokens (also /messages/count_tokens) |
{"input_tokens": N}, computed by running the same conversion and tokenizer as a real request. Falls back to characters / 4 if that fails. |
GET /v1/models (also /models) |
A fixed list: claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5-20251001. |
GET /health |
status, model, prefill_size, rss_gb, mx_active_gb, mx_cache_gb, mx_peak_gb. |
HEAD any path |
200 |
| Any other path | 200 with {} |
The server does not check x-api-key or Authorization.
Launchers¶
The .command files in launchers/ are bash scripts for macOS. All but the two Native Engine launchers source launchers/lib/claude-local-common.sh.
| Launcher | Default model | Starts the server with | Claude Code flags and extras |
|---|---|---|---|
Claude Local.command |
divinetribe/gemma-4-31b-it-abliterated-4bit-mlx |
ensure_mlx_server |
--permission-mode auto --bare --append-system-prompt-file ~/.claude/CLAUDE.md --mcp-config ~/.claude.json, ANTHROPIC_API_KEY=sk-local |
Gemma 4 Code.command |
divinetribe/gemma-4-31b-it-abliterated-4bit-mlx |
ensure_mlx_server |
--permission-mode auto --settings lib/local-settings.json --append-system-prompt-file ~/.claude/CLAUDE.md --mcp-config ~/.claude.json |
Qwen 3.8 Code.command |
lmstudio-community/Qwen3.8-27B-MLX-8bit |
ensure_mlx_server |
same as Gemma 4 Code |
Claude Chat.command |
mlx-community/Qwen2.5-Coder-14B-Instruct-4bit |
ensure_mlx_server, MLX_KV_BITS=4, MLX_KV_QUANT_START=0 |
--tools "" --effort low, offline env vars, ANTHROPIC_AUTH_TOKEN, DISABLE_LOGIN_COMMAND=1 |
Claude Agentico.command |
mlx-community/Qwen2.5-Coder-14B-Instruct-4bit |
same as Chat | --effort low --permission-mode auto, offline env vars, ANTHROPIC_AUTH_TOKEN, DISABLE_LOGIN_COMMAND=1 |
Narrative Gemma.command |
divinetribe/gemma-4-31b-it-abliterated-4bit-mlx |
force_restart_mlx_server with MLX_APPEND_SYSTEM_PROMPT_FILE |
Runs inside NarrativeGemma/ so its CLAUDE.md narration persona loads; starts NarrateClaude dictation if ~/NarrateClaude/dictation/bin/dictation exists |
Browser Agent.command |
divinetribe/gemma-4-31b-it-abliterated-4bit-mlx |
force_restart_mlx_server with MLX_BROWSER_MODE=1 |
Starts Brave with --remote-debugging-port=9222, then runs ~/.local/browser-agent/agent.py from the separate browser-agent repo. No Claude Code. |
Gemma 4 Code (Native Engine).command |
divinetribe/gemma-4-31b-it-abliterated-4bit-mlx |
none, model loads in-process | AGENT_DIALECT=prompted, runs agent/agent.py from ~ |
Qwen 3 Coder (Native Engine).command |
lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-MLX-8bit |
none, model loads in-process | AGENT_DIALECT=native, runs agent/agent.py from ~ |
"Offline env vars" means CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1, DISABLE_AUTOUPDATER=1, CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL=1 and CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1. lib/local-settings.json sets "apiKeyHelper": "echo sk-local".
TODO-VERIFY
- Only Chat and Agentico set the offline env vars (see Quickstart).
Claude Local,Gemma 4 Code,Qwen 3.8 CodeandNarrative Gemmapass~/.claude/CLAUDE.mdand~/.claude.jsonto Claude Code without checking that they exist. Behavior when they are missing is untested here.docs/MAC-BASE-SETUP.mdsays--baredoes not exist in recent CLI versions, while the README says an old CLI is the reason--barefails. OnlyClaude Local.commanduses it.
Settings every launcher reads¶
| Variable | Default | Used by |
|---|---|---|
MLX_MODEL |
per launcher, see table | all |
MLX_SERVER |
~/.local/mlx-native-server/server.py |
launchers using the shared library, start-mlx-server.sh, keepgoing |
MLX_PYTHON |
~/.local/mlx-server/bin/python3 |
all |
CLAUDE_BIN |
first of: claude on PATH, ~/.local/bin/claude, ~/.claude/local/claude, /opt/homebrew/bin/claude, /usr/local/bin/claude |
Claude Code launchers |
MLX_MODEL_LABEL |
Gemma 4 31B |
display name only, in Claude Local and Browser Agent |
MLX_KV_BITS, MLX_KV_QUANT_START |
empty | forwarded to the server by the shared library |
Two details of the shared library:
- Model-aware restart.
ensure_mlx_serverreads/healthand compares the last path component of the running model with the one you asked for, ignoring case. If they differ, it stops the server (pkill -f mlx-native-server/server.py) and starts the right one.force_restart_mlx_serveralways restarts, because some settings only apply at process start. - Local folders first.
resolve_mlx_modeluses a flat folder such as~/.cache/huggingface/hub/gemma-4-31b-it-abliterated-4bit-mlxif it exists and containsconfig.json, so mlx-lm loads from disk instead of downloading. Otherwise it passes the Hugging Face ID.
The server log goes to /tmp/mlx-server.log. The health wait is 180 checks two seconds apart (six minutes).
The Desktop launcher made by setup.sh¶
~/Desktop/Claude Local.command is generated, not copied. It has the chosen model, server path and Python path written into it, starts the server only if nothing is on port 4000 (it does not check which model is running), and runs Claude Code with ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY=sk-local and --model claude-sonnet-4-6, without the extra flags of launchers/Claude Local.command.
Native Engine: agent/agent.py¶
Command line¶
| Flag | Meaning |
|---|---|
-p, --prompt |
Run one prompt, print the final answer, exit |
--model |
Model ID or path (default: AGENT_MODEL) |
-C, --dir |
Change to this directory first |
Environment¶
| Variable | Default | Meaning |
|---|---|---|
AGENT_MODEL |
lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-MLX-8bit |
Model to load (mlx) or name to send (http) |
AGENT_TITLE |
last part of the model ID | Name shown in the banner and the system prompt |
AGENT_BACKEND |
mlx |
mlx loads the model in this process. http sends requests to an Anthropic-format server. |
AGENT_DIALECT |
native |
native passes the tools to the model's own chat template. prompted describes an XML tool format in the system prompt instead (used for Gemma 4). |
AGENT_BASE_URL |
empty | Server URL for the http backend, for example http://localhost:4000 |
AGENT_AUTH_TOKEN |
sk-local |
Sent as x-api-key and Authorization: Bearer on the http backend |
AGENT_MAX_TOKENS |
4096 |
Output limit per step |
AGENT_TEMP |
0.3 |
Sampling temperature |
AGENT_MAX_STEPS |
40 |
Tool-call steps per user turn |
AGENT_BASH_TIMEOUT |
120 |
Seconds before a Bash tool call is killed (stdin is closed so interactive programs exit) |
AGENT_CTX_LIMIT |
from the model config, else 131072 |
Context size used by the /context meter |
AGENT_ROLLING_KV |
unset | 1 keeps Gemma's stock rotating KV cache instead of swapping in plain caches. See How it works. |
AGENT_SPEAK |
unset | 1, true or yes speaks each final answer through ~/.local/bin/speak |
AGENT_PROMPT_FILE |
unset | Extra system prompt text, read once at startup |
AGENT_MEM_BROKER_DIR |
unset | Directory containing an external mem_client.py. When set, the engine reserves memory before loading and releases it on exit. Without it, nothing happens. |
AGENT_LEASE_NAME |
agent-local |
Name of that reservation |
AGENT_LEASE_GB |
36 (mlx) or 0 (http) |
Size of that reservation; 0 skips it |
Tool output fed back to the model is clipped to 30,000 characters. Grep needs rg (ripgrep) installed.
Commands inside the agent¶
| Command | Effect |
|---|---|
/exit, /quit |
Quit |
/reset |
Clear the conversation (and the KV cache) |
/context |
Show tokens used out of the context limit |
/tools |
List the tools |
/cwd |
Show the working directory |
/model |
Show the model path |
Keep going¶
keep going (or keepgoing) runs bin/keepgoing, which calls bin/keepgoing.py to find the newest Claude Code conversation for the current folder in ~/.claude/projects/*/*.jsonl and show a menu.
| Setting | Meaning |
|---|---|
OPENROUTER_API_KEY |
Free key from openrouter.ai. Unlocks the free cloud list. |
KEEPGOING_BEFORE_LOCAL |
Shell command run before a local model is started |
KEEPGOING_AFTER_LOCAL |
Shell command run when the local session ends |
MLX_PORT, MLX_PYTHON, MLX_SERVER |
Same meaning as for the server and launchers |
Settings can also live in ~/.config/claude-code-local/keepgoing.env, which is sourced first.
- Free cloud list: up to three OpenRouter models whose ID ends in
:free, that support tools and have at least 128,000 tokens of context, largest context first. Claude Code is pointed athttps://openrouter.ai/apiwithANTHROPIC_AUTH_TOKENset to your key. - Local list: the model already running on the port (if any), then the five
setup.shmodels whose memory requirement (8, 16, 32, 64, 96 GB) your Mac meets. Choosing one kills whatever is on the port, starts the server and waits up to 20 minutes for it. The local path sets the four offline env vars.
To get the reminder in Claude Code's status line, point statusLine in ~/.claude/settings.json at bash ~/claude-code-local/scripts/statusline-keepgoing.sh.
Helper scripts¶
| Script | Arguments and settings |
|---|---|
install.sh |
CCL_DIR sets the install folder (default ~/claude-code-local) |
setup.sh |
none |
uninstall.sh |
--keep-models, -h/--help |
scripts/doctor.sh |
--bench; reads HF_HOME |
scripts/start-mlx-server.sh |
Model as first argument, else MLX_MODEL; MLX_PORT, MLX_PYTHON, MLX_SERVER |
scripts/download-and-import.sh |
Short name or Hugging Face ID (list); MLX_MODEL, MLX_PYTHON |
scripts/persistent-download.sh |
Same arguments, retried every 10 s |
scripts/upload-mlx-quant.sh |
<local-folder> <hf-repo-id>; needs hf auth login or HF_TOKEN; installs hf_transfer into the MLX venv |
bin/fia |
start/code/brain, gemma, qwen, voice/narrate, browser, phone, make film\|music, status, help. A front door that runs the matching launcher or prints where to get the missing piece. |
smart-router/ (experimental)¶
smart-router/router.py listens on ONE_AI_PORT (default 4010) and forwards each Anthropic request to one of several local backends using keyword and size rules (/deep, /glm, /fast, /code overrides; over ~100k estimated tokens to a DeepSeek server on port 8000; short greetings to Gemma; everything else to Qwen3-Coder). warm_pool.sh keeps two models loaded on ports 4000 and 4001.
TODO-VERIFY
Both files hardcode paths under ~/Desktop/PROJECTS/Local AI Setup and ~/.lmstudio/models, and expect other servers (a DeepSeek ds4 server, a GLM model) that this repo does not install. They look like the maintainer's own setup rather than something meant to run as shipped.