deploy-kimi-k26-on-rtx-pro-6000 — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited deploy-kimi-k26-on-rtx-pro-6000 (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Serve Kimi-K2.6 (1T MoE; MLA; 256K; MoonViT vision) in a user-chosen quantization, with an official-image Docker container — OpenAI-compatible API on :30000, TP=8, weights bind-mounted read-only from local NVMe, all in VRAM. Both the quantization and the engine are chosen at deploy time (steps 2–3) with a hardware-based recommendation:
--quantization modelopt_fp4); vLLM only (SGLang NVFP4 = NaN on sm_120). Needs a patched CUDA-13 image (build_nvfp4_image.sh) + offline remote-code prep (prep_remote_code.sh). On sm_120 it gives no throughput win (PCIe-comm-bound: Marlin ≈ native b12x, native is actually ~12% slower) — prefer it on datacenter Blackwell (sm_100/B200) where native FP4 (cutedsl) is tuned, or when you specifically need the NVFP4 checkpoint.Hardware target: 8× RTX PRO 6000 Blackwell Server Edition (GB202, 96 GB, sm_120) — ~595 GB of weights + KV cache need the full 8×96 GB pool; PCIe-only, no NVLink. Same-chip Workstation/Max-Q variants should behave identically (unverified). The host needs only the NVIDIA driver (≥570, open kernel module, incl. nvidia-persistenced), Docker, and nvidia-container-toolkit — no CUDA toolkit, no Python packages (the download check uses stock python3 + curl).
Why Docker-only (current best practice): the official images ship precompiled sm_120 kernels with their own CUDA + glibc, so the host-JIT failure class a native venv fights (glibc≥2.41 rsqrt header conflict, ninja, JIT pre-warm against host CUDA) doesn't exist here, and the deploy reproduces across hosts — both of those sm_120 fixes are empirically confirmed unnecessary in-container (image glibc 2.39; the CuTe-DSL norm ICE does not reproduce). GPU access uses CDI (--device nvidia.com/gpu=all, plain runc — not the legacy --gpus runtime hook). Treat step 6 as the go/no-go gate before fronting traffic.
nvidia-smi: GPU model/count/VRAM (this drives the quantization + enginerecommendations in steps 2–3); persistence daemon active (systemctl is-active nvidia-persistenced — ships with the driver and still matters for containers: it keeps GPU state resident across container restarts; ad-hoc fallback sudo nvidia-smi -pm 1); ~650 GB free on local NVMe; GPU containers work via CDI (spec: sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml):
docker run --rm --device nvidia.com/gpu=all --entrypoint nvidia-smi <engine-image>(Legacy alternative to CDI: --gpus all — see REFERENCE.md.)
INT4 QAT and NVFP4 (the tool adds "Other"), marking one (Recommended) by the step-1 GPU:
engines verified, stock images (no patch). NVFP4 here buys no throughput — the box is PCIe-comm-bound (no NVLink), so Marlin-of-INT4 ≈ Marlin-of-NVFP4, and the native FP4 path (flashinfer_b12x) measured ~12% slower than Marlin in a 2026-06-11 A/B; it also needs a patched CUDA-13 image + offline remote-code prep (step 4b). Pick NVFP4 only if you specifically need that checkpoint.
tuned there; the FP4 tensor cores are the real win. (Not verified by this skill — upstream path.)
Sets the checkpoint + flags — INT4: moonshotai/Kimi-K2.6 (compressed-tensors→Marlin, auto-detected, no --quantization). NVFP4: nvidia/Kimi-K2.6-NVFP4 (--quantization modelopt_fp4, fp8 KV, --disable-custom-all-reduce, --moe-backend marlin|flashinfer_b12x).
serve_docker_sglang.shhard-refuses it).
serves full 256K at mem-fraction 0.85; vLLM here needs util 0.95 and ~131K with bf16 KV.
The (QUANT, FRAMEWORK) pair is the whole deploy identity; it goes in the env file (step 7), not the service name.
3b. NVFP4 only — choose the MoE backend (skip entirely for INT4) — AskUserQuestion "Which NVFP4 MoE backend?":
the box is PCIe-comm-bound, so the native-FP4 GEMM speedup never reaches the wire) and leaves more KV (b12x reserves extra workspace). The safe throughput pick.
patched image step 4b builds anyway). Pick it to exercise the FP4 tensor cores, or on hardware where native FP4 is tuned (datacenter Blackwell uses flashinfer_cutedsl instead). Confirm the dispatch after launch with scripts/assert-native.sh kimi-k26 (NATIVE FP4 vs MARLIN fallback). Sets MOE_BACKEND in the env file (step 7); serve_docker_vllm.sh defaults to marlin if unset. (A/B numbers: the llm-inference-benchmark skill.)
3c. Choose the KV-cache dtype — AskUserQuestion "Which KV-cache dtype?", options derived from the (engine, quant) just chosen; mark the first (Recommended):
2× (116K→232K tokens, full-256K single request fits), verify 5/5 incl. vision, throughput parity through c64 and +13.5% at c128. | auto (bf16 — engine default, most conservative numerics, pool 116K) | fp8_e5m2 (more exponent range, less mantissa — accepted by SGLang's Triton MLA backend, runtime-unverified here).
context** on 96 GB GPUs (bf16 KV tops out ~131K MAX_MODEL_LEN). | auto (bf16 — the verified 0.95/131K config).
FP8 KV scales; serve_docker_vllm.sh already defaults it for QUANT=nvfp4. | auto (ignores the shipped scales; bigger KV bytes — only for debugging numerics). (Why the vLLM rows list no `fp8_e5m2`: on sm_120 vLLM serves Kimi through the TRITON_MLA attention backend, whose KV menu is `{auto/bf16, fp8 = fp8_e4m3}` only — `fp8_e5m2`, `nvfp4`, `turboquant_ belong to non-MLA backends and hard-fail backend validation at startup. Verified in-image, vLLM 0.22.1. SGLang uses a different MLA kernel, so its row is governed by its own supported set — see the SGLang+INT4 row.)* KV dtype changes numerics → re-run verify.sh after switching. Sets KV_CACHE_DTYPE in the env file (step 7). (Measured impact tables: the llm-inference-benchmark` skill.)
(default ~/.cache/huggingface; set HF_HOME to a big-NVMe cache root) — never hardcode paths. hf/Xet may deadlock → the script falls back to parallel curl, verifies size/count vs the paginated HF tree API (curl + python3 stdlib only), writes refs/main:
bash scripts/download.sh moonshotai/Kimi-K2.6 <commit-sha> # INT4
bash scripts/download.sh nvidia/Kimi-K2.6-NVFP4 <commit-sha> # NVFP44b. NVFP4 only — build the patched image + fix offline remote-code (skip entirely for INT4):
bash scripts/build_nvfp4_image.sh # -> kimi-k26-nvfp4-vllm:cu130-mla
bash scripts/prep_remote_code.sh nvidia/Kimi-K2.6-NVFP4 # de-symlink snapshot .py (run as cache owner, not root)Why: native FP4 MoE needs CUDA 13, and Kimi MLA on sm_120 can only use TRITON_MLA, whose grouped-decode kernel OOMs at graph capture (smem 102400 > 101376) until the num_stages patch; and offline trust_remote_code (transformers ≥5.10) can't resolve the custom module's relative imports from the symlinked cache (FileNotFoundError: …/blobs/tool_declaration_ts.py). Both fixes are baked into those two scripts. (REFERENCE.md → "NVFP4 on sm_120".)
DETACH=1 = -d --restart unless-stopped).QUANT selects the checkpoint + flags; the container is always kimi-k26:
docker pull lmsysorg/sglang:v0.5.12.post1-cu130 # INT4+SGLang (FULL image; Marlin JIT needs ninja+nvcc)
docker pull vllm/vllm-openai:v0.22.1 # INT4+vLLM (NVFP4+vLLM uses the locally-built image)
QUANT=int4 bash scripts/serve_docker_sglang.sh # INT4 on SGLang (run the pre-launch gates first — REFERENCE.md)
QUANT=int4 bash scripts/serve_docker_vllm.sh # INT4 on vLLM
QUANT=nvfp4 IMAGE=kimi-k26-nvfp4-vllm:cu130-mla bash scripts/serve_docker_vllm.sh # NVFP4 on vLLMContainer: CDI GPUs, --ipc=host --network host (host-net required for NCCL transport / IB-RoCE RDMA; server binds 0.0.0.0, Caddy upstreams over loopback → see REFERENCE "Access model"), weights :ro, memlock/nofile ulimits, HF_HUB_OFFLINE=1. Load ~10–15 min from NVMe (~4–5 min warm cache); ready on "The server is fired up and ready to roll!" (SGLang) / "Application startup complete" (vLLM) — docker logs -f kimi-k26.
bash scripts/verify.sh
bash scripts/assert-native.sh kimi-k26 # NVFP4: confirm the MoE backend (NATIVE FP4 vs MARLIN fallback)Vision debug (dumps content + reasoning_content for a red PNG): python3 scripts/vision-probe.py --model kimi-k2.6. Optional throughput check: use the `llm-inference-benchmark` skill — the canonical bench_sweep.sh, the sweep methodology, and this hardware's recorded baselines all live there.
FRAMEWORK/QUANT/IMAGE). Only one 595 GB variant fits the 8-GPU pool, so the service name never changes — switch quant/engine by editing the env file + `sudo systemctl restart kimi-k26` (no disable/enable). Use the unit or DETACH=1's restart policy, never both. The launcher goes on the root disk (/usr/local/bin) so the service never depends on a /data mount being present at boot.
sudo install -m755 scripts/serve_docker_vllm.sh scripts/serve_docker_sglang.sh /usr/local/bin/ # launcher (root disk)
sudo mkdir -p /var/lib/kimi-k26 # service state dir (WorkingDirectory)
sudo cp scripts/kimi-k26.env.example /etc/kimi-k26.env # EDIT: FRAMEWORK, QUANT, IMAGE, HF_HOME (BARE values!)
sudo cp scripts/kimi-k26.service /etc/systemd/system/kimi-k26.service
sudo systemctl daemon-reload && sudo systemctl enable --now kimi-k26 # journalctl -u kimi-k26 -f⚠ Keep `/etc/kimi-k26.env` values bare — systemd EnvironmentFile folds an inline # comment into the value (mangles HF_HOME → LocalEntryNotFoundError). fp8 KV: add KV_CACHE_DTYPE (vLLM fp8, SGLang fp8_e4m3) — verified, ~2× KV pool. TLS + Bearer-API-key reverse proxy (engine-agnostic): scripts/setup_proxy.sh. Access model: the --network host server binds `0.0.0.0`, so raw :30000 answers unauthenticated on loopback/ LAN/tailnet — the auth boundary is Caddy `:443` (off-box clients) + the router (no public IP), not the bind. Caddy upstreams over loopback (`127.0.0.1`), never the LAN IP — a LAN-IP upstream is a DHCP time-bomb (lease moves → Caddy 502s with an empty body; cost us two outages). No host firewall (setup_proxy retires any legacy kimi-fw/kimi-netguard). The Caddyfile sets admin off, so apply proxy changes with sudo systemctl restart caddy, not reload. See REFERENCE.md "Access model".
/dev/shm breaks it. NCCL "unhandled system error"/SIGBUS right after the load ⇒ check this first.
--quantization flag.--quantization modelopt_fp4 + the patched CUDA-13 image(build_nvfp4_image.sh): native FP4 (--moe-backend flashinfer_b12x) requires CUDA 13 ("b12x fused MoE requires CUDA 13") and the TRITON_MLA num_stages smem patch (else graph-capture OOM 102400 > 101376). It genuinely dispatches the FP4 GEMM (no silent dequant) but measured ~12% slower than Marlin on this PCIe-comm-bound box, so --moe-backend marlin is the throughput pick. SGLang NVFP4 = NaN on sm_120 — don't. Offline load also needs prep_remote_code.sh or it dies with FileNotFoundError …/blobs/tool_declaration_ts.py (transformers ≥5.10 + symlinked cache).
--tool-call-parser kimi_k2; vLLM needs both--tool-call-parser kimi_k2 and --enable-auto-tool-choice (missing ⇒ no tool_calls).
--mem-fraction-static = weights+KV pool with transients outside it — 0.85 is the verified ceiling here, 0.90 OOM-crashes the server (vision tower and big-batch transients allocate outside the pool). vLLM's --gpu-memory-utilization caps the total footprint — 0.85 leaves ~0.5 GB for KV (won't start); 0.95 is the working setting, and 256K context needs fp8 KV. FP8 KV (KV_CACHE_DTYPE env in both scripts) doubles the KV pool at zero throughput cost.
reasoning_content/content;disable per request with chat_template_kwargs:{"thinking":false}.
image_url URL-fetch gets 403 fromUA-filtering hosts (e.g. Wikimedia) — fixture issue, not a MoonViT failure. vLLM additionally wants --mm-encoder-tp-mode data (SGLang needs nothing extra). Debug an empty vision reply with scripts/vision-probe.py — it shows whether the answer landed in reasoning_content (a <think>-block artifact, fixed with more max_tokens) vs a real MoonViT failure.
no kernel image is available on sm_120 ⇒ the image predates Blackwell support — bump the tag.off an ad-hoc deployment), a ~595 GB / 8-GPU teardown takes 30–60 s; starting too soon OOMs the workers at executor init (Engine core initialization failed, before weight load) and a failed init can leak GPU memory that turns into a crash-loop. The serve scripts now wait (WAIT_GPU_FREE); if a loop already leaked, nvidia-smi --query-compute-apps, kill -9 the orphan, confirm GPUs → 0, restart. To preserve the client contract across a migration, keep MODEL_NAME stable (it's the OpenAI model id).
setup_proxy.sh points Caddy at127.0.0.1:30000, not the LAN IP — the engine binds 0.0.0.0 so loopback works, and it survives DHCP LAN-IP changes. A LAN-IP upstream is a silent 502-empty-body time-bomb when the host's lease moves (localhost:30000 keeps working, so it looks like the engine is fine). And the Caddyfile's admin off disables the :2019 admin API, so systemctl reload caddy fails (dial :2019: connection refused) — apply Caddyfile/cert/key changes with `sudo systemctl restart caddy`.
See [REFERENCE.md](REFERENCE.md): per-engine Docker paths (image pinning, CDI, NCCL/shm, the SGLang pre-launch gates, the SGLang↔vLLM flag map, py-spy load-vs-hang diagnosis), checkpoint-download gotchas, KV-cache/256K tuning, and productionization (systemd vs restart policy, proxy, monitoring).
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.