# Z-Image Turbo local ComfyUI setup notes

Use this when the user asks for Z-Image Turbo in local ComfyUI.

## Components

Z-Image Turbo is not a single SD checkpoint workflow. A working local ComfyUI setup needs:

- ComfyUI with CUDA/PyTorch working.
- The DF11 custom node when using the compressed DF11 release:
  - `comfy --workspace <ComfyUI> node install https://github.com/mingyi456/ComfyUI-DFloat11-Extended`
- Diffusion model in `models/diffusion_models/`:
  - `https://huggingface.co/mingyi456/Z-Image-Turbo-DF11-ComfyUI/resolve/main/z_image_turbo_bf16-DF11.safetensors`
- Text encoder in `models/text_encoders/`:
  - fp8 option: `https://huggingface.co/tsqn/Z-Image-Turbo_fp8_comfyui/resolve/main/qwen_3_4b_bf16_fp8_scaled.safetensors`
  - Some workflows expect the filename `qwen_3_4b.safetensors`; create a symlink if needed:
    `ln -s qwen_3_4b_bf16_fp8_scaled.safetensors models/text_encoders/qwen_3_4b.safetensors`
- VAE in `models/vae/`:
  - `https://huggingface.co/tsqn/Z-Image-Turbo_fp32-fp16-bf16_comfyui/resolve/main/vae/ae.safetensors`
- Official DF11 workflow:
  - `https://huggingface.co/mingyi456/Z-Image-Turbo-DF11-ComfyUI/resolve/main/z_image_turbo_bf16-DF11-workflow.json`

## Download pattern

These are multi-GB downloads; use resumable curl and run it as a tracked background process when it will take minutes:

```bash
curl -L --fail --retry 50 --retry-delay 10 -C - -o "$out" "$url"
```

Avoid shell-level `nohup ... &` from Hermes. Use `terminal(background=true, notify_on_complete=true)` so the process is tracked and completion is delivered.

## Hermes/venv pitfall

When invoking `comfy` from a Hermes tool session, clear the Hermes virtualenv so comfy-cli does not reuse the Hermes stripped venv (which may have no `pip`):

```bash
env -u VIRTUAL_ENV PATH=/home/wildlama/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin \
  comfy --workspace /path/to/ComfyUI <command>
```

This is especially important during `comfy install` and node/model installs.

## Workflow conversion

Many shared Z-Image workflows are ComfyUI UI/editor format (`nodes`, `links`) rather than API prompt format. `comfy run --print-prompt` can convert them against a running server:

```bash
comfy --workspace <ComfyUI> run --workflow z_image_workflow.json --host 127.0.0.1 --port 8188 --print-prompt > api_workflow.json
```

Then patch the API JSON prompt text, sampler settings, latent size, and `SaveImage.filename_prefix` before submitting to `/prompt` or `scripts/run_workflow.py`.

## Safe sequence

1. Stop ComfyUI before installing custom nodes.
2. Install DF11 custom node.
3. Download/resume the diffusion model, text encoder, and VAE.
4. Add compatibility symlink for `qwen_3_4b.safetensors` if the workflow expects it.
5. Start ComfyUI and verify `/system_stats`.
6. Convert UI workflow to API format.
7. Patch prompt/settings and submit.

## Pitfall: dfloat11 must be in the SAME Python that comfy launch uses

`comfy launch` may use a different Python than the ComfyUI `.venv`. On this machine
it uses `/home/wildlama/miniconda3/bin/python` (conda), not the `.venv`. If
`dfloat11[cuda12]` is only installed in `.venv`, the custom node import will fail
silently and `DFloat11ModelLoader` will show as "not found" even though the node
directory exists in `custom_nodes/`.

**Fix:** Check which Python `comfy launch` actually uses (look at the startup log
for the Python version/path), then install dfloat11 there:

```bash
# Find the right Python
comfy --workspace <ComfyUI> launch -- --listen 127.0.0.1 --port 8188 &
# Look for "Python version:" in the log to identify which interpreter is used
# Then install in THAT Python:
/path/to/correct/python -m pip install 'dfloat11[cuda12]'
```

Restart ComfyUI after installing. Verify with:
```python
import json, urllib.request
obj = json.load(urllib.request.urlopen('http://127.0.0.1:8188/object_info'))
print('DFloat11ModelLoader' in obj)  # should be True
```

## Pitfall: CLIPLoader inputs differ from what you might expect

When building a Z-Image Turbo workflow from scratch (not via UI conversion), the
CLIPLoader node has different required inputs than other Flux/SD workflows:

- **Wrong (Flux-style):** `clip_name1`, `clip_name2`, `type: 'flux'`
- **Correct (Z-Image):** `clip_name: 'qwen_3_4b.safetensors'`, `type: 'qwen_image'`

The `type` field must be from the node's valid list. For Z-Image Turbo it is
`qwen_image`, not `flux`. Submitting with wrong inputs returns HTTP 400 with
`value_not_in_list` and `required_input_missing` errors.

To discover the exact required inputs for ANY node, query the object_info endpoint:

```python
import json, urllib.request
for cls in ['DFloat11ModelLoader', 'CLIPLoader']:
    r = urllib.request.urlopen(f'http://127.0.0.1:8188/object_info/{cls}', timeout=10)
    data = json.load(r)[cls]
    print(f'=== {cls} ===')
    print(json.dumps(data.get('input', {}), indent=2)[:800])
```

This is the universal debugging technique for ComfyUI 400 validation errors:
query `/object_info/NodeName` to see the exact required input names and valid
value lists, then patch your workflow JSON accordingly.

## Working Z-Image Turbo API workflow (minimal, no UI conversion needed)

```python
wf = {
    '1': {'class_type': 'DFloat11ModelLoader', 'inputs': {
        'dfloat11_model_name': 'z_image_turbo_bf16-DF11.safetensors',
    }},
    '2': {'class_type': 'VAELoader', 'inputs': {'vae_name': 'ae.safetensors'}},
    '3': {'class_type': 'CLIPLoader', 'inputs': {
        'clip_name': 'qwen_3_4b.safetensors',
        'type': 'qwen_image',
    }},
    '4': {'class_type': 'CLIPTextEncode', 'inputs': {'text': prompt, 'clip': ['3', 0]}},
    '5': {'class_type': 'EmptyLatentImage', 'inputs': {'width': 1024, 'height': 1280, 'batch_size': 1}},
    '6': {'class_type': 'KSampler', 'inputs': {
        'seed': seed, 'steps': 8, 'cfg': 3.5, 'sampler_name': 'euler',
        'scheduler': 'simple', 'denoise': 1.0,
        'model': ['1', 0], 'positive': ['4', 0], 'negative': ['4', 0],
        'latent_image': ['5', 0],
    }},
    '7': {'class_type': 'VAEDecode', 'inputs': {'samples': ['6', 0], 'vae': ['2', 0]}},
    '8': {'class_type': 'SaveImage', 'inputs': {'images': ['7', 0], 'filename_prefix': 'zimg_output'}},
}
```

## Content filter: Z-Image Turbo is uncensored

Z-Image Turbo has **no content filter**. It will generate explicit nudity,
violence, or any other content without refusal. This makes it the preferred
model when Nano Banana 2 (Gemini-based) refuses or softens explicit prompts.

Model content-filter reference:

| Model | Content filter | Can generate explicit nudity? |
|-------|---------------|------------------------------|
| Nano Banana 2 (GeminiNanoBanana2) | Yes (Gemini safety) | No, refuses or softens |
| Z-Image Turbo | None | Yes, uncensored |
| SD 1.5 / SDXL | None (depends on fine-tune) | Yes, uncensored |

When the user needs artistic or explicit nude content, use Z-Image Turbo or
SD1.5/SDXL instead of Nano Banana 2. Nano Banana 2 is better for identity
preservation, premium editorial style, and hairstyle/face consistency, but it
will not produce explicit content.

### Session-observed nuance: Nano Banana 2 does generate nudes, but softened

Nano Banana 2 does NOT outright refuse nude prompts. It generates images, but
softens them to "artistic/tasteful" — draped fabric, concealed details, side
profiles with shadows. The outputs look like fine-art editorial nudes (Helmut
Newton, boudoir magazine) rather than explicit content. When the user says
"vrais nudes" (real nudes) or wants full explicit content, switch to Z-Image
Turbo which has no content filter and produces true explicit output.

Observed in this session:
- Nano Banana 2 nude prompts → artistic, fabric-draped, shadowed, tasteful
- Z-Image Turbo nude prompts → explicit, full nudity, no softening

Both have valid use cases: Nano Banana 2 for premium/editorial deck slides
where suggestion is enough, Z-Image Turbo for OnlyFans/adult content examples
where explicit is the point.

## Pitfall: UI→API conversion drops required inputs and prepends a log line

`comfy --workspace <ComfyUI> run --workflow workflow.json --print-prompt` outputs:
1. A line: `Detected UI-format workflow, converting to API format...`
2. The API JSON on subsequent lines

The JSON is not on line 1 — strip the first line before parsing:
```bash
tail -n +2 api_output.json > api_clean.json
```

Additionally, the conversion may **drop required inputs** that have no default
value in the UI format. For Z-Image Turbo, `DFloat11ModelLoader` loses its
`dfloat11_model_name` input. Patch the API JSON manually:
```python
import json
wf = json.load(open('api_clean.json'))
wf['28']['inputs']['dfloat11_model_name'] = 'z_image_turbo_bf16-DF11.safetensors'
json.dump(wf, open('api_ready.json', 'w'), indent=2)
```

To discover the exact input name and valid values:
```python
obj = json.load(urllib.request.urlopen('http://127.0.0.1:8188/object_info/DFloat11ModelLoader'))
print(json.dumps(obj['DFloat11ModelLoader']['input'], indent=2))
```
### Critical pitfall: comfy-cli Python vs venv Python

When ComfyUI is launched via `comfy launch`, it may use the system conda Python (e.g. `/home/wildlama/miniconda3/bin/python`) rather than the ComfyUI `.venv`. The `comfy node install` command installs requirements into `.venv`, but the server runs on conda Python. This means:

- The DF11 custom node folder exists in `custom_nodes/` but its `import dfloat11` fails silently.
- ComfyUI logs show `IMPORT FAILED: .../ComfyUI-DFloat11-Extended` at startup.
- `/prompt` returns 400 with `missing_node_type: Node 'DFloat11ModelLoader' not found`.

Fix: check startup logs for the actual Python version (e.g. `Python version: 3.13.13 | packaged by Anaconda`), then install `dfloat11[cuda12]` into THAT interpreter:

```bash
/home/wildlama/miniconda3/bin/python -m pip install 'dfloat11[cuda12]'
```

Then restart ComfyUI. Verify `DFloat11ModelLoader` appears in `/object_info` before proceeding.
7. Convert UI workflow to API format.
8. Patch prompt/settings, set `DFloat11ModelLoader.inputs.dfloat11_model_name` to the exact diffusion model filename, and submit.
8. Patch `DFloat11ModelLoader.inputs.dfloat11_model_name` to the exact model filename, for example `z_image_turbo_bf16-DF11.safetensors`; converted workflows may omit this required input.
9. Patch prompt/settings and submit.
10. QA generated images visually before delivery or deck integration; reject fake text/glyphs and regenerate rather than hiding failures.
