strata generate --pack DIR --tokens "1,2,3" [options]

  --pack DIR           the pack directory (default pack/full)
  --tokens LIST        the prompt as comma-separated token IDS (required)
  --tokens-file PATH   pretokenized prompt, commas or whitespace (alternative to --tokens)
  --gpu LIST           run on these GPUs, comma-separated nvidia-smi/PCI indices (default: every
                       visible one); sets CUDA_VISIBLE_DEVICES/CUDA_DEVICE_ORDER inside the engine,
                       so a caller never has to export environment variables
  --ple-gguf PATH      required PLE table (original second GGUF shard); with --native, the model's
                       shard that holds per_layer_token_embd.weight when not given
  --no-ple             explicit diagnostic ablation of the PLE layer
  --ple-io direct|mmap|ram  n-gram table reads (plan v0.3 P2). direct (default): unbuffered SSD
                       reads, the table never enters RAM or the file cache; mmap: A/B arm;
                       ram: the whole table locked in RAM at start (VirtualLock on Windows,
                       mlock elsewhere), so no SSD read sits on the prompt or token path
  --ple-row-cache N    bounded cache of fetched rows, 90 B each (default 1048576; 0 = off)
  --ple-inflight N     outstanding SSD reads (default 256)
  --ple-delay-us U     fault injection: each row read completes no earlier than U us
  --ple-sync-submit    A/B arm: submit table reads on the token thread (default: an I/O thread)
  --kv fp16|int8       KV storage (plan v0.3 P7): int8 codes + fp16 scale per 64 values, half the
                       VRAM; default fp16 until gate G-C accepts int8
  --kv q4_0            4-bit K/V after a Hadamard rotation (PR #21): half of int8's memory,
                       slightly lower precision (see bench/results/2026-09-27-kv-q4)
  --kv k8v4            hybrid: INT8 K (exact attention scores) + rotated Q4_0 V, 816 B/cell
                       (vs int8's 1,056); streams with --kv-resident too
  --kv-resident N      KV streaming: keep N cells of each QSA layer in VRAM (min 20480) and the
                       whole K/V in pinned RAM; the freed VRAM goes to expert slots. 0 (default):
                       all of it in VRAM. A context of N cells or fewer is not streamed
  --kv-grow            the K/V takes VRAM only for the cells the requests reach and the expert
                       cache holds the rest, giving slots back as the context grows (one GPU, with
                       --expert-profile; STRATA_KV_GROW=1/0 also). Default: the whole --max-context
                       allocated at start
  --stream-token       enqueue token work on the session stream (experimental)
  --check-logits       copy and check all logits in the stream-token path
  --gr-fp32-activations  experimental CUDA-oracle GR activation precision
  --gr-native-mmvf      experimental pinned GR norm/projections; implies FP32 activations
  --native-bf16         experimental CUDA-oracle SSM/router/indexer BF16 projections
  --native-bf16-extra   experimental CUDA-oracle PLE/shared gate BF16 projections
  --native-ple-key      experimental native PLE key; requires --native-dense-gguf
  --native-moe-combine  experimental pinned CUDA routed/shared combination
  --native-gdn          experimental pinned CUDA GDN norms/gates/recurrence
  --native-flash-attn-short  diagnostic pinned vector attention; --max-context <=256
  --native-qsa-indexer  experimental pinned indexer key cache and pooling
  --native-qsa          experimental pinned QSA normalization and output gate
  --native-rope         experimental pinned text-only CUDA rotary arithmetic
  --native-ple-postops  experimental pinned PLE postprojection arithmetic
  --native-router       experimental pinned CUDA 512-expert top-10 routing
  --cpu-oracle-q8-0     experimental pinned CPU expert quantization and dot reduction
  --native SHARD1      every full-context native path at once (plan v0.3 P1): stream-token,
                       GR MMVF, BF16, head, dense + PLE key, MoE combine, GDN, router, QSA,
                       indexer, RoPE, PLE postops, and the CPU q8_0 contract unless the
                       expert cache is on. Individual --native-* flags stay for A/B.
  --native-head-gguf PATH  native Q5_K head from model shard 1; requires --stream-token
  --embd-gguf PATH     the token embedding from this GGUF instead of --native's (tools/embd_bf16_pack.py:
                       BF16 as the checkpoint ships it; mapped host memory, no VRAM)
  --native-dense-gguf PATH native GDN/QSA/shared projections; repeat for each source model shard
  --expert-cache-cpu-order  experimental GPU expert reduction matching CPU order
  --max-new N          tokens to generate (default 16)
  --max-context N      KV/state capacity (default 4096)
  --rope-scaling T     extend the context past the trained one: none, linear
                       (position interpolation) or yarn - llama.cpp's types and names.
                       Default: the model file's rope keys, else none. Fixed at startup:
                       K in the cache is post-RoPE, so one run one scaling
  --rope-scale F       the extension factor for linear/yarn (default: the model file's
                       factor, else 1 = off)
  --rope-freq-base N   the raw ggml knobs: the frequency base (0 = the model's 1e7) and
  --rope-freq-scale F  the angle shrink (0 = 1/--rope-scale)
  --yarn-orig-ctx N    the trained context the correction targets (0 = 262144)
  --yarn-ext-factor F --yarn-attn-factor F --yarn-beta-fast F --yarn-beta-slow F
                       YaRN's knobs; defaults: -1 (auto: 1 for yarn), 1, 32, 1
  --greedy             argmax (the default)
  --seed S             enable sampling with this Philox seed
  --top-k N --top-p F --temperature F
  --dump-logits PATH   write one line of raw logits per position
  --logits-stride N    store every Nth row plus final input (default 1); N>1 requires --max-new 1
  --dump-residual PATH write the final R (hc x n_embd, f32) for head bisection
  --dump-layers PATH   write R after EVERY layer, per position: the C1 bisection ladder
  --dump-halves PATH   write both halves' block_out and inject per layer: the half bisection
  --dump-routing PATH  write the routed expert ids and weights per layer per position (P0.S8)
  --no-capture         run the layers directly instead of replaying graphs
  --shared-late        A/B: shared expert after the CPU pool (default: overlapped with it)
  --keep-canonical     A/B: also load canonical copies of natively served tensors (more VRAM)
  --vision             --serve takes images too (GENI requests; embeddings from strata-vision)
  --prompt-cache N     --serve: keep N conversation checkpoints between requests (default 6, ~118 MB
                       of RAM each; 0 = read every prompt from the start)
  --conversation-cache-mib N  --serve: RAM budget for parked conversations (default: sized from the free RAM, up to 8192; 0 = off)
  --conversation-cache-slots N  --serve: at most N parked conversations (default 4)
  --conversation-cache-min-free-mib N  --serve: RAM floor (under MemAvailable, the cgroup limits and
                       --memory-limit-mib) when parking, saving or restoring a session (default 2560)
  --memory-limit-mib N  --serve: the total RAM (MiB) this engine's container or cgroup may use, when
                       the container cannot see its real limit (also STRATA_MEMORY_LIMIT_MIB; the flag
                       wins; 0 = none). Parking and session save/restore keep their floor under it
  --conversation-cache-min-tokens N  --serve: park only conversations of at least N tokens, so
                       short side requests do not take the slots a long one needs (default 0 = park any)
  --conversation-cache-park-gain N  --serve: park only after the conversation advanced N tokens past
                       the copy it would supersede, so a turn that grew by a few hundred tokens does not
                       write a whole snapshot that the next turn drops (default 0 = park every turn)
  --session-min-free-mib N  --serve: disk space a SAVE must leave free (default 4096; 0 = no check)
  --session-save-reclaim  --serve: reclaim unpinned host caches if SAVE needs RAM (opt-in)
  --vram-elastic       --serve (#533, opt-in, NVIDIA): the expert cache in segments (--vram-segment-mib,
                       default 512), so the command `VRAM <reserve_mib>` (the server's POST /v1/vram) can
                       give VRAM back to other programs between requests and take it back later
  --batch N / --slots N  --serve (opt-in): up to N requests decode together in batch slots (2..8
                       normally; --batch-mtp waves more through eight-row windows),
                       each slot with its own session (VRAM like the main one); docs/BATCHING.md
  --batch-mtp          --batch (opt-in, needs --mtp and --spec): each slot also verifies one MTP proposal per
                       window (STRATA_BATCH_MTP=1 does the same); works on one GPU and on a layer split (the
                       slot drafters sit on the last stage's GPU; not with --batch-groups); needs VRAM per slot
  --batch-groups G     --batch with a layer split: the slots in G groups pipelined through the GPUs
  --pipeline-windows N --serve with a layer split on two GPUs (on by default for 2+ stages on AMD gfx12;
                       STRATA_PIPELINE_AUTO=0 or N=0 turns it off): one conversation's verify windows
                       with the GPUs overlapped - 1 = the prompt's short reads, 2 = decode as well
                       (stage 0 runs the next window while stage 1 verifies this one); docs/MULTI_GPU.md
  --trim-stage-weights an explicit --layer-split: each GPU loads only its own layers' dense weights
  --prompt-cache-every N  --serve: also checkpoint every N fresh prompt tokens (default 16384, 0 = off)
  --prompt-cache-tail  --serve, single GPU: one extra checkpoint near the prompt's end, at an existing
                       chunk boundary (default off; requires --prompt-cache and --prompt-cache-every > 0)
  --prompt-cache-spread  --serve: keep the checkpoints spread back from the conversation's end (dense
                       near it, thinner further back) instead of the most recently used: a client that
                       rewrites its history N tokens back reads about N again, not the whole conversation
  --turn-token ID      --serve: the token that opens a chat turn (default 248045, <|im_start|>)
  --tail-role-token ID --serve: a turn of this role right before the last turn is left out of
                       the conversation checkpoint (a trailing effort turn; default -1 = off)
  --short-read N       --serve: read at most N fresh text tokens through the decode windows instead
                       of the batched prompt path (default 64, 0 = off)
  --prefill-head-alias --serve: unload the native output head while each fresh prompt is read,
                       then release prompt buffers and reload it before decode
  --suffix-draft N     prompt lookup: draft from an earlier repeat of the last N+ tokens of context
                       when it pays (default 3; 0 = MTP only)
  --mtp-max-t M        cap the MTP's windows at M tokens (0 = --spec; longer ones come from suffixes)
  --lookup-max-t N     prompt-lookup windows up to N (<= 16) tokens (default 12 on one GPU in the 8-row CUDA build, not Metal; 0 = off);
                       copy-heavy edits gain, each extra window size costs a graph (~20-35 MiB of VRAM)
  --lookup-sizes A,B   the lookup window sizes past the MTP's (default: MTP+1, MTP+2 and N)
  --spec N             the MTP drafter's verify window: how many tokens it proposes per check (setup
                       writes 4; --suffix-draft lets it grow by 2, up to 8, where a repeat is likely)
  --spec-min-p P       how sure the draft layer must be to extend a verify window by another guess
                       (setup writes 0.5; --calibrate measures it on this PC, see docs/DETAILS.md)
  --lookup-chain K     opt-in: after the MTP's drafts, add up to K prompt-lookup drafts that continue
                       them (the window grows to at most 8; default 0 = off)
  --lookup-chain-min M  the shortest context match --lookup-chain extends on (default 3)
  --mtp-hnorm pooled|stream  the draft layer's hidden-input norm: one RMS over all four streams
                       (default) or one per stream (llama.cpp's MTP graph)
  --mtp-q4 all|proj|head  opt-in: the draft layer's projections and/or draft head as 4-bit copies
  --mtp-draft-vocab FILE  opt-in: the draft head's token subset (default <mtp>/draft_vocab.bin)
  --draft mtp|dflash2  the draft source (default mtp); dflash2 needs --draft-model PACK (tools/dflash2_pack.py)
                       and loads no MTP layer (--draft-fallback mtp keeps it as the fallback) (opt-in, Flash-Next, CUDA / HIP)
  --draft-fallback mtp|none  with --draft dflash2 (default none): none = the MTP layer is not loaded at all, DFlash2 is the only drafter and a DFlash2 that cannot start is an error;
                       mtp = load both, the MTP drafts if DFlash2 cannot start (--draft auto always loads both)
                       (the MTP layer's ~0.9 GiB of VRAM goes to the expert cache; --mtp DIR is still needed for DIR/draft_vocab.bin)
  --draft-conf P       with --draft dflash2: end the window where the product of the selector's probabilities falls below P (default 0 = --spec-min-p)
  --draft auto         (serve) both drafters stay current; a request picks one: draft=mtp|dflash2, else --draft-rule df2|mtp|learn;
                       MTP requests use --draft-mtp-spec N (default 4) and --draft-mtp-min-p P
  --draft-cap N        the widest verify window with --draft dflash2 (default by card: 5 on Strix Halo / iGPU, --spec as given elsewhere)
  --control-vector-scaled FILE:SCALE[,...]  a control vector GGUF on the residual stream (llama.cpp's
                       format; --control-vector FILE = scale 1).  --serve: requests switch it (cvec=0|1)
  --control-vector-layer-range A B  the layers it follows (inclusive; default 1 .. the last)
  --cvec-mode add|project  h += s v (default) or h -= s (h.v) v with v unit
  --cvec-dir per-layer|single:L  each layer's own direction (default) or layer L's everywhere (project)
  --no-token-graph     A/B: two graphs per layer (the host launches each) instead of one per token
  --no-fused-gr        A/B: the six-kernel hyper-connection read and a separate write (native)
  --prefill CHUNK      batched prompt processing in chunks of CHUNK tokens (needs --native); auto =
                       the largest chunk up to 8192 whose buffers the expert cache can lend;
                       auto:16384 / auto:32768 (or STRATA_PREFILL_AUTO_MAX) allow bigger ones
  --prefill-pipe R     opt-in, a layer split: prompt chunks sized so the stages read at once - R is
                       this PC's b/a in tokens (setup's --calibrate measures it); 1 only evens out
                       the buffers' chunk count (STRATA_PREFILL_EQUAL's rule); 0 off (default; or
                       STRATA_PREFILL_PIPE)
  --no-pool            skip the CPU expert pool (the GPU-only floor)
  --sync-every-layer   debug: synchronise after every layer
  --ple-gguf PATH      the n-gram/PLE shard.  WITHOUT IT LAYER 1's PLE IS SILENTLY SKIPPED,
                       which changes every number downstream - pass it for any real run
  --dump-mixed PATH    write the post-attention residual (n_embd, f32)
  --stage-timing       per-stage KERNEL-COUNT shares.  NOT a time profile: an uncaptured
                       event interval includes host gaps, so run with --gpu-only-full first
  --graph-only         MEASURE: replay the 48 `pre` graphs only.  OMITS the 48 `post` graphs
                       and the LM head, so it is NOT the GPU floor (R0.3, Memory/ERRORS.md A4)
  --gpu-only-full      MEASURE: replay pre+post for all 48 layers plus the LM head, no pool.
                       THE TRUE PER-TOKEN GPU FLOOR.  Quote this one, not --graph-only.
  --stats              print the per-stage breakdown
  --spec-follow PATH   benchmarks: emit this continuation (token ids) instead of the argmax and
                       accept the drafts that match it, so speculation settings compare on the
                       same text (with --spec; not --serve)
  --window-hashes PATH per verify window, a line with its index, position, size, a 64-bit hash of
                       its final residual rows and its argmaxes: two builds that do the same
                       arithmetic write the same file (use with --spec-follow, --adapt-every 0)
  --gpu-stages         R0.9: capture the layer as three graphs (mixer / ffn+router / post)
                       and time them from OUTSIDE the capture.  The per-stage table on the
                       real graph that --stage-timing cannot give.  Prints and exits.
  --expert-profile P   R4.2e: pre-load the VRAM tier from a `profile.bin` (see
                       tools/make_profile.py) instead of admitting on first use.
  --expert-profile-save P  --serve, #477: save what the adaptive tier learned (the experts in
                       VRAM, then the routing counted since the start) as a profile at P, on
                       QUIT and every --expert-profile-save-every MIN minutes (default 10;
                       0 = on QUIT only) between requests; start from it with --expert-profile P
  --no-hit-poke        R4.2d's A/B arm.  The hit path pokes the driver once right after its
                       launch so the GPU starts while the CPU pool runs; without it the work
                       waits for the next driver entry and does not overlap at all.
  --no-ple-prefetch     A/B arm: read the PLE table's sixteen rows one at a time, instead of
                       issuing them in one PrefetchVirtualMemory call.
  --expert-cache N     R4: keep N expert blobs resident in VRAM and compute their rows on the
                       GPU via `moe_hit_grouped_s2`.  DEFAULT 0.  Measured at 4096 slots
                       with --expert-cache-per-layer: 54.4% hits, CPU pool drain 19.1 -> 10.3
                       ms/token, -2.7 ms/token end to end.
  --expert-cache-device1 N|auto  fill CUDA1 with N experts or as many as fit
  --expert-cache-device2 N|auto  fill CUDA2 with more experts
  --expert-cache-device3 N|auto  fill CUDA3 with more experts
  --remote-expert-opt   enable remote-expert decode optimizations (serve mode)
  --expert-cache-remote-placement stripe|layer  distribute expert ranks or whole
                       layers across CUDA1..3 (default: stripe)
  --peer-device N      a second GPU as an adaptive expert-cache tier (rows over P2P; it also
                       computes its experts' prompt rows).  Not with --layer-split or
                       --expert-cache-device1..3.  Default output unchanged without it.
  --peer-reserve-mib N  VRAM the peer tier leaves free on its card (default 600)
  --peer-slots N       expert slots on the peer (default: what fits)
  --peer-adapt-swaps N  peer cache swaps per adaptation step (default: --adapt-swaps)
  --peer-prefill-rows N  prompt rows per layer the peer computes (default half of chunk x top-k;
                       0 = the prompt path stays on the primary)
  --expert-cache-per-layer  R4.2g: give each layer its OWN slots instead of letting the first
                       position take all of them.  The default policy fills in arrival order
                       from one shared counter, so 256 slots went to ~26 layers of position 0
                       and measured **2.97%**.  Per-layer, the same routing gives 21.4% at 8
                       slots/layer and 70.4% at 64.  On a native pack, N is still the budget of N
                       largest blobs; each layer's slots are that layer's own blob.
  --no-host-worker     R2.2: the A/B arm.  By default the HOST THREAD joins the drain, so the
                       pool is six threads on six cores instead of five plus an idle core;
                       this flag restores the five-worker form for comparison on `pool phases`.
  --pool-workers N     R2.2: CPU expert pool worker count.  Default 0 = every physical core
                       except the one the host loop spins on (with --pool-affinity auto or
                       p-cores on a hybrid CPU: P-cores minus 1).  A sweep is how the pool's
                       deviation from `cpu_s2` is attributed.
  --pool-tasks N       Batched CPU expert tasks per GU/Down phase (0..4096). Default 0 =
                       3 per participating thread; positive counts are capped by row count.
  --host-core WHERE    The host thread's core: first (the default: the first physical core, as always) or
                       last (the last physical core, the workers on the others).  Windows sends a GPU's
                       interrupts to one logical processor, usually the first, and every copy that lands
                       raises one: a spinning host there waits for them.  Moves threads only, never a
                       result.  Not on hybrid CPUs.  sibling: the first core's other hardware thread
                       (SMT), so the interrupts keep the first logical processor and the workers keep
                       every core; hybrid CPUs too, first without SMT (STRATA_HOST_CORE sets it too).
  --pool-cores LIST    Experimental, off by default: pin the CPU workers to exactly these logical
                       processors (0,2,4,6 or 2-14:2; the numbers Task Manager and lscpu show).  The
                       default is one worker per physical core, which the start-up line names.  Two
                       entries on one core, or the host's own, are kept with a warning; processors the
                       process may not use are left out.  The worker count is the list's length unless
                       --pool-workers says otherwise.  Moves threads only, never a result.
                       STRATA_POOL_CORES sets it too.
  --aux-cpus SET       Where the threads that are neither pool workers nor the host thread run (the
                       adaptive tier's job thread, the prefill helpers, the CUDA driver's threads, ...):
                       off (the default: wherever they were created), auto (the SMT siblings of the host's
                       core, then physical cores with no worker; never a CPU that shares a core with a
                       worker; nothing is done when none is spare) or a CPU list such as 24,26 (Linux; the
                       host's and the workers' CPUs are dropped from it).  Moves threads only, never a
                       result.  STRATA_AUX_CPUS sets it too; a request's strata_tune aux_cpus=0|1 beats it.
  --pool-affinity MODE Worker CPU affinity: all (default: one worker per physical core, as
                       always), auto (hybrid CPUs: P-cores first, then their SMT siblings,
                       then E-cores) or p-cores (P-cores and their siblings only).  measure (opt-in,
                       hybrid CPUs, native packs): all and p-cores are timed on the pack's own experts
                       at start (about a second) and the faster one is taken
  --coupled-draft      enable coupled draft sampling for MTP drafter under sampling (STRATA_SPEC_COUPLED)
  --no-coupled-draft   disable coupled draft sampling (propose argmax drafts)
  --mmap-experts       R2.1: opt OUT of the resident expert arena, back to MapViewOfFile.
                       The A/B arm: the mmap's rate depends on the OS page cache holding
                       34 GB, and measured 71.97 vs 34.78 ms/token cold vs warm.
  --shared-expert-arena FILE  Linux: back the resident arena with one MAP_SHARED file.
                       Put this file on /dev/shm, not ordinary SSD storage.
                       A small header binds an existing backing file to the same pack.
  --resident-cpu-experts  with mmap and a static profile, keep the experts the GPU cache does not
                       hold resident in ordinary RAM (and the prompt path's lend region as far as
                       RAM allows); adaptive swaps exchange them, so none is read from the file again.
  --resident-experts   the low-RAM PC's resident mode (setup): --mmap-experts --resident-cpu-experts
                       with the copy page-locked when possible, 4 GiB headroom, plain mmap if it
                       does not fit.  Same answers as --mmap-experts for the same placement.
  --ram-keep-gib W     RAM to leave free for your own work, in GiB (default 0; STRATA_RAM_KEEP_GIB is the
                       same).  The expert arena is used only if W GiB stay available after it; otherwise
                       the hottest experts are kept in a RAM copy that leaves max(W, 8 GiB on Windows /
                       4 GiB elsewhere) free and the rest are read from the files.  0 = the arena whenever
                       it fits.  STRATA_RESIDENT_HEADROOM_GIB, when set, decides the headroom instead.
  --adapt-min-gain F  the adaptive tier swaps an expert in only when its decayed routing count beats
                       the one it replaces by more than F (default 1.5; higher = fewer, surer swaps)
  --adapt-async 0|1    --serve with the resident RAM mode or the arena (one GPU): the adaptive
                       tier's swaps advance between verify windows instead of a window waiting for a
                       whole round (the arena: copy-in only).  Not bit-exact run to run.  Without the flag,
                       the expert arena on one CUDA GPU (no --batch) starts blocking and tries it for a
                       while when the swaps hold the windows up, keeping it only if it is faster; 0 = the
                       blocking tier always (also STRATA_ADAPT_ASYNC=0); 1 = always on.
