Cookbook Migrate Model
Convert one legacy cookbook page to the config-driven format, faithfully. The
legacy page — its generator widget and its measured benchmark blocks — is the
single source of truth. You are transcribing it into the new data model,
not improving it.
Reuses the cookbook-add-model skill's assets (read them on demand):
../cookbook-add-model/templates/config.jsx.tmpl, page.mdx.tmpl, benchmarks.jsx.tmpl
../cookbook-add-model/references/authoring-reference.md (config/cells/playground contract)
../cookbook-add-model/references/mintlify-authoring.md (MDX rules)
Migration-specific references in this skill:
- references/dimension-mapping.md — legacy-control → new-dimension mapping rules, command rewrite table, per-family strategy sets, and the Qwen3.5 pilot as a worked example (PR #27848).
The round's per-model inventory (scope, batch order, quirks, measured-data
survey) is tracked by the migration maintainer outside the repo — expect it in
your dispatch prompt, or ask for it.
Hard rules (non-negotiable)
- Never modernize. Env vars, flags, TP values, docker tags, version strings
are copied verbatim from the legacy page — even when today's defaults differ
(e.g. a flag whose behavior has since become the default; keep it anyway). The recipe
that was verified is the recipe as written. Allowed normalizations are ONLY
the five alias rewrites in dimension-mapping.md §2 (
launch_server→sglang serve, --model→--model-path, --tp-size→--tp, abbreviated
--speculative-algo→--speculative-algorithm,
--expert-parallel-size→--ep). Accuracy-degrading flags
(--kv-cache-dtype fp8_e4m3, W4A4-style runtime quant) follow a
deterministic rule — enforced in migration, no asking: offered as a
legacy selectable option → never select it (cells mirror the
accuracy-safe side), and the option survives as a Playground axis —
an existing one where it fits, else add one via a separate prior engine
PR (rule 4); a legacy choice never degrades to a tips mention. Baked
into the recipe's default/unconditional command → keep it verbatim
(the recipe was measured with it, and fp8 KV halves KV memory —
stripping could OOM it). See dimension-mapping.md §2 caveats.
- Never invent versions or numbers. Benchmark numbers only from the
legacy page's measured blocks, and a result migrates ONLY when its
sglang_version is a reproducible anchor — the bar is reproducibility,
not "must be a release":
- ✅ release tag/version (
v0.5.9 / 0.5.9), commit hash, OR — for
Day-0 support (the enabling PR isn't merged and no release is cut
yet) — a specific PR (PR #27944) or commit you can gh pr checkout
/ git checkout <sha>. Commit is most precise; a PR pin is fine for day-0.
- ❌ a moving ref —
"main branch", "main (2026-06-11)", open-ended
"0.5.8+" — is NOT reproducible: drop the WHOLE result (speed AND
accuracy), not just speed. Keep benchmarkCommands so ⚡Reproduce still
guides re-measurement against a pinned build.
Never inherit cross-model numbers — measurements the legacy page
attributes to a different model (e.g. a K2.6 page carrying K2.5-measured
speed) are dropped regardless of version. When kept, sglang_version is the
legacy page's string verbatim. Docker tags only the ones the legacy page
pinned (unmapped hw falls back to :dev).
- Verified policy (strictest tier).
verified: true ONLY when (a) the
legacy page has concrete measured data for that exact 5-dim combo AND
(b) the cell's flags equal the deployment command used for that measurement
— modulo {{HOST_IP}}/{{PORT}}, the five alias rewrites, and parser
flags: --reasoning-parser/--tool-call-parser are stripped from every
cell (Playground-only feature; when the measured run had them on, say so in
the benchmarks file header). When the measured command diverges from the
generator default, the verified cell follows the measured command; the
generator default stays as the sibling strategy/cell or a tips note. Everything else is unverified (yellow) —
including combos that look memory-infeasible; keep them verbatim and list
them in the PR body for the re-verification track.
- Engines are read-only.
_deployment.jsx / _playground.jsx must not
change in a migration PR. Model-specific features are config DATA consumed
by generic axis handlers (MegaMoE precedent), so they need NO engine change.
A titled single-select that strips a flag family — KV Cache DType
(--kv-cache-dtype), mamba (--mamba-radix-cache-strategy), … — is already
covered by the merged generic flagSelects axis: declare it in the
config (a list of { id, title, stripPrefixes, options }; see the Qwen3.5
mamba example), no engine PR. Only a genuinely new control shape that
flagSelects can't express would need a one-time generic primitive (never a
model-named handler) on a separate prior PR (engine-axis.md).
github.cookbookModel must be set (<hf-org>/<page-slug>, e.g.
qwen/qwen3.5) and the block never pruned — without it Submit ↗ mislabels
as deepseek-v4. The issue template itself needs NO edits (free-form input).
- Strategy tiers are signal-driven. A cell goes under
low-latency /
high-throughput ONLY on a signal present in the legacy source (an
explicit performance toggle, a named recipe, or prose stating the
operating point); no signal → balanced. Never derive a slant from
your own hardware intuition — re-tiering on measured evidence is the
hardware owner's follow-up PR, not part of a migration
(dimension-mapping.md §4).
Workflow (one model = one PR)
1. Inventory the legacy assets
- Read the legacy generator (
docs/src/snippets/autoregressive/<slug>-deployment.jsx)
end-to-end: every option dimension (radio vs checkbox vs dynamic), every
gate/SUPPORT matrix, the full emitted command per reachable combo (env
prefixes, # Error pseudo-commands included).
- Read the legacy MDX: §2 install docker tags →
dockerImages (pinned, not
upgraded); §3.2 tips → new §2; §4 invocation examples → new §3 (keep real
Output Examples verbatim); §5 benchmark blocks → transcribe each measured
block: deploy command used, bench command (dataset/isl/osl/num-prompts/
concurrency), P50 (median) TTFT/TPOT, output tok/s, hardware, version string.
- Inbound-anchor sweep:
grep -rn "<PageName>" docs/ --include='*.mdx' —
find links/#fragments into this page (mint broken-links does NOT check
fragments). Fix referrers or add <a id="old-anchor" /> shims in the same PR.
- Check the maintainer-provided inventory notes for this model's known quirks —
but treat them (and the §4 family table) as a survey snapshot: re-verify
every dimension against the live legacy files before mapping. Pages keep
receiving updates (precedent: Kimi-K2.6's live generator has a speculative
toggle the 2026-06-10 survey notes lack).
2. Design the 5-dim mapping
Apply references/dimension-mapping.md. Key
decision — which legacy toggle becomes the strategies dimension: a toggle
that changes other parts of the command (TP, mem) must (the Playground
can't do coupled changes), and so does a toggle the legacy page itself labels
with operating-point words — e.g. a dpattention radio whose options are
subtitled "Low Latency" / "High Throughput" (GLM-5.1 / Kimi-K2.6 pattern) —
even when its flags are uncoupled (--dp N --enable-dp-attention is a pure
flag add). Any other toggle that only adds/removes its own flags becomes a
Playground axis with the flags baked into cells when the legacy default was
ON — EXCEPT parsers:
--reasoning-parser/--tool-call-parser are NEVER baked into cells, they are
Playground-only (DSv4 convention). Every legacy control survives as an
interactive control — a dimension or a Playground axis, never a tips-only
mention — and a model-specific control is config data, not engine code
(MegaMoE W4A4 is all DSv4 config on the existing moe axis). It's pure
config whenever it fits an existing axis's data schema. A titled
single-select that strips a flag family (Nemotron3's "KV Cache DType",
mamba --mamba-radix-cache-strategy, …) fits the merged generic flagSelects
axis — so it too is config-only (declare a flagSelects list). Only a control
whose shape flagSelects still can't express would need a ONE-TIME generic
primitive (never a model-named handler) on a separate PRIOR engine PR, keeping
the migration PR data-only (hard rule 4, engine-axis.md). The strategy count follows the page's
operating points: one recipe → a single balanced; two → low-latency +
high-throughput; three → the full trio (the ideal). The tiers apply per
(hw × variant × quant) combination — a single-recipe combination on a
multi-strategy page parks under its semantically honest tier (no
latency/throughput slant → balanced; the page's list is the union). When the
legacy toggle is MTP / speculative decoding, the direction is a deterministic
default — apply without asking: MTP on → low-latency, MTP off →
high-throughput (reversed only with maintainer confirmation). Tier
placement is signal-driven (hard rule 6). Never invent a recipe just to fill
strategy chips (see dimension-mapping.md §4). Record the outcome as a
strategy mapping table for the PR body — one row per group of
combinations sharing the same legacy signal (e.g. "all GPU combos: MTP
toggle → low-latency / high-throughput"; "xeon: (none) → balanced"), with a
one-line rationale each; don't enumerate 60 identical rows. The table is what
hardware owners sign off on at review.
3. Generate the config (codegen, then audit)
- For >~30 cells, port the legacy
generateCommand() into a throwaway Node
script that enumerates combos and emits the cells:[...] literal (output
must stay a pure literal — Mintlify forbids runtime spreads/calls). Apply the
verified-cell override in the script. See the pilot scripts embedded in the
worked example of dimension-mapping.md §5.
- Independent equivalence audit (required): extract the ORIGINAL generator
from git (
git show main:<path> — NOT HEAD:, the migration branch deletes
the file, see dimension-mapping.md §5 item 7), stub React hooks, run it for
every combo, and diff token-by-token against the new cells. Expected deltas
only: the appended --host {{HOST_IP}}/--port {{PORT}}, the
engine-injected multi-node trio, the §2 alias rewrites (the entrypoint
rewrite doesn't appear in cell tokens — cells hold flags only; the audit
script normalizes it on the legacy side), and the intentional verified-cell
override. Paste the PASS count + the audit script in the PR body
(collapsed <details>).
- Hand-author the non-cells fields per authoring-reference.md. Structural
self-checks: every cell resolves a
modelNames key; no --nnodes/--node-rank/ --dist-init-addr/--host/--port literals; every {{KEY}} declared; every
supportedHardware id has ≥1 cell.
4. Benchmarks file
One entry per measured block only (cells without entries already render
"pending" — bare {match} stubs are unnecessary). tokens_per_sec_per_gpu =
total (in+out) tok/s/GPU = output tok/s ÷ (tp × nnodes) × (isl+osl)/osl — stored directly (the card shows it as-is). TTFT/TPOT
take the P50 (median) rows; set config.latencyPercentile (default "P50"; use
"Mean" only for legacy Mean-recorded data — temporary, being migrated to P50; an
entry-level latencyPercentile overrides the page value per cell).
Put the workload's
num_prompts into workload. config.accuracyLabels is required whenever
the benchmarks carry accuracy data — the engine ships no default eval set
(#27842), so missing labels means the accuracy rows silently don't render;
extra context (sample counts, suites that don't fit) goes in the entry's
notes. Zero-measured-data pages: skip the file and the benchmarks prop
entirely, but keep benchmarkCommands so ⚡Reproduce still guides users.
5. Rewrite the MDX
From page.mdx.tmpl: keep the original title (nav identity), write a fresh
SEO description (top-level — delete any legacy metatags.description), no
tag: NEW (a migration is not a launch), no mode:. Install accordion
carries the legacy install content + pinned images. Keep the template's
DSv4-style strategy bullets — serving semantics first (single-user chat /
typical multi-user / batch throughput), trimmed to the strategies the page
ships, plus at most a one-line note on what each strategy changes on this
model; do NOT rewrite them as toggle-/migration-centric explanations.
Legacy §5 benchmark prose is deleted (numbers → benchmark card, commands →
⚡Reproduce); legacy prose deploy commands are deleted (doc↔config parity —
fold their unique flags into §2 tips). Invocation examples + real outputs carry
over verbatim, but wrapped in Accordions — §3 commands and outputs are
collapsible (required, DeepSeek-V4 pattern): code in an
<Accordion title="… (Python)">, output in a following
<Accordion title="Example Output">; legacy pages kept them inline.
6. Delete the legacy generator
Remove docs/src/snippets/autoregressive/<slug>-deployment.jsx and its
import. grep -rn "<slug>-deployment" docs/ must return nothing (config
provenance comments must not name the deleted path). Site wiring needs no
changes: docs.json path/title unchanged, vendor card + logo already exist.
7. Validate
grep -rn '__[A-Z_]*__' on the new files (no template tokens).
cd docs && mint validate && mint broken-links (pre-existing breaks on
main are not yours — say so in the PR).
mint dev browser smoke: initial selection = the verified cell (first in
cells[]) with green badge; multi-node cells show the injected trio +
header; AMD cells show env prefixes; Docker mode wraps with the pinned image
and passes cell env as --env; condition-hidden combos grey out; benchmark
card values; NO parser flags in any Deploy command; Playground parser
toggles ADD the parser flags (green additions) while spec toggles strike
the baked spec flags (red); Submit ↗ prefills this model. Probe pitfall: drive at most
ONE programmatic click per evaluation and wait for React to settle —
multiple clicks in one synchronous script batch and read stale DOM.
- Token-level audit from step 3 passes.
8. PR + review
One PR per model. PR body: migration framing, verified policy applied, the
strategy mapping table (step 2), the audit PASS count + script, any
inherited-infeasible combos flagged for re-verification. Then run /cookbook-review-pr <N> and fix findings.
FYI: docs previews only build for in-repo (sgl-project/sglang) branches —
a fork-headed PR is perfectly fine but renders no preview; a maintainer can
re-push the branch in-repo if a preview is wanted for review.
9. Keep this skill current
Any new convention, engine behavior, or pitfall you discover while migrating
(naming decisions, audit-script gotchas, review-rule conflicts, …) MUST be fed
back into this skill — same PR if it's skill-file-only, or an immediate
follow-up commit on the skill's branch/PR. The next agent runs on what's
written here, not on your session's context.
1---2name: cookbook-migrate-model3description: Migrate a legacy-template SGLang cookbook page (monolithic per-model generator under docs/src/snippets/autoregressive/) onto the config-driven template (shared _deployment.jsx / _playground.jsx engines + per-model config). Use when asked to migrate, convert, or port an existing cookbook page — NOT for brand-new models (use cookbook-add-model for those). Run with /cookbook-migrate-model <Model page name, e.g. GLM-5.1>.4---5
6# Cookbook Migrate Model
7
8Convert one legacy cookbook page to the config-driven format, faithfully. The
9legacy page — its generator widget and its measured benchmark blocks — is the
10**single source of truth**. You are transcribing it into the new data model,
11not improving it.
12
13Reuses the `cookbook-add-model` skill's assets (read them on demand):
14- `../cookbook-add-model/templates/config.jsx.tmpl`, `page.mdx.tmpl`, `benchmarks.jsx.tmpl`
15- `../cookbook-add-model/references/authoring-reference.md` (config/cells/playground contract)
16- `../cookbook-add-model/references/mintlify-authoring.md` (MDX rules)
17
18Migration-specific references in this skill:
19- [references/dimension-mapping.md](references/dimension-mapping.md) — legacy-control → new-dimension mapping rules, command rewrite table, per-family strategy sets, and the Qwen3.5 pilot as a worked example (PR #27848).
20
21The round's per-model inventory (scope, batch order, quirks, measured-data
22survey) is tracked by the migration maintainer outside the repo — expect it in
23your dispatch prompt, or ask for it.
24
25## Hard rules (non-negotiable)
26
271. **Never modernize.** Env vars, flags, TP values, docker tags, version strings
28 are copied verbatim from the legacy page — even when today's defaults differ
29 (e.g. a flag whose behavior has since become the default; keep it anyway). The recipe
30 that was verified is the recipe as written. Allowed normalizations are ONLY
31 the five alias rewrites in dimension-mapping.md §2 (`launch_server`→`sglang
32 serve`, `--model`→`--model-path`, `--tp-size`→`--tp`, abbreviated
33 `--speculative-algo`→`--speculative-algorithm`,
34 `--expert-parallel-size`→`--ep`). **Accuracy-degrading flags**
35 (`--kv-cache-dtype fp8_e4m3`, W4A4-style runtime quant) follow a
36 deterministic rule — enforced in migration, no asking: offered as a
37 legacy **selectable option** → never select it (cells mirror the
38 accuracy-safe side), and the option **survives as a Playground axis** —
39 an existing one where it fits, else add one via a separate prior engine
40 PR (rule 4); a legacy choice never degrades to a tips mention. Baked
41 into the recipe's **default/unconditional command** → keep it verbatim
42 (the recipe was measured with it, and fp8 KV halves KV memory —
43 stripping could OOM it). See dimension-mapping.md §2 caveats.
442. **Never invent versions or numbers.** Benchmark numbers only from the
45 legacy page's measured blocks, and a result migrates ONLY when its
46 `sglang_version` is a **reproducible anchor** — the bar is reproducibility,
47 not "must be a release":
48 - ✅ release tag/version (`v0.5.9` / `0.5.9`), commit hash, OR — for
49 **Day-0 support** (the enabling PR isn't merged and no release is cut
50 yet) — a specific **PR (`PR #27944`) or commit** you can `gh pr checkout`
51 / `git checkout <sha>`. Commit is most precise; a PR pin is fine for day-0.
52 - ❌ a moving ref — `"main branch"`, `"main (2026-06-11)"`, open-ended
53 `"0.5.8+"` — is NOT reproducible: **drop the WHOLE result (speed AND
54 accuracy)**, not just speed. Keep `benchmarkCommands` so ⚡Reproduce still
55 guides re-measurement against a pinned build.
56 **Never inherit cross-model numbers** — measurements the legacy page
57 attributes to a *different model* (e.g. a K2.6 page carrying K2.5-measured
58 speed) are dropped regardless of version. When kept, `sglang_version` is the
59 legacy page's string verbatim. Docker tags only the ones the legacy page
60 pinned (unmapped hw falls back to `:dev`).
613. **Verified policy (strictest tier).** `verified: true` ONLY when (a) the
62 legacy page has concrete measured data for that exact 5-dim combo AND
63 (b) the cell's flags equal the deployment command used for that measurement
64 — modulo `{{HOST_IP}}`/`{{PORT}}`, the five alias rewrites, and **parser
65 flags**: `--reasoning-parser`/`--tool-call-parser` are stripped from every
66 cell (Playground-only feature; when the measured run had them on, say so in
67 the benchmarks file header). When the measured command diverges from the
68 generator default, **the verified cell follows the measured command**; the
69 generator default stays as the sibling strategy/cell or a tips note. Everything else is unverified (yellow) —
70 including combos that look memory-infeasible; keep them verbatim and list
71 them in the PR body for the re-verification track.
724. **Engines are read-only.** `_deployment.jsx` / `_playground.jsx` must not
73 change in a migration PR. Model-specific features are config DATA consumed
74 by generic axis handlers (MegaMoE precedent), so they need NO engine change.
75 A **titled single-select that strips a flag family** — KV Cache DType
76 (`--kv-cache-dtype`), mamba (`--mamba-radix-cache-strategy`), … — is already
77 covered by the merged generic **`flagSelects`** axis: declare it in the
78 config (a list of `{ id, title, stripPrefixes, options }`; see the Qwen3.5
79 mamba example), **no engine PR**. Only a genuinely new control *shape* that
80 `flagSelects` can't express would need a one-time generic primitive (never a
81 model-named handler) on a separate prior PR (engine-axis.md).
825. **`github.cookbookModel` must be set** (`<hf-org>/<page-slug>`, e.g.
83 `qwen/qwen3.5`) and the block never pruned — without it Submit ↗ mislabels
84 as deepseek-v4. The issue template itself needs NO edits (free-form input).
856. **Strategy tiers are signal-driven.** A cell goes under `low-latency` /
86 `high-throughput` ONLY on a signal present in the legacy source (an
87 explicit performance toggle, a named recipe, or prose stating the
88 operating point); **no signal → `balanced`**. Never derive a slant from
89 your own hardware intuition — re-tiering on measured evidence is the
90 hardware owner's follow-up PR, not part of a migration
91 (dimension-mapping.md §4).
92
93## Workflow (one model = one PR)
94
95### 1. Inventory the legacy assets
96- Read the legacy generator (`docs/src/snippets/autoregressive/<slug>-deployment.jsx`)
97 end-to-end: every option dimension (radio vs checkbox vs dynamic), every
98 gate/SUPPORT matrix, the full emitted command per reachable combo (env
99 prefixes, `# Error` pseudo-commands included).
100- Read the legacy MDX: §2 install docker tags → `dockerImages` (pinned, not
101 upgraded); §3.2 tips → new §2; §4 invocation examples → new §3 (keep real
102 Output Examples verbatim); §5 benchmark blocks → transcribe each measured
103 block: deploy command used, bench command (dataset/isl/osl/num-prompts/
104 concurrency), P50 (median) TTFT/TPOT, output tok/s, hardware, version string.
105- Inbound-anchor sweep: `grep -rn "<PageName>" docs/ --include='*.mdx'` —
106 find links/`#fragments` into this page (`mint broken-links` does NOT check
107 fragments). Fix referrers or add `<a id="old-anchor" />` shims in the same PR.
108- Check the maintainer-provided inventory notes for this model's known quirks —
109 but treat them (and the §4 family table) as a **survey snapshot**: re-verify
110 every dimension against the live legacy files before mapping. Pages keep
111 receiving updates (precedent: Kimi-K2.6's live generator has a speculative
112 toggle the 2026-06-10 survey notes lack).
113
114### 2. Design the 5-dim mapping
115Apply [references/dimension-mapping.md](references/dimension-mapping.md). Key
116decision — which legacy toggle becomes the `strategies` dimension: a toggle
117that **changes other parts of the command** (TP, mem) must (the Playground
118can't do coupled changes), and so does a toggle the legacy page itself labels
119with operating-point words — e.g. a `dpattention` radio whose options are
120subtitled "Low Latency" / "High Throughput" (GLM-5.1 / Kimi-K2.6 pattern) —
121even when its flags are uncoupled (`--dp N --enable-dp-attention` is a pure
122flag add). Any other toggle that only adds/removes its own flags becomes a
123Playground axis with the flags baked into cells when the legacy default was
124ON — EXCEPT parsers:
125`--reasoning-parser`/`--tool-call-parser` are NEVER baked into cells, they are
126Playground-only (DSv4 convention). **Every legacy control survives as an
127interactive control** — a dimension or a Playground axis, never a tips-only
128mention — and a model-specific control is **config data, not engine code**
129(MegaMoE W4A4 is all DSv4 config on the existing `moe` axis). It's pure
130config whenever it fits an existing axis's data schema. A **titled
131single-select that strips a flag family** (Nemotron3's "KV Cache DType",
132mamba `--mamba-radix-cache-strategy`, …) fits the merged generic **`flagSelects`**
133axis — so it too is config-only (declare a `flagSelects` list). Only a control
134whose *shape* `flagSelects` still can't express would need a ONE-TIME generic
135primitive (never a model-named handler) on a separate PRIOR engine PR, keeping
136the migration PR data-only (hard rule 4, engine-axis.md). The strategy count follows the page's
137operating points: **one recipe → a single `balanced`; two → `low-latency` +
138`high-throughput`; three → the full trio (the ideal)**. The tiers apply per
139(hw × variant × quant) combination — a single-recipe combination on a
140multi-strategy page parks under its semantically honest tier (no
141latency/throughput slant → `balanced`; the page's list is the union). When the
142legacy toggle is MTP / speculative decoding, the direction is a deterministic
143default — apply without asking: **MTP on → `low-latency`, MTP off →
144`high-throughput`** (reversed only with maintainer confirmation). Tier
145placement is signal-driven (hard rule 6). Never invent a recipe just to fill
146strategy chips (see dimension-mapping.md §4). Record the outcome as a
147**strategy mapping table** for the PR body — one row per group of
148combinations sharing the same legacy signal (e.g. "all GPU combos: MTP
149toggle → low-latency / high-throughput"; "xeon: (none) → balanced"), with a
150one-line rationale each; don't enumerate 60 identical rows. The table is what
151hardware owners sign off on at review.
152
153### 3. Generate the config (codegen, then audit)
154- For >~30 cells, port the legacy `generateCommand()` into a throwaway Node
155 script that enumerates combos and emits the `cells:[...]` literal (output
156 must stay a pure literal — Mintlify forbids runtime spreads/calls). Apply the
157 verified-cell override in the script. See the pilot scripts embedded in the
158 worked example of dimension-mapping.md §5.
159- **Independent equivalence audit (required):** extract the ORIGINAL generator
160 from git (`git show main:<path>` — NOT `HEAD:`, the migration branch deletes
161 the file, see dimension-mapping.md §5 item 7), stub React hooks, run it for
162 every combo, and diff token-by-token against the new cells. Expected deltas
163 only: the appended `--host {{HOST_IP}}`/`--port {{PORT}}`, the
164 engine-injected multi-node trio, the §2 alias rewrites (the entrypoint
165 rewrite doesn't appear in cell tokens — cells hold flags only; the audit
166 script normalizes it on the legacy side), and the intentional verified-cell
167 override. Paste the PASS count + the audit script in the PR body
168 (collapsed `<details>`).
169- Hand-author the non-cells fields per authoring-reference.md. Structural
170 self-checks: every cell resolves a `modelNames` key; no `--nnodes/--node-rank/
171 --dist-init-addr/--host/--port` literals; every `{{KEY}}` declared; every
172 `supportedHardware` id has ≥1 cell.
173
174### 4. Benchmarks file
175One entry per measured block only (cells without entries already render
176"pending" — bare `{match}` stubs are unnecessary). `tokens_per_sec_per_gpu` =
177total (in+out) tok/s/GPU = `output tok/s ÷ (tp × nnodes) ×
178(isl+osl)/osl` — stored directly (the card shows it as-is). TTFT/TPOT
179take the P50 (median) rows; set `config.latencyPercentile` (default `"P50"`; use
180`"Mean"` only for legacy Mean-recorded data — temporary, being migrated to P50; an
181entry-level `latencyPercentile` overrides the page value per cell).
182Put the workload's
183`num_prompts` into `workload`. **`config.accuracyLabels` is required whenever
184the benchmarks carry accuracy data** — the engine ships no default eval set
185(#27842), so missing labels means the accuracy rows silently don't render;
186extra context (sample counts, suites that don't fit) goes in the entry's
187`notes`. Zero-measured-data pages: skip the file and the `benchmarks` prop
188entirely, but keep `benchmarkCommands` so ⚡Reproduce still guides users.
189
190### 5. Rewrite the MDX
191From `page.mdx.tmpl`: keep the original `title` (nav identity), write a fresh
192SEO `description` (top-level — delete any legacy `metatags.description`), **no
193`tag: NEW`** (a migration is not a launch), **no `mode:`**. Install accordion
194carries the legacy install content + pinned images. Keep the template's
195DSv4-style strategy bullets — serving semantics first (single-user chat /
196typical multi-user / batch throughput), trimmed to the strategies the page
197ships, plus at most a one-line note on what each strategy changes on this
198model; do NOT rewrite them as toggle-/migration-centric explanations.
199Legacy §5 benchmark prose is deleted (numbers → benchmark card, commands →
200⚡Reproduce); legacy prose deploy commands are deleted (doc↔config parity —
201fold their unique flags into §2 tips). Invocation examples + real outputs carry
202over verbatim, but **wrapped in Accordions** — §3 commands and outputs are
203collapsible (required, DeepSeek-V4 pattern): code in an
204`<Accordion title="… (Python)">`, output in a following
205`<Accordion title="Example Output">`; legacy pages kept them inline.
206
207### 6. Delete the legacy generator
208Remove `docs/src/snippets/autoregressive/<slug>-deployment.jsx` and its
209import. `grep -rn "<slug>-deployment" docs/` must return nothing (config
210provenance comments must not name the deleted path). Site wiring needs **no
211changes**: docs.json path/title unchanged, vendor card + logo already exist.
212
213### 7. Validate
214- `grep -rn '__[A-Z_]*__'` on the new files (no template tokens).
215- `cd docs && mint validate && mint broken-links` (pre-existing breaks on
216 main are not yours — say so in the PR).
217- `mint dev` browser smoke: initial selection = the verified cell (first in
218 `cells[]`) with green badge; multi-node cells show the injected trio +
219 header; AMD cells show env prefixes; Docker mode wraps with the pinned image
220 and passes cell env as `--env`; condition-hidden combos grey out; benchmark
221 card values; NO parser flags in any Deploy command; Playground parser
222 toggles ADD the parser flags (green additions) while spec toggles strike
223 the baked spec flags (red); Submit ↗ prefills this model. **Probe pitfall:** drive at most
224 ONE programmatic click per evaluation and wait for React to settle —
225 multiple clicks in one synchronous script batch and read stale DOM.
226- Token-level audit from step 3 passes.
227
228### 8. PR + review
229One PR per model. PR body: migration framing, verified policy applied, the
230strategy mapping table (step 2), the audit PASS count + script, any
231inherited-infeasible combos flagged for re-verification. Then run `/cookbook-review-pr <N>` and fix findings.
232FYI: docs previews only build for in-repo (`sgl-project/sglang`) branches —
233a fork-headed PR is perfectly fine but renders no preview; a maintainer can
234re-push the branch in-repo if a preview is wanted for review.
235
236### 9. Keep this skill current
237Any new convention, engine behavior, or pitfall you discover while migrating
238(naming decisions, audit-script gotchas, review-rule conflicts, …) MUST be fed
239back into this skill — same PR if it's skill-file-only, or an immediate
240follow-up commit on the skill's branch/PR. The next agent runs on what's
241written here, not on your session's context.