How to use from
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
Quick Links
Janus-27B banner

License Base Model Architecture Quant Sibling

Buy me a coffee — support Janus-27B

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-Preserved converted to GGUF and MTP-stripped so stock llama.cpp and Ollama can load it. The Teacher: field above and the datasets: 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_relation is quantized for 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 and ollama 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-HERETIC serves it directly, and ollama create janus -f Modelfile works from a fresh clone.

It is llmfan46/…-MTP-Preserved-GGUF's Q4_K_M (sha256 97298d4b0f99a3f4c46b2dd013abd0ca1628d68be4c3960817b39998a60f0eaf) run through ./scripts/strip_mtp.py: the NextN block at index 64 is dropped, block_count 65 → 64, nextn_predict_layers removed, and every kept tensor copied byte-for-byte — no re-quantization. chat_template.jinja is 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 as qwen35 / 26.9B dense with tools and thinking; and a full tool-call round-trip on /v1/chat/completions, including the replay turn whose string arguments used to fail.

The repo previously shipped a 35B-A3B MoE quant, which is where the Janus-35B-HERETIC slug 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_interval 4, 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 no qwen38 arch 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 tag hf.co/FoolDev/Janus-35B-HERETIC, or run ollama cp hf.co/FoolDev/Janus-35B-HERETIC janus once to create the short tag.

On memory-tight hosts, cap num_ctx first. /v1/chat/completions (OpenAI-compat) has no num_ctx knob, 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_0 on the server brings it to ~26 GiB (see Hardware requirements). Either call /api/chat with "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 4096 and /save janus, and point clients at janus — 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_p does not survive the OpenAI-compatible endpoint. Ollama's /v1/chat/completions layer applies OpenAI's own default of top_p 1.0, overwriting the 0.95 baked into params / the Modelfile. Measured on this model: the same request logs top_p = 0.950 on /api/chat and top_p = 1.000 on /v1/chat/completions. Since the default profile also sets top_k 0 (disabled), a /v1 request samples with no truncation at all at temperature 1.0 — the "loop insurance" above is only in effect on the native API. If you need that guard on /v1, send top_p explicitly on every request, or bake min_p (e.g. PARAMETER min_p 0.05) into a local tag — min_p and top_k both pass through /v1 untouched, top_p does 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 (34 GiB); a 32 GB host needs OLLAMA_KV_CACHE_TYPE=q8_0 (26 GiB, tight) or 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 (26 GiB) is tight, num_ctx 65536 (19-21 GiB) is comfortable

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's preserve_thinking: true switches it back on for that request.
  • Ollama — edit the template. In the assistant branch of both the Modelfile and template (so make 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 $lastUserIdx loop 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.gguf has chat_template.jinja stamped 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 master a2878d3 and 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 into tool_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-file flag 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.jinja

On 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_predict inside the <think> block before the call is emitted.
  • Allow at least num_predict: 1024 (or max_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.jinja renders 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 parsed tool_calls array — verified on Ollama and on standalone llama-server (llama.cpp master a2878d3 and 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 without parallel_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 with OLLAMA_GO_TEMPLATE=0), drop identical consecutive calls.
  • No mmproj in this release. The base Qwen3.8 supports image and video input via a separate mmproj file, which is not included here. Text-only inference works out of the box; multimodal inference requires fetching Qwen3.8-27B-Ultra-Uncensored-Heretic-Native-MTP-Preserved-mmproj-BF16.gguf (or equivalent) from upstream — run ./scripts/fetch_vision.sh and 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_ctx to 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, raise repeat_penalty to 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 content in a write_file call) the model can fail to escape it, so the field arrives undefined and 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-HERETIC slug comes from; the model it names is now the dense 27B described above.)

Credits

License inherited from upstream: Apache-2.0.

Downloads last month
421
GGUF
Model size
27B params
Architecture
qwen35
Hardware compatibility
Log In to add your hardware

4-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for FoolDev/Janus-35B-HERETIC

Datasets used to train FoolDev/Janus-35B-HERETIC

Space using FoolDev/Janus-35B-HERETIC 1