Skip to content

Finalize

finalize

Installation finalization — Steps 11-12.

Post-install tasks that wrap up the installation:

  • CLI (Step 11): installs comfyui-installer into the venv so generated tool scripts (Update, Download-Models) work.
  • Settings (Step 11): copies custom ComfyUI UI settings from the local scripts/comfy.settings.json.
  • Launchers (Step 11): generates .bat / .sh launcher and tool scripts.
  • Models (Step 12): offers interactive model pack downloads from model_manifest.json.

install_cli_in_environment(python_exe, log)

Install the comfyui-installer CLI into the venv.

Uses pip install -e so the CLI stays in sync with the installer source. Required for generated tool scripts (UmeAiRT-Update.bat, UmeAiRT-Download-Models.bat).

Parameters:

Name Type Description Default
python_exe Path

Path to the venv Python executable.

required
log InstallerLogger

Installer logger for user-facing messages.

required
Source code in src/installer/finalize.py
def install_cli_in_environment(
    python_exe: Path,
    log: InstallerLogger,
) -> None:
    """Install the ``comfyui-installer`` CLI into the venv.

    Uses ``pip install -e`` so the CLI stays in sync with the
    installer source. Required for generated tool scripts
    (``UmeAiRT-Update.bat``, ``UmeAiRT-Download-Models.bat``).

    Args:
        python_exe: Path to the venv Python executable.
        log: Installer logger for user-facing messages.
    """
    log.item("Installing comfyui-installer CLI into environment...")
    installer_root = Path(__file__).resolve().parent.parent.parent
    uv_install(python_exe, editable=installer_root)
    log.sub("comfyui-installer CLI available in environment.", style="success")

install_comfy_settings(install_path, log, *, source_dir=None)

Copy custom ComfyUI UI settings from the local source.

Searches for comfy.settings.json in the source scripts/ directory and copies it to install_path/user/default/.

Parameters:

Name Type Description Default
install_path Path

Root installation directory.

required
log InstallerLogger

Installer logger for user-facing messages.

required
source_dir Path | None

Pre-resolved source scripts directory.

None
Source code in src/installer/finalize.py
def install_comfy_settings(
    install_path: Path,
    log: InstallerLogger,
    *,
    source_dir: Path | None = None,
) -> None:
    """Copy custom ComfyUI UI settings from the local source.

    Searches for ``comfy.settings.json`` in the source ``scripts/``
    directory and copies it to ``install_path/user/default/``.

    Args:
        install_path: Root installation directory.
        log: Installer logger for user-facing messages.
        source_dir: Pre-resolved source scripts directory.
    """
    import shutil

    if source_dir is None:
        from src.installer.environment import find_source_scripts
        try:
            source_dir = find_source_scripts()
        except FileNotFoundError:
            log.warning("Source scripts directory not found. Skipping settings.", level=2)
            return

    settings_src = source_dir / "comfy.settings.json"
    if not settings_src.exists():
        log.warning("comfy.settings.json not found in source scripts.", level=2)
        return

    dest = install_path / "user" / "default" / "comfy.settings.json"
    dest.parent.mkdir(parents=True, exist_ok=True)

    if dest.exists() and settings_src.stat().st_mtime <= dest.stat().st_mtime:
        log.sub("ComfyUI settings already up to date.", style="success")
        return

    shutil.copy2(settings_src, dest)
    log.item("ComfyUI custom settings provisioned.")

create_launchers(install_path, log, *, cuda_tag=None)

Generate cross-platform launcher and tool scripts.

Creates:

  • Performance launcher: --use-sage-attention --auto-launch
  • interactive network mode prompt (local/open).
  • LowVRAM launcher: same + --lowvram --disable-smart-memory --fp8.
  • Tool scripts: Model Downloader and Updater wrappers.

The --listen address is chosen by the user at launch time via the prompt embedded in each launcher script (default: local 127.0.0.1, option 0.0.0.0 for RunPod/cloud).

On Windows, creates .bat files; on Linux/macOS .sh files with the executable bit set. Appends --directml to ComfyUI launch arguments if running on Windows AMD.

Parameters:

Name Type Description Default
install_path Path

Root installation directory.

required
log InstallerLogger

Installer logger for user-facing messages.

required
cuda_tag str | None

The active GPU tag (used to detect 'directml').

None
Source code in src/installer/finalize.py
def create_launchers(
    install_path: Path,
    log: InstallerLogger,
    *,
    cuda_tag: str | None = None,
) -> None:
    """Generate cross-platform launcher and tool scripts.

    Creates:

    - **Performance launcher**: ``--use-sage-attention --auto-launch``
      + interactive network mode prompt (local/open).
    - **LowVRAM launcher**: same + ``--lowvram --disable-smart-memory --fp8``.
    - **Tool scripts**: Model Downloader and Updater wrappers.

    The ``--listen`` address is chosen by the user at launch time
    via the prompt embedded in each launcher script (default: local
    ``127.0.0.1``, option ``0.0.0.0`` for RunPod/cloud).

    On Windows, creates ``.bat`` files; on Linux/macOS ``.sh`` files
    with the executable bit set.
    Appends ``--directml`` to ComfyUI launch arguments if running on Windows AMD.

    Args:
        install_path: Root installation directory.
        log: Installer logger for user-facing messages.
        cuda_tag: The active GPU tag (used to detect 'directml').
    """
    log.item("Creating launcher scripts...")

    is_windows = sys.platform == "win32"

    perf_args = "--use-sage-attention --auto-launch"
    if cuda_tag == "directml":
        perf_args = f"--directml {perf_args}"
    lowvram_args = f"{perf_args} --disable-smart-memory --lowvram --fp8_e4m3fn-text-enc"

    launchers: list[tuple[str, str, str]] = [
        ("UmeAiRT-Start-ComfyUI", "Performance Mode", perf_args),
        ("UmeAiRT-Start-ComfyUI_LowVRAM", "Low VRAM / Stability Mode", lowvram_args),
    ]

    for name, mode_label, args in launchers:
        if is_windows:
            _write_bat_launcher(install_path, name, mode_label, args, log)
        else:
            _write_sh_launcher(install_path, name, mode_label, args, log)

    # Tool scripts (model downloader, updater)
    if is_windows:
        tools: list[tuple[str, str, str]] = [
            ("UmeAiRT-Download-Models", "Model Downloader",
             'umeairt-comfyui-installer download-models --path "%InstallPath%"'),
            ("UmeAiRT-Update", "Updater",
             'umeairt-comfyui-installer update --path "%InstallPath%"'),
        ]
        for tool_name, tool_label, tool_cmd in tools:
            _write_bat_tool(install_path, tool_name, tool_label, tool_cmd, log)
    else:
        tools = [
            ("UmeAiRT-Download-Models", "Model Downloader",
             'umeairt-comfyui-installer download-models --path "$SCRIPT_DIR"'),
            ("UmeAiRT-Update", "Updater",
             'umeairt-comfyui-installer update --path "$SCRIPT_DIR"'),
        ]
        for tool_name, tool_label, tool_cmd in tools:
            _write_sh_tool(install_path, tool_name, tool_label, tool_cmd, log)

offer_model_downloads(install_path, log, *, source_dir=None)

Offer interactive model pack downloads via the unified catalog.

Searches for model_manifest.json in multiple locations:

  1. install_path/scripts/
  2. Source scripts/ directory (development checkout).
  3. Parent of source scripts/ directory.

If found, prompts the user and delegates to :func:src.downloader.engine.interactive_download.

Parameters:

Name Type Description Default
install_path Path

Root installation directory.

required
log InstallerLogger

Installer logger for user-facing messages.

required
source_dir Path | None

Pre-resolved source scripts directory.

None
Source code in src/installer/finalize.py
def offer_model_downloads(
    install_path: Path,
    log: InstallerLogger,
    *,
    source_dir: Path | None = None,
) -> None:
    """Offer interactive model pack downloads via the unified catalog.

    Searches for ``model_manifest.json`` in multiple locations:

    1. ``install_path/scripts/``
    2. Source ``scripts/`` directory (development checkout).
    3. Parent of source ``scripts/`` directory.

    If found, prompts the user and delegates to
    :func:`src.downloader.engine.interactive_download`.

    Args:
        install_path: Root installation directory.
        log: Installer logger for user-facing messages.
        source_dir: Pre-resolved source scripts directory.
    """

    # Search for catalog in multiple locations
    search_paths = [
        install_path / "scripts" / "model_manifest.json",
    ]

    # Also check source scripts directory (running from source checkout)
    if source_dir is None:
        from src.installer.environment import find_source_scripts
        try:
            source_dir = find_source_scripts()
        except FileNotFoundError:
            source_dir = None

    if source_dir:
        search_paths.append(source_dir / "model_manifest.json")
        search_paths.append(source_dir.parent / "model_manifest.json")

    catalog_path = None
    for path in search_paths:
        if path.exists():
            catalog_path = path
            break

    if catalog_path is None:
        log.info("No model catalog found. Searched:")
        for p in search_paths:
            log.sub(f"  {p}", style="dim")
        log.info("You can download models later with: comfyui-installer download-models")
        return

    log.sub(f"Catalog found: {catalog_path}", style="success")

    if not confirm("Would you like to download model packs now?"):
        log.sub("Model downloads skipped. You can download later with: comfyui-installer download-models")
        return

    from src.downloader.engine import interactive_download, load_catalog

    catalog = load_catalog(catalog_path)
    models_dir = install_path / "models"
    interactive_download(catalog, models_dir)