From 7c77326c336442d30894d3c290b4afcebc451463 Mon Sep 17 00:00:00 2001
From: Frank
Date: Fri, 9 Oct 2026 16:47:19 -0700
Subject: [PATCH] =?UTF-8?q?llm:=20complete=20the=20Protoss=20rename=20on?=
=?UTF-8?q?=20the=20wire=20=E2=80=94=20served=20ids=20frank-archon/dragoon?=
=?UTF-8?q?/zealot?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The 2026-10-08 rename moved the harness model ids and the homepage cards;
the served aliases on the wire stayed frank-primary/frank-large/
frank-secondary. This closes the gap: the alias each endpoint announces is
now the family name, while the services, units, scripts, env files and
runbooks keep the old names (container identity stays stable).
- scripts/frank-secondary.env ALIAS, scripts/frank-large.env
HALOGEN_MODEL_ID, scripts/frank-primary.env FRANK_PRIMARY_SERVED_NAME
(+ the two serve-script defaults/gate messages)
- seams re-pinned: frank_secondary/frank_large/frank_primary unit bats
- fleet harnesses retargeted: bench-probe, deep-probe, calib-push,
fleet-probes-swift15, autoresearch(+measure), bench-threads-batch-http,
bench-decode
- shared/homepage/docs.html: api-id annotations and the "switchover will
rename the ids" footnote removed — the page's names are now the ids;
opencode/Pi/curl examples send frank-zealot
- dankclaw/hermes/config.yaml.example: frank-large -> frank-dragoon and the
live 262144 context (Hermes routes by served id; see Hermes.md)
Consumers with live state re-keyed out-of-band in the same window:
OpenWebUI (model row, access_grant, openai.api_configs model_ids) and the
Hermes config.yaml.
---
dankclaw/hermes/config.yaml.example | 12 +++----
scripts/autoresearch-bench.py | 2 +-
scripts/autoresearch-frank-primary.sh | 2 +-
scripts/autoresearch/frank-primary-measure.py | 2 +-
scripts/bench-decode.sh | 2 +-
scripts/bench-probe.py | 2 +-
scripts/bench-threads-batch-http.py | 2 +-
scripts/calib-push.py | 2 +-
scripts/deep-probe.py | 2 +-
scripts/fleet-probes-swift15.sh | 10 +++---
scripts/frank-large.env | 5 ++-
scripts/frank-primary.env | 6 +++-
scripts/frank-secondary.env | 8 ++++-
scripts/serve-frank-large.sh | 2 +-
scripts/serve-frank-secondary.sh | 2 +-
shared/homepage/docs.html | 32 +++++++++----------
tests/frank_large_unit.bats | 6 ++--
tests/frank_primary_unit.bats | 2 +-
tests/frank_secondary_unit.bats | 4 +--
19 files changed, 58 insertions(+), 47 deletions(-)
diff --git a/dankclaw/hermes/config.yaml.example b/dankclaw/hermes/config.yaml.example
index afaa784..7b2154c 100644
--- a/dankclaw/hermes/config.yaml.example
+++ b/dankclaw/hermes/config.yaml.example
@@ -10,15 +10,15 @@ model:
provider: dankclaw-large
base_url: http://192.168.0.143:7770/v1
api_key: not-needed
- default: frank-large
+ default: frank-dragoon
providers:
dankclaw-large:
api: http://192.168.0.143:7770/v1
discover_models: false
models:
- frank-large:
- context_length: 114688
+ frank-dragoon:
+ context_length: 262144
dankserver-small:
api: http://192.168.0.235:7770/v1
discover_models: false
@@ -29,7 +29,7 @@ providers:
# Auxiliary routing from the live configuration. Named providers route via
# their `api:` URL; `custom` entries route by their explicit `base_url`.
auxiliary:
- vision: {provider: dankclaw-large, model: frank-large}
+ vision: {provider: dankclaw-large, model: frank-dragoon}
web_extract: {provider: dankserver-small, model: frank-medium}
compression: {provider: dankserver-small, model: frank-medium}
skills_hub: {provider: dankserver-small, model: frank-medium}
@@ -50,8 +50,8 @@ auxiliary:
effort: none
memory_query_rewrite: {provider: custom, model: frank-medium, base_url: http://192.168.0.235:7770/v1}
tts_audio_tags: {provider: custom, model: frank-medium, base_url: http://192.168.0.235:7770/v1}
- triage_specifier: {provider: dankclaw-large, model: frank-large}
- kanban_decomposer: {provider: dankclaw-large, model: frank-large}
+ triage_specifier: {provider: dankclaw-large, model: frank-dragoon}
+ kanban_decomposer: {provider: dankclaw-large, model: frank-dragoon}
profile_describer: {provider: dankserver-small, model: frank-medium}
curator: {provider: dankserver-small, model: frank-medium}
diff --git a/scripts/autoresearch-bench.py b/scripts/autoresearch-bench.py
index 3c1fb15..8fd102a 100755
--- a/scripts/autoresearch-bench.py
+++ b/scripts/autoresearch-bench.py
@@ -104,7 +104,7 @@ def stream_completion(url: str, model: str, prompt: str):
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--url", default="http://127.0.0.1:7770")
- ap.add_argument("--model", default="frank-large")
+ ap.add_argument("--model", default="frank-dragoon")
args = ap.parse_args()
with urllib.request.urlopen(args.url.rstrip("/") + "/v1/models",
diff --git a/scripts/autoresearch-frank-primary.sh b/scripts/autoresearch-frank-primary.sh
index 9d9f857..5407bdb 100755
--- a/scripts/autoresearch-frank-primary.sh
+++ b/scripts/autoresearch-frank-primary.sh
@@ -146,7 +146,7 @@ while n < TGT:
n += len(seg) + 1
prompt = " ".join(parts)
json.dump(
- {"model": "frank-primary", "prompt": prompt,
+ {"model": "frank-archon", "prompt": prompt,
"max_tokens": 256, "temperature": 0.0, "stream": False,
"stop": ["<|im_end|>"]},
open(sys.argv[1], "w"),
diff --git a/scripts/autoresearch/frank-primary-measure.py b/scripts/autoresearch/frank-primary-measure.py
index f3d3b09..6974118 100755
--- a/scripts/autoresearch/frank-primary-measure.py
+++ b/scripts/autoresearch/frank-primary-measure.py
@@ -45,7 +45,7 @@ import urllib.error
import urllib.request
BASE = os.environ.get("AR_BASE", "http://127.0.0.1:7770")
-MODEL = os.environ.get("AR_MODEL", "frank-primary")
+MODEL = os.environ.get("AR_MODEL", "frank-archon")
PROMPT_CEILING = int(os.environ.get("AR_PROMPT_CEILING", "100000"))
DEPTHS = (115, 1056, 4096)
WARM_TOKENS = 64
diff --git a/scripts/bench-decode.sh b/scripts/bench-decode.sh
index a130d0f..9431ca0 100755
--- a/scripts/bench-decode.sh
+++ b/scripts/bench-decode.sh
@@ -57,7 +57,7 @@ run_bench() {
# Warmup (small request)
curl -s -m 60 http://127.0.0.1:$PORT/v1/chat/completions \
-H "Content-Type: application/json" \
- -d '{"model":"frank-large","messages":[{"role":"user","content":"Hi"}],"max_tokens":16,"stream":false}' > /dev/null 2>&1 || true
+ -d '{"model":"frank-dragoon","messages":[{"role":"user","content":"Hi"}],"max_tokens":16,"stream":false}' > /dev/null 2>&1 || true
# Build 8K prompt
local prompt
diff --git a/scripts/bench-probe.py b/scripts/bench-probe.py
index 234ed59..6bc3e83 100755
--- a/scripts/bench-probe.py
+++ b/scripts/bench-probe.py
@@ -26,7 +26,7 @@ def build_prompt():
def probe(salt):
prompt = f"[probe {salt}]\n" + build_prompt()
body = json.dumps({
- "model": "frank-primary",
+ "model": "frank-archon",
"prompt": prompt, "temperature": 0.0, "max_tokens": 512,
}).encode()
req = urllib.request.Request(URL, data=body,
diff --git a/scripts/bench-threads-batch-http.py b/scripts/bench-threads-batch-http.py
index c63a472..d6fe095 100755
--- a/scripts/bench-threads-batch-http.py
+++ b/scripts/bench-threads-batch-http.py
@@ -39,7 +39,7 @@ def send_prefill_request():
with open(PROMPT_FILE, "r") as f:
prompt = f.read()
body = json.dumps({
- "model": "frank-large",
+ "model": "frank-dragoon",
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 1,
"stream": False
diff --git a/scripts/calib-push.py b/scripts/calib-push.py
index ac0b069..562ffca 100755
--- a/scripts/calib-push.py
+++ b/scripts/calib-push.py
@@ -51,7 +51,7 @@ def tap_done(container):
def push_one(url, prompt):
body = json.dumps({
- "model": "frank-primary",
+ "model": "frank-archon",
"prompt": prompt,
"max_tokens": 1,
"temperature": 0,
diff --git a/scripts/deep-probe.py b/scripts/deep-probe.py
index 2653e8a..8e2b9e0 100755
--- a/scripts/deep-probe.py
+++ b/scripts/deep-probe.py
@@ -18,7 +18,7 @@ def build():
def main(salt):
body = json.dumps({
- "model": "frank-primary",
+ "model": "frank-archon",
"messages": [{"role": "user", "content": f"[probe {salt}] Continue and summarize this material in English, 400 words.\n\n" + build()}],
"temperature": 0.0, "max_tokens": 512,
"stream": True, "stream_options": {"include_usage": True},
diff --git a/scripts/fleet-probes-swift15.sh b/scripts/fleet-probes-swift15.sh
index 9d329cd..36ddd78 100755
--- a/scripts/fleet-probes-swift15.sh
+++ b/scripts/fleet-probes-swift15.sh
@@ -16,7 +16,7 @@ def png(color):
+ chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0))
+ chunk(b"IDAT", zlib.compress(raw)) + chunk(b"IEND", b""))
b64 = base64.b64encode(png((255, 0, 0))).decode()
-body = json.dumps({"model": "frank-primary", "max_tokens": 256, "temperature": 0,
+body = json.dumps({"model": "frank-archon", "max_tokens": 256, "temperature": 0,
"messages": [{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": "data:image/png;base64," + b64}},
{"type": "text", "text": "What color is this image? Answer with one word."}]}]}).encode()
@@ -30,7 +30,7 @@ PY
echo "== tools (expect tool_calls)"
curl -s -m 120 $B/chat/completions -H 'Content-Type: application/json' -d '{
- "model":"frank-primary","temperature":0,"max_tokens":128,
+ "model":"frank-archon","temperature":0,"max_tokens":128,
"messages":[{"role":"user","content":"What is 23 times 47? Use the calculator tool."}],
"tools":[{"type":"function","function":{"name":"calculator","description":"evaluate arithmetic",
"parameters":{"type":"object","properties":{"expr":{"type":"string"}},"required":["expr"]}}}]}' \
@@ -40,17 +40,17 @@ echo "== reasoning_effort fold (xhigh/medium/low/high all 200 on froggeric v22.5
for lvl in xhigh medium low high; do
code=$(curl -s -o /dev/null -w "%{http_code}" -m 120 $B/chat/completions \
-H 'Content-Type: application/json' \
- -d "{\"model\":\"frank-primary\",\"max_tokens\":8,\"reasoning_effort\":\"$lvl\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}")
+ -d "{\"model\":\"frank-archon\",\"max_tokens\":8,\"reasoning_effort\":\"$lvl\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}")
echo " reasoning_effort=$lvl -> HTTP $code"
done
echo "== reasoning_content channel"
curl -s -m 120 $B/chat/completions -H 'Content-Type: application/json' \
- -d '{"model":"frank-primary","max_tokens":64,"messages":[{"role":"user","content":"Is 97 prime? Think briefly."}]}' \
+ -d '{"model":"frank-archon","max_tokens":64,"messages":[{"role":"user","content":"Is 97 prime? Think briefly."}]}' \
| python3 -c 'import json,sys; m=json.load(sys.stdin)["choices"][0]["message"]; print("has reasoning_content:", bool(m.get("reasoning_content")), "| content:", (m.get("content") or "")[:60].replace(chr(10)," "))'
echo "== response_format json_object"
curl -s -m 120 $B/chat/completions -H 'Content-Type: application/json' \
- -d '{"model":"frank-primary","max_tokens":64,"response_format":{"type":"json_object"},"messages":[{"role":"user","content":"Return JSON {\"ok\": true}"}]}' \
+ -d '{"model":"frank-archon","max_tokens":64,"response_format":{"type":"json_object"},"messages":[{"role":"user","content":"Return JSON {\"ok\": true}"}]}' \
| python3 -c 'import json,sys; d=json.load(sys.stdin); print("JSON MODE:", (d["choices"][0]["message"].get("content") or "")[:60])'
echo "PROBES_DONE"
diff --git a/scripts/frank-large.env b/scripts/frank-large.env
index da3caaa..1008c56 100644
--- a/scripts/frank-large.env
+++ b/scripts/frank-large.env
@@ -130,7 +130,10 @@ FRANK_LARGE_TOKENIZER_FILES="tokenizer.json chat_template.jinja tokenizer_config
# --- engine flags (docs/FLAGS.md of the flash-server repo; anything unset
# stays at the image default, which is what was qualified) ------------------
-HALOGEN_MODEL_ID=frank-large
+# Served model id — Protoss name (wire rename 2026-10-09); the service, unit,
+# scripts and this file keep the frank-large name. OpenWebUI api_configs
+# model_ids for the :7770 backend MUST name this value.
+HALOGEN_MODEL_ID=frank-dragoon
HALOGEN_CTX=262144
HALOGEN_KV_POOL_POSITIONS=524288
HALOGEN_KV_SLOTS=2
diff --git a/scripts/frank-primary.env b/scripts/frank-primary.env
index 8088eef..f59ea7a 100644
--- a/scripts/frank-primary.env
+++ b/scripts/frank-primary.env
@@ -86,7 +86,11 @@ FRANK_PRIMARY_STATE_DIR=/home/dank/radiance-state
# the GPUs or the port.
FRANK_PRIMARY_CONTAINER=frank-primary
FRANK_PRIMARY_LEGACY_CONTAINERS="frank-primary-qwen frank-primary-r9v qwen-fp8 glm-probe"
-FRANK_PRIMARY_SERVED_NAME=frank-primary
+# Served model id — Protoss name (wire rename 2026-10-09). The container,
+# unit, scripts and this file keep the frank-primary name above; only the
+# alias on the wire moved. Radiance validates the requested model name, so
+# every client (harness, bench scripts, probes) MUST send this value.
+FRANK_PRIMARY_SERVED_NAME=frank-archon
FRANK_PRIMARY_PORT=7770
# Frank's chat-template call: froggeric's fixed Qwen3.8 template (the
# repo's root chat_template.jinja, vendored here; the checkpoint's own
diff --git a/scripts/frank-secondary.env b/scripts/frank-secondary.env
index bc0da57..9f63aa8 100644
--- a/scripts/frank-secondary.env
+++ b/scripts/frank-secondary.env
@@ -35,7 +35,13 @@
LLAMA_BIN=/home/dank/GitPackages/llama-master/build-cuda/bin/llama-server
MODEL_FILE=/home/dank/models/Qwen35-9B-HauhauCS-Q6K/Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-Q6_K.gguf
MMPROJ_FILE=/home/dank/models/Qwen35-9B-HauhauCS-Q6K/mmproj-Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-BF16.gguf
-ALIAS=frank-secondary
+# Served model id — the harness/family name (Protoss rename completed to the
+# wire 2026-10-09: harness ids + homepage cards 2026-10-08, /v1/models aliases
+# this day). The SERVICE, unit, scripts and this env file keep the
+# frank-secondary name; only the alias on the wire changed. Consumers that
+# key on the served id: OpenWebUI (model row, access_grant, api_configs
+# model_ids) and the harness models.yml.
+ALIAS=frank-zealot
BIND_ADDR=0.0.0.0
LISTEN_PORT=7771
# CTX_SIZE is the POOL llama.cpp divides across slots: 401,408 / 2 = 200,704
diff --git a/scripts/serve-frank-large.sh b/scripts/serve-frank-large.sh
index e92323e..c67cd94 100755
--- a/scripts/serve-frank-large.sh
+++ b/scripts/serve-frank-large.sh
@@ -51,7 +51,7 @@ set +a
: "${FRANK_LARGE_VISION_TOWER:?FRANK_LARGE_VISION_TOWER must name the tower}"
: "${FRANK_LARGE_VISION_BYTES:?FRANK_LARGE_VISION_BYTES must pin the tower size}"
: "${FRANK_LARGE_TOKENIZER_FILES:?FRANK_LARGE_TOKENIZER_FILES must list the tokenizer dir contents}"
-: "${HALOGEN_MODEL_ID:?HALOGEN_MODEL_ID must be the served alias (frank-large)}"
+: "${HALOGEN_MODEL_ID:?HALOGEN_MODEL_ID must be the served alias (frank-dragoon)}"
: "${HALOGEN_CTX:?HALOGEN_CTX must be set (per-slot window)}"
: "${HALOGEN_KV_POOL_POSITIONS:?HALOGEN_KV_POOL_POSITIONS must be set}"
: "${HALOGEN_KV_SLOTS:?HALOGEN_KV_SLOTS must be set}"
diff --git a/scripts/serve-frank-secondary.sh b/scripts/serve-frank-secondary.sh
index 864d983..ba95d8a 100755
--- a/scripts/serve-frank-secondary.sh
+++ b/scripts/serve-frank-secondary.sh
@@ -39,7 +39,7 @@ fi
# --- defaults (used when the env file does not set them) -------------------
: "${LLAMA_BIN:=/home/dank/GitPackages/llama-master/build-cuda/bin/llama-server}"
: "${MODEL_FILE:=/home/dank/models/Qwen35-9B-HauhauCS-Q6K/Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-Q6_K.gguf}"
-: "${ALIAS:=frank-secondary}"
+: "${ALIAS:=frank-zealot}"
: "${BIND_ADDR:=0.0.0.0}"
: "${LISTEN_PORT:=7771}"
# ctx-size is the POOL llama.cpp divides across slots: 401,408 / 2 = 200,704
diff --git a/shared/homepage/docs.html b/shared/homepage/docs.html
index 5b9f28f..450f5b0 100644
--- a/shared/homepage/docs.html
+++ b/shared/homepage/docs.html
@@ -70,8 +70,7 @@
conversations are saved to your account, so history follows you between devices.
Below the text box, the model box on the right chooses which model answers you.
- Family accounts get frank-zealot — the fleet's fast all-rounder
- (Open WebUI lists models by their API id; this one is frank-secondary),
+ Family accounts get frank-zealot — the fleet's fast all-rounder,
which also sees images: drag a photo or screenshot straight into the chat box.
Frank's account can additionally reach the bigger models.
@@ -85,11 +84,11 @@
The homepage "Model Information" panel shows whether each one is up right now —
and plays the unit's voice if you click its quoted line.
-
+
- frank-zealot — the fast utility model (api id: frank-secondary)
+ frank-zealot — the fast utility model
- Model: Qwen3.5-9B-Uncensored (Q6_K) on the RTX 3090 — roughly 95 tokens per second.
- Equivalent: last year's frontier level (2025).
@@ -101,7 +100,7 @@
- Warning:
⚠ uncensored model
Uncensored model: output can include adult content, content that describes harmful, hateful, or illegal acts, content concerning “sensitive offensive cybersecurity topics”, and other output that may carry severe legal risk. Take this warning seriously — don’t ruin this server for everybody.
- frank-dragoon — deep reasoning (api id: frank-large)
+ frank-dragoon — deep reasoning
- Model: Qwen3.8-Flash-Next v2 Swift1.5 abliterated (halogen flash-server, ~62 GiB) on the Strix Halo iGPU — an abliterated (censorship-removed) edition that thinks before answering.
- Equivalent: Claude Sonnet 5 / OpenAI-Luna (Summer 2026 frontier intelligence).
@@ -111,7 +110,7 @@
- Supervision: safe for autonomous, low-supervision use.
- Warning:
⚠ uncensored model
Uncensored model: output can include adult content, content that describes harmful, hateful, or illegal acts, content concerning “sensitive offensive cybersecurity topics”, and other output that may carry severe legal risk. Take this warning seriously — don’t ruin this server for everybody.
- frank-archon — the big one (api id: frank-primary)
+ frank-archon — the big one
- Model: our own build — a GPTQ-w4 quant of Swift1.5-Qwen3.8-Flash-Next, quantized and tuned in-house (radiance, ~114 GiB) on twin AMD R9700s with more than 200 GB of system RAM — the biggest brain on the network and the fastest runtime.
- Equivalent: Claude Opus 4.8 / OpenAI-Terra (Summer 2026 frontier intelligence).
@@ -123,9 +122,8 @@
+ Frank first). Every name on this page is the id the Open WebUI picker and
+ the raw API answer to.
@@ -154,14 +152,14 @@
Step 2 — the three details every tool asks for
- Base URL:
https://ai.franksdank.cloud/api/v1
- - Model:
frank-secondary — this is frank-zealot, the family utility model (the API uses the id, not the family name)
+ - Model:
frank-zealot — the family utility model (this is the id the API expects)
- API key: the
sk-… from step 1 — sent as the header Authorization: Bearer sk-…
Proof that it works, from any terminal (replace the key):
curl https://ai.franksdank.cloud/api/v1/chat/completions \
-H "Authorization: Bearer PASTE-YOUR-KEY" \
-H "Content-Type: application/json" \
- -d '{"model": "frank-secondary", "messages": [{"role": "user", "content": "Hello!"}]}'
+ -d '{"model": "frank-zealot", "messages": [{"role": "user", "content": "Hello!"}]}'
Step 3a — Opencode
Install once (npm install -g opencode-ai), then create the file
@@ -177,13 +175,13 @@
"apiKey": "PASTE-YOUR-KEY"
},
"models": {
- "frank-secondary": { "name": "frank-secondary" }
+ "frank-zealot": { "name": "frank-zealot" }
}
}
}
}
Start opencode and pick the model with /model —
- it appears as frank/frank-secondary.
+ it appears as frank/frank-zealot.
Step 3b — Pi
Create the file ~/.pi/agent/models.json with:
@@ -194,12 +192,12 @@
"api": "openai-completions",
"apiKey": "PASTE-YOUR-KEY",
"models": [
- { "id": "frank-secondary" }
+ { "id": "frank-zealot" }
]
}
}
}
- Then start Pi with pi --model frank/frank-secondary.
+ Then start Pi with pi --model frank/frank-zealot.