HaDeS MOSS Suite
ComfyUI nodes for the MOSS-Image model family: block and multi-model (TIES, DARE, Model Stock, SLERP) mergers for the 42-layer single-stream DiT, a model saver (bf16, float32, int8 ConvRot), LoRA tools (extractor, merger, resize, per-layer-group strength), a latent node, a layout compiler, a KSampler with metadata and a turbo input for our own 4-step LoRAs, and a telemetry node.
HaDeS MOSS Suite
ComfyUI nodes for the MOSS-Image model family (OpenMOSS / Comfy Org: 42-layer single-stream DiT, Qwen3.5-9B text encoder, FLUX.2 VAE), in the style of the HaDeS Anima Suite.
Claims about what layer groups do are measured with tools/moss_eval.py, not assumed.
Turbo (0.2.0): few-step LoRAs we trained for MOSS-Image SFT, HaDeS MOSS Turbo and Turbo Diverse (4 steps at CFG 1, 3.4 MB each), joined by Turbo 8-steps v0.7 (8 steps), and a turbo input on MOSS KSampler that applies them with their settings. How they were trained and measured: tools/RESULTS.md, tools/moss_dmd_train.py.
Installation
cd ComfyUI/custom_nodes
git clone https://github.com/Devildonia/HaDeS-MOSS-Suite
No extra dependencies. Needs a ComfyUI with MOSS-Image support (tested on 0.43.0) and the MOSS-Image weights from Comfy-Org/MOSS-Image.
Nodes
MOSS Model Block Merger (HaDeS/MOSS Mergers)
- Class:
HaDeSMossModelBlockMerger - Purpose: merges two MOSS-Image models (e.g. SFT and Base) with one ratio per group of 6 layers and for the parts outside the layers.
0.0= Model 1,1.0= Model 2; values outside0..1extrapolate. - Inputs:
model1,model2(MODEL) with the same q/k/v layout. Quantized models (int8 ConvRot, fp8) are dequantized and merged with a warning ininfo: the quantization rounding stays in the result, and a quantizedmodel1makes the result quantized again, so connect the bf16 model asmodel1. The one int8 finetune measured differs from SFT by about as much as the int8 rounding itself (tools/RESULTS.md).layers_00_05…layers_36_41(FLOAT, default0.5).text_embedder(projection of the Qwen3.5 hidden states and its 2 text blocks),time_modulation(time_embedding+shared_block_modulation),io(video_embedder+ output head).recipe_override(STRING, optional): one ratio per layer (42), thentext_embedder,time_modulation,io, comma-separated.
- fp16-fixed files: some fp16 releases store the residual stream scaled down (measured: x 1/16 on
video_embedder, the text embedder outputs and the modulation gates), which is the same model in another scale. The merger detects the scale and bringsmodel2tomodel1's before merging, and says so ininfo. - Outputs:
MODEL,info. - Memory: the merge is a lazy patch computed when the model loads; no merged copy is kept in RAM.
MOSS Multi-Model Merger (HaDeS/MOSS Mergers)
- Class:
HaDeSMossMultiModelMerger - Purpose: merges 2–4 MOSS-Image models with the community's standard methods. Every method except SLERP works on task vectors (
model − base_model):TIES: keeps each task vector's largest entries (density), elects a sign per entry from their sum and averages the agreeing ones.DARE/DARE-TIES: drops entries at random with keep probabilitydensityand rescales the rest, then averages (DARE) or elects signs like TIES (DARE-TIES).seedfixes the drop mask.Task Arithmetic: weighted average of the task vectors.Model Stock(Jang et al. 2024): the average of the models pulled towardbase_model, per tensor, by the angle between their task vectors; it ignores weights,densityandscale.SLERP: spherical blend ofmodel_1andmodel_2only,t = weight_2 / (weight_1 + weight_2); needs nobase_model.
- Inputs:
model_1,model_2(MODEL),model_3,model_4,base_model(optional; required by every method except SLERP),weight_1…weight_4(0..2, normalized by their sum),density(0.05..1, default0.5),scale(0..2, default1.0;1.0has the strength of an average),seed. - base_model: the checkpoint the models were finetuned from. Community MOSS finetunes come from SFT or from Base; when they mix, use Base, which SFT was trained from.
- Inputs it accepts: like the Block Merger, quantized models are dequantized (with a warning; with TIES / DARE a quantized model's task vector carries its rounding), and fp16-fixed files are brought to the anchor's residual scale (
base_model, ormodel_1for SLERP). - Not measured: which method gives better images.
MOSS LoRA Extractor (HaDeS/MOSS Mergers)
- Class:
HaDeSMossLoraExtractor - Purpose: saves
model_tuned − model_baseas a LoRA inmodels/loras/: truncated SVD per linear layer (lora_up/lora_down/alpha), full.diff/.diff_bfor norms and biases, identical tensors skipped. Keys arediffusion_model.*with fusedproj.qkv, which the stock LoRA loaders apply to the Comfy-Org files. - Inputs:
model_tuned,model_base(MODEL; merge / LoRA patches on either are included),rank(4..256, default32),export_filename,overwrite_existing. - Inputs it accepts: quantized models are dequantized (with a warning: the difference includes their rounding), and an fp16-fixed
model_tunedis brought tomodel_base's residual scale first. - Outputs:
saved_lora_path,info(size, energy kept: the share of the difference the rank holds). - Measured:
galenaCAT − SFTat rank 64 (252 MB) keeps 95.9% of the energy and renders 4–12 from the finetune on SFT; a rank-32 LoRA of an int8 finetune reproduced it within the int8 noise on three of four images. Seetools/RESULTS.md.
MOSS LoRA Block Weight (HaDeS/MOSS Mergers)
- Class:
HaDeSMossLoraBlockWeight - Purpose: applies one LoRA with a separate strength per group of 6 layers (
layers_00_05…layers_36_41) andother_layersfor LoRA weights outside the layers. Loads every community MOSS format through ComfyUI's own key map (kohya, PEFT split or fused q/k/v); at 1.0 everywhere it renders the same image as the stockLoraLoaderModelOnly. - Inputs:
model,lora_name,strength_model, the seven group multipliers andother_layers(-2..3, default1.0). - Outputs:
MODEL,info(how many LoRA weights fall in each group, e.g. 20 instead of 24 inlayers_18_23for LoRAs trained without layer 22). - Measured: layers 30–35 carry a large share of all four community LoRAs tested, but beyond that each acts in different layers (24–35, 30–41 or 00–05 and 30–35), so the node has no style / identity presets;
tools/moss_eval.py --mode lorameasures a given LoRA. Seetools/RESULTS.md.
MOSS LoRA Merger (HaDeS/MOSS Mergers)
- Class:
HaDeSMossLoraMerger - Purpose: merges two LoRAs into one file,
weight_a × A + weight_b × B, compressed per layer with an exact SVD of the stacked factors (QR first, never the full matrix). Any community MOSS format in (kohya, PEFT split or fused q/k/v), the model's layout out. - Inputs:
model(the model the LoRAs are for; it sets the q/k/v layout),lora_a,weight_a,lora_b,weight_b,rank(max per layer; rank A + rank B is exact),export_filename, optionaldynamic_energyandoverwrite_existing. Never overwrites a source LoRA. - Outputs:
saved_lora_path,info(layers in A only / B only / both, size, rank, energy kept). - Measured: retro (rank 32) + lenovo (rank 16) merged at rank 48 or 32 renders within the noise of loading the two LoRAs in the opposite order (
tools/RESULTS.md).
MOSS LoRA Resize (HaDeS/MOSS Mergers)
- Class:
HaDeSMossLoraResize - Purpose: lowers a LoRA's rank with the same exact SVD, fixed (
target_rank) or per layer by an energy target (dynamic_energy), and saves a new file inmodels/loras/; the source is never overwritten. Split q/k/v LoRAs come out fused on fused models. - Inputs:
model,lora_name,target_rank,export_filename, optionaldynamic_energy,overwrite_existing. - Outputs:
saved_lora_path,info(sizes, rank, mean and worst-layer energy kept). - Measured: AnubisCitronOC (142 MB) at rank 32 (126 MB, 97.9% energy) stays within the noise floor; rank 16 (63 MB, 91.1%) and dynamic 0.90 (56 MB) drift visibly from the source.
MOSS Model Saver (HaDeS/MOSS Mergers)
- Class:
HaDeSMossModelSaver - Purpose: saves a
MODELwith its merge / LoRA patches baked in, loadable by the stockLoad Diffusion Modelnode, and passes the model through. - Inputs:
filename_prefix: path underComfyUI/output(defaultdiffusion_models/MOSS_HaDeS_Merged). Move the file tomodels/diffusion_modelsto load it.precision:bfloat16(10.2 GB),int8 ConvRot (Comfy-Org layout)(5.4 GB: the four linears of every layer in int8 with Hadamard rotation and int8 attention, everything else in bfloat16, the same keys and dtypes as Comfy-Org's*_int8_convrotfiles) orfloat32.include_metadata,custom_author,custom_model_title: ModelSpec metadata.
- Outputs:
model(pass-through),saved_path,info. - Measured: a live merge renders slightly differently from the same merge saved and reloaded (same subject and composition, small details change), in ComfyUI's own merger too; see
tools/RESULTS.md.
MOSS Latent (HaDeS/MOSS Pipeline)
- Class:
HaDeSMossLatent - Purpose: empty MOSS-Image latent (128 channels, 16 px grid) from an aspect ratio (
1:1,4:3,3:2,16:9,21:9and their portrait forms) and a size in megapixels (1.0= 1024×1024), or a custom width / height snapped to 16 px. Outputswidth/heightfor layout prompts. - Inputs:
aspect_ratio,megapixels(0.25..4.0, default1.0),custom_width,custom_height,batch_size; optionalvae(rejects a VAE that is not the 128-channel FLUX.2 one). - Outputs:
latent,width,height,info. - Measured: square images from 768 to 2048 render clean at the model's default shift 5.0, with no repeated subjects; larger canvases show more of the scene. Raising the shift is not needed at any of these sizes. Non-square ratios are not measured. See
tools/RESULTS.md. - Upscaling a MOSS latent (hi-res fix): use the core
Upscale Latent By(LatentUpscaleBy), notUpscale Latent(LatentUpscale). The latter takes a size in pixels and divides it by 8, as for SD VAEs, while the MOSS latent is 16 px per cell: asked for 1024 x 1024, it gives a 2048 x 2048 image.
MOSS Layout Compiler (HaDeS/MOSS Pipeline)
- Class:
HaDeSMossLayoutCompiler - Purpose: compiles an OpenMOSS layout draft (the schema of the official
moss-image-prompt-enhancer:width/height,bbox_coord_space: "abs",bbox_format: "xyxy"in top-left pixels,summaryand a flatitemsarray) into the model-facing prompt (boxes centered on the canvas,yxyx), with the same validation as the officialcompile_prompt.pyand byte-identical output. Also outputs the empty latent andwidth/heightof the draft's own canvas, so prompt and image size cannot drift apart. A{"caption": ...}draft passes through as plain text. - Inputs:
draft(STRING, JSON),batch_size. - Outputs:
prompt(toCLIPTextEncode),latent,width,height,info(lists multi-line text items with their box size). - Line breaks: write them as
\nintext. Measured, the box shape decides whether they are kept: a two-line title in an 832×192 box came out on one line in 3 of 6 seeds, in a 640×384 box on two lines in 6 of 6; a literal newline instead of\nchanged nothing (tools/RESULTS.md). - Unlike the core
MOSS-Image Layout Prompt(boxes fromCreate Bounding Boxes), this node takes hand-written or LLM-written drafts, includingmeta,canvas,paletteandtags.
MOSS KSampler (HaDeS/MOSS Samplers)
- Class:
HaDeSMossKSampler - Purpose: KSampler with the official ComfyUI MOSS-Image template settings as defaults (25 steps, CFG 2.5,
er_sde/simple, the model's shift 5.0), an optional flow shift, optional skip-layer guidance and optional decode. With the same settings it renders the same image as the stock graph (KSampler,ModelSamplingAuraFlow,SkipLayerGuidanceDiTSimple,VAEDecode). - Inputs:
model,positive,negative,latent_image,seed,steps,cfg,sampler_name,scheduler,denoise,flow_shift(0keeps the model's 5.0),slg(off,block 22, first half (Base template),block 22, all steps); optionalvae, optionalturbo(fromMOSS Turbo LoRA: applies the LoRA and samples at CFG 1, euler / simple, SLG off and the turbo node's steps, whatever those widgets say). - Outputs:
latent,image(when a VAE is connected),info(the settings actually used). - Measured (
tools/RESULTS.md): shift 5.0 is clean from 768 to 2048 px; SLG on block 22 did not change text accuracy on SFT or Base (blocks 24 / 26 made the only errors, on Base), so it is off by default; with euler, 25 steps render nearly the 60-step image with any scheduler and euler / beta does so at 15.
MOSS Turbo LoRA (HaDeS/MOSS Samplers)
- Class:
HaDeSMossTurbo - Purpose: picks a few-step LoRA for the
turboinput ofMOSS KSampler, which loads it the way the stockLoraLoaderModelOnlydoes and samples at CFG 1, euler / simple and its ownstepswidget, 4 by default (seed, denoise and flow shift still come from the KSampler). Measured counts: 4 for Turbo and Turbo Diverse, 8 for Turbo 8-steps; Turbo and Turbo Diverse give 6–10% less colour than SFT at 4 steps at 1024 (6–14% at 2048) and are back near it at 8 (only colour was measured for them at 8). Other counts run, their quality is untested. Checked in ComfyUI: it renders the stockLoraLoaderModelOnly+KSamplerimage pixel for pixel (both LoRAs, 8 images, with the KSampler's own widgets left at 25 steps, CFG 2.5, er_sde / beta and SLG on). - Inputs:
lora_name(frommodels/loras),strength(default1.0, the only strength measured),steps(default4). - The LoRAs: HaDeS MOSS Turbo and Turbo Diverse v0.6 (for 4 steps) and Turbo 8-steps v0.7 (for 8 steps), 3.4 MB each, on Hugging Face; put them in
models/loras. Trained in this repository (tools/moss_dmd_train.py) from MOSS-Image SFT, which they are for. - Measured (
tools/RESULTS.md, 1024 x 1024 against akhaliq's 4-step v2.0 LoRA at the same settings): Turbo spelled every test string right on signs and posters at 1024 x 1024, 6 / 6 on layout JSON and 3 / 3 on a 16:9 poster, while at 2048 x 2048 the sign's small line was right in 1 / 3 (akhaliq's 2 / 3); Turbo Diverse keeps SFT's spread of faces on an open prompt (about 10 East Asian women in 16 seeds, against about 15 for Turbo and akhaliq's LoRA). Turbo 8-steps at 8 steps, in blind pairs on 20 varied prompts: beat akhaliq's 4-step LoRA (full file) 18 to 5, and against lodestones' 8-step DMD2 LoRA for MOSS-Image Base / Kromoss run on SFT (full file) 10 to 7 at 1024 and 0 to 5 at 2048, where it has less colour; it is for up to 1024. lodestones' SFT 8-step LoRA was not compared. Not measured: other base models, other strengths or step counts, denoise below 1.0; they run (an int8 finetune as the base, img2img at denoise 0.6 were checked), their quality is untested, and Telemetry cannot tell which model the KSampler got.
MOSS Sampler Metadata (HaDeS/MOSS Samplers)
- Class:
HaDeSMossSamplerMetadata - Purpose: reads the settings a MOSS KSampler actually sampled with from its
info(seed, steps, cfg, sampler, scheduler, denoise, flow shift, andturbo: the turbo LoRA file and strength, empty without one), for image-saver metadata.
MOSS Suite Telemetry (HaDeS/MOSS Pipeline)
- Class:
HaDeSMossSuiteTelemetry - Purpose: reads the
infooutputs of up to 8 HaDeS MOSS nodes (theirHADES_METAtrailer) and checks the pipeline against what was measured:- error: layout, latent and KSampler on different canvas sizes (a layout prompt places its boxes on its own canvas);
- warning: quantized models in a merge, TIES / DARE with a quantized model, LoRAs extracted / resized / merged below 90% energy;
- note: KSampler size outside 768²–2048², shift other than 5.0, SLG on, turbo LoRA at a strength other than 1.0, at a step count other than 4 or 8 or at denoise below 1.0, fp16-fixed residual scale normalized, multi-line layout text with its box proportions.
- Outputs:
report(Markdown),json,summary(one line).
Interface
The nodes draw their own moss-green rows on the canvas (the HaDeS Anima Suite widget library with its own palette), in the classic canvas and in Nodes 2.0:
- every widget becomes a styled row by type (combo, slider, number, toggle, text); the layout draft keeps ComfyUI's text editor;
- tooltips are the node's own, with the measurements behind each value;
- Block Merger: a bar chart of the 42 layers and 3 parts colored by depth group, each group labeled with the share of the SFT → Base change it carries, and buttons M1, 50/50, 24–35 M2 (the groups that carry most of that change) and M2;
- LoRA Block Weight: a bar per layer group; KSampler and Latent: a status line with the settings or the final size. With the turbo input connected the KSampler's status reads TURBO and the rows it overrides (steps, cfg, sampler, scheduler, SLG) are drawn faded, still editable for when it is unplugged.
Settings → HaDeS MOSS Suite → Use standard ComfyUI widgets (or HaDeS MOSS Suite in a node's right-click menu) switches to the plain widgets. It does not affect HaDeS Anima Suite nodes when both suites are installed.
Example workflows
In examples/ (drag a file into ComfyUI). They use the official Comfy-Org file names and carry their download links, so ComfyUI offers to download missing models.
- Merge, Save and Telemetry: SFT with layers 24–35 from Base through the Block Merger, MOSS Latent and MOSS KSampler, telemetry report. Model Saver and a SLERP Multi-Model Merger come muted, ready to switch on.
- Layout Poster: an OpenMOSS layout draft through the Layout Compiler, whose prompt and latent feed the sampler, with telemetry.
- Turbo: MOSS Turbo LoRA into the MOSS KSampler's
turboinput, 4 steps at CFG 1 on SFT; ComfyUI offers to download the LoRA from Hugging Face. - LoRA Toolkit: a LoRA through LoRA Block Weight into the sampler; LoRA Merger, LoRA Resize and LoRA Extractor (with a finetune loader) come muted, since they write files. Pick your own LoRA in
lora_name.
Every example was run end to end in ComfyUI 0.43.0 (muted nodes left out). tools/make_examples.py regenerates them from the node definitions of a running ComfyUI.
Tests
tests/test_moss_suite.py checks the nodes against the real ComfyUI core on a tiny synthetic MOSS-Image model (CPU, a few seconds, no model download). From the ComfyUI folder:
python custom_nodes/HaDeS-MOSS-Suite/tests/test_moss_suite.py
Tools
tools/moss_eval.py --mode bias | compare: ethnic bias on neutral and explicit prompts, SFT vs Base on photo, illustration, text and layout prompts, with stock nodes only.tools/moss_eval.py --mode groups: which layer groups carry the SFT → Base change (needs this suite installed).tools/moss_eval.py --mode lora --lora <name> --lora-model <file>: which layer groups carry a LoRA's effect.tools/moss_eval.py --mode bias_merge: ethnic bias of SFT / Base merges.tools/moss_eval.py --mode shift: square sizes x flow shifts (composition scale, native detail).tools/moss_eval.py --mode slg: skip-layer guidance blocks on text and portrait prompts, SFT and Base.tools/moss_eval.py --mode schedulers: sampler x scheduler x steps against a 60-step reference.tools/moss_eval.py --mode attention | progressive: attention backends and int8 speed; two-resolution sampling.tools/moss_eval.py --mode turbo | turbo_groups | turbo_files: few-step LoRAs against each other, which layer groups carry them, LoRA files at any prompt set, size or aspect (--height).tools/moss_dmd_train.py: trains a few-step LoRA by DMD on one GPU (shared base, hooked LoRAs, regression term, gradient checkpointing, atomic checkpoints and resume); the turbo LoRAs come from it.tools/moss_activations.py,tools/moss_bias_turbo.py,tools/moss_bias_fit.py: per-step biases in place of (or on top of) a few-step LoRA.