| name | add-comfyui-node |
| description | Adds a custom ComfyUI Python node to MooshieUI — Python class in mooshie_nodes.py, Rust required-class registration, and optional workflow template chain hookup. Use for new image-processing nodes (detailers, detectors, compositors) or /add-comfyui-node. |
Add Custom ComfyUI Node (MooshieUI)
MooshieUI deploys its own ComfyUI nodes from src-tauri/src/comfyui/mooshie_nodes.py (embedded via include_str!, written to ComfyUI's custom_nodes/ at startup). Existing examples: MooshieSaveImage, MooshieFaceDetailer, MooshieSegmentDetailer.
Touchpoints (in order)
1. Python — src-tauri/src/comfyui/mooshie_nodes.py
class MooshieMyNode:
"""One-line summary of what the node does."""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"model": ("MODEL",),
"vae": ("VAE",),
"positive": ("CONDITIONING",),
"negative": ("CONDITIONING",),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xFFFFFFFFFFFFFFFF}),
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS,),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "process"
CATEGORY = "mooshie"
def process(self, image, ...):
return (result,)
Register at the bottom of the file:
NODE_CLASS_MAPPINGS = { ..., "MooshieMyNode": MooshieMyNode }
NODE_DISPLAY_NAME_MAPPINGS = { ..., "MooshieMyNode": "Mooshie My Node" }
2. Rust verification — src-tauri/src/comfyui/nodes.rs
Add the class name to REQUIRED_MOOSHIE_NODE_CLASSES so startup verifies ComfyUI actually loaded it (catches stale-server cases where files exist on disk but /object_info lacks the class until restart).
3. Workflow hookup — src-tauri/src/templates/
- New post-process chain →
append_*_chain(result, params, image, seed) -> (String, u32) module, called from finish_workflow in mod.rs.
finish_workflow chain order matters: upscale → facefix → segment → MooshieSaveImage. Insert new steps deliberately.
- Seed offsets: base seed for KSampler,
seed+2 facefix, seed+3+i segments. Pick an unused offset.
Python node conventions
- Heavy imports (
transformers, ultralytics) go inside methods, not module top — keeps node load cheap and the dependency optional.
- Model weights cache under
folder_paths.models_dir subdirs (e.g. models/clipseg/); del model objects in finally to release VRAM.
- Sample with
comfy.sample.sample(...) + comfy.sample.prepare_noise; preview via latent_preview.prepare_callback.
- Soft masks blend better than binary: return sigmoid/confidence values and let the composite weight per-pixel.
- Guard empty detections (
mask is None, ys.numel() == 0) — return the input image unchanged, print a [MooshieMyNode] prefixed line for diagnosability (ComfyUI stdout, not Tauri logs).
- Python deps the node needs at runtime: ensure via
installPipPackage("pkg==x.y.z") from the frontend before generation (see ensureFacefixPythonDependency in GenerateButton.svelte).
Verify
python -m py_compile src-tauri/src/comfyui/mooshie_nodes.py
cargo check --manifest-path src-tauri/Cargo.toml
- [ ] Class + NODE_CLASS_MAPPINGS + NODE_DISPLAY_NAME_MAPPINGS
- [ ] REQUIRED_MOOSHIE_NODE_CLASSES in nodes.rs
- [ ] finish_workflow / template chain wired (if workflow-facing)
- [ ] ComfyUI restarted when testing (deploy alone doesn't reload classes)