Instructions to use FoolDev/Janus-35B-HERETIC with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use FoolDev/Janus-35B-HERETIC with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="FoolDev/Janus-35B-HERETIC") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("FoolDev/Janus-35B-HERETIC", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use FoolDev/Janus-35B-HERETIC with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf FoolDev/Janus-35B-HERETIC:Q4_K_M # Run inference directly in the terminal: llama cli -hf FoolDev/Janus-35B-HERETIC:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf FoolDev/Janus-35B-HERETIC:Q4_K_M # Run inference directly in the terminal: llama cli -hf FoolDev/Janus-35B-HERETIC:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf FoolDev/Janus-35B-HERETIC:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf FoolDev/Janus-35B-HERETIC:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf FoolDev/Janus-35B-HERETIC:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf FoolDev/Janus-35B-HERETIC:Q4_K_M
Use Docker
docker model run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M
- LM Studio
- Jan
- vLLM
How to use FoolDev/Janus-35B-HERETIC with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "FoolDev/Janus-35B-HERETIC" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FoolDev/Janus-35B-HERETIC", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M
- SGLang
How to use FoolDev/Janus-35B-HERETIC with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "FoolDev/Janus-35B-HERETIC" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FoolDev/Janus-35B-HERETIC", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "FoolDev/Janus-35B-HERETIC" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FoolDev/Janus-35B-HERETIC", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Ollama
How to use FoolDev/Janus-35B-HERETIC with Ollama:
ollama run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M
- Unsloth Desktop
- Pi
How to use FoolDev/Janus-35B-HERETIC with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf FoolDev/Janus-35B-HERETIC:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "FoolDev/Janus-35B-HERETIC:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use FoolDev/Janus-35B-HERETIC with Docker Model Runner:
docker model run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M
- Lemonade
How to use FoolDev/Janus-35B-HERETIC with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull FoolDev/Janus-35B-HERETIC:Q4_K_M
Run and chat with the model
lemonade run user.Janus-35B-HERETIC-Q4_K_M
List all available models
lemonade list
- Hermes Agent
How to use FoolDev/Janus-35B-HERETIC with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf FoolDev/Janus-35B-HERETIC:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default FoolDev/Janus-35B-HERETIC:Q4_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use FoolDev/Janus-35B-HERETIC with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf FoolDev/Janus-35B-HERETIC:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "FoolDev/Janus-35B-HERETIC:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Janus-27B
Flagship Reasoning. Dense 27B. Uncensored. llmfan46's Heretic abliteration of Qwen 3.8 27B, repackaged with Claude Fable 5 in the teacher slot.
Architecture: Qwen 3.8 27B (dense) | Parameters: 27B (all active) | Context: 262,144 native / 1,010,000 extensible | Base: Heretic (llmfan46) | Teacher: Claude Fable 5 | Type: Distilled + Abliterated Dense LLM
A personal fork of llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved — an uncensored Heretic-style (MPOA, MTP-preserved) abliteration of Qwen/Qwen3.8-27B, the dense 27B multimodal base — repackaged as Janus-27B with Claude Fable 5 reasoning data in the teacher slot. Refusal-trained behavior is dialed back at the base layer.
Provenance. This repo repackages and quantizes — no training is performed here. What ships is
llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preservedconverted to GGUF and MTP-stripped so stock llama.cpp and Ollama can load it. TheTeacher:field above and thedatasets:list in the frontmatter are carried over from earlier revisions of this card. The current base does not claim them — its card lists no datasets and names no teacher — and nothing in this repo reproduces or measures them. One listed dataset,Crownelius/Opus-4.7-Reasoning, is not publicly reachable: the Hub answers 401, as it does for a private or missing repo. Treat them as unverified attribution, not as a training record.base_model_relationisquantizedfor the same reason.
On the repo name: the model is Janus-27B, but the Hub slug stays
FoolDev/Janus-35B-HERETIC— renaming it would break every existing link andollama run hf.co/…pull. Use the URLs exactly as written below. The Ollama tag (janus) is unchanged too.
TL;DR
One-liner via Hugging Face (pulls a GGUF + this repo's root-level
template / system / params files, including the tool-calling
template — HF's Ollama bridge ingests those three files, not
Modelfile):
ollama run hf.co/FoolDev/Janus-35B-HERETIC # default tag, Q4_K_M
ollama run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M # same blob, explicit tag
Or build locally (uses this repo's Modelfile, kept in sync with the
three bridge files):
git clone https://huggingface.co/FoolDev/Janus-35B-HERETIC && cd Janus-35B-HERETIC
ollama create janus -f Modelfile && ollama run janus
After either path, ollama show janus lists completion, tools,
and thinking under Capabilities. Hardware: the default num_ctx is the full
262,144 native window — ~34 GiB with Ollama's default f16 KV cache, ~26 GiB
with OLLAMA_KV_CACHE_TYPE=q8_0 — so on a smaller host use the q8_0 cache or
lower it (65536 is ~21 GiB), or raise it on to 1,010,000 with YaRN (not baked
in, so context past ~262K degrades). See
Hardware requirements.
To halve the KV cache, start the Ollama server with the q8_0 cache and flash
attention (for a systemd install, add them as Environment= lines with
sudo systemctl edit ollama):
OLLAMA_KV_CACHE_TYPE=q8_0 OLLAMA_FLASH_ATTENTION=1 ollama serve
What's here
| File | Use |
|---|---|
Janus-27B.Q4_K_M.gguf |
Recommended default, ~17 GB. MTP-stripped so stock llama.cpp / Ollama can load it (see Architecture). |
Modelfile |
Ollama wrapper for local builds (ollama create janus -f Modelfile) — carries the Go template that Ollama runs in preference to the GGUF's embedded one (see Which template Ollama runs). |
template, system, params |
Used by HF's Ollama bridge when users ollama run hf.co/FoolDev/Janus-35B-HERETIC directly. The bridge does not read Modelfile (see HF Ollama docs); it ingests these three root-level files instead. Kept in sync with the Modelfile's TEMPLATE / SYSTEM / PARAMETER directives. |
chat_template.jinja |
Chat template for llama.cpp / llama-server, already stamped into the bundled GGUF (pass --chat-template-file only for an unstamped quant). The base model's own embedded template with two changes: preserve_thinking and preserve_reasoning never raise when they disagree (preserve_thinking wins), while earlier turns' reasoning is replayed by default, as upstream does; and reasoning_effort is normalised instead of validated. Tool calls keep upstream's XML default, the form llama-server's parser reads. Also stamped into the GGUF by scripts/build.sh. See Tool / function calling. |
scripts/build.sh |
Pulls a GGUF from llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-GGUF (default Q4_K_M), runs it through strip_mtp.py, then runs ollama create janus. Quants published there: BF16, Q3_K_L, Q3_K_M, Q4_K_M, Q4_K_S, Q5_K_M, Q5_K_S, Q6_K, Q8_0. The bundled Q4_K_M is already this Heretic quant (stripped); use this to build the others locally. |
scripts/check_bridge_sync.py |
Run before pushing a Modelfile / template / system / params edit to verify the four configurations remain in sync. Exits 0 if in sync, 1 with a per-key diff if not. |
scripts/check.sh |
Local lint: bash -n, shellcheck, py_compile, footgun-grep, Modelfile-vs-bridge-files sync, the chat_template.jinja render checks and the Go template guard (make check) |
scripts/check_chat_template.py |
Renders chat_template.jinja with jinja2 and asserts the tool-call, thinking, reasoning-replay (default, opt-outs, conflicting kwargs, live tool chain) and reasoning_effort behaviour (check 8 in check.sh) |
scripts/check_go_template.py |
Guards the Go template: Ollama's thinking detection, the condition that replays earlier turns' reasoning, the tool round trip and JSON tool signatures (check 9 in check.sh) |
scripts/live_check.sh |
Live end-to-end checks in an isolated, CPU-only Ollama (own port and model store; it refuses to run if Ollama reports a GPU): template selection, one tool call, string-argument replay, an earlier turn's reasoning replayed and a live tool chain's kept, every reasoning_effort value and the effort lines — 17 checks (make live-check) |
scripts/verify_arch.py |
Cross-checks the README Architecture bullets (layer count, hidden size, dense FFN width, native context, vocab) plus the underlying forward-pass structure (Gated Attention + Gated DeltaNet head dims, partial RoPE, full-attention interval) against the bundled GGUF's qwen35 metadata. Run on demand (python3 scripts/verify_arch.py); loads the ~17 GB GGUF (LFS smudge required) and exits non-zero on any mismatch. block_count is checked against 64 — the MTP-stripped value — so an unstripped bundle reports 65 and fails. |
scripts/strip_mtp.py |
Drops the MTP / NextN layer from a qwen35 GGUF (python3 scripts/strip_mtp.py IN.gguf OUT.gguf): removes the extra blk.<last>.* block, decrements block_count, drops nextn_predict_layers. Kept tensors are copied byte-for-byte (no re-quant); a conditional no-op (hardlink) on already-clean quants. Required, not optional: the base is MTP-preserved, so quants from the source repo carry a NextN block at index 64 that stock llama.cpp / Ollama cannot load. With --chat-template FILE it also restamps the GGUF's embedded chat template in the same pass (see Tool / function calling). build.sh runs this on every fetched quant, and the bundled Q4_K_M ships already stripped (block_count 64). Parity with the dense sibling FoolDev/Thanatos-27B-HERETIC. |
scripts/smoke_test.sh |
Integration smoke test against a running Ollama daemon: server reachable, model loaded, tools capability present, chat round-trip, and no control-token leakage. TOOLS_TEST=1 adds a tool-call round-trip. Defaults to MODEL=janus. |
scripts/bench.sh |
Measures tok/s from Ollama's eval_count / eval_duration over a short/medium/long prompt mix (with a discarded warmup). Defaults to MODEL=janus. |
scripts/load_bundle.sh |
Loads the bundled Janus-27B.Q4_K_M.gguf into Ollama as a local janus tag without an upstream pull (if the working-tree file is still an LFS pointer it downloads the real blob into .cache/ — it does not smudge in place — then checks the arch is qwen35). |
scripts/cap_ctx.sh |
Bakes a small-num_ctx local janus tag (bundled blob + this repo's Modelfile, num_ctx→4096, num_batch 256) for OpenAI /v1 clients — which can't override the baked num_ctx and OOM on small hosts (see Inference examples). Run ./scripts/cap_ctx.sh (or CTX=8192 ...). |
scripts/fetch_vision.sh |
Downloads the vision projector (Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf) from the Heretic GGUF repo for llama.cpp image input (Ollama vision is broken upstream — see Vision). |
examples/ |
Ready-to-run Python clients for Ollama, Transformers, and llama-cpp-python (text, tools, and vision — see examples/README.md) |
GGUF-only release. Pull the Heretic safetensors from llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved if you need the transformers tree (or the vanilla pre-Heretic base from Qwen/Qwen3.8-27B). The safetensors also keep the MTP head that the bundled GGUF has stripped — that's the path to speculative decoding under vLLM / SGLang.
Bundled blob status: the dense 27B is published
The bundled GGUF is
Janus-27B.Q4_K_M.gguf(~17.3 GB) — the dense Qwen 3.8 27B this card describes.ollama run hf.co/FoolDev/Janus-35B-HERETICserves it directly, andollama create janus -f Modelfileworks from a fresh clone.It is
llmfan46/…-MTP-Preserved-GGUF's Q4_K_M (sha25697298d4b0f99a3f4c46b2dd013abd0ca1628d68be4c3960817b39998a60f0eaf) run through./scripts/strip_mtp.py: the NextN block at index 64 is dropped,block_count65 → 64,nextn_predict_layersremoved, and every kept tensor copied byte-for-byte — no re-quantization.chat_template.jinjais stamped into its metadata in the same pass, so llama.cpp and LM Studio's llama.cpp runtime get working tool calls with no extra flags (both tested; KoboldCpp and Jan were checked on 2026-09-14, see Tool / function calling).Verified before publishing: all 14 Architecture claims below via
python3 scripts/verify_arch.py; loads in Ollama asqwen35/ 26.9B dense withtoolsandthinking; and a full tool-call round-trip on/v1/chat/completions, including the replay turn whose stringargumentsused to fail.The repo previously shipped a 35B-A3B MoE quant, which is where the
Janus-35B-HERETICslug comes from. That blob is no longer published; it remains in git history.
Architecture
A dense hybrid stack: linear-attention (Gated DeltaNet) layers with a full Gated Attention layer every fourth block. No experts, no router — all 27B parameters run on every token.
- Qwen 3.8, 27B dense (no experts, no routing, nothing conditionally skipped)
- 64 layers, 16 × (3 × Gated DeltaNet → MLP / 1 × Gated Attention → MLP) —
full_attention_interval4, so 16 full-attention and 48 linear-attention layers - Hidden size 5120, dense FFN intermediate 17408
- Gated Attention: 24 Q-heads / 4 KV-heads (GQA), head_dim 256, gated output projection, partial RoPE (factor 0.25 — 64 of 256 dims rotated)
- Gated DeltaNet: 48 V-heads / 16 QK-heads, head dim 128, conv kernel 4
- 262 144 native context (extensible to 1 010 000 with YaRN, but YaRN is not enabled in the bundled GGUF)
- Vision + video supported by upstream (mmproj not included in this release)
- Vocab 248,320
- GGUF arch stamp
qwen35— the canonical upstream label for the whole Qwen 3.5 / 3.6 / 3.8 family; there is noqwen38arch in llama.cpp
MTP head (stripped). The base is MTP-preserved: its GGUFs carry a NextN
block at index 64 for vLLM / SGLang speculative decoding, and stock llama.cpp and
Ollama refuse to load it. The bundled Janus-27B.Q4_K_M.gguf is therefore
MTP-stripped — block 64 removed, block_count 65 → 64 — by
scripts/strip_mtp.py, exactly as the dense sibling Thanatos does. If you want
the MTP head, run the upstream safetensors under vLLM / SGLang, or take an
unstripped quant straight from the source GGUF repo.
Quick start
llama.cpp / LM Studio
Drop the GGUF into your loader of choice. The chat template is embedded in the GGUF metadata, and llama.cpp and LM Studio use it by default, so no --chat-template flag is needed (llama.cpp has no --chat-template auto mode; it would take "auto" as the template itself).
Tool calling works out of the box — the bundled GGUF carries this repo's chat_template.jinja in its metadata, so --jinja alone is enough. Tool calls use Qwen's native XML form, the one llama-server's parser reads. (Upstream's template raises on reasoning_effort: "max" and on conflicting preserve_thinking / preserve_reasoning, both HTTP 500s on llama-server. Pass the file explicitly if you are running an unstamped quant:)
llama-server -m Janus-27B.Q4_K_M.gguf --jinja --chat-template-file chat_template.jinja
A GGUF built by ./scripts/build.sh has that template baked in and needs no flag.
See Tool / function calling for what differs and why.
Ollama
Ollama chooses between the GGUF's embedded template and a Go template at load time (see Which template Ollama runs); this repo ships a Go template so Ollama keeps its JSON tool-call format. Two paths deliver it:
# A. Pull straight from HF (uses the root-level template/system/params files):
ollama run hf.co/FoolDev/Janus-35B-HERETIC # default tag, Q4_K_M
ollama run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M # same blob, explicit tag
# Note: HF's Ollama bridge does NOT read Modelfile; it reads template/system/params.
# B. Build locally (uses Modelfile, which is kept in sync with the three above):
ollama create janus -f Modelfile && ollama run janus
After the local build (path B), ollama show janus lists completion, tools, and thinking under Capabilities. (The HF-pull paths register the model under the full tag hf.co/FoolDev/Janus-35B-HERETIC, not janus.)
Inference examples
Once the model is loaded (via ollama run janus, lms server, or llama-server), all the standard OpenAI-compatible clients work. Examples assume the loader is listening on http://localhost:11434 (Ollama default) — adjust the port for LM Studio (:1234) or llama.cpp (:8080). Runnable versions of everything below live in examples/.
The examples use
model: "janus", the tag from the local build (path B). If you pulled via the TL;DR one-liner instead, use the full taghf.co/FoolDev/Janus-35B-HERETIC, or runollama cp hf.co/FoolDev/Janus-35B-HERETIC janusonce to create the short tag.
On memory-tight hosts, cap
num_ctxfirst./v1/chat/completions(OpenAI-compat) has nonum_ctxknob, so it loads at the baked 262,144 default (16 GiB KV / ~34 GiB total with Ollama's default f16 cache), which does not fit a 32 GB box;OLLAMA_KV_CACHE_TYPE=q8_0on the server brings it to ~26 GiB (see Hardware requirements). Either call/api/chatwith"options": {"num_ctx": 4096}, or bake a small-context tag for OpenAI clients:ollama run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M, then/set parameter num_ctx 4096and/save janus, and point clients atjanus— or in one step,./scripts/cap_ctx.sh(which bakes exactly that tag).
curl
curl -s http://localhost:11434/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "janus",
"messages": [
{"role": "system", "content": "You are Janus, a precise reasoning assistant."},
{"role": "user", "content": "Sketch an algorithm to detect cycles in a directed graph."}
],
"temperature": 0.6,
"max_tokens": 800
}' | jq -r '.choices[0].message.content'
Python (openai-compat)
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ignored")
resp = client.chat.completions.create(
model="janus",
messages=[
{"role": "user", "content": "Write a haiku about a stack overflow."}
],
temperature=0.8,
top_p=0.95,
)
print(resp.choices[0].message.content)
Streaming
stream = client.chat.completions.create(
model="janus",
messages=[{"role": "user", "content": "Explain RoPE briefly."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content or ""
print(delta, end="", flush=True)
Recommended sampling
| Use | temp | top_p | top_k | repeat_penalty |
|---|---|---|---|---|
| Default (Fable-matched) | 1.0 | 0.95 | 0 | 1.05 |
| Tighter reasoning | 0.6 | 0.95 | 20 | 1.05 |
| Creative / RP | 0.8 | 0.95 | 40 | 1.02 |
The shipped default is Fable-matched — warm (temperature 1.0), no top_k, with top_p 0.95 + repeat_penalty 1.05 kept as loop insurance. Drop to the reasoning row for tighter, more deterministic output; lower temperature (0.4–0.6) and bump repeat_penalty to 1.08 if it loops inside <think> tags.
top_pdoes not survive the OpenAI-compatible endpoint. Ollama's/v1/chat/completionslayer applies OpenAI's own default oftop_p 1.0, overwriting the0.95baked intoparams/ theModelfile. Measured on this model: the same request logstop_p = 0.950on/api/chatandtop_p = 1.000on/v1/chat/completions. Since the default profile also setstop_k 0(disabled), a/v1request samples with no truncation at all attemperature 1.0— the "loop insurance" above is only in effect on the native API. If you need that guard on/v1, sendtop_pexplicitly on every request, or bakemin_p(e.g.PARAMETER min_p 0.05) into a local tag —min_pandtop_kboth pass through/v1untouched,top_pdoes not.
System prompt
You are Janus, a precise and capable assistant for reasoning, writing, coding, and long-form dialogue.
Behavior rules:
- Answer the user's actual request directly.
- Be accurate, complete, and structured.
- Think before answering, but do not get stuck in repetitive loops or meta-commentary.
- If the request is ambiguous or incomplete, state what is missing and make the smallest reasonable assumption needed to continue.
- If the user wants creative writing, preserve tone, continuity, and character consistency.
- If the user wants analysis or technical help, prefer concrete steps, examples, and decisions over fluff.
- Finish with a usable answer, not just planning.
Vision
The Qwen 3.8 base supports image (and video) input via a separate
mmproj projector. The full multimodal stack is:
Janus-27B.Q4_K_M.gguf (~17 GB, the text decoder)
Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf (the vision projector)
The projector and other-quant text decoders live at
llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-GGUF
(BF16 mmproj only). This repo intentionally does not redistribute it;
./scripts/fetch_vision.sh pulls the projector into the repo root.
Loader compatibility
| Loader | Text | Vision (mmproj) | Notes |
|---|---|---|---|
llama.cpp (llama-mtmd-cli, llama-server --mmproj) |
✅ | ✅ | Reference path. Upstream has the qwen35 arch entry. |
| llama-cpp-python | ✅ | ✅ | See examples/llama_cpp_vision.py. |
| Ollama 0.24+ | ✅ | ❌ | Text inference works: Ollama's Go engine has the qwen35 arch entry. Vision (mmproj) is still broken: the C++ llama.cpp fallback that Ollama switches to when an mmproj is attached lacks it. ollama create accepts a dual-FROM (text + mmproj) and ollama show reports vision capability — but the first inference request fails with an unknown model architecture load error, and once mmproj is attached this blocks text inference too. See ollama/ollama#14575 (closed as completed on 2026-08-04; #15898 was closed as its duplicate and the sync PR #15899 closed unmerged). Re-test on a current Ollama before assuming vision is still broken — this table has not been re-verified since it closed. |
| LM Studio | ✅ | ✅ | Uses upstream llama.cpp directly. |
Vision via llama.cpp
# Fetch the projector first (into the repo root):
./scripts/fetch_vision.sh # Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf
# A. HTTP via llama-server (the easiest path):
llama-server \
-m Janus-27B.Q4_K_M.gguf \
--mmproj Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf \
--host 127.0.0.1 --port 8765 -c 8192 -ngl 99
# then POST OpenAI-style chat completions with an image_url content block —
# e.g. {"type":"image_url","image_url":{"url":"data:image/jpeg;base64,..."}}
# The thinking trace arrives in message.reasoning_content; the visible
# answer is in message.content. Budget ≥500 max_tokens so the reasoning
# block doesn't crowd out the final answer.
# B. CLI via llama-mtmd-cli (one-shot). It's a separate cmake target, so a
# selective build can skip it; a plain `cmake --build build` produces it.
llama-mtmd-cli \
-m Janus-27B.Q4_K_M.gguf \
--mmproj Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf \
--image photo.jpg \
-p "Describe this image."
# C. Python via llama-cpp-python:
python examples/llama_cpp_vision.py \
--gguf Janus-27B.Q4_K_M.gguf \
--mmproj Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf \
--image /path/to/photo.jpg \
--prompt "What is in this image?"
The Ollama issue is closed upstream but this table has not been re-verified since; until you have re-tested, treat Ollama as text-only for this model. The bundled Q4_K_M decoder pairs with the projector directly — the mmproj is family-wide for Qwen 3.8 27B, so no separate text download is needed for vision.
Hardware requirements
This is a ~17 GB Q4_K_M GGUF. Measured on Ollama 0.33.3's CPU backend (2026-09-14, from llama.cpp's own allocation log lines), it needs 16.1 GiB for the weights, 0.15 GiB of fixed recurrent state for the 48 linear-attention layers, a 0.3-0.8 GiB compute buffer with flash attention (Ollama's default auto enables it; forcing it off grows the buffer to ~25 GiB at 262144), and a KV cache for the 16 full-attention layers of exactly 2 GiB per 32K tokens at f16 — Ollama's default — or 1.06 GiB per 32K at q8_0 (OLLAMA_KV_CACHE_TYPE=q8_0, with OLLAMA_FLASH_ATTENTION=1).
num_ctx |
f16 cache (default) | q8_0 cache |
|---|---|---|
| 262144 (default) | 16 GiB KV, ~34 GiB total | 8.5 GiB KV, ~26 GiB total |
| 65536 | 4 GiB KV, ~21 GiB total | 2.1 GiB KV, 19.2 GiB total (measured) |
| 32768 | 2 GiB KV, ~19 GiB total | 1.1 GiB KV, ~18 GiB total |
| 1010000 (needs YaRN) | 61.6 GiB KV, ~80 GiB total | 32.7 GiB KV, ~50 GiB total |
KV and recurrent sizes are exact (measured at 8K, 32K and 65K, and linear in num_ctx); totals at 262144 and above add llama.cpp master's llama-fit-params projection of the compute buffer (~1-1.5 GiB), which ran ~0.35 GiB above what Ollama allocated at 65536. It's extensible to 1,010,000, but this GGUF ships no baked YaRN rope-scaling, so positions past the 262144 native window use untrained RoPE and output degrades — reaching the 1.01M ceiling needs YaRN (see below); keep real work within ~262K otherwise.
How to override it: ollama run has no -o flag, and OLLAMA_CONTEXT_LENGTH
only sets a default that the baked num_ctx overrides — so set it per-session
from the interactive prompt. The model loads lazily on the first message, so
/set applies before the default context is allocated:
ollama run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M
>>> /set parameter num_ctx 4096
>>> /set parameter num_batch 256
Programmatic callers pass the same via the API options field:
"options": {"num_ctx": 4096, "num_batch": 256}.
| Hardware | Status |
|---|---|
| ≥48 GB RAM (CPU-only) | Works at the 262144 default (OLLAMA_KV_CACHE_TYPE=q8_0 (num_ctx 65536 (~21 GiB) |
| Single H100/A100 80 GB | Works, full offload |
| RTX 4090 24 GB / 5090 32 GB + 32 GB RAM | Works, partial offload |
| Mac Studio M2/M3 Ultra 64 GB+ unified | Works |
| 32 GB unified-memory laptops (Ryzen AI Max+, Apple M-series) | Does not fit the 262144 default with the f16 cache; the q8_0 cache (num_ctx 65536 ( |
Throughput, measured on CPU only: ~5.0 tok/s. On a Ryzen AI Max+ 395 with
Ollama 0.33.3's CPU backend, ./scripts/bench.sh measured 4.97 tok/s at Q4_K_M
(3-prompt mix, flash attention, q8_0 KV cache), and llama-server generated at about
the same rate on the same CPU. Partial GPU offload is covered below.
The tok/s figures this table used to carry were taken before the 27B rebase and say
nothing about this model, so they've been removed rather than carried over; the
rows above are fit estimates from the memory math. ./scripts/bench.sh measures
tok/s on your own host.
GPU offload on a Strix Halo iGPU (Radeon 8060S): a small gain, and a trap. On a
Vulkan integrated GPU, llama.cpp - including the build Ollama 0.33.3 bundles - turns
mmap off and puts every layer it does not offload into GPU-reachable host memory from
the same pool as the GPU, so num_gpu alone does not limit GPU memory: a first attempt
with llama-server filled the pool and took the desktop down with it. With
LLAMA_ARG_NO_HOST=1 in the Ollama server's environment (llama.cpp's --no-host) those
layers stay in ordinary RAM. Measured that way on this model (a private Ollama 0.33.3
with the ollama-vulkan backend and OLLAMA_IGPU_ENABLE=1; flash attention, q8_0 KV
cache, num_ctx 4096, a short generation): 4.8 tok/s at num_gpu 4, 4.9 at 8, 5.3 at 16
and 5.7 at 24 (7.9 GiB of the GPU pool), against about 5.0 on CPU only; prompt processing
roughly doubled (61 against 30 tok/s). The step to 32 layers ran the 27 GiB host short of
RAM and was stopped: the GPU's GTT is system RAM, so offloading frees none. On a machine
like this, CPU-only is nearly as fast; if you try the GPU, set LLAMA_ARG_NO_HOST=1 and a
fixed num_gpu. The mechanism is reported upstream in
ggml-org/llama.cpp#27360.
Reaching a coherent ~1.01M context (opt-in YaRN). The bundled GGUF ships no YaRN rope-scaling, so raising num_ctx toward the 1.01M ceiling degrades past the 262144 native window (see above). Ollama has no rope knob, so for a genuinely coherent long context run the GGUF under llama.cpp with YaRN enabled:
llama-server -m Janus-27B.Q4_K_M.gguf \
--rope-scaling yarn --yarn-orig-ctx 262144 --rope-scale 3.853 -c 1010000
--rope-scale 3.853 ≈ 1010000 / 262144; use a smaller factor for a smaller window. Static YaRN rescales all prompts, so enable it only when you actually need > 262K — it slightly degrades short-context quality otherwise.
Chat template
The model uses the standard Qwen 3.x ChatML format with <|im_start|> / <|im_end|> role markers. The template is embedded in the GGUF metadata for plain conversation use, but on Ollama the Go template / Modelfile TEMPLATE is what runs: Ollama picks between it and the embedded template at load time (see Which template Ollama runs).
Plain conversation
<|im_start|>system
You are Janus, a precise and capable assistant…<|im_end|>
<|im_start|>user
What is the time complexity of mergesort?<|im_end|>
<|im_start|>assistant
With reasoning trace
When the model decides to think, the assistant turn contains a <think>…</think> block followed by the visible answer:
<|im_start|>assistant
<think>
The user is asking about mergesort. Mergesort divides the array, recursively sorts each half, then merges. The recurrence T(n) = 2T(n/2) + O(n) solves to O(n log n).
</think>
Mergesort runs in **O(n log n)** time in the worst, average, and best cases. The recurrence is T(n) = 2T(n/2) + O(n), which solves to Θ(n log n) by the master theorem.<|im_end|>
Most clients (Open WebUI, LibreChat, etc.) hide the <think> block by default and show only the final answer. If your client doesn't, set its "show reasoning" toggle off.
Thinking is replayed across turns
Traces from earlier assistant turns are replayed back into the prompt: every
assistant message that carries reasoning renders its <think>…</think> block, so the
model can see how it reached its previous answers. The turn in progress — including a
tool-call chain, where the model calls a tool and then continues after the result —
keeps its own either way. On llama.cpp this is upstream's default; on Ollama it
departs from Qwen's stock condition, which kept only the turn in progress.
The client has to send the reasoning back. The server returns it — Ollama's
/api/chat in the response's thinking field, llama.cpp in reasoning_content —
but only reasoning that arrives in the history's assistant messages is replayed, and
each endpoint reads one field:
| Endpoint | Field read from each assistant message |
|---|---|
Ollama /api/chat |
thinking |
Ollama /v1/chat/completions |
reasoning only — reasoning_content and thinking are dropped silently, and a message whose content is an array of parts keeps its reasoning only if it also has tool_calls |
llama-server /v1/chat/completions |
reasoning_content |
Checked live on 2026-09-13 with the restamped blob, CPU only: Ollama 0.33.3
replayed thinking on /api/chat (232 prompt tokens with it, 187 without) and
reasoning on /v1 (215 vs 187) and ignored reasoning_content on /v1 (187);
llama-server master rendered reasoning_content and dropped a reasoning field.
That Ollama's /v1 also drops thinking, and the array-content rule, come from
Ollama's v0.33.3 and v0.34.0 source, and still hold on the current release:
openai/openai.go and server/prompt.go are byte-identical from v0.33.3 through
v0.34.2 (source, 2026-09-17). Ollama never passes reasoning to the GGUF's
embedded Jinja template, so on Ollama only the Go template decides what is replayed.
On llama.cpp, while replay is on, an earlier assistant turn with no reasoning still
gets an empty <think>\n\n</think> block, as upstream renders it.
The cost is context. Every retained trace stays in the prompt, measured at 181 prompt tokens without / 464 with on a 3-message conversation whose first assistant turn carried a ~240-word trace. Prefill grows with every retained trace, and on a CPU-only host prefill is the slow part. Releases 0.3.0 through 0.3.2 turned replay off for that reason; the CHANGELOG has the history.
Tested on llama.cpp on 2026-09-13 with a 260K-parameter test model and
--chat-template-file (the template, not the model, decides the prompt), via
/apply-template and /v1/chat/completions, on master 4a89937 (b10941), b10760
(the llama-server Ollama 0.33.3 bundles) and b10519 (LM Studio's avx2 CPU runtime
2.30.0): with default flags an earlier turn's reasoning was replayed; with
--no-reasoning-preserve, or a per-request preserve_thinking: false or
preserve_reasoning: false, it was not; preserve_thinking: true replayed it even
against --no-reasoning-preserve; a live tool-call chain kept its reasoning in every
mode, and no request returned an error. Master (b10763 and later) passes
preserve_reasoning=true unless the server runs with --no-reasoning-preserve, and
logs "chat template supports preserving reasoning, it is enabled by default"; b10760
and b10519 pass nothing, log "consider enabling it via --reasoning-preserve", and
replay anyway, because the template's own default is on. On the restamped blob
itself, with its embedded template and default flags, llama-server master rendered a
3-message conversation in 69 prompt tokens with the earlier turn's reasoning and 39
with --no-reasoning-preserve or either false kwarg (43 with no reasoning sent,
for the empty think block), and a real tool-result turn with string arguments
returned HTTP 200.
Which llama.cpp an Ollama carries. 0.33.3 and 0.34.0 bundle b10760; 0.34.1
bundles b10864 and 0.34.2 b10969 (each release's LLAMA_CPP_VERSION). From 0.34.1
on that is a b10763-or-later llama-server — the family that passes
preserve_reasoning=true by default — but it changes nothing here: text inference
for this model runs Ollama's own Go engine, and the bundled llama.cpp comes into
play only when Ollama falls back to its C++ engine, as it does once an mmproj is
attached (see Loader compatibility).
Conflicting settings do not fail the request. A request's preserve_thinking
replaces the copy llama-server derives from preserve_reasoning, so the template can
see the two disagree. Upstream's template raises on that, and llama-server returns the
raise as HTTP 500 — verified on master for a preserve_thinking: false request under
default flags, and on all three builds for preserve_thinking: true against
--no-reasoning-preserve. This template lets preserve_thinking win and never raises.
To turn replay off:
- llama-server — start it with
--no-reasoning-preserve, or send"chat_template_kwargs": {"preserve_thinking": false}(or{"preserve_reasoning": false}) on a request. A request'spreserve_thinking: trueswitches it back on for that request. - Ollama — edit the template. In the assistant branch of both the
Modelfileandtemplate(somake check's bridge sync stays green), change{{ if (and $.IsThinkSet .Thinking) -}}back to Qwen's stock{{ if (and $.IsThinkSet (and .Thinking (or $last (gt $i $lastUserIdx)))) -}}(keep the-}}; the$lastUserIdxloop at the top of the template is still there for it). Do not delete the block instead — see Which template Ollama runs.make check's Go-template guard will then fail, since it pins the replay condition.
Disabling thinking
This is a reasoning-first model — it opens a <think> block by default. For a direct answer with no reasoning trace (simple or latency-sensitive calls), turn thinking off:
ollama run hf.co/FoolDev/Janus-35B-HERETIC:Q4_K_M --think=false
or send "think": false on /api/chat. With thinking off the model skips the reasoning trace and answers straight into content; with it on (the default) reasoning is emitted into the thinking field.
Reasoning effort
OpenAI-compatible clients can send reasoning_effort. Ollama's /v1 layer accepts
eight values. Where chat_template.jinja sees the value as sent (llama.cpp), it maps
each to one of three tiers or switches thinking off:
reasoning_effort |
Effect |
|---|---|
high, xhigh, max, ultra |
xhigh — the model is told to think carefully and check its assumptions |
medium, unset, null |
medium — the default; no effort instruction is added |
low, minimal |
low — the model is told to keep its thinking brief |
none |
thinking off for that request, the same as "think": false |
Anything unrecognised falls back to the medium default rather than failing the
request. The two siblings differ here, each following its base model's template:
an unset or unrecognised value is medium on Janus and xhigh on Thanatos. Upstream's template raised on unfamiliar values, so reasoning_effort: "max" broke every request. On Ollama, while it ran the embedded template, that surfaced as
HTTP 500.
On Ollama's default path the Go template runs instead (see
Which template Ollama runs), and it adds the same
instruction from Ollama's think level. Ollama folds the eight values into four
levels before any template sees them, so the Go template maps levels, not values:
high, xhigh, max and ultra get the xhigh line; low and minimal get the
low line; medium and an unset value get no line; none switches thinking off. "think": "high",
"low" and "max" on /api/chat map the same way. Mixed case such as "HIGH"
is rejected by Ollama itself with HTTP 400 before any template runs. Verified on
Ollama 0.33.3 and 0.34.0 with scripts/live_check.sh, which sends /api/chat think levels: on a one-line chat, high and max
each added 38 prompt tokens and low 26, while medium and an unset value added
none. The /v1 value-to-level mapping above comes from Ollama's source, unchanged
from v0.33.3 through v0.34.2 (2026-09-17).
On llama.cpp every value except none reaches chat_template.jinja as sent;
llama-server handles none itself by switching thinking off. Tested on llama.cpp
master a2878d3: all eight values, "HIGH" and an unknown word each
returned HTTP 200, and the rendered prompt carried the tier in the table. The
template lower-cases and trims the value itself. LM Studio's CPU engine (llama.cpp b10519) passed the same checks; the LM Studio app's own API layer is untested.
Which template Ollama runs
This repo ships two templates for the same ChatML model: the Go template (served
by HF's Ollama bridge) / Modelfile TEMPLATE, and chat_template.jinja, stamped
into the GGUF. They do not render identical prompts — the Go template pins JSON
tool calls and takes the reasoning-effort line from Ollama's think level, while the
Jinja template has its own tool instructions, uses the XML <function=…> form
unless a replayed call carries string arguments, and takes the line from the
request's reasoning_effort.
Ollama 0.33.3 and 0.34.0 (both verified) pick one at load time: they prefer the
embedded template when that advertises more capabilities — tools, thinking — and
keep the Go template when they tie. They tie, so Ollama runs the Go template;
llama.cpp and LM Studio run the embedded Jinja template. That selection code is
unchanged through v0.34.2 (source, 2026-09-17), and Ollama's built-in renderers —
it ships a qwen35 one — displace both templates only when the model's own config
names a renderer or parser, which this repo's does not. Ollama logs the choice:
msg="template selection" ... selected=go_template go_template="[completion tools thinking]"
The Go template's "thinking" entry comes from its single .Thinking reference —
the block that renders each assistant turn's reasoning. Removing it drops that
capability: Ollama switches to the embedded template, a single tool call can
come back twice (seen once; cause inferred, not confirmed — see
Known limitations), and reasoning_effort suddenly selects
the Jinja template's tiers — under upstream's version of that template it raised
instead, which is what caused the HTTP 500s. That happened once; the CHANGELOG has
the details. Setting OLLAMA_GO_TEMPLATE=1 or =0 on the Ollama server forces one
template or the other for every model.
Tool / function calling
The model emits whichever format the system prompt specifies. The Ollama path pins JSON. On llama.cpp the template defaults to XML, the model's native form and the only one llama-server's tool-call parser reads; tool_call_format: "auto" is an opt-in for loaders that pass arguments through as strings (below).
Ollama path (this repo's Modelfile). The TEMPLATE advertises tools inside <tools>…</tools> and asks the model to reply in JSON-in-XML — the form Ollama's tool-call extractor parses into a structured tool_calls array on /api/chat and /v1/chat/completions. The tool definitions go in with {{ json .Function }}: on Ollama 0.14 and later a bare {{ .Function }} prints Go struct syntax instead of JSON (ollama/ollama#14601; fix proposed in ollama/ollama#18391). The model replies like this:
<tool_call>
{"name": "get_weather", "arguments": {"city": "Tokyo"}}
</tool_call>
Embedded-jinja path (llama.cpp, llama-cpp-python, LM Studio). The bundled GGUF already embeds chat_template.jinja, so this path works as-is. Like the upstream Qwen 3.8 template, it defaults to the XML form:
<tool_call>
<function=get_weather>
<parameter=city>
Tokyo
</parameter>
</function>
</tool_call>
Keep XML on llama-server. llama-server recognises this template as Qwen3-Coder-style and parses the model's reply with a parser — and, once the model opens <tool_call>, a grammar — that accept only <function=…><parameter=…>. A prompt that teaches the JSON form gets replies that parser cannot read. 0.3.0 to 0.4.0 defaulted to auto; 0.5.0 went back to xml for that reason.
Replayed tool calls render on llama-server. Every OpenAI-compatible client hands assistant tool calls back with function.arguments as a JSON string, and the XML parameter form needs the individual key/value pairs — a chat template has tojson but no inverse. llama-server decodes the string into a mapping before it renders the template, so the second turn of a tool call renders in XML with no error. Tested on 2026-09-14 with a 260K-parameter test model and this template, replaying a call whose arguments was the string {"city": "Paris"}: /apply-template and /v1/chat/completions returned HTTP 200 with the call rendered as <parameter=city> on llama.cpp master 97e4ca7, b10760 (the llama-server Ollama 0.33.3 bundles) and b10519 (LM Studio's avx2 CPU runtime 2.30.0).
Other loaders, checked 2026-09-14. KoboldCpp v1.120 renders the template with Python's jinja2 only when run with --jinja --jinja_tools (without --jinja_tools, requests with tools skip the template), and parses JSON-string arguments with json.loads first: with this template and a string-argument replay it returned HTTP 200 and rendered the call as XML (tested with a 260K-parameter model). Jan runs llama.cpp's own server code — v0.8.4 downloads llama-server from the janhq/llama.cpp fork (b9967), and its main branch links ggml-org llama.cpp b10809 — so it inherits the conversion above (from source, untested). The LM Studio app renders templates with its own JavaScript Jinja engine rather than llama-server's, and also parses the arguments first: through LM Studio 0.4.24's /v1/chat/completions (CPU runtime avx2 2.37.0, a 260K-parameter model carrying this template) a string-argument replay returned HTTP 200 with the call rendered as XML, and a request whose arguments were not valid JSON returned HTTP 500 before the template ran, with or without tool_call_format: "auto". If a loader does raise the message below, change 'xml' to 'auto' in the template's _requested_tool_format default (in LM Studio, under the model's Prompt Template setting).
A loader that hands the template the raw string instead gets this raise under the default:
tool_call_format="xml" requires tool-call arguments to be mappings, but received
a JSON string. Parse the JSON string into a mapping before applying the template,
or set tool_call_format="auto" (or "json") to use the lossless JSON tool-call
representation.
For those, tool_call_format also accepts auto — the whole prompt in JSON form whenever a historical tool call carries string arguments, byte-identical to xml when every argument is a mapping — and json. Pass it with --chat-template-kwargs or a request's chat_template_kwargs:
llama-server -m Janus-27B.Q4_K_M.gguf --jinja \
--chat-template-kwargs '{"tool_call_format":"auto"}'
On llama-server auto changes nothing, because arguments reach the template as mappings; do not set json there, for the parser reason above.
chat_template.jinja in this repo is the base model's own template with two deliberate changes, each marked CHANGED FROM UPSTREAM in the file: preserve_thinking / preserve_reasoning never raise — when they disagree preserve_thinking wins, where upstream raises and llama-server returns HTTP 500 — while earlier turns' reasoning is replayed by default, as upstream does (see Thinking is replayed across turns); and reasoning_effort is normalised instead of validated (see Reasoning effort). The tool-call format, max_tool_arg_chars, auto_disable_thinking_with_tools, the vision handling and the whitespace contract are upstream's. The stock template still raises on reasoning_effort: "max", which llama-server passes to the template, so run an unstamped quant with this file:
llama-server -m Janus-27B.Q4_K_M.gguf --jinja --chat-template-file chat_template.jinja
With it the same client code should work against either server, as long as both return a parsed tool_calls array — verified on Ollama and on standalone llama-server (llama.cpp master a2878d3 and b10760, under the earlier auto default); the prompt format underneath differs (see Which template Ollama runs).
The bundled GGUF already carries this template — you do not need the flag.
Janus-27B.Q4_K_M.ggufhaschat_template.jinjastamped into its metadata, so a loader that reads the embedded template and parses Qwen's<tool_call>output gets working tool calls with no configuration: llama-server (tested on llama.cpp mastera2878d3and b10760) and LM Studio's CPU runtime (llama.cpp b10519, tested). llama-cpp-python renders the tools but, per its source, does not parse<tool_call>output intotool_calls. KoboldCpp (with--jinja --jinja_tools) was tested and Jan checked from source; see above../scripts/build.sh(make build) stamps it into every quant it builds, too. The--chat-template-fileflag above is only needed for a GGUF that was not built or stamped that way — a quant pulled straight from upstream, for instance. To restamp one you already have:python3 scripts/strip_mtp.py IN.gguf OUT.gguf --chat-template chat_template.jinjaOn an already-MTP-clean input that rewrites the file purely to swap the template; tensor data is copied byte-for-byte either way, so there is no re-quantization.
Example (Ollama, OpenAI-compatible API)
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ignored")
resp = client.chat.completions.create(
model="janus",
messages=[
{"role": "user", "content": "Call get_weather for Tokyo. Respond ONLY with the tool call."}
],
tools=[{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}],
temperature=0.3,
)
print(resp.choices[0].message.tool_calls)
# [ToolCall(id='call_xxx', type='function',
# function=Function(name='get_weather', arguments='{"city":"Tokyo"}'))]
Tips
- Use direct prompts ("Call X for Y") rather than soft hints ("Use the tool"). The model thinks before committing to a call, and weak prompts can exhaust
num_predictinside the<think>block before the call is emitted. - Allow at least
num_predict: 1024(ormax_tokens: 1024) for tool-calling turns, more if the schemas are large. - The JSON-in-XML format is what Ollama's tool-call extractor understands, and the Go template pins it.
chat_template.jinjarenders the XML<function=…>form unless a replayed call carries string arguments, so the prompt format does change when you swap loaders. Client code should not have to, as long as the server returns a parsedtool_callsarray — verified on Ollama and on standalone llama-server (llama.cpp mastera2878d3and b10760).
Known limitations
- On the embedded-template path, a single tool call can come back twice. In one test Ollama 0.33.3, running the embedded template, returned a first-turn tool call twice. A separate raw generation showed the model drafting the call inside
<think>before emitting it once after</think>, so the parser most likely matched such a draft (inferred, not confirmed). It did not reproduce on standalone llama.cpp master (a2878d3, CPU): across both models, 12 first-turn calls (three prompts, with and withoutparallel_tool_calls) and two streamed runs each came back exactly once. Nor on b10760, the llama.cpp build Ollama 0.33.3 bundles and the one the duplicate came through: six more first-turn calls and a streamed run on this model each came back once. LM Studio's CPU engine (llama.cpp b10519) passed the same checks; the LM Studio app's own API layer is untested. Ollama's default path — the Go template, see Which template Ollama runs — returned one call in a comparable test; whether the prompt or the parser makes the difference was not isolated. If your client executes tools wherever the embedded template renders (llama.cpp, LM Studio, or Ollama withOLLAMA_GO_TEMPLATE=0), drop identical consecutive calls. - No mmproj in this release. The base Qwen3.8 supports image and video input via a separate
mmprojfile, which is not included here. Text-only inference works out of the box; multimodal inference requires fetchingQwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf(or equivalent) from upstream — run./scripts/fetch_vision.shand see Vision for the full path. - Quantization-induced quality loss. Q4_K_M is a strong general-purpose quant but does measurably degrade math and code accuracy compared to BF16. If you need maximum quality, run the upstream safetensors on a host with room for the full BF16 weights.
- No MTP head on the GGUF path. The base preserves the multi-token-prediction (NextN) block, but stock llama.cpp and Ollama can't load it, so the bundled quant is MTP-stripped (see Architecture). No speculative decoding here — use the upstream safetensors under vLLM / SGLang, or an unstripped quant from the source GGUF repo, if you need it.
- Dense, so the whole model is resident. There's no expert sparsity to hide behind: all 27B parameters are touched on every token, and the ~16.5 GiB weights-plus-compute footprint is a floor, not an average. Trim
num_ctxto fit a smaller host — there is no expert-offload trick to fall back on. - Thinking traces can loop. Like most reasoning-distilled models, Janus-27B occasionally gets stuck repeating itself inside
<think>tags. Mitigations: lower temperature to 0.4-0.6, raiserepeat_penaltyto 1.08, or set a<think>-token budget cap if your loader supports it. - Large tool-call arguments can be dropped. Ollama's JSON-in-XML tool format makes the model JSON-escape the entire arguments object inline; for a big/complex payload (e.g. a file's
contentin awrite_filecall) the model can fail to escape it, so the field arrivesundefinedand the call fails. Qwen's native<function=…><parameter=…>format (raw values, no escaping) was tested as a fix but parses unreliably through Ollama, so the template deliberately keeps JSON-in-XML. Mitigation: write large files in smaller pieces per call. - Uncensored base — not aligned with any specific safety policy. This is a personal repackage of an open-weight base whose refusal behavior has been abliterated away (the llmfan46 Heretic base). There is no RLHF refusal layer; the model will attempt most requests, so downstream safety is entirely the operator's responsibility.
- No formal evaluation in this card. The hardware table is fit estimates from the memory math — the measured throughput figures are 4.97 tok/s on CPU and a short partial-GPU-offload series on the same Ryzen AI Max+ 395, and the pre-rebase numbers were dropped rather than carried over. No task benchmarks are claimed either. If you produce real numbers (tok/s, MMLU, HumanEval, …) and want them included, file a PR.
Related models
| Model | Size | Notes |
|---|---|---|
| llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved | 27B dense | Immediate base. Uncensored Heretic (MPOA-style) abliteration of Qwen 3.8 27B, with the MTP head preserved; transformers-native safetensors. |
| llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-GGUF | 27B dense | Heretic GGUFs — BF16, Q3_K_L, Q3_K_M, Q4_K_M, Q4_K_S, Q5_K_M, Q5_K_S, Q6_K, Q8_0, plus the BF16 mmproj. MTP-preserved, so strip before loading on llama.cpp / Ollama; the bundled Q4_K_M is this quant, already stripped. |
| Qwen/Qwen3.8-27B | 27B dense | Upstream pre-Heretic base model. transformers-native multimodal weights. |
| FoolDev/Thanatos-27B-HERETIC | 27B dense | Sibling on the same Qwen 3.8 27B architecture, abliterated the other way — the ARA-based heretic-org/Qwen3.8-27B-heretic-ara. Same teacher (Fable 5), same dataset family. (The older FoolDev/Thanatos-27B and Thanatos-27B-Heretic slugs now 307 to this path.) |
| Crownelius/Crow-9B-HERETIC-4.6 | 9B dense | Heretic-flavored fine-tune on a smaller 9B Qwen base. Useful as a fast first-pass model when 27B is too heavy for the host. |
Janus vs Thanatos. After this rebase the two are the same model on paper: dense Qwen 3.8 27B, 64 layers, the same hybrid Gated-DeltaNet / Gated-Attention stack, the same 262,144 native window, the same Claude Fable 5 teacher slot and dataset family. The only real difference is which abliteration sits underneath — Janus on llmfan46's Heretic / MPOA-style, MTP-preserved base, Thanatos on heretic-org's ARA base; both bundles are MTP-stripped for the same llama.cpp / Ollama reason. Janus is not bigger, not a mixture-of-experts, and not architecturally distinct from its sibling; choose between them on how each abliteration behaves, not on capacity. (This repo used to ship a 35B-A3B MoE build, which is where the
Janus-35B-HERETICslug comes from; the model it names is now the dense 27B described above.)
Credits
- Immediate base: llmfan46/Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved — Heretic-style (MPOA, MTP-preserved) abliteration of Qwen 3.8 27B
- Upstream base: Qwen/Qwen3.8-27B (Alibaba)
- Reasoning teacher: Claude Fable 5 (Anthropic)
- Distillation lineage and dataset curation: Crownelius
License inherited from upstream: Apache-2.0.
- Downloads last month
- 421
4-bit
Model tree for FoolDev/Janus-35B-HERETIC
Base model
Qwen/Qwen3.8-27B
Install from pip and serve model
# Install vLLM from pip: pip install vllm# Start the vLLM server: vllm serve "FoolDev/Janus-35B-HERETIC"# Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FoolDev/Janus-35B-HERETIC", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'