Deploy Macos
DevOps & Securitydeploy-macosDeploy Macos is an Agent Skill for devops & security published in the Mesh-LLM/mesh-llm repository on GitHub: a SKILL.md instruction file an AI agent can load to do this task.
Use this skill when deploying, installing, launching, or serving mesh-llm on a macOS machine (local or remote over SSH), including installing a release, shipping a dev build bundle, codesign/quarantine fixes, choosing a model, and verifying it serves.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/Mesh-LLM/mesh-llm/blob/HEAD/.skills/deploy-macos/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/deploy-macos, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
deploy-macos
Use this when standing up mesh-llm on a macOS machine — either installing a release or shipping a locally built dev binary to a remote Mac for testing.
This is the macOS counterpart to deploy-linux-gpu. The current binary embeds
the staged llama.cpp runtime: the bundle is a single mesh-llm binary.
There is no rpc-server, no llama-server, and no .dylib set anymore — if
you see instructions mentioning those, they are outdated.
Related skills/docs:
deploy-linux-gpu— remote Linux/CUDA nodesdeploy-windows— Windows nodesmesh-join— creating/joining private and public meshes (tokens, NAT, multi-node)connect-agents— pointing Goose/Claude Code/OpenCode/Pi at a running meshdocs/USAGE.md— install details, service mode, model storagedocs/CLI.md— full command and model-ref reference
The one rule that matters most
mesh-llm resolves and downloads the model itself. Pass --model <ref> and
it fetches the GGUF into the standard Hugging Face cache on first use. Do NOT
pre-download with hf/huggingface-cli, do NOT scp GGUFs around. (Only
--gguf takes a local file path you manage yourself.)
Install path A: official release (most cases)
curl -fsSL https://raw.githubusercontent.com/Mesh-LLM/mesh-llm/main/install.sh | bash
The binary lands at ~/.local/bin/mesh-llm (may not be on a non-interactive
SSH PATH — use the full path or bash -lc). Metal is the macOS backend; the
installer picks it automatically.
To install as a per-user background service (launchd agent) in the same step:
curl -fsSL https://raw.githubusercontent.com/Mesh-LLM/mesh-llm/main/install.sh | bash -s -- --service
Service files: ~/Library/LaunchAgents/com.mesh-llm.mesh-llm.plist, shared env
in ~/.config/mesh-llm/service.env, startup models in ~/.mesh-llm/config.toml.
Install path B: dev build to a remote Mac
Build and bundle locally (from the repo):
just release-build # serious testing must use the release binary
just bundle # /tmp/mesh-llm-bundle.tar.gz (single mesh-llm binary)
Ship and unpack:
scp -P <SSH_PORT> /tmp/mesh-llm-bundle.tar.gz user@host:
ssh -p <SSH_PORT> user@host 'mkdir -p ~/bin && tar xzf mesh-llm-bundle.tar.gz -C ~/bin --strip-components=1'
Fix macOS quarantine — ALWAYS after scp
Files transferred via scp get provenance/quarantine xattrs that make macOS SIGKILL the binary on launch (exit 137). After every scp:
codesign -s - ~/bin/mesh-llm
xattr -cr ~/bin/
Verify: xattr ~/bin/mesh-llm should print nothing. Note codesign changes the
file hash — don't compare local vs remote hashes after signing.
Verify the version on the remote matches what you built:
~/bin/mesh-llm --version
Launch
Serve a model and join the public mesh:
mesh-llm serve --model unsloth/Qwen3.6-27B-GGUF:UD-Q4_K_XL --auto
--autodiscovers and joins the community mesh; local serving and mesh joining happen together.- Without
--auto(and without--join/--discover) you create a private mesh and an invite token is emitted — see themesh-joinskill. --modelaccepts catalog names,repo:QUANT,repo/file.gguf, or a full HF URL.--gguf /path/file.ggufserves a local file directly.- API on
:9337, management console on:3131(override with--port/--console).
Notes / gotchas:
- Do NOT use
--headlessto "go quiet" — it only disables the embedded web UI and does nothing for backgrounding. For machine-readable output use--log-format json. - Model load takes time. Poll
/v1/modelsuntil your model appears before concluding anything is broken. - For background test runs from an agent:
bash -c 'nohup mesh-llm serve --model <ref> --auto > /tmp/mesh.log 2>&1 & disown'. For persistence across reboots, prefer the--serviceinstall.
Verify it's actually serving
# Ports bound
lsof -nP -iTCP:9337 -iTCP:3131 -sTCP:LISTEN
# Models (union of local + mesh peers)
curl -s http://localhost:9337/v1/models | python3 -m json.tool
# Status / peers
curl -s http://localhost:3131/api/status | python3 -m json.tool
# Inference — the returned "model" field tells you which node/model answered
curl -s http://localhost:9337/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"auto","messages":[{"role":"user","content":"hi"}],"max_tokens":16}'
To force your local model specifically, pass its exact id from /v1/models
instead of auto.
Logs and state
~/.mesh-llm/runtime/<pid>/logs/skippy-native.log— embedded llama.cpp/skippy native logs. Check here first if a model fails to load.~/.mesh-llm/key— persistent node identity.~/.mesh-llm/config.toml— startup models and defaults for baremesh-llm serve.- HF cache (
~/.cache/huggingface/...) — downloaded GGUFs; you generally never need to touch this.
Stop / clean up
mesh-llm stop # scoped stop of tracked instances (preferred)
# emergency only:
pkill -9 -f mesh-llm
A clean stop removes the instance runtime dir under ~/.mesh-llm/runtime/.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Exit 137 immediately after scp | macOS quarantine/provenance xattr | codesign -s - <bin>; xattr -cr <dir> |
mesh-llm: command not found over SSH | ~/.local/bin not on non-interactive PATH | Full path or bash -lc |
Empty /v1/models | Model still downloading/loading | Wait; watch skippy-native.log |
| "No inference server available" | Election in progress or load failed | Check stderr + skippy-native.log |
| Stale runtime dir after crash | Unclean exit | rm -rf ~/.mesh-llm/runtime/<stale_pid>/ (auto-GC'd after 1h too) |