Nodes/ComfyUI-CFG-Ctrl/CFG-Ctrl / SMC-CFG Guider
ComfyUI Node

CFG-Ctrl / SMC-CFG Guider

Prompt adherence without the burn

By xmarre·Created 6 months ago·Updated 6 months ago· 2
CFG-Ctrl / SMC-CFG Guider
  • model
  • positive
  • negative
  • GUIDER
cfg4.0
enable_smctrue
smc_lambda6.0
smc_k0.30
no_cfg_warmup_steps0
active_start_step0
active_end_step1000000000
active_start_percent0.00
active_end_percent1.00
switch_modesign
boundary_epsilon0.000
epsilon_modeabsolute
math_dtypefloat32
state_dtypematch
apply_only_if_cfg_gt_1false
reset_on_shape_changetrue
detach_prevtrue

Every CFG has a ceiling. You push the scale up to make the model obey your prompt harder, and somewhere past the sweet spot the image stops getting more obedient and just starts burning - oversaturated, contrast-cranked, faces going feral. That's the wall this node attacks.

CFGCtrlSMCGuider (sold as "CFG-Ctrl / SMC-CFG Guider") is a ComfyUI port of the CFG-Ctrl paper, a March 2026 method that reframes classifier-free guidance as a control problem and stabilizes it with sliding mode control. It's one of the cleaner research-to-ComfyUI ports I've seen: a single GUIDER output that drops into your existing custom-sampling workflow, no model downloads, no extra dependencies. If you've been running CFG 6–9 on SDXL-lineage models and hitting the burn wall, this is the "more prompt adherence without cranking the dial" play.

Why sliding mode control, anyway

Here's the failure mode. Vanilla CFG computes uncond + cfg * (cond − uncond) at every step. The (cond − uncond) difference is noisy, and it oscillates step to step - so cranking the scale amplifies both the signal and the wobble, and the wobble is what reads as burn and overshoot. SMC-CFG instead treats that difference as a sliding surface and actively drives it toward a stable target instead of just multiplying it.

The node's source spells the whole controller out in a docstring:

e_t  = cond - uncond
s_t  = (e_t - e_{t-1}) + lambda * e_{t-1}
u_sw = -K * sign(s_t)
e'_t = e_t + u_sw
guided = uncond + cfg_scale * e'_t

So it looks at how the guidance changed since the previous step (e_t − e_{t-1}, the derivative term) plus a proportional term scaled by smc_lambda, then applies a switching correction u_sw tuned by smc_k. The result is you can get prompt adherence you'd normally need a higher CFG for, without the deep-fry. It works across architectures - the paper authors demoed it on a spread of models including Wan video, and the r/StableDiffusion thread got a warm reception, with the usual "run 20 gens before you believe the comparison" skepticism attached.

The inputs that actually matter

The node takes model, positive, negative and the rest of the defaults are sane. You'll set:

  • cfg - same dial as always. Default 4, and on SDXL-family models you'll often find yourself lowering it from 7 once SMC is doing the adherence work.
  • smc_lambda (default 6) - the paper's reported sweet spot. Sliding-surface shaping; leave it near 6 unless you're exploring.
  • smc_k (default 0.3) - switching gain. The README is refreshingly honest that 0.3 is a generic starter, not a paper-optimal default, and that FLUX-like flow models often tolerate higher k.
  • switch_mode - sign is the paper behavior. If you see chattering (grainy flickering between steps), flip to tanh or sat with boundary_epsilon around 1e-31e-2 to smooth the switching.
  • no_cfg_warmup_steps - runs the first N steps on the conditional prediction alone, no CFG mixing. Note the README's emphasis: this is conditional-only warmup, not "unconditional."
  • active_start_percent / active_end_percent - gate when the controller is active by denoising progress. The README recommends these over the raw step windows for portability, and the node converts them via percent_to_sigma, so the gating holds across samplers.

The single output is a GUIDER, and that's the whole gotcha in one word: this is not a KSampler drop-in. Feed the guider into SamplerCustom or SamplerCustomAdvanced, not a regular KSampler.

Install

Via ComfyUI Manager (search ComfyUI-CFG-Ctrl), or the manual route:

cd ComfyUI/custom_nodes
git clone https://github.com/xmarre/ComfyUI-CFG-Ctrl
# restart ComfyUI

That's it. The pyproject.toml lists no external dependencies beyond PyTorch/ComfyUI itself - no model files, no weights to fetch. It's pure math on the tensors your sampler already produces.

Traps and troubleshooting

  • Wrong sampler node. Wiring the GUIDER into a plain KSampler fails immediately. Use custom sampling.
  • Distilled / flow models at CFG 1. Guidance-distilled checkpoints bake CFG in and run at scale 1; SMC is fixing a problem you don't have there. The apply_only_if_cfg_gt_1 toggle exists exactly because the author refused to silently self-disable at cfg ≤ 1 - but on a distilled model you should just turn enable_smc off.
  • Chattering or overshoot. Drop to tanh/sat and raise boundary_epsilon. That's the intended stability knob, not a hack.
  • Nothing changes. If enable_smc is off, this is just a plain CFG guider with extra steps - check you actually toggled it on.

It's one of those rare nodes where the defaults are worth trusting first: lambda=6, k=0.3, sign, adjust only if the output tells you to.

Categorysampling/custom_sampling/guiders

Inputs (20)

NameTypeDefaultDescription
modelMODEL
positiveCONDITIONING
negativeCONDITIONING
cfgFLOAT4.00–100
enable_smcBOOLEANtrue
smc_lambdaFLOAT6.00–50
smc_kFLOAT0.300–5
no_cfg_warmup_stepsINT00–50
active_start_stepINT00–10000
active_end_stepINT10000000000–1000000000
active_start_percentFLOAT0.000–1
active_end_percentFLOAT1.000–1
switch_modeCOMBOsign4 options: sign, sat, tanh, vector_norm
boundary_epsilonFLOAT0.0000–10
epsilon_modeCOMBOabsolute2 options: absolute, relative
math_dtypeCOMBOfloat324 options: float32, match, float16, bfloat16
state_dtypeCOMBOmatch4 options: match, float16, bfloat16, float32
apply_only_if_cfg_gt_1BOOLEANfalse
reset_on_shape_changeBOOLEANtrue
detach_prevBOOLEANtrue

Outputs (1)

NameTypeDescription
GUIDERGUIDER