GenConsistent
Where CharaConsist finally pays off
- model
- subject
- cross_sim
- MODEL
This is the payoff node - the one that makes the whole two-pass dance worth it. ExtractAttn cached your subject's attention during a reference pass, GetCrossSim worked out which pixels in the new image correspond to which pixels of the subject, and GenConsistent is where the cached data gets used. You wire it in front of the KSampler that renders your target image - the character in a new pose, new outfit, new scene - and it patches the model so the fresh generation can attend to the reference subject's own key/value tensors while it denoises. No LoRA, no training, no IP-Adapter. Just a second chance to look at the reference mid-generation.
That's the training-free CharaConsist recipe at work, and it sits in a different lane than the character-consistency advice you'll find in most 2026 threads. The mainstream answer today is instruction editing - Qwen-Image-Edit and friends - or a properly trained character LoRA. Those are usually easier and more robust. GenConsistent is for when you want consistency inside the generation itself, baked into the sampling, without touching weights.
How it works
During sampling, the node hooks attention the same way ExtractAttn does. At each layer and step in range it does two things.
First, KV expansion: if GetCrossSim found matching foreground tokens between the subject and the current render, it pulls the subject's saved keys and values and concatenates them onto the current layer's keys and values. The new image's queries can now attend to the reference's own attention vectors, so it can literally copy the subject's visual structure. The rotary positional encoding gets reapplied to those saved keys so positions line up.
Second, hidden-state blending: if ada_tome_alpha is above zero, it blends the current vision-token hidden states with the matched saved subject states, weighted by that alpha and by the cross-similarity score. This is the smoother, softer version of the injection - alpha 0 disables it entirely.
Inputs and outputs that matter
model- the MODEL for the target generation.subject(ATTN) - the cache from ExtractAttn's reference pass.cross_sim(CROSSSIM) - the match data from GetCrossSim. Miss this and the node can't find any subject positions to inject, so it runs but changes nothing.kv_start_step/kv_end_step- the window where KV expansion happens (defaults 1–5).x_start_step/x_end_step- the window for hidden-state blending (defaults 1–5).ada_tome_alpha(FLOAT, 0–1) - how strongly blended states pull toward the reference.
Output is a single patched MODEL, which you feed straight into a KSampler. Notice the step defaults here (1–5) are narrower than ExtractAttn's (1–9). That's deliberate - you don't want to hold the injection through the whole sample; like ControlNet start/end step control, you apply it while composition is forming and let the model finish free. If your ExtractAttn and GetCrossSim runs used different step ranges, make sure the windows overlap or the node silently has nothing to inject.
Install
ComfyUI Manager → search "Comfyui_CharaConsist", or:
cd ComfyUI/custom_nodes
git clone https://github.com/thatname/Comfyui_CharaConsist.git
Restart, look under the chara_consist category. No pip dependencies. Model-wise it's Flux-family only: Chroma (the README's "best"), Flux, Qwen-Image, Chroma1-Radiance. The RAM appetite from the reference pass carries over - the subject cache lives in system RAM, so this pack assumes 32GB+ before you even get here.
Common issues
The usual failure is the quiet one: the node runs, the image looks no different, and nothing throws. That means the cross-sim match found nothing - check sim_threshold in GetCrossSim (too high kills all matches) and confirm cross_sim_step exists in both attention caches. When it does work, you'll see it in the details: the character's face, outfit structure, and key features holding across generations that would otherwise drift. Just don't expect the kind of community support you get on popular packs - CharaConsist has essentially zero discussion anywhere, so the console prints and the two example workflows in the repo are your documentation. Take a deep breath, wire it by the examples, and it's genuinely satisfying when the face finally sticks.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| subject | ATTN | — | |
| cross_sim | CROSSSIM | — | |
| kv_start_step | INT | 1 | — |
| kv_end_step | INT | 5 | — |
| x_start_step | INT | 1 | — |
| x_end_step | INT | 5 | — |
| ada_tome_alpha | FLOAT | 0.00–1 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MODEL | MODEL | — |