Skip to content

Install Orchestrator

install

Unified installation orchestrator.

Single entry point for the complete ComfyUI installation. All logic lives in domain modules; this file only coordinates the 12-step flow.

Steps:

===== ================================ =================================== Step Label Module ===== ================================ =================================== 1 System Configuration :mod:.system 2 Checking Prerequisites :mod:.system 3 Creating Python Environment :mod:.environment 4 Provisioning Configuration :mod:.environment 5 Setting Up ComfyUI :mod:.repository 6 External Folders :mod:.repository 7 Core Dependencies :mod:.dependencies 8 Python Packages :mod:.dependencies 9 Custom Nodes :mod:.dependencies 10 Performance Optimizations :mod:.optimizations 11 Finalization :mod:.finalize 12 Model Downloads :mod:.finalize ===== ================================ ===================================

Error handling convention

Each module follows one of three strategies:

FatalSystemExit(1) or re-raise. Used when the step is blocking and the installation cannot continue (e.g. Git missing, venv creation failure, ComfyUI clone failure after retries).

Log + continue — Log a warning and return False or None. Used for non-critical enhancements that should not block the installation (e.g. aria2 missing → fallback to httpx, optimization packages failing, individual custom node clone failure).

Best-effortsubprocess.run with return code silently ignored. Used only for truly optional side-effects (e.g. conda init). Always annotated with # best-effort, ignore errors.

All subprocess.run() calls without check=True are annotated with one of these conventions for quick auditability.

Typical usage::

from src.installer.install import run_install
run_install(install_path=Path("D:/ComfyUI"))

run_install(install_path, install_type=InstallType.VENV, *, verbose=False, node_tier=NodeTier.FULL, cuda_version='', skip_nodes=False)

Run the complete ComfyUI installation in 12 unified steps.

Resolves install_path to an absolute path, initialises the logger, then executes each step sequentially. Any fatal failure raises :class:~src.enums.InstallerFatalError.

Parameters:

Name Type Description Default
install_path Path

Root installation directory. Will be resolved to an absolute path.

required
install_type InstallType

Environment type — :attr:InstallType.VENV (default) or :attr:InstallType.CONDA.

VENV
verbose bool

If True, show full subprocess output during installs and git clones.

False
node_tier NodeTier

Custom nodes bundle tier — :attr:NodeTier.MINIMAL, :attr:NodeTier.UMEAIRT, or :attr:NodeTier.FULL (default).

FULL

Raises:

Type Description
InstallerFatalError

On missing prerequisites or fatal errors.

Source code in src/installer/install.py
def run_install(
    install_path: Path,
    install_type: InstallType = InstallType.VENV,
    *,
    verbose: bool = False,
    node_tier: NodeTier = NodeTier.FULL,
    cuda_version: str = "",
    skip_nodes: bool = False,
) -> None:
    """Run the complete ComfyUI installation in 12 unified steps.

    Resolves *install_path* to an absolute path, initialises the
    logger, then executes each step sequentially.  Any fatal
    failure raises :class:`~src.enums.InstallerFatalError`.

    Args:
        install_path: Root installation directory. Will be
            resolved to an absolute path.
        install_type: Environment type — :attr:`InstallType.VENV`
            (default) or :attr:`InstallType.CONDA`.
        verbose: If ``True``, show full subprocess output during
            installs and git clones.
        node_tier: Custom nodes bundle tier —
            :attr:`NodeTier.MINIMAL`, :attr:`NodeTier.UMEAIRT`,
            or :attr:`NodeTier.FULL` (default).

    Raises:
        InstallerFatalError: On missing prerequisites or fatal errors.
    """
    # Resolve to absolute path
    install_path = install_path.resolve()

    log = setup_logger(
        log_file=install_path / "logs" / "install_log.txt",
        total_steps=TOTAL_STEPS,
        verbose=verbose,
    )
    log.banner("UmeAiRT", "ComfyUI — Auto-Installer", __version__)

    # ── Detect previous failed installation ───────────────────────
    marker = install_path / ".install_in_progress"
    _handle_partial_install(install_path, marker, log)

    # Create marker — removed only on successful completion
    install_path.mkdir(parents=True, exist_ok=True)
    marker.write_text("started", encoding="utf-8")

    # ── Load user settings ────────────────────────────────────────
    load_settings(install_path / "scripts" / "local-config.json")

    # ── Step 1: System Configuration ──────────────────────────────
    log.step("System Configuration")
    platform = get_platform()
    platform.enable_long_paths()

    # ── Step 2: Checking Prerequisites ────────────────────────────
    log.step("Checking Prerequisites")

    # Load source dependencies early for tool URLs
    from src.installer.environment import find_source_scripts
    source_dir = find_source_scripts()
    source_deps_file = source_dir / "dependencies.json" if source_dir else None
    if source_deps_file and source_deps_file.exists():
        source_deps = load_dependencies(source_deps_file)
        git_url = source_deps.tools.git_windows.url
        git_sha256 = source_deps.tools.git_windows.sha256
        aria2_url = source_deps.tools.aria2_windows.url
        aria2_sha256 = source_deps.tools.aria2_windows.sha256
    else:
        git_url = ""
        git_sha256 = ""
        aria2_url = ""
        aria2_sha256 = ""

    if not check_prerequisites(log):
        kwargs: dict[str, str] = {}
        if git_url:
            kwargs["git_url"] = git_url
        if git_sha256:
            kwargs["git_sha256"] = git_sha256
        if not install_git(log, **kwargs):
            raise InstallerFatalError("Git is required but could not be installed.")

    ensure_aria2(install_path, log, aria2_url=aria2_url, aria2_sha256=aria2_sha256)

    # ── Step 3: Creating Python Environment ───────────────────────
    log.step("Creating Python Environment")
    python_exe = setup_environment(install_path, install_type, log)

    # ── Step 4: Provisioning Configuration ────────────────────────
    log.step("Provisioning Configuration")
    provision_scripts(install_path, log)

    # Save the installation type for launchers and tools
    scripts_dir = install_path / "scripts"
    (scripts_dir / "install_type").write_text(install_type.value, encoding="utf-8")

    # ── Load dependencies for remaining steps ─────────────────────
    comfy_path = install_path / "ComfyUI"
    deps_file = scripts_dir / "dependencies.json"

    if not deps_file.exists():
        log.error(f"dependencies.json not found at {deps_file}")
        raise InstallerFatalError(f"dependencies.json not found at {deps_file}")

    deps = load_dependencies(deps_file)

    # Set UTF-8 environment
    os.environ["PYTHONUTF8"] = "1"
    os.environ["PYTHONIOENCODING"] = "utf-8"

    # ── Step 5: Setting Up ComfyUI ────────────────────────────────
    log.step("Setting Up ComfyUI")
    setup_git_config(log)
    clone_comfyui(install_path, comfy_path, deps, log)

    # ── Step 6: External Folders ──────────────────────────────────
    log.step("External Folders Architecture")
    setup_junction_architecture(install_path, comfy_path, log)

    # ── Step 6b: GPU Detection & Selection ────────────────────────────
    from src.installer.gpu_setup import detect_and_select_gpu

    cuda_tag = detect_and_select_gpu(platform, deps, log, cuda_override=cuda_version)

    # ── Step 7: Core Dependencies ─────────────────────────────────
    log.step("Core Dependencies")
    install_core_dependencies(python_exe, comfy_path, deps, log, cuda_tag=cuda_tag)

    # ── Step 8: Python Packages ───────────────────────────────────
    log.step("Installing Python Packages")
    install_python_packages(python_exe, deps, log, cuda_tag=cuda_tag)
    install_wheels(python_exe, install_path, deps, log, cuda_tag=cuda_tag)

    # ── Step 9: Custom Nodes ──────────────────────────────────────────
    if skip_nodes:
        log.step(f"Custom Nodes ({node_tier})")
        log.sub("Skipped (--skip-nodes). Nodes will be installed at runtime.", style="cyan")
    else:
        log.step(f"Custom Nodes ({node_tier})")
        install_custom_nodes(python_exe, comfy_path, install_path, log, node_tier=node_tier, source_dir=source_dir)

    # ── Step 10: Performance Optimizations ────────────────────────
    if skip_nodes:
        log.step("Performance Optimizations")
        log.sub("Skipped (--skip-nodes). Optimizations will be applied at runtime.", style="cyan")
    else:
        log.step("Performance Optimizations")
        install_optimizations(python_exe, comfy_path, install_path, deps, log)

    # ── Step 11: Finalization ─────────────────────────────────────
    log.step("Finalization")
    install_cli_in_environment(python_exe, log)
    install_comfy_settings(install_path, log, source_dir=source_dir)
    create_launchers(install_path, log, cuda_tag=cuda_tag)

    # ── Step 12: Model Downloads ──────────────────────────────────
    log.step("Model Downloads")
    offer_model_downloads(install_path, log, source_dir=source_dir)

    # ── Done ──────────────────────────────────────────────────────
    marker.unlink(missing_ok=True)

    # Installation summary table
    from rich.table import Table

    summary = Table(title="Installation Summary", show_header=False, border_style="green")
    summary.add_column("Key", style="bold")
    summary.add_column("Value")
    summary.add_row("Install Path", str(install_path))
    summary.add_row("Environment", install_type.value)
    summary.add_row("Node Tier", node_tier.value)
    summary.add_row("CUDA", cuda_tag)
    summary.add_row("Python", str(python_exe))
    summary.add_row("Platform", platform.name)
    from src.utils.logging import console
    console.print(summary)

    log.success("Installation Complete!", level=0)
    log.success("ComfyUI and all components have been installed.", level=1)
    log.item("Double-click UmeAiRT-Start-ComfyUI to launch!")