Fan out subagents to compare mainline llama.cpp, charlie12345/ROCmFPX,
and ik_llama.cpp, then add their findings to the project knowledge base:
- docs/Research/Llama Cpp Runtimes.md (positioning + quantization + server fit)
- docs/Research/Llama Cpp Code Diff.md (code-level quant diff, table, recommendations)
- docs/Research/SGLang.md (what SGLang is, comparison, our-boxes fit)
- docs/Research/index.md (Research progressive-disclosure index)
Cross-linked from docs/index.md (root) and docs/LLM/index.md.
AGENTS.md:
- Add Documentation Authoring section: docs/ is an OKF bundle; point doc authors
at the canonical spec in the system-config knowledge base
(~/.pi/agent/docs/references/okf-spec.md), not the orphaned
docs/references/okf-spec.md; consolidate read-index/one-concept-per-file/
progressive-disclosure/citation rules.
- Map AGENTS.md to docs_completeness.bats in the focused pre-commit hook (it was
last committed before the hook existed and had no mapping).
frank-default-large now serves the kingjones Qwen3.8-27B-ROCmFPX-Q8_0-AGENT
model with a standalone MTP draft head (Q4_0), f16 K + TurboQuant V KV cache,
and the Sharp chat template. Context is maxed to 262144 (one slot); reasoning
is on with preserve_thinking + preserve_reasoning in the chat kwargs.
- frank-default-large.env: Q8_0 AGENT model paths, CTX_SIZE=262144, REASONING=on,
REASONING_FORMAT=none, CHAT_TEMPLATE_KWARGS {enable_thinking, preserve_thinking,
preserve_reasoning}
- serve-frank-large.sh: standalone draft-mtp profile (already switched off the
Kairic/PromptForge path)
- download-q8agent.sh: reproducible HF fetch of the three payload files
- docs/LLM/kingjones-q8agent-rocmfpx.md: Q8_0 AGENT runbook
- AGENTS.md: topology + ACTIVE runtime section + TTM/GTT load note
- qwen3.8-strix-optimizations, Dankclaw Improvements: TTM pages_limit now 114 GiB
(applied 2026-08-25), full 262k KV + Q8 payload fit in one slot
- frank_large_config.bats: assert 262144 context, reasoning + preserve_* enabled
The TTM/GTT was raised to 114 GiB (29,883,536 pages) to hold the full 262k KV.
Replace the retired kingjones ROCmFP4 STRIX MTP payload on Dankclaw with
cafonz/Qwen3.8-27B-ROCmI4-MTP-GGUF (eemin namespace, public), served by the
charlie12345/ROCmFPX llama.cpp build (ROCmI4 W4A4, c49ebdbd) on the Strix Halo
iGPU. Q4_0_ROCMI4 with an embedded NextN/MTP head (no separate draft file);
strict-Qwen MTP n16/p0.60/backend sampling on ROCm0. Binary
/home/dank/rocmi4-qwen38/ROCmFPX/build-rocmi4-w4a4/bin/llama-server; model dir
/home/dank/models/eemin-Qwen3.8-27B-ROCMI4-MTP. Updated serve script + env,
ubatch bench, large-config bats test, docs, AGENTS.md.
3 slots x 229376 (262144 - 32768) = 688128 total context. Updates the
.env, models.json (contextWindow/maxTokens 229376 per slot), and the
index/deployment/ornith runbook references.
- frank-default-small (Dankserver): Ornith-1.5-35B-A3B-CRACK Q8_0, bundled
native draft-mtp (n_max 4), MoE expert FFN tensors pinned to CPU via an
explicit --override-tensor \.ffn_(up|down|gate|gate_up)_(ch|)exps=CPU
(replaces --n-cpu-moe), Qwen-Sharp chat template.
- frank-default-large (Dankclaw): kingjones Qwen3.8-27B-Uncensored-Q6_0
ROCmFP4 AGENT dense GGUF, standalone mtp-Qwen3.8-27B-Q4_0 draft head
(--model-draft, draft-mtp n_max 4), Qwen-Sharp chat template. Drop the
retired PromptForge .pfs sidecar lanes.
- Track scripts/chat-template.jinja (v22.4.0 Sharp) and apply via
--chat-template-file on both services.
- Docs: new kingjones-strix-mtp and dealign-ornith-crack runbook pages;
update index, deployment, and both system specs; models.json names.
Smoke-tested both models on the real hardware on scratch ports before
commit: model loads, MTP draft attaches, Sharp template applies, chat
completion returns.
The homepage user page + shared data now use a dedicated CADDY_HOMEPAGE_HASH
(username dankuser), separate from the shared family password (CADDY_BASICAUTH_HASH,
username dank, still used by the other vhosts) and the operator password
(CADDY_ADMIN_HASH, username frank, the /admin/ page). This lets the homepage be
re-logged independently without touching the other sites. deploy.sh renders the
new placeholder; the .env.example documents all three hashes.
Two real bugs found on the first production deploy:
- /admin/ 404'd: file_server looked for /srv/homepage/admin/ (a dir), but the
page is admin.html. Add '@admin rewrite * /admin.html' so the /admin/ path
serves admin.html.
- The pages used relative refs (style.css, app.js, services.json, status.json),
which from /admin/ resolved to /admin/... (404). Add <base href="/"> so all
refs resolve to the site root on both pages.
- status.json was written 0600 (root); the checker now chmods it 0644 so Caddy
can serve it regardless of its user.
The homepage deploy's mkdir/cp/write of /srv/homepage ran as the deploy user
and hit 'Permission denied' (/srv is root-owned). Prefix them with the sudo
wrapper, write deployed.js via a temp file + sudo cp, and chmod the tree
a+rX so Caddy can serve it. Run the one-off checker as root too (it writes
status.json into /srv/homepage).
A missing CADDY_*_HASH in the .env made the 'grep | tail | cut' pipeline
return non-zero, which aborted the deploy under 'set -e' before it could warn
and keep the placeholder. Add '|| true' so an absent hash warns instead of
aborting. (The homepage deploy aborted here because CADDY_ADMIN_HASH was not
in the repo-root .env the deploy reads.)
Red tests first.
- tests/homepage_deploy.bats: the deploy ships the homepage (assets to
/srv/homepage, the checker timer, both Caddy hashes, deployed.js) and is
git-driven (pulls main); the checker runs as a systemd timer.
- scripts/homepage-status.service / .timer: the checker as a oneshot service
+ a 3-minute timer (Q2/Q35).
- scripts/deploy.sh: the Caddyfile render now substitutes BOTH hashes
(REPLACE_WITH_HASH <- CADDY_BASICAUTH_HASH, REPLACE_WITH_ADMIN_HASH <-
CADDY_ADMIN_HASH). A new homepage step copies the assets to /srv/homepage,
generates deployed.js from the deployed commit's datetime (Q43), installs
the checker timer, and runs the checker once so status.json exists at once.
- tests/llm_units.bats: scoped the three LLM-unit tests to
frank-default-*.service (the homepage unit is a different pattern: it
installs to /usr/local/bin and runs from /srv at deploy time).
Red test first: a raw TCP listener that never speaks HTTP must read down
under an http probe (up under tcp), while a real HTTP server reads up. This
test caught a real hang — the backgrounded listener inherited the test
runner's stdout pipe and held it open; fixed by redirecting its output and
killing both listeners in teardown.
scripts/homepage-status.py: probe() now dispatches on method. http does an
urlopen (any HTTP status = up; no connection = down); tcp connects.
The checker is now complete: tcp + http + wip + atomic write + generated_at.
Remaining slices: services.json schema, the pages + theme + toggle, the
Caddyfile (validate + two hashes), the git-driven deploy.
Full TDD (Q36): red test first, then the minimal implementation.
- tests/homepage_checker.bats: seam = homepage-status.py <services.json>
<out.json>. Asserts an open port is up, a closed port is down, a wip
service is wip (not probed), and the output carries generated_at.
- scripts/homepage-status.py: reads the config, probes each backend (tcp,
5 s timeout), skips wip, writes status.json atomically (temp + rename).
Remaining slices: http probe method, services.json schema, the pages +
theme + toggle, the Caddyfile (validate + two hashes), the git-driven deploy.
The explanatory comment contained an unescaped loop-variable token, which
the local shell (set -u) tried to expand while building the double-quoted
remote script ('unit: unbound variable'). Reword the comment.
The relink loop wrapped the source path in single quotes, which shipped a
literal ${unit} to the remote and created a dangling symlink
(/etc/systemd/system/frank-default-large.service -> .../${unit}.service),
so 'systemctl enable' failed with 'unit does not exist'. The path has no
spaces; unquoting lets ${unit} expand on the remote for both source and
destination.
Operator request (2026-08-22): the primary inference server
(frank-default-large, the 27B CIRU model on Dankclaw) moves to the
standard llama.cpp port 7770. Both LLM services now listen on :7770,
distinguished by host (dankserver vs dankclaw).
Functional changes:
- scripts/frank-default-large.env: LISTEN_PORT 52625 -> 7770
- scripts/serve-frank-large.sh: default LISTEN_PORT 52625 -> 7770
- scripts/deploy.sh: LLM_HEALTH[dankclaw] -> :7770
- open-webui quadlet: OPENAI_API_BASE_URL -> 192.168.0.143:7770
(re-pointed so chat keeps working; data dir preserved)
- scripts/bench-fast-greedy.sh: PORT 52625 -> 7770
Tests updated to the new topology (both LLM endpoints on :7770 by host;
open-webui -> :7770). Docs + pi KB updated; dated historical runbooks
keep their point-in-time ports. models.json (pi client) re-pointed to
:7770 separately, effective on the next client restart.
deploy.sh now deploys both workloads per target in one run:
push -> pull on /home/dank/serverAppConfigs -> podman stack steps
(dankclaw) -> LLM unit relink + daemon-reload + service restart ->
homepage health + LLM health (up to 20 min model-load wait).
Sudo: plain sudo on the fleet hosts (passwordless verified
2026-08-22); FRANK_SUDO_PW covers headless runs elsewhere. The
vllmScripts deploy.sh is superseded.
Units: frank-default-{small,large,npu}.service now reference
/home/dank/serverAppConfigs/scripts/... (the merged checkout).
bench-spec-stack.sh: env file path updated to the merged checkout.
The LLM fleet serve scripts, systemd units, env tunables, and bench
harnesses join the deploy scripts. The vllmScripts deploy.sh is
removed here; its functionality is folded into the unified
scripts/deploy.sh in a follow-up commit.
bench-spec-stack.sh gains the executable bit (required by the
scripts_syntax test seam).
A 'caddy reload' delivered over the admin API cannot apply a config
that disables the admin API -- the fix cannot ride the API it is meant
to enable (2026-08-22: admin off sat in the running config across
deploys). Track the reload result; on failure, restart the container
so it reads the rendered file on start.