TensorSort - The Model Organizer that READS, not guesses

TensorSort - The Model Organizer
"Because filenames lie, but tensors don't."
Who is this for?
Beginners:**
"Error loading LoRA" and no idea why?
→ TensorSort shows you what each file is.
Collectors:**
100+ files, duplicates somewhere, chaos?
→ TensorSort brings order.
Power Users:**
400+ models, grown organically, wildly named?
→ TensorSort gives you clean structure.Your download folder looks like this?:
downloads/
├── aDetailedPurposeV2_v14e.safetensors ← Checkpoint? LoRA? For SDXL?
├── flux_lora_style_v3_FINAL_REAL.safetensors ← Really Flux? Or SDXL?
├── some_model_q8_0.gguf ← Is that Q8? Or Q4?
├── controlnet_thing_fp16.safetensors ← ControlNet? T2I-Adapter?
├── pony_or_sdxl_idk_v2.safetensors ← ???
└── ... 73 moreYou don't know:
What each file is (Checkpoint vs LoRA vs VAE vs ControlNet)
Which model it was trained for (Flux vs SDXL vs SD1.5 vs Pony)
Where it belongs in ComfyUI (checkpoints? unet? loras? controlnet?)
If you already have it (Duplicates with different names?)
The usual "solutions"
**Sort manually?**
→ With 50+ files? Good luck.
**ComfyUI-Manager?**
→ Installs **Nodes**, not model organization.
**Model-Manager Extensions?**
→ GUI to **view** files. You still need to know what's what.
**Trust the filename?**
→ LOL. Filenames lie. Constantly.TensorSort does it differently
TensorSort doesn't guess . It READS.
Every .safetensors and .gguf file has a header with metadata. TensorSort opens the file binary and reads this data directly:
┌─────────────────────────────────────────────────────────────────┐
│ FILE: random_lora_thing_v2.safetensors │
│─────────────────────────────────────────────────────────────────│
│ │
│ TensorSort reads Bytes 0-8: Header-Size = 14,847 bytes │
│ TensorSort parses Header: JSON with 847 Tensor-Keys │
│ │
│ FOUND KEYS: │
│ ├── lora_unet_double_blocks.0.img_attn.proj.lora_down.weight │
│ ├── lora_unet_double_blocks.0.img_attn.proj.lora_up.weight │
│ └── ... (844 more) │
│ │
│ ANALYSIS: │
│ ✓ Keys with "lora_" prefix → FILE TYPE: LoRA │
│ ✓ Keys with "double_blocks" → BASE MODEL: Flux │
│ ✓ Tensor dtype: bfloat16 → PRECISION: BF16 │
│─────────────────────────────────────────────────────────────────│
│ RESULT: │
│ Name: FluxD_LoRA-BF16_General_Thing_v2.safetensors │
│ Folder: loras/ │
└─────────────────────────────────────────────────────────────────┘
The filename said: "random_lora_thing"
The tensor keys say: "Flux LoRA in BF16"
Who's right? The keys.
This is where it gets really interesting.
GGUF files often have WRONG quantization in the filename . The uploader writes "Q8_0" but the file is actually Q4_K_M.
┌─────────────────────────────────────────────────────────────────┐
│ FILE: flux1-schnell-Q8_0-whatever.gguf │
│─────────────────────────────────────────────────────────────────│
│ │
│ TensorSort reads GGUF-Header: │
│ ├── Magic Bytes: "GGUF" │
│ ├── Version: 3 │
│ ├── Tensor Count: 394 │
│ └── Metadata KV Count: 27 │
│ │
│ TensorSort reads Metadata: │
│ └── general.file_type = 15 │
│ │
│ Mapping: 15 → Q4_K_M │
│ │
│─────────────────────────────────────────────────────────────────│
│ FILENAME SAYS: Q8_0 │
│ FILE SAYS: Q4_K_M │
│ │
│ The filename LIED. │
│─────────────────────────────────────────────────────────────────│
│ RESULT: │
│ Name: FluxS_GGUF-Q4_K_M_Whatever_v1.gguf │
│ Folder: unet/ │
└─────────────────────────────────────────────────────────────────┘What TensorSort Detects
File Types (from Tensor-Key-Patterns)
Type | Detection Pattern | Target Folder
----------------|--------------------------------------|---------------
Checkpoint | model.diffusion_model.* | checkpoints/
Flux UNET | double_blocks.*, single_blocks.* | unet/
LoRA | lora_up.weight, lora_down.weight | loras/
LyCORIS | hada_w1, lokr_w1 | loras/LyCORIS/
VAE | decoder.conv_in, encoder.conv_out | vae/
ControlNet | control_model.* | controlnet/
CLIP | text_model.encoder.* | clip/
Embedding | emb_params | embeddings/
Base Models (from Architecture-Patterns)
| Model | Detection Pattern |
|-------|-------------------|
| Flux Dev/Schnell | `double_blocks`, `single_blocks` |
| SDXL | `conditioner.embedders`, `model.diffusion_model` with SDXL-Shapes |
| Pony | SDXL-Architecture + Metadata-Check (ss_base_model, sd_merge_models) |
| SD 1.5 | `cond_stage_model.transformer` |
| Z-Image | `context_refiner`, `noise_refiner` |
| WAN Video | `diffusion_model.blocks.*.cross_attn` (without Flux blocks) |
| Qwen-Image-Edit | `model.diffusion_model.txt_in` (without Flux blocks) |
| Lotus-Depth | `class_embedding` + `down_blocks.*.attentions` |
Before → After
Your Download Folder (BEFORE)
downloads/
├── aDetailedPurposeV2_v14e.safetensors
├── flux-dev-fp16-some-finetune.safetensors
├── ponyDiffusionV6XL_v6StartWithThisOne.safetensors
├── some_lora_nsfw_v3_FINAL.safetensors
├── flux1-schnell-Q8.gguf
└── ... (41 more)
Your ComfyUI models/ Folder (AFTER)
models/
├── checkpoints/
│ ├── SDXL_Full-FP16_Realism_DetailedPurpose_v14.safetensors
│ └── Pony_Full-FP16_General_PonyDiffusion_v6.safetensors
│
├── unet/
│ ├── FluxD_Full-FP16_General_SomeFinetune_v1.safetensors
│ └── FluxS_GGUF-Q5_K_M_Schnell_v1.gguf ← Was NOT Q8!
│
├── loras/
│ └── Flux_NSFW_SomeLora_Trig-nude_v3.safetensors
│
├── controlnet/
│ └── SDXL_CN-Canny_FP16_v2.safetensors
│
└── upscale_models/
└── 4x_UltraSharp.pth
At a glance you can see: [/BOLD] What it is • Which model • Which precision • Name and version
The 15 Modules
| # | Module | Detects | Target Folder |
|---|--------|---------|---------------|
| 1 | Base Models | Checkpoints, UNET, GGUF, WAN, Lotus, Qwen-Edit | checkpoints/, unet/, diffusion_models/ |
| 2 | VAE | VAE, TAESD, VAE-Approx | vae/, vae_approx/ |
| 3 | Text Encoders | CLIP, T5, UMT5, Qwen3, BERT | clip/, text_encoders/ |
| 4 | LoRAs | LoRA, LoHa, LoKr, LoCon, WAN-LoRA | loras/, loras/LyCORIS/ |
| 5 | ControlNet | ControlNet, T2I-Adapter | controlnet/, t2i_adapter/ |
| 6 | Upscalers | ESRGAN, RealESRGAN, SwinIR | upscale_models/ |
| 7 | Embeddings | Textual Inversion | embeddings/ |
| 8 | PhotoMaker | PhotoMaker v1/v2 | photomaker/ |
| 9 | InsightFace | Face Analysis Models | insightface/ |
| 10 | IP-Adapter | SD/SDXL/Flux variants | ipadapter/, xlabs/ |
| 11 | AnimateDiff | Motion Modules | animatediff_models/ |
| 12 | SAM | Segment Anything | sams/ |
| 13 | GroundingDINO | Object Detection | grounding-dino/ |
| 14 | YOLO | Ultralytics Models | ultralytics/ |
| 15 | VLM & LLM | Vision/Language Models | VLM/, LLM/ |
The Two Modes
Mode A: Installation
1. Put files in downloads/
2. Start TensorSort → Mode A
3. PREVIEW: See what TensorSort detected
4. Confirm
5. Files get sorted + renamed
Mode B: Cleanup
1. Start TensorSort → Mode B
2. Scans ALL files in models/
3. Finds: Wrong folders, wrong names, duplicates
4. Shows what would be changed
5. You confirm → Chaos becomes order
Bonus Features
### Recursive Scanning
Already organized your downloads into subfolders? No problem!### Duplicate Detection (SHA256)
TensorSort calculates a SHA256 hash for each file. Identical files are detected - **no matter what they're named**.
### Cross-Folder Rescue
File in the wrong folder? TensorSort finds it and moves it automatically:
```
checkpoints/some_lora.safetensors ← LoRA in checkpoint folder!
→ TensorSort Mode B detects this
→ Moves to loras/Flux_LoRA-BF16_Some_v1.safetensorsTrigger-Word Extraction (LoRAs)
TensorSort reads `ss_tag_frequency` from LoRA metadata and adds the most frequent tag as trigger word in the name:
```
Before: some_anatomy_lora_v3.safetensors
After: Flux_Anatomy_SomeLora_Trig:nude_v3.safetensors
^^^^^^^^
Extracted from metadata!Quick Start
### Requirements
- ComfyUI installed (Standard OR Portable)
- That's it!**ComfyUI Portable users:** No system Python needed! TensorSort automatically finds the `python_embeded` from your ComfyUI folder.
**First run without config?** TensorSort asks once for the ComfyUI path - completely without Python, pure batch logic.On first start: Enter ComfyUI path → Config is created → Done!
ComfyUI caches filenames in the browser. After TensorSort changes:
**Ctrl + Shift + R** (Windows/Linux)
**Cmd + Shift + R** (Mac)
Download & Support
Author: K0DA Parallax Studio
Email: [email protected]
GitHub: https://github.com/K0DA-PARALLAXStudio
Patreon: https://patreon.com/K0DAParallaxStudio
Instagram: https://www.instagram.com/k0da_parallax_studio/
Buy Me Coffee: https://www.buymeacoffee.com/K0DA_Parallax_Studio
*"Because filenames lie, but tensors don't."*