Tell Zen one way, in Zen's names

The Zen page called zen6 a 27B dense model and led with no reason to
pick Zen; the models index listed Zen 7 as "upcoming" and HIP-0904 as
"dense, coder and ternary checkpoints"; examples called zen5 and one
called zen5-coder-32b-instruct, which the gateway does not serve.

Zen is now told as the gateway serves it: Zen 7 in research preview
with Request access, Zen 6 the new Zen architecture (zen6,
zen6-coder), Zen 5.8 the one before, Zen 5 earlier. It leads with its
two jobs, agentic coding on your own machine and marketing work, and
names Zoo Labs Foundation, a 501(c)(3) non-profit, as its maker.
Examples call zen6.

Upstream base models appear only in the Architecture value and the
License & attribution section, both data-upstream. check-zen reads
every Zen page in pre-build and fails the build on a name from
zen.upstream anywhere else.
This commit is contained in:
2026-09-29 21:36:37 -07:00
parent ad888ecc50
commit 8e7e92d634
34 changed files with 296 additions and 65 deletions
+8 -2
View File
@@ -137,9 +137,9 @@ zt-docs) predate the unified `content/docs/` model — migrate their content int
`content/docs/<section>/` (or a `hanzo-docs/<team>` submodule) then archive the
app.
## Two build guards, and why prose needs them
## Build guards, and why prose needs them
`scripts/pre-build.ts` ends with two checks that fail the build. Both exist for
`scripts/pre-build.ts` ends with checks that fail the build. The first two exist for
the same reason: a generated page cannot be wrong about the API, an authored one
can, and a reader cannot tell which kind of page they are on.
@@ -149,6 +149,12 @@ can, and a reader cannot tell which kind of page they are on.
and `api-keys.mdx` must teach every class the document carries. Both
directions, so renaming, adding or removing a key class in cloud stops the
build here instead of publishing a stale page.
- **`check-zen.ts`** — a Zen page (`models/index.mdx`, `models/zen*`) names no
upstream base model outside a `data-upstream` element. Two places carry one:
the Architecture value (the loader string from the weights' own config) and
the License & attribution section. The names live in `apps/docs/zen.upstream`
and only there; title and description are read too, since they become the
meta and OG tags.
The key classes come from `Document.keys` (`openapi-doc.ts`), read out of the
`/v1/keys` prose — cloud's own Go doc comments, lifted by zipdoc. `secretKey(doc)`
+1 -1
View File
@@ -18,7 +18,7 @@ const use = [
['Python', 'python', `# pip install hanzoai\nfrom hanzoai.cloud import AiApi, ApiClient, Configuration\n\nai = AiApi(ApiClient(Configuration()))\n\nprint(len(ai.get_models().data or []), "models")`],
['Go', 'go', `// go get github.com/hanzoai/go-sdk/v8\nimport hanzoai "github.com/hanzoai/go-sdk/v8"\n\nclient := hanzoai.NewAPIClient(hanzoai.NewConfiguration())\n\nmodels, _, err := client.AiAPI.GetModels(ctx).Execute()`],
['Rust', 'rust', `// cargo add hanzo-client\nuse hanzo_client::apis::{ai_api, configuration::Configuration};\n\nlet cfg = Configuration::new();\n\nlet models = ai_api::get_models(&cfg).await?;`],
['HTTP', 'bash', `curl https://api.hanzo.ai/v1/chat/completions \\\n -H "Authorization: Bearer $HANZO_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d '{"model":"zen5","messages":[{"role":"user","content":"Hello!"}]}'`],
['HTTP', 'bash', `curl https://api.hanzo.ai/v1/chat/completions \\\n -H "Authorization: Bearer $HANZO_API_KEY" \\\n -H "Content-Type: application/json" \\\n -d '{"model":"zen6","messages":[{"role":"user","content":"Hello!"}]}'`],
] as const;
function Group({ rows }: { rows: readonly (readonly [string, string, string])[] }) {
+4 -4
View File
@@ -102,9 +102,9 @@ const commands = [
];
const zen = [
{ name: 'zen6', spec: '27B dense, 1M context' },
{ name: 'zen6-coder', spec: 'Agentic code' },
{ name: 'zen6-flash', spec: 'Ternary vision' },
{ name: 'zen6', spec: 'New architecture' },
{ name: 'zen6-coder', spec: 'Local agentic code' },
{ name: 'zen5.8', spec: 'Previous generation' },
{ name: 'zen5', spec: 'Hosted' },
{ name: 'zen-embedding', spec: 'Retrieval' },
{ name: 'zen-guard', spec: 'Safety' },
@@ -381,7 +381,7 @@ export function Landing({ install, use }: { install: ReactNode; use: ReactNode }
</Text>
</XStack>
<Text fontSize={14} lineHeight={22} maxW={672} whiteSpace="normal" {...muted}>
The generative family: reasoning, code, vision, speech, embeddings and safety. Weights on Hugging Face; the same ids hosted on api.hanzo.ai, routed by Enso.
The generative family, chosen for two jobs: agentic coding that runs on your own machine, and marketing work — copy in your brand's voice and the images and speech beside it. Weights on Hugging Face; the same ids hosted on api.hanzo.ai, routed by Enso.
</Text>
<Grid columns={{ min: 130, max: 6 }} gap={12}>
{zen.map((m) => (
+5 -5
View File
@@ -38,14 +38,14 @@ curl https://api.hanzo.ai/v1/chat/completions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "zen5",
"model": "zen6",
"messages": [{"role": "user", "content": "Hello, Zen."}]
}'
```
```bash tab="CLI"
hanzo chat completions \
--model zen5 \
--model zen6 \
--messages '[{"role":"user","content":"Hello, Zen."}]'
```
@@ -55,7 +55,7 @@ import { Hanzo } from '@hanzo/ai'
const hanzo = new Hanzo({ secretKey: process.env.HANZO_API_KEY })
const completion = await hanzo.chat.completions.create({
model: 'zen5',
model: 'zen6',
messages: [{ role: 'user', content: 'Hello, Zen.' }],
})
console.log(completion.choices[0].message.content)
@@ -71,7 +71,7 @@ client = OpenAI(
)
response = client.chat.completions.create(
model="zen5",
model="zen6",
messages=[{"role": "user", "content": "Hello, Zen."}]
)
print(response.choices[0].message.content)
@@ -80,7 +80,7 @@ print(response.choices[0].message.content)
`/v1/chat/completions` takes and returns the chat-completions JSON shape, which
is why the Python tab is the `openai` client with its base URL moved: any client
already written against that shape works here unchanged. Model ids are not
portable across vendors, though — `zen5` and `enso` exist only here. [The
portable across vendors, though — `zen6` and `enso` exist only here. [The
SDKs](/docs/sdks) covers what each language ships and when to reach past the
chat route into the rest of `/v1`.
+1 -1
View File
@@ -7,7 +7,7 @@ icon: Rocket
One key authenticates every request. `sk-` keys resolve to a user and belong on a server; `pk-` keys resolve only to an organisation and are safe in a browser.
```bash
export HANZO_API_KEY=sk-... # platform.hanzo.ai
export HANZO_API_KEY=sk-... # console.hanzo.ai
hanzo auth login # or sign in through Hanzo IAM
```
@@ -14,7 +14,7 @@ from agno.agent import Agent
from agno.models.openai.like import OpenAILike
model = OpenAILike(
id="zen5",
id="zen6",
api_key="sk-...",
base_url="https://api.hanzo.ai/v1",
)
@@ -14,7 +14,7 @@ from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_core.models import ModelFamily
client = OpenAIChatCompletionClient(
model="zen5",
model="zen6",
base_url="https://api.hanzo.ai/v1",
api_key="sk-...",
model_info={
@@ -27,7 +27,7 @@ export class Researcher extends Agent {
this.ctx.waitUntil(
(async () => {
const stream = await client.chat.completions.create({
model: "zen5",
model: "zen6",
messages: [{ role: "user", content: await request.text() }],
stream: true,
});
@@ -13,7 +13,7 @@ pip install crewai
from crewai import LLM, Agent
llm = LLM(
model="openai/zen5",
model="openai/zen6",
base_url="https://api.hanzo.ai/v1",
api_key="sk-...",
)
@@ -13,7 +13,7 @@ pip install dspy
import dspy
lm = dspy.LM(
"openai/zen5",
"openai/zen6",
api_base="https://api.hanzo.ai/v1",
api_key="sk-...",
model_type="chat",
@@ -14,7 +14,7 @@ from google.adk.agents import LlmAgent
from google.adk.models.lite_llm import LiteLlm
model = LiteLlm(
model="openai/zen5",
model="openai/zen6",
api_base="https://api.hanzo.ai/v1",
api_key="sk-...",
)
@@ -35,7 +35,7 @@ Each page below says which one its snippet lands on.
curl -s https://api.hanzo.ai/v1/models | jq -r '.data[].id'
```
Pass the `id` through verbatim as the framework's model name — `zen5`, `claude-sonnet-4-6`, `gpt-5.5`. Every record carries `id`, `owned_by` and `premium`; `pricing` and `context_window` are on nearly all of them; `supports_tools` and `supports_vision` on a handful. An absent field is undeclared, not false.
Pass the `id` through verbatim as the framework's model name — `zen6`, `claude-sonnet-4-6`, `gpt-5.5`. Every record carries `id`, `owned_by` and `premium`; `pricing` and `context_window` are on nearly all of them; `supports_tools` and `supports_vision` on a handful. An absent field is undeclared, not false.
Some frameworks want those same facts restated in their own constructor — AutoGen's `model_info`, LlamaIndex's `is_chat_model` — and the page says so where it applies.
@@ -14,7 +14,7 @@ from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
model = ChatOpenAI(
model="zen5",
model="zen6",
base_url="https://api.hanzo.ai/v1",
api_key="sk-...",
)
@@ -13,7 +13,7 @@ pip install llama-index-llms-openai-like
from llama_index.llms.openai_like import OpenAILike
llm = OpenAILike(
model="zen5",
model="zen6",
api_base="https://api.hanzo.ai/v1",
api_key="sk-...",
context_window=1000000,
@@ -17,7 +17,7 @@ export const agent = new Agent({
name: "Researcher",
instructions: "Answer precisely.",
model: {
id: "hanzo/zen5",
id: "hanzo/zen6",
url: "https://api.hanzo.ai/v1",
apiKey: process.env.HANZO_API_KEY,
},
@@ -15,7 +15,7 @@ from agents import Agent, Runner, AsyncOpenAI, OpenAIChatCompletionsModel, set_t
set_tracing_disabled(disabled=True)
client = AsyncOpenAI(api_key="sk-...", base_url="https://api.hanzo.ai/v1")
model = OpenAIChatCompletionsModel(model="zen5", openai_client=client)
model = OpenAIChatCompletionsModel(model="zen6", openai_client=client)
agent = Agent(name="Assistant", instructions="Answer precisely.", model=model)
result = Runner.run_sync(agent, "Hello")
@@ -15,7 +15,7 @@ from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.openai import OpenAIProvider
model = OpenAIChatModel(
'zen5',
'zen6',
provider=OpenAIProvider(base_url='https://api.hanzo.ai/v1', api_key='sk-...'),
)
@@ -16,7 +16,7 @@ using Microsoft.SemanticKernel;
IKernelBuilder builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(
modelId: "zen5",
modelId: "zen6",
apiKey: "sk-...",
endpoint: new Uri("https://api.hanzo.ai/v1")
);
@@ -37,7 +37,7 @@ from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
kernel = Kernel()
kernel.add_service(OpenAIChatCompletion(
ai_model_id="zen5",
ai_model_id="zen6",
async_client=AsyncOpenAI(base_url="https://api.hanzo.ai/v1", api_key="sk-..."),
))
```
@@ -14,7 +14,7 @@ import os
from smolagents import OpenAIModel, CodeAgent
model = OpenAIModel(
model_id="zen5",
model_id="zen6",
api_base="https://api.hanzo.ai/v1",
api_key=os.environ["HANZO_API_KEY"],
)
@@ -20,7 +20,7 @@ const hanzo = createOpenAICompatible({
});
const { text } = await generateText({
model: hanzo('zen5'),
model: hanzo('zen6'),
prompt: 'Name the three laws of thermodynamics.',
});
```
@@ -135,7 +135,7 @@ Hanzo. The call is the trace, and the second command is a read, not a write:
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"model":"zen5","messages":[{"role":"user","content":"how do I rotate a key?"}]}'
-d '{"model":"zen6","messages":[{"role":"user","content":"how do I rotate a key?"}]}'
curl -sS "https://api.hanzo.ai/v1/o11y/llm/traces?limit=20" \
-H "Authorization: Bearer $HANZO_API_KEY"
@@ -39,7 +39,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/account/keys \
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
# 3. Evaluator's benchmark mode, as an admission rather than a local run
curl -sS -X POST https://api.hanzo.ai/v1/benchmark/runs \
@@ -50,7 +50,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/benchmark/runs \
Step 2 is the request your code already sends. NIM and the NVIDIA API are
OpenAI-shaped, so the body is unchanged and the edit is the base URL, the key and
the model name; `GET /v1/models` publishes the names, `zen5` among them. Step 3
the model name; `GET /v1/models` publishes the names, `zen6` among them. Step 3
answers 202 with a receipt, and the numbers appear on
`GET /v1/benchmark/leaderboard` as the harness completes them — the same
benchmarks `nel eval run --bench` would run on your machine, run for you.
@@ -74,7 +74,7 @@ Five tables, one per NeMo concern.
| NeMo | Hanzo |
|---|---|
| Nemotron, called through `integrate.api.nvidia.com/v1` | `zen5`, `zen5-pro`, `zen5-coder`, `zen5-flash`, `zen5-mini` at `POST /v1/chat/completions` — 14 Zen models among the 432 that `GET /v1/models` lists |
| Nemotron, called through `integrate.api.nvidia.com/v1` | `zen6` and `zen6-coder`, with the `zen5.8` and `zen5` lines beside them, at `POST /v1/chat/completions`; `GET /v1/models` lists every Zen id |
| NIM container serving `/v1/chat/completions` on your GPU | The same address, served. No container to pull; the model is a name in the catalogue |
| NIM embedding and reranker microservices | `POST /v1/embeddings` with `zen-embedding`, `POST /v1/rerank` with `zen-rerank` |
| Nemotron content-safety model | `zen-guard`, a 128K-context safety classifier, called like any other model |
@@ -177,7 +177,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
curl -sS "https://api.hanzo.ai/v1/o11y/llm/traces?limit=20" \
-H "Authorization: Bearer $HANZO_API_KEY"
@@ -30,7 +30,7 @@ curl -sS -X POST https://api.hanzo.ai/v1/account/keys \
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
# 3. the catalogue the model name in step 2 comes from
curl -sS https://api.hanzo.ai/v1/models
@@ -175,7 +175,7 @@ Plain inference is the base URL and nothing else:
curl -sS -X POST https://api.hanzo.ai/v1/chat/completions \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"model":"zen5","messages":[{"role":"user","content":"summarise Q3"}]}'
-d '{"model":"zen6","messages":[{"role":"user","content":"summarise Q3"}]}'
```
The run call answers the run — id, status, model, `output`, duration, error —
+1 -1
View File
@@ -182,7 +182,7 @@ languages. See [Engineering Philosophy](/docs/architecture/philosophy) for the *
- [SDKs](/docs/sdks) — Python, TypeScript, Go, Rust and more, all derived from one contract
- [API reference](/docs/openapi) — every endpoint, generated from its spec
- [ZAP protocol](/docs/zap) — Zero-Copy App Proto, the wire the Go and Rust halves speak
- [Zen models](https://zenlm.org) — frontier open-weight models, 4B edge to 1T+ reasoning
- [Zen models](https://zenlm.org) — open-weight models for agentic coding that runs locally and for marketing work
- [Architecture](/docs/architecture) — one binary, one contract, and why
## Resources
+4 -4
View File
@@ -11,7 +11,7 @@ ones you can download, and which ids the gateway serves right now.**
| Family | Role | Weights | Reach it at | Status |
|---|---|---|---|---|
| **[Zen](/docs/models/zen)** | generates: reasoning, code, language, vision, speech, embeddings | open, on [Hugging Face](https://huggingface.co/zenlm) | `zen*` ids on `/v1/chat/completions` | shipped |
| **[Zen](/docs/models/zen)** | generates: agentic coding that runs locally, marketing copy and assets; also vision, speech, embeddings | open, on [Hugging Face](https://huggingface.co/zenlm) | `zen*` ids on `/v1/chat/completions` | shipped |
| **[Enso](/docs/models/enso)** | routes and orchestrates: picks the model, context and tools per request | router code open ([hanzoai/engine](https://github.com/hanzoai/engine)); family SKUs hosted | `model: "auto"` and `enso-*` ids | shipped |
| **[Kai](/docs/models/kai)** | decides: typed, calibrated answers to bounded questions | hosted, not published; the baseline it starts from is open ([hanzoai/kai-1-multilingual](https://huggingface.co/hanzoai/kai-1-multilingual)) | `model: "kai"` on [`POST /v1/decisions`](/docs/decisions) | live: stage a7, $0.021 per million input tokens |
| **Policy** | governs: deterministic allow / ask / deny | — | your rules, in every Decision Program | a part of Hanzo Decision, not a model |
@@ -27,8 +27,8 @@ action, and a model can make a verdict stricter, never looser.
| Name | What it is | Status |
|---|---|---|
| **Zen7** | the next Zen generation; succeeds Satori | upcoming — no release, no weights |
| **Satori** | a video-generation line, never trained | retiring; replaced by Zen7 |
| **Zen 7** | the next Zen generation; succeeds Satori | research preview — no weights, no id to call · [Request access](https://hanzo.ai/research-access) |
| **Satori** | a video-generation line, never trained | retiring; replaced by Zen 7 |
| **Jin** | a multimodal model specified in [HIP-0003](https://hips.hanzo.ai/docs/hip-0003-jin-multimodal-ai-architecture) | not built; no weights |
| **Enso Diffusion** | a sparse mixture-of-experts diffusion transformer, forked from DiT-MoE: [zenlm/enso](https://github.com/zenlm/enso) | research code, no released weights |
| **Enso Browser** | a Firefox-based desktop browser | not released |
@@ -74,7 +74,7 @@ covers what happens when the balance runs out.
|---|---|---|
| [HIP-0511](https://hips.hanzo.ai/docs/hip-0511-model-families) | Model families: every line, its HIP, its API and where it runs | Living |
| [HIP-0039](https://hips.hanzo.ai/docs/hip-0039-zen-model-architecture) | Zen model architecture | Final |
| [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) | Zen6: dense, coder and ternary checkpoints | Final |
| [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) | The `zenlm/zen6*` repositories on Hugging Face: what each holds | Final |
| [HIP-0510](https://hips.hanzo.ai/docs/hip-0510-enso-learned-router) | Enso: learned per-request routing | Final |
| [HIP-1332](https://hips.hanzo.ai/docs/hip-1332-kai-the-decision-model) | Kai: the decision model and the decision plane | Draft |
| [HIP-0003](https://hips.hanzo.ai/docs/hip-0003-jin-multimodal-ai-architecture) | Jin: a multimodal model that was not built | Draft |
+66 -16
View File
@@ -1,15 +1,30 @@
---
title: Zen
description: "Zen generates: open-weight models for reasoning, code, vision, speech, embeddings and safety. Download them, or call them hosted."
description: "Zen is the open-weight model family from Zoo Labs Foundation, for two jobs: agentic coding that runs on your own machine, and marketing work — campaign copy in your brand's voice and the images and speech that go with it."
icon: Sparkle
---
**After this page you can call a Zen model on the API, find its weights, and
know which generation is current.**
**After this page you know which Zen model does which job, how to call it,
where its weights are, and which generation is current.**
Zen is the generative family: open questions — reason, write, code, explain —
answered in text, images or audio. Weights are published under
[huggingface.co/zenlm](https://huggingface.co/zenlm); each model card states its
Zen is the open-weight generative family of Zen LM, from [Zoo Labs Foundation](https://zoo.ngo), a
501(c)(3) non-profit, and served first-party on `api.hanzo.ai`. It is chosen for two jobs.
**Agentic coding that runs locally.** `zen6-coder` is a mixture of 512 experts
that sends each token through 10 of them, reads 262,144 tokens natively, and
takes tool definitions in its chat template, so it can drive a coding loop over
a whole repository on your own machine. A multi-token-prediction drafter ships
beside it for faster decoding. The weights are GGUF for llama.cpp, 97.8 GB with
the drafter; the model card reports prefill on an AMD Strix Halo machine with
128 GB of unified memory. Hosted, the same id takes a 1,000,000-token context.
**Marketing work.** [`POST /v1/content/generate`](/docs/openapi/content/post-content-generate) drafts
campaigns and social posts from a brief, with the brand-voice guidance you pass
and the Zen model you name, and files each one in the CMS as a draft. `zen-vl`
reads images, documents and charts. The Zen 3 weights make the images
(`zen3-image`) and speech (`zen3-tts`) that go with the copy.
Weights are published under [huggingface.co/zenlm](https://huggingface.co/zenlm); each model card states its
license, base and serving instructions. The same ids answer hosted on
`api.hanzo.ai`.
@@ -17,17 +32,31 @@ license, base and serving instructions. The same ids answer hosted on
| Generation | Models | Where | Status |
|---|---|---|---|
| **Zen7** | — | — | upcoming; replaces Satori, which is retiring |
| **Zen6** | [`zen6`](https://huggingface.co/zenlm/zen6) — 27B dense, NVFP4, 1M-token context (YaRN) · [`zen6-coder`](https://huggingface.co/zenlm/zen6-coder) — mixture-of-experts for agentic coding · [`zen6-flash`](https://huggingface.co/zenlm/zen6-flash) — 27B ternary vision-language model for one GPU or a laptop | weights on Hugging Face; `zen6` and `zen6-coder` hosted | shipped |
| **Zen5** | `zen5`, `zen5-coder`, `zen5-pro`, `zen5-flash`, `zen5-mini`, `zen5.8`, `zen5.8-coder` | hosted; GGUF builds on Hugging Face (`zen5-gguf`, `zen5-coder-gguf`, …) | shipped |
| **Zen3** | speech (`zen3-asr`, `zen3-tts`), image (`zen3-image`), `zen3-vl`, `zen3-omni`, `zen3-nano`, `zen3-guard` | weights on Hugging Face | shipped |
| **Zen 7** | — | no weights; no id to call | research preview · [Request access](https://hanzo.ai/research-access) · succeeds Satori |
| **Zen 6** | `zen6`, `zen6-coder` — the new Zen architecture | hosted; weights at [`zenlm/zen6-coder`](https://huggingface.co/zenlm/zen6-coder) | available now |
| **Zen 5.8** | `zen5.8`, `zen5.8-coder`, `zen5.8-evo`, `zen5.8-spark` | hosted | previous generation |
| **Zen 5** | `zen5`, `zen5-coder`, `zen5-flash`, `zen5-mini`, `zen5-pro`, `zen5-evo`, `zen5-spark` | hosted; GGUF builds on Hugging Face (`zen5-gguf`, `zen5-coder-gguf`, …) | earlier |
| **Zen 3** | speech (`zen3-asr`, `zen3-tts`), image (`zen3-image`), `zen3-vl`, `zen3-omni`, `zen3-nano`, `zen3-guard` | weights on Hugging Face | shipped |
Task lines sit beside the generations: `zen-embedding` and `zen-reranker`
(0.6B, 4B, 8B) for retrieval, `zen-guard` for safety, `zen-vl`
for vision. [`zen-router`](https://huggingface.co/zenlm/zen-router) is a
for vision. `zen-free` and `hanzo/zen` answer on the gateway too.
[`zen-router`](https://huggingface.co/zenlm/zen-router) is a
classifier, not a generator; the gateway also accepts its name as an alias for
[`auto`](/docs/models/enso).
## Zen 6 weights
| | [`zenlm/zen6-coder`](https://huggingface.co/zenlm/zen6-coder) |
|---|---|
| Format | GGUF, IQ4_XS in three files, with a multi-token-prediction drafter |
| Size | 97.8 GB with the drafter |
| Experts | 512, 10 active per token |
| Layers | 48 |
| Context | 262,144 tokens |
| Tools | tool definitions in the chat template |
| Architecture | <span data-upstream>`qwen4exp`</span> (GGUF `general.architecture`) |
## Call one
```bash
@@ -54,12 +83,16 @@ that command disagree, believe the command.
## Run one yourself
```bash
hf download zenlm/zen6 --local-dir zen6
hf download zenlm/zen6-coder --local-dir zen6-coder
```
Each card carries the serving command its model was built for: an SGLang launch
for `zen6`, llama.cpp for `zen6-coder`, `zen6-flash` and the GGUF builds. A server that speaks
`/v1/chat/completions` takes the same request as above with its own base URL.
Each card carries the serving command its model was built for: llama.cpp for
`zen6-coder` and the GGUF builds. A server that speaks `/v1/chat/completions`
takes the same request as above with its own base URL.
Two more repositories carry the Zen 6 name, [`zenlm/zen6`](https://huggingface.co/zenlm/zen6)
and [`zenlm/zen6-flash`](https://huggingface.co/zenlm/zen6-flash); each card
says what it holds.
## Where Zen sits
@@ -69,4 +102,21 @@ questions a typed answer settles — that is [Kai](/docs/models/kai). An agent
built on all three spends generative compute only where generation is the work.
Specifications: [HIP-0039](https://hips.hanzo.ai/docs/hip-0039-zen-model-architecture) for the
family, [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) for Zen6.
family; [HIP-0904](https://hips.hanzo.ai/docs/hip-0904-zen6) records what each `zenlm/zen6*`
repository on Hugging Face holds.
<section data-upstream>
## License & attribution
Each repository's own license governs its files; the model card names it.
- `zenlm/zen6-coder`: `qwen-community-1.0`, as its card declares. Built with
Qwen3.8-Flash-Next by the Qwen team (`Qwen/Qwen3.8-Flash-Next`); GGUF
quantization by Unsloth (`unsloth/Qwen3.8-Flash-Next-GGUF`).
- `zenlm/zen6`: Apache-2.0. Base models, as its card declares:
`RadixArk/Qwen3.8-27B-NVFP4` and `incoai/Qwen3.8-27B-DFlash2`.
- `zenlm/zen6-flash`: Apache-2.0. Base models, as its card declares:
`prism-ml/Ternary-Bonsai-2-27B-gguf` and `ProCreations/Ternary-Bonsai-2-27B-DFlash2`.
</section>
+1 -1
View File
@@ -43,7 +43,7 @@ number that changes every run. PoAI removes the non-determinism:
### Roadmap
- **Production-size models.** The precompile runs a small reference model today;
a Qwen3-0.6B / zen-nano port is in progress. The model line is small,
a zen-nano port is in progress. The model line is small,
fully-verifiable models plus sampled verification of large ones.
- **Cryptographic proofs.** zkML proofs and TEE confidential execution are
designed and stubbed for a later release. Today's guarantee is determinism you
+3 -3
View File
@@ -102,7 +102,7 @@ await ast.recordInteraction({
role: 'assistant',
content: 'Quantum computing uses quantum bits (qubits) that can be 0, 1, or both at the same time...',
},
model: 'zen5-coder-32b-instruct',
model: 'zen6',
tokens: { input: 42, output: 156 },
latencyMs: 1240,
},
@@ -224,7 +224,7 @@ app.post('/v1/chat', async (req, res) => {
const { messages } = req.body;
const completion = await llm.chat.completions.create({
model: 'zen5-coder-32b-instruct',
model: 'zen6',
messages,
});
@@ -284,7 +284,7 @@ AST stores all records in a normalized JSON format compatible with common fine-t
},
"output": {
"message": {"role": "assistant", "content": "..."},
"model": "zen5-coder-32b-instruct",
"model": "zen6",
"tokens": {"input": 42, "output": 156},
"latency_ms": 1240
},
+1 -1
View File
@@ -140,7 +140,7 @@ import { Hanzo } from '@hanzo/ai'
const hanzo = new Hanzo({ secretKey: process.env.HANZO_API_KEY })
const answer = await hanzo.chat.completions.create({
model: 'zen5',
model: 'zen6',
messages: [{ role: 'user', content: 'Explain quantum computing' }],
})
```
+1 -1
View File
@@ -69,7 +69,7 @@ client = OpenAI(
)
answer = client.chat.completions.create(
model="zen5",
model="zen6",
messages=[{"role": "user", "content": "Explain quantum computing"}],
)
print(answer.choices[0].message.content)
+2 -2
View File
@@ -40,7 +40,7 @@ import { Hanzo } from '@hanzo/ai'
const hanzo = new Hanzo({ secretKey: process.env.HANZO_API_KEY })
const answer = await hanzo.chat.completions.create({
model: 'zen5',
model: 'zen6',
messages: [{ role: 'user', content: 'Explain quantum computing' }],
})
@@ -63,7 +63,7 @@ chunks:
```typescript
const stream = await hanzo.chat.completions.create({
model: 'zen5-coder',
model: 'zen6',
messages: [{ role: 'user', content: 'Write a haiku about AI' }],
stream: true,
})
+135
View File
@@ -0,0 +1,135 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Nodes, Root } from 'mdast';
import { remark } from 'remark';
import remarkGfm from 'remark-gfm';
import remarkMdx from 'remark-mdx';
import YAML from 'yaml';
// Zen is told in Zen's names.
//
// A Zen page reads as Zen from its title to its last table. The upstream models
// some Zen weights are built from are named in two places only, and both carry
// `data-upstream` so this check can step over them:
//
// Architecture the loader string from the weights' own config.json or
// GGUF header, which a developer passes verbatim
// License & attribution the fine print at the bottom of the page
//
// Everything else a reader meets is read here: the title and description (the
// page's meta and OG tags), headings, prose, tables, code, image alt text and
// the string props of components. A name from zen.upstream in any of it fails
// the build. The list lives in that one file.
const APP = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const MODELS = path.join(APP, 'content/docs/models');
export const NAMES = path.join(APP, 'zen.upstream');
/** The Zen pages: the families overview, which carries Zen's generations, and every zen page. */
export const isZen = (rel: string) => rel === 'index.mdx' || rel.startsWith('zen');
/** The names in zen.upstream: one per line, `#` comments and blank lines ignored. */
export function loadNames(file = NAMES): string[] {
const names = fs
.readFileSync(file, 'utf8')
.split('\n')
.map((l) => l.replace(/#.*$/, '').trim())
.filter(Boolean);
if (!names.length) throw new Error(`${file} names nothing, so the check would pass anything`);
return names;
}
/** Any of `names` as a whole word, in any case: no letter directly before or after it. */
export function matcher(names: string[]): RegExp {
const alt = names.map((n) => n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
return new RegExp(`(?<![a-z])(?:${alt})(?![a-z])`, 'gi');
}
type Jsx = Extract<Nodes, { type: 'mdxJsxFlowElement' | 'mdxJsxTextElement' }>;
const isJsx = (n: Nodes): n is Jsx =>
n.type === 'mdxJsxFlowElement' || n.type === 'mdxJsxTextElement';
/** Every string of an MDX page a reader reads, leaving out `data-upstream` elements. */
export function readThrough(src: string): string[] {
const out: string[] = [];
let body = src;
const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/.exec(src);
if (fm) {
const meta = (YAML.parse(fm[1]) ?? {}) as Record<string, unknown>;
for (const key of ['title', 'description']) {
if (typeof meta[key] === 'string') out.push(meta[key]);
}
body = src.slice(fm[0].length);
}
const visit = (node: Nodes) => {
if (isJsx(node)) {
if (node.attributes.some((a) => a.type === 'mdxJsxAttribute' && a.name === 'data-upstream'))
return;
for (const a of node.attributes) {
if (a.type === 'mdxJsxAttribute' && typeof a.value === 'string') out.push(a.value);
}
}
// Imports, exports and `{/* comments */}` are the page's source, never rendered.
const unread =
node.type === 'mdxjsEsm' ||
((node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') &&
/^\s*\/\*[\s\S]*\*\/\s*$/.test(node.value));
if ('value' in node && typeof node.value === 'string' && !unread) out.push(node.value);
if ('alt' in node && node.alt) out.push(node.alt);
if ('title' in node && node.title) out.push(node.title);
if ('children' in node) for (const child of node.children) visit(child as Nodes);
};
visit(remark().use(remarkMdx).use(remarkGfm).parse(body) as Root);
return out;
}
export interface ZenCheck {
/** The Zen pages read, relative to content/docs/models. */
pages: string[];
/** Page, the name found, and the text it was found in. */
found: Array<[string, string, string]>;
}
export function checkZen(): ZenCheck {
const re = matcher(loadNames());
const pages = fs
.readdirSync(MODELS, { recursive: true, encoding: 'utf8' })
.filter((rel) => rel.endsWith('.mdx') && isZen(rel))
.sort();
// A check over no pages passes everything: the section moved, not the story.
if (!pages.length) throw new Error(`no Zen pages under ${MODELS}`);
const found: ZenCheck['found'] = [];
for (const rel of pages) {
for (const text of readThrough(fs.readFileSync(path.join(MODELS, rel), 'utf8'))) {
for (const m of text.matchAll(re)) {
const at = m.index ?? 0;
found.push([
rel,
m[0],
text.slice(Math.max(0, at - 40), at + m[0].length + 40).replace(/\s+/g, ' '),
]);
}
}
}
return { pages, found };
}
/** Report every upstream name a Zen page says outside `data-upstream`. */
export function report(found: ZenCheck['found']): void {
for (const [page, name, text] of found)
console.error(` models/${page}: "${name}" in …${text}…`);
}
if (import.meta.main) {
const { pages, found } = checkZen();
if (found.length) {
console.error(`[zen] FAIL — ${found.length} upstream name(s) outside data-upstream:`);
report(found);
process.exit(1);
}
console.log(
`[zen] ${pages.length} Zen pages read; no name from zen.upstream outside data-upstream`,
);
}
+11
View File
@@ -13,6 +13,7 @@ import { checkCapabilities, report as reportCapabilities } from './check-capabil
import { checkRoutes, report as reportRoutes } from './check-routes';
import { checkEndpoints, report } from './check-endpoints';
import { checkKeys, report as reportKeys } from './check-keys';
import { checkZen, report as reportZen } from './check-zen';
async function main() {
// The document first, then its projections: the reference (one page per
@@ -129,6 +130,16 @@ async function main() {
`[keys] ${keys.checked} credential literals checked against ` +
keys.keys.map((k) => k.prefix).join(' / '),
);
// A Zen page tells Zen's story in Zen's names: an upstream model's name may
// stand only in a `data-upstream` element — the Architecture value and the
// License & attribution section. zen.upstream holds the names.
const zen = checkZen();
if (zen.found.length) {
reportZen(zen.found);
throw new Error(`${zen.found.length} upstream model name(s) in the read-through of a Zen page`);
}
console.log(`[zen] ${zen.pages.length} Zen pages read, no upstream name outside data-upstream`);
}
await main().catch((e) => {
+29
View File
@@ -0,0 +1,29 @@
# The upstream names a Zen page does not tell Zen's story with. Read by
# scripts/check-zen.ts, which runs in pre-build and fails the build on a hit.
#
# One name per line; `#` starts a comment. Case is ignored and a name matches as
# a whole word — no letter directly before or after it — so `Qwen` also catches
# Qwen3, Qwen3.5, qwen4exp and Qwen3_5ForConditionalGeneration.
#
# A Zen page says these names in two places only, and marks both `data-upstream`:
# the Architecture value (the loader string from the weights' own config, which a
# developer has to pass verbatim) and the License & attribution section at the
# bottom. Everything else on the page — title, description, headings, prose,
# tables, code, alt text — says Zen.
#
# The list starts from the base models the zenlm cards on Hugging Face declare
# (`base_model`), by the name a reader would meet them under. A new one goes
# here, and nowhere else.
Qwen
QwenLM
Flash-Next
Nemotron
Bonsai
DeepSeek
MiniMax
FLUX
Wan
TRELLIS
YuE
Granite
SSD-1B