KIE • Save Character Variant
Outfits are versions, the face is not
- character_pack
- approved_image
- character_variant
- variant_prompt
What it is
This node saves an approved look - an outfit, a haircut, a costume, a time-skip appearance - as a versioned child of an existing Character Pack. It writes the image and a manifest to disk and hands you back a CHARACTER_VARIANT handle plus the composed prompt.
The reason to split looks off from identity: the thing that breaks character consistency work is scope creep in the reference. You start with "this is what she looks like" and end up with "this is what she looks like, in this jacket, in this room, at this time of day" - and now every other scene inherits the jacket. Keeping wardrobe in a variant means the parent stays the character, and the parent's hash is recorded on every variant so it can't quietly drift.
How it works
character_pack must be a loaded pack - the input is typed, so it comes from KIE • Load Character Pack. The node verifies the pack sits inside your active character library and that its manifest hash matches what the handle claims. If the pack was re-saved with different content since your workflow loaded, you get "Character Pack identity changed since this workflow was built" rather than a variant attached to the wrong identity.
variant_name, version and appearance are all required - the node explicitly refuses if any is blank. approved_image must be exactly one image: a batch of four throws "A Character variant requires exactly one approved IMAGE." That's deliberate; a variant is one look, not a selection of options.
On disk it lands in character_variants/<pack_id>/<slug(name)>__v<slug(version)>/, containing approved.png and a variant.json that records the parent pack ID, the parent's content hash, the appearance text, the optional scene allowance, and the image's SHA-256. Saves are staged in a .saving directory and renamed into place, so a crash mid-write doesn't leave a half-record.
The variant_prompt output is the useful text: identity description, visual style and continuity rules from the parent, then your appearance line, then "Scene allowance: …" if you filled it in.
Inputs and outputs
character_pack- required, from Load Character Pack.variant_name,version,appearance,approved_image- required. Defaults areDay look/1.scene_allowance- optional. Use it for the boundary: what may change around this look without breaking it.- Outputs:
character_variant(handle) andvariant_prompt(STRING).
Typical loop: generate candidate looks, pick one with KIE • Consistency Board, save the winner here, then load it in every future scene.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/felipederosilva/ComfyUI-KIE-Nodes-Next
python -m pip install -r ComfyUI-KIE-Nodes-Next/requirements.txt
No API key, no cost - it's local file writing. Variants live in ComfyUI's user data folder, so updating the pack won't destroy your library. It is an output node, so it always executes and always writes.
Where people get burned
- "This Character variant version already has different content." Same name and version, different pixels or text. Bump the version - that's the immutability contract, and it's what makes old renders reproducible.
- A batch on
approved_image. Split it first. If you have four candidates, that's a Consistency Board decision followed by a save of one. - Re-saves are safe. Saving byte-identical content again returns the existing record rather than erroring. Handy when you re-queue a graph.
- The parent must be loaded, but not modified. Change the pack's identity notes and every variant under the old version stops loading until you re-generate against the new one. Which is the point, and also occasionally infuriating.
- It isn't identity. A variant prompt plus a reference image doesn't lock a face across models. How much the character holds is the model's business, not the node's.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| character_pack | CHARACTER_PACK | — | |
| variant_name | STRING | Day look | — |
| version | STRING | 1 | — |
| appearance | STRING | — | |
| approved_image | IMAGE | — | |
| scene_allowanceopt | STRING | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| character_variant | CHARACTER_VARIANT | — |
| variant_prompt | STRING | — |