Nodes/Causal Forcing for ComfyUI/Causal Forcing Runtime
ComfyUI Node

Causal Forcing Runtime

Causal Forcing Runtime is just a picker — and that's the whole point

By hiroki-abe-58·Created 23 days ago·Updated 23 days ago· 2
Causal Forcing Runtime
    • runtime
    ◄runtime_id▾►

    What this node does, and why it exists

    It's a dropdown with an output. That's it. You pick a name, the node hands you a CAUSALFORCING_RUNTIME token, and you plug that token into Causal Forcing Generate. Nothing here loads a model or touches a GPU.

    That looks pointless until you know what ComfyUI-CausalForcing actually does. Causal Forcing is a 2026 autoregressive distillation of Wan2.1-T2V-1.3B - frame-wise, few-step, the line of work that runs from Self-Forcing through Causal Forcing++ (wan-video.md has the Self-Forcing background). Rather than porting it into ComfyUI's Python, this pack runs the official upstream code, unmodified, in its own Python environment on disk. The node clones nothing, installs nothing, imports no CUDA. It shells out to a separate runtime.

    Which raises the obvious question: which runtime? You - or whoever runs the box - answer that in a config file, not in the workflow. That's deliberate. A workflow can only name a runtime (runtime_id). It can never name an executable, a command line or a WSL distro. Since ComfyUI workflows are routinely pasted around and driven over the HTTP API, letting a graph choose what to execute would be a gift-wrapped remote code execution. The config file lives at <ComfyUI user dir>/causalforcing.runtimes.json - the root of the user directory, outside the per-user folder the userdata API serves - or wherever COMFYUI_CAUSALFORCING_CONFIG points.

    So the honest description of this node: it's the gate between your graph and a Linux venv that has flash-attn 2 and the pinned Causal Forcing checkout in it.

    Inputs and output

    runtime_id is the only input, and it's an enum whose choices are read from that JSON file when ComfyUI starts. Untouched install, no config: the only option is literally (no runtime configured).

    The output is runtime, typed CAUSALFORCING_RUNTIME. It's a small dict ({"runtime_id": "..."}), not a handle to anything loaded. One Runtime node can feed several Generate nodes - the pack's own causalforcing_2step_vs_4step.json does exactly that so both models share one runtime.

    Generate re-resolves the id at execution time. Rename or delete a runtime after you've saved a workflow and you'll get a ValueError telling you the id isn't configured and printing the path it looked in - not a silent fallback.

    Setting up a runtime

    Clone the node first (ComfyUI Manager → search "Causal Forcing", or):

    cd ComfyUI/custom_nodes
    git clone https://github.com/hiroki-abe-58/ComfyUI-CausalForcing
    

    The pack adds zero Python dependencies to ComfyUI. The expensive part is the runtime, and per docs/SETUP.md it's Linux-side only (WSL2 on a Windows host):

    uv venv --python 3.10 /opt/causalforcing/venv
    uv pip install --python /opt/causalforcing/venv/bin/python \
      --index-url https://download.pytorch.org/whl/cu128 torch==2.8.0+cu128 torchvision==0.23.0+cu128
    # flash-attn 2.8.3 wheel from the GitHub release; check the sha256 from runtime/requirements-reference.txt
    uv pip install --python /opt/causalforcing/venv/bin/python ./flash_attn-2.8.3+cu12torch2.8cxx11abiTRUE-cp310-cp310-linux_x86_64.whl
    uv pip install --python /opt/causalforcing/venv/bin/python -r requirements-reference.txt
    
    git clone https://github.com/thu-ml/Causal-Forcing /opt/causalforcing/Causal-Forcing
    git -C /opt/causalforcing/Causal-Forcing checkout da3ddf1a590f30c9edc568e11c2f77170995c31c
    

    flash-attn 2 isn't optional - upstream's cross-attention path has no SDPA fallback here. Then the weights: Wan2.1-T2V-1.3B at the pinned revision (~17 GB) and zhuhz22/Causal-Forcing checkpoints (~5.7 GB each). Upstream's own README also downloads the 14B Wan, which is training-only; skip it.

    Copy examples/causalforcing.runtimes.example.json to ComfyUI/user/causalforcing.runtimes.json, keep one entry, fix the paths, and restart ComfyUI.

    The keys you'll actually touch: kind (wsl or posix), distro (from wsl -l -v, WSL only), python, upstream_dir, models_dir, and checkpoints - a map of model id → checkpoint path. Only profiles listed there are selectable in Generate. Set offload_text_encoder: true on anything under 40 GB of VRAM; that mirrors what upstream's inference.py does automatically. env is allowlisted to CC, TRITON_CACHE_DIR, TORCHINDUCTOR_CACHE_DIR, XDG_CACHE_HOME, HF_HOME and CUDA_VISIBLE_DEVICES, and unknown keys make the whole file invalid rather than quietly ignored.

    Common issues

    • "no runtime configured" in the dropdown - the config file is missing or at the wrong path. Restart ComfyUI after creating it; the enum is read at import.
    • WSL job paths - job temp files on a network or UNC path break the /mnt/<drive> translation. Local drives only.
    • Native Windows runtimes aren't supported, and Linux hosts with real weights are explicitly listed as untested upstream in the README - the reference setup was Windows 11 + WSL2 Ubuntu 24.04 on a 5090.
    • Nothing is verified yet: run Causal Forcing Doctor before you queue a video and you'll know whether the venv, the commit and the checkpoints line up.

    One framing note, since it explains why this pack exists at all: the popular way people got Causal Forcing into ComfyUI was a community safetensors repack driving a custom ar_sampler. This pack goes the other direction - official checkpoints, official pipeline, and it refuses a partial weight load. That's a heavier install for a promise of "the same video the official script makes."

    CategoryCausalForcing

    Inputs (1)

    NameTypeDefaultDescription
    runtime_idCOMBORuntimes come from causalforcing.runtimes.json (administrator config), never from the workflow.

    Outputs (1)

    NameTypeDescription
    runtimeCAUSALFORCING_RUNTIME—