- spec matrix: new 'Production state' section — PP head (RPC0+ROCm0, split 0.40/0.60), pool 401400 / n_ctx_slot 200704 live, MTP n_max 4 over ngram-mod fallback (journal acceptance stats), f16 KV. 2026-08-15 standalone state marked superseded (Vulkan0 verdict was standalone-only; PP head runs ROCm0 by default). - deployment.md: fix frank-default-large section (MTP not 'no draft', ROCm0 not Vulkan0, 200704/slot not 262144, f16 not q8_0 KV, serve-pp-head.sh not serve-llama-frank-large.sh). - PP deployment doc: production-state section; test-day open questions resolved with journal evidence. - index.md: NPU line now qwen3.6-moe:35b-a3b @262k ctx; Sibling projects section -> serverAppConfigs. - AGENTS.md: overview reflects PP+MTP reality; sibling pointer.
9.6 KiB
AGENTS.md — vllmScripts Agent Rules
Overview
This project manages deployment scripts for the LLM inference fleet.
Dankclaw runs a llama.cpp pipeline-parallel head for Qwen3.8-27B (unsloth
UD-Q8_K_XL): MTP draft (bundled head, --spec-draft-n-max 4) over the
--spec-default ngram-mod fallback, 2 parallel slots at 200704 context
(pool 401400), tensors split 0.40/0.60 to the Dankserver RTX 3090
ggml-rpc worker, head GPU side on ROCm0 (no --device flag), port 7770.
The Dankclaw NPU endpoint (FastFlowLM, frank-default-small, port 52625)
serves Qwen3.6-35B-A3B as registry tag qwen3.6-moe:35b-a3b at 262144 ctx
(swapped in 2026-08-16; the old llama.cpp 35B service on Dankserver is
stopped). See docs/deployment.md for the deployment
process, docs/qwen3.8-spec-matrix.md for the
spec history and current production state, and
docs/Pipeline Parallelism/Qwen3.8 PP Deployment.md
for the PP runbook.
Sibling project: ../serverAppConfigs manages the
Podman app stack on the same hosts (OpenWebUI, Gitea, observability). Its
OpenWebUI consumes the :7770 endpoint; its Gitea instance hosts this
repository. Cross-links live in both knowledge-base indexes.
Benchmarking Policy (MANDATORY)
STOP the production service BEFORE running any benchmark on a target. These servers serve real users (about 3 people). Running a bench while the service is up starves the GPU and corrupts results. Restart the service when the bench finishes. The users will call if they need the model.
Rules:
- Stop the service before any benchmark:
systemctl stop frank-default-large(Dankclaw) orsystemctl stop frank-default-small(Dankclaw NPU). Use the passwordless helper or the passwordAssface.3241withsudo -S. - Run the bench on a scratch port (never the service port 7770).
- Restart the service when the bench completes:
systemctl start <svc>. - Verify health before reporting:
curl http://127.0.0.1:7770/health.
Do not skip this policy. A stale GPU contention or a dead production box is worse than a slow bench.
Git Workflow
All script edits must flow through git. Do not edit files on the remote machine directly.
Protocol
- Source the script from the target machine — fetch it from the server where it runs
- Place it in this repo — commit the fetched version
- Edit here — make all changes locally in the working tree
- Commit and push — push to origin (Gitea on dankclaw)
- Pull on the target —
git pullon the remote machine before restarting - Restart the service — use the updated script on the target
Deployment & Update Process
Use scripts/deploy.sh to deploy committed changes to a target. It pushes main, pulls on the target, restarts the service, and checks the health endpoint.
./scripts/deploy.sh dankclaw # PP head (frank-default-large, port 7770)
./scripts/deploy.sh dankserver # PP worker (frank-pp-worker, RPC 50052)
./scripts/deploy.sh dankclaw --dry-run # preview without changes
Deployment workflow:
graph LR
A[Edit locally] --> B[Commit]
B --> C[Push to origin]
C --> D[deploy.sh: pull on target]
D --> E[restart service]
E --> F[health check]
Target map:
| Target | Host | Runtime | Service | Port |
|---|---|---|---|---|
| Dankclaw | dank@dankclaw | llama.cpp PP head (Qwen3.8-27B UD-Q8_K_XL, split 0.40/0.60 to the Dankserver worker via RPC, MTP+ngram-mod, f16 KV) | frank-default-large | 7770 |
| Dankclaw | dank@dankclaw | FastFlowLM NPU (XDNA2 50 TOPS, qwen3.6-moe:35b-a3b, 262144 ctx; see FastFlowLM NPU Inference) | frank-default-small | 52625 |
| Dankserver | dank@dankserver | ggml-rpc worker (RTX 3090, receives the head's tensor share) | frank-pp-worker | 50052 |
Runtime & Troubleshooting
Env var naming rule — HIP runtime collision
The ROCm HIP runtime reads the bare environment variables TEMP, HOST, and GPU_MAX_HEAP_SIZE. The serve scripts export the env file with set -a. A tunable named TEMP leaks into HIP. On 2026-08-13 TEMP=1.0 made HIP use the path 1.0 for its JIT kernel cache, then segfaulted every model load. Commit 227ce01 fixed it by renaming the sampling variable to TEMPERATURE.
Never name a tunable TEMP, HOST, or GPU_MAX_HEAP_SIZE. Check for collisions with this command:
strings /opt/rocm-*/lib/libamdhip64.so.* | grep -xE "TEMP|HOST|GPU_MAX_HEAP_SIZE"
Crash-loop diagnostic procedure
When a llama service segfaults during model load, follow these steps.
graph TD
A[Service SEGVs at load] --> B[Read journal + kernel segfault line]
B --> C{Segfault in libamdhip64?}
C -- yes --> D[Bisect script vs raw binary]
C -- no --> E[Check config, memory, model files]
D --> F[Run gdb for backtrace]
F --> G[Find root cause]
- Read the service journal with
journalctl -u <service> -n 100. Then read the kernel segfault line withjournalctl -k. A segfault at address 8 inlibamdhip64means a NULL unref in the HIP runtime. - Run the serve script directly. Then run the raw binary with the same flags. A different outcome isolates the env file sourcing.
- Run gdb for the backtrace with this command:
gdb -batch -ex run -ex "bt 25" --args bash scripts/serve-llama-frank-large.shllama-serverbuffers its timed stdout. On SIGSEGV the log tail is lost. Trust gdb, not the log. - Kernel spam about
amdgpu: SVM mapping failedis a symptom, not the root cause. Investigate other causes before assuming memory pressure.
Operational quirks
sudoon both boxes needs a tty. The remote sudo steps indeploy.shfail non-interactively. Useecho '<password>' | sudo -S <command>.- Passwordless restarts: each target has a root-owned helper (
/usr/local/sbin/frank-restart-large.shon Dankclaw,frank-restart-small.shon Dankserver) and a sudoers NOPASSWD drop-in (/etc/sudoers.d/frank-*).deploy.shprefers the helper. The sudoers rules match commands exactly: no extra arguments (for example,--no-pagerbreaks thesystemctl statusrule). See docs/deployment.md. - Never run
pkill -fwith a pattern that appears in your own command line. It kills your ssh session. Usepkill -x <exact-name>. - Model load is slow: about 3 minutes warm, 8-17 minutes cold (measured 17 minutes on 2026-08-13 after a cache drop). Health returns
503 Loading modelthe whole time. That is normal. Do not kill the process.deploy.shwaits up to 20 minutes on Dankclaw (seeHEALTH_WAIT). - Page-cache state confounds crash tests. Cold-cache loads are slow and survive. Warm-cache loads crash fast. Control for it when testing.
deploy.shdrops caches on Dankclaw before restart (seeDROP_CACHES); manual restarts must runsync && echo 3 | sudo tee /proc/sys/vm/drop_cachesfirst. - A client abort and a server release look different in the journal. A client abort logs
W srv stop: cancel task, id_task = N. A natural stop (EOS or limit) logs onlyslot releasewithtruncated = 0. The server never preempts a running generation; when all slots are busy, new tasks defer into a queue. See the 2026-08-13 incident in docs/deployment.md. - Dankserver crash signature under parallel load:
CUDA error: an unsupported value or parameter was passed to the functionincublasSgemm_v2atggml-cuda.cu:1541, thenstatus=6/ABRT, then503 Loading modelfor ~5 minutes. Happened twice on 2026-08-13 under a 5-researcher subagent storm (llama.cpp b10121, driver 595.84). Root cause not yet determined; do not confuse it with speculative decoding. - DFlash premature EOS under parallel load: on Dankclaw,
draft-dflashends a generating slot ~1s after a new task lands with high prompt-cache reuse (LCP ~0.99), withfinish_reason "stop"and nocancel tasklog. It is a DFlash shared-draft-context bug. DFlash is retired from Dankclaw. DSpark (draft-dspark, its semi-autoregressive successor) is also unsafe here: two concurrent 16k prose prompts crashed the ROCm backend withROCm error: an illegal memory access(status 6/ABRT). Production uses--spec-default(ngram-mod, draftless) at PARALLEL=2 on the Vulkan0 backend. See docs/qwen3.8-spec-matrix.md.
Dankclaw memory model
The GPU budget on Dankclaw is the rocm-smi figure: 96 GiB addressable VRAM (SVM). The GPU node reports local_mem_size 0, so all allocations are GTT/SVM-backed. Trust rocm-smi and the runtime. Do not use free or dmidecode for the GPU budget; they show the CPU-side carve-out. This is intentional. Do not change it.
Why
Direct edits on the remote drift from version control. Future agents will not know what changed. Git is the single source of truth.
User request → Fetch script from remote → Commit here → Edit → Commit → Push → Pull on remote → Restart
Summary
| Context | Action |
|---|---|
| Editing a deployment script | Work through git — fetch, commit, edit, push, pull, restart. Never edit on the remote directly. |
| Script exists only on remote | Pull it into the repo first — commit the fetched version before making changes. |
| Unstaged local changes | Commit or discard — check git status before starting work. Ask the user if unsure. |
| Deploying a committed change | Run scripts/deploy.sh <target> — it pushes, pulls on the target, restarts the service, and checks health. See docs/deployment.md. |
| Tests exist | Run them — verify tests pass after every change. Do not commit failing tests. |