DGX Spark Model Deployer
LMDS (Local Model Deploy Studio, repo neronain/AutoDeployDGXProject) is the tool for this job. Its generated controllers already carry every failure this team has hit on GB10 — port-ownership guards, runtime-architecture checks, KV pinning, crash explanations, live logs and feature tests. Drive LMDS and read its evidence. Do not hand-write launch scripts or docker run lines: a hand-made controller silently drops those fixes, and the lesson gets relearned on a customer machine.
If a machine has no LMDS, install it (git clone https://github.com/neronain/AutoDeployDGXProject && cd AutoDeployDGXProject && ./install.sh) rather than improvising.
Match the user's language (this team writes Thai).
Know the environment first
Read config/team-profile.yaml. The facts that matter most:
- The hub is a control plane without a GPU (an OrbStack VM). It holds bundles, the node registry and the web console on port 8600. Run
lmds there from ~: lmds deploy writes to ./bundles of the current directory, and a second copy of a slug in another bundle root makes later commands pick the wrong one.
- Nodes are reached through the hub:
lmds node run <node> <lmds command> runs LMDS on the node, lmds node ctl <node> <slug> <verb> runs a controller verb. lmds node list is the source of truth for node names, IPs and sites.
- Running on a node itself (for example an OpenClaw agent on the Spark), the hub is usually out of reach. Run the same LMDS commands locally without the
node run <node> prefix (lmds ps, lmds fit <slug> --slots 3, lmds logs <slug> -f) and controller verbs through the bundle's script: ~/bundles/<slug>/<slug>-single.sh test-tools (-stacked.sh on a stacked head). New models, clones and fleet updates belong to the hub — hand the owner the hub command instead of improvising locally.
- The hub's git checkout (
main) is the source of truth for code. Hub and nodes must run the same commit.
Deploy a model to a node
- Gather evidence instead of guessing sizes, parsers or images:
lmds inspect <repo>
lmds recipes <repo>
lmds plan <repo> --target dgx-spark-single --no-llm --json
inspect gives size, architecture, native context and special files; a recipe is an image + flags + parsers that already ran on GB10. Weights up to ~95 GB fit one Spark; larger needs a stacked pair (--target dgx-spark-stacked, see references/runtime-notes.md). Embedding and reranker repos are detected automatically (--task embed or --task rerank overrides).
- Generate on the hub:
lmds deploy <repo> --target dgx-spark-single --no-llm --yes. Add --gguf Q8_0 to pick a GGUF variant and --name <slug> when the repo name is long — slugs over 64 characters cannot be pushed.
- Ship it:
lmds node push <node> <slug> --download downloads the weights on the node and verifies them. When another node already has the weights, lmds node clone <slug> --from <a> --to <b> copies node-to-node over the fastest shared link and verifies — minutes instead of a Hugging Face download.
- Size it before starting:
lmds node run <node> fit <slug> --slots <n> shows the RAM picture with every other model on that node counted; apply with lmds node run <node> set <slug> --fit --slots <n>. Rules in references/sizing.md.
- Start and prove it:
lmds node run <node> start <slug>, then lmds node ctl <node> <slug> test-text plus the verbs that fit the model — test-tools, test-reasoning, test-vision, test-embed, test-rerank. A server that answers /health is not done until its feature tests pass.
- Keep it:
lmds node run <node> enable <slug> turns on autostart. When replacing a model, leave the old bundle and weights in place (or lmds node run <node> remove <slug> --keep-weights --yes) so rollback is just a start.
- Report: endpoint
http://<node-ip>:<port>/v1, served model id, context per request, slots, RAM used/total, tests passed, what was stopped, and anything clients must change (model id, max_tokens).
Sizing in one paragraph
A DGX Spark has one 121 GB pool shared with the OS; keep about 12 GB free. vLLM's gpu-memory-utilization is a fraction of the whole pool and is checked against free memory at start, so a leftover 0.85 makes restarts fail as soon as a neighbour model runs. Pin the KV cache (--kv-cache-memory) and set gpu-util to what the model needs — set --fit does both. Context can never exceed the model's native max_position_embeddings: beyond it quality collapses without any error, and LMDS refuses. In llama.cpp --ctx-size is a pool shared by all slots, so context per request is ctx ÷ slots. Formulas and measured numbers: references/sizing.md.
Changing something that already runs
Many nodes serve customers. Before a restart check recent use (lmds node ctl <node> <slug> logs 200) or ask the owner, and prefer quiet hours. lmds set only saves settings; the running server keeps its old values until restart (the console shows "restart to apply"). Re-run the tests afterwards and never delete weights you might roll back to.
When something fails
lmds node run <node> doctor <slug> names the cause and the fix.
- Read the controller's own diagnosis: failed starts end with a "สาเหตุจาก log" line, and
lmds node ctl <node> <slug> logs -f streams live.
- Find the symptom in
references/troubleshooting.md before changing anything, and change one variable at a time.
Updating the hub and nodes
"Matches the hub" means three things on every node: the same LMDS commit, controllers rendered from the current templates, and a runtime (llama.cpp build or image) that knows every deployed model's architecture. An unknown axis is not a pass. The update sequence and checks are in references/fleet-ops.md; code changes always end with commit + push, hub install, node rollout and lmds fleet check.
Guardrails
- Never type sudo passwords, HF tokens or API keys for the user — print the command and let the owner run it.
- Customer machines are read-only until the owner says go, and every change keeps a rollback path.
- Say "hardware-validated" only after the tests ran on that node; otherwise say "static-validated".
- Uncensored and red-team models are for authorized security work only.
- Debug vLLM inside its container; do not install host PyTorch or random packages.
Skill files
| File |
Read when |
config/team-profile.yaml |
Always, first |
references/sizing.md |
Choosing slots/context/KV, or putting two models on one Spark |
references/runtime-notes.md |
Picking engine, image or parsers; stacked pairs; MTP; multimodal |
references/fleet-ops.md |
Hub and node access, clone, safe swaps, updates and rollouts |
references/troubleshooting.md |
Any error message or odd behaviour |
references/research-workflow.md |
A model with no recipe or an unfamiliar architecture |
references/special-files-checklist.md |
Remote code, projectors, templates or parser plugins in the repo |
references/security.md |
Exposing endpoints or wiring agents and tools |
scripts/check_lmds_commands.py |
After an LMDS upgrade — confirms every lmds command in this skill still exists |
scripts/validate_skill.py |
After editing this skill |
1---2name: dgx-spark-model-deployer3description: Deploy, size, move and repair LLMs on NVIDIA DGX Spark (GB10) fleets with LMDS — fit, push/clone, stacked pairs, start failures, fleet updates.4---56# DGX Spark Model Deployer78LMDS (Local Model Deploy Studio, repo `neronain/AutoDeployDGXProject`) is the tool for this job. Its generated controllers already carry every failure this team has hit on GB10 — port-ownership guards, runtime-architecture checks, KV pinning, crash explanations, live logs and feature tests. Drive LMDS and read its evidence. Do not hand-write launch scripts or `docker run` lines: a hand-made controller silently drops those fixes, and the lesson gets relearned on a customer machine.910If a machine has no LMDS, install it (`git clone https://github.com/neronain/AutoDeployDGXProject && cd AutoDeployDGXProject && ./install.sh`) rather than improvising.1112Match the user's language (this team writes Thai).1314## Know the environment first1516Read `config/team-profile.yaml`. The facts that matter most:1718- The **hub** is a control plane without a GPU (an OrbStack VM). It holds bundles, the node registry and the web console on port 8600. Run `lmds` there **from `~`**: `lmds deploy` writes to `./bundles` of the current directory, and a second copy of a slug in another bundle root makes later commands pick the wrong one.19- **Nodes** are reached through the hub: `lmds node run <node> <lmds command>` runs LMDS on the node, `lmds node ctl <node> <slug> <verb>` runs a controller verb. `lmds node list` is the source of truth for node names, IPs and sites.20- **Running on a node itself** (for example an OpenClaw agent on the Spark), the hub is usually out of reach. Run the same LMDS commands locally without the `node run <node>` prefix (`lmds ps`, `lmds fit <slug> --slots 3`, `lmds logs <slug> -f`) and controller verbs through the bundle's script: `~/bundles/<slug>/<slug>-single.sh test-tools` (`-stacked.sh` on a stacked head). New models, clones and fleet updates belong to the hub — hand the owner the hub command instead of improvising locally.21- The hub's git checkout (`main`) is the source of truth for code. Hub and nodes must run the same commit.2223## Deploy a model to a node24251. **Gather evidence** instead of guessing sizes, parsers or images:26 ```bash27 lmds inspect <repo>28 lmds recipes <repo>29 lmds plan <repo> --target dgx-spark-single --no-llm --json30 ```31 `inspect` gives size, architecture, native context and special files; a recipe is an image + flags + parsers that already ran on GB10. Weights up to ~95 GB fit one Spark; larger needs a stacked pair (`--target dgx-spark-stacked`, see `references/runtime-notes.md`). Embedding and reranker repos are detected automatically (`--task embed` or `--task rerank` overrides).322. **Generate on the hub**: `lmds deploy <repo> --target dgx-spark-single --no-llm --yes`. Add `--gguf Q8_0` to pick a GGUF variant and `--name <slug>` when the repo name is long — slugs over 64 characters cannot be pushed.333. **Ship it**: `lmds node push <node> <slug> --download` downloads the weights on the node and verifies them. When another node already has the weights, `lmds node clone <slug> --from <a> --to <b>` copies node-to-node over the fastest shared link and verifies — minutes instead of a Hugging Face download.344. **Size it before starting**: `lmds node run <node> fit <slug> --slots <n>` shows the RAM picture with every other model on that node counted; apply with `lmds node run <node> set <slug> --fit --slots <n>`. Rules in `references/sizing.md`.355. **Start and prove it**: `lmds node run <node> start <slug>`, then `lmds node ctl <node> <slug> test-text` plus the verbs that fit the model — `test-tools`, `test-reasoning`, `test-vision`, `test-embed`, `test-rerank`. A server that answers `/health` is not done until its feature tests pass.366. **Keep it**: `lmds node run <node> enable <slug>` turns on autostart. When replacing a model, leave the old bundle and weights in place (or `lmds node run <node> remove <slug> --keep-weights --yes`) so rollback is just a start.377. **Report**: endpoint `http://<node-ip>:<port>/v1`, served model id, context per request, slots, RAM used/total, tests passed, what was stopped, and anything clients must change (model id, `max_tokens`).3839## Sizing in one paragraph4041A DGX Spark has one 121 GB pool shared with the OS; keep about 12 GB free. vLLM's `gpu-memory-utilization` is a fraction of the **whole** pool and is checked against free memory at start, so a leftover `0.85` makes restarts fail as soon as a neighbour model runs. Pin the KV cache (`--kv-cache-memory`) and set gpu-util to what the model needs — `set --fit` does both. Context can never exceed the model's native `max_position_embeddings`: beyond it quality collapses without any error, and LMDS refuses. In llama.cpp `--ctx-size` is a pool shared by all slots, so context per request is ctx ÷ slots. Formulas and measured numbers: `references/sizing.md`.4243## Changing something that already runs4445Many nodes serve customers. Before a restart check recent use (`lmds node ctl <node> <slug> logs 200`) or ask the owner, and prefer quiet hours. `lmds set` only saves settings; the running server keeps its old values until restart (the console shows "restart to apply"). Re-run the tests afterwards and never delete weights you might roll back to.4647## When something fails48491. `lmds node run <node> doctor <slug>` names the cause and the fix.502. Read the controller's own diagnosis: failed starts end with a "สาเหตุจาก log" line, and `lmds node ctl <node> <slug> logs -f` streams live.513. Find the symptom in `references/troubleshooting.md` before changing anything, and change one variable at a time.5253## Updating the hub and nodes5455"Matches the hub" means three things on every node: the same LMDS commit, controllers rendered from the current templates, and a runtime (llama.cpp build or image) that knows every deployed model's architecture. An unknown axis is not a pass. The update sequence and checks are in `references/fleet-ops.md`; code changes always end with commit + push, hub install, node rollout and `lmds fleet check`.5657## Guardrails5859- Never type sudo passwords, HF tokens or API keys for the user — print the command and let the owner run it.60- Customer machines are read-only until the owner says go, and every change keeps a rollback path.61- Say "hardware-validated" only after the tests ran on that node; otherwise say "static-validated".62- Uncensored and red-team models are for authorized security work only.63- Debug vLLM inside its container; do not install host PyTorch or random packages.6465## Skill files6667| File | Read when |68|---|---|69| `config/team-profile.yaml` | Always, first |70| `references/sizing.md` | Choosing slots/context/KV, or putting two models on one Spark |71| `references/runtime-notes.md` | Picking engine, image or parsers; stacked pairs; MTP; multimodal |72| `references/fleet-ops.md` | Hub and node access, clone, safe swaps, updates and rollouts |73| `references/troubleshooting.md` | Any error message or odd behaviour |74| `references/research-workflow.md` | A model with no recipe or an unfamiliar architecture |75| `references/special-files-checklist.md` | Remote code, projectors, templates or parser plugins in the repo |76| `references/security.md` | Exposing endpoints or wiring agents and tools |77| `scripts/check_lmds_commands.py` | After an LMDS upgrade — confirms every `lmds` command in this skill still exists |78| `scripts/validate_skill.py` | After editing this skill |