# Fooocus Admin & Developer Guide

This guide is for operators, system administrators, and developers who deploy, harden, extend, or audit Fooocus. It documents the architecture, the complete configuration surface, the security model, operational procedures, and the internal code structure in enough depth to operate Fooocus confidently or rebuild an understanding of it from scratch.

For end-user, task-oriented documentation (installation, generation modes, prompts), see the [User Guide](lllyasviel__Fooocus__UserGuide.md).

> [!NOTE]
> Fooocus is in **limited long-term support (LTS) — bug fixes only**, built entirely on Stable Diffusion XL. There are no current plans to migrate to newer architectures. Operationally, this means the codebase is stable and the dependency pins are fixed; the main maintenance burden is keeping the runtime (PyTorch, drivers, NumPy) compatible with newer hardware. This guide flags those points explicitly.

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Architecture](#2-architecture)
3. [The Vendored `ldm_patched` Backend and Monkey-Patching](#3-the-vendored-ldm_patched-backend-and-monkey-patching)
4. [Requirements and Dependencies](#4-requirements-and-dependencies)
5. [Startup and the Generation Pipeline](#5-startup-and-the-generation-pipeline)
6. [Configuration Mastery](#6-configuration-mastery)
7. [Presets](#7-presets)
8. [Command-Line Reference](#8-command-line-reference)
9. [Model Management and Auto-Download](#9-model-management-and-auto-download)
10. [Security Analysis](#10-security-analysis)
11. [Deployment](#11-deployment)
12. [Operations](#12-operations)
13. [Repository Structure](#13-repository-structure)
14. [Module Reference](#14-module-reference)
15. [Code Quality and Patterns](#15-code-quality-and-patterns)
16. [Potential Improvements](#16-potential-improvements)
17. [Quick Reference](#17-quick-reference)

---

## 1. Executive Summary

Fooocus (version **2.5.5** at the documented commit) is a single-process Python application that wraps a **Stable Diffusion XL** diffusion pipeline behind a **Gradio** web UI. Its defining characteristic is opinionated automation: a large body of sampling, prompt-expansion, and scheduling logic is applied automatically so that users do not configure the model.

Key architectural facts an operator must know:

- **Single process, single GPU.** Fooocus runs one Gradio server and one background worker thread. There is no horizontal scaling primitive; multi-GPU means multiple independent instances.
- **No bundled models.** All weights are downloaded on demand from Hugging Face on first run and on preset switches. This is the single largest operational and supply-chain consideration.
- **A vendored, monkey-patched diffusion backend.** The `ldm_patched/` package is a renamed fork of the ComfyUI backend, and Fooocus patches it at import time (`modules/patch*.py`, `modules/sample_hijack.py`). Upgrading the vendored backend can silently break those patches.
- **Auto-update on launch.** The recommended entry point (`entry_with_update.py`) performs a `git fetch` + hard reset to `origin` before every run.
- **Minimal but real attack surface.** Optional network exposure (`--listen`, `--share`), a simple SHA-256 auth file, globally disabled TLS verification, and known community-reported issues (arbitrary code execution via `eval()`, a path-traversal report) make hardening important when Fooocus is exposed beyond `localhost`.

```text
                    ┌──────────────────────────────────────────────┐
   Browser  ───────▶│  Gradio server (Blocks, port 7865)           │
                    │   webui.py — UI definition + event wiring     │
                    └───────────────┬──────────────────────────────┘
                                    │ AsyncTask queued
                                    ▼
                    ┌──────────────────────────────────────────────┐
                    │  Background worker thread (async_worker.py)   │
                    │   process_prompt → diffusion → save_and_log   │
                    └───────────────┬──────────────────────────────┘
                                    │ calls
                                    ▼
                    ┌──────────────────────────────────────────────┐
                    │  default_pipeline.py  (Fooocus orchestration) │
                    │   patched via modules/patch*.py at import     │
                    └───────────────┬──────────────────────────────┘
                                    │ wraps
                                    ▼
                    ┌──────────────────────────────────────────────┐
                    │  ldm_patched/  (vendored ComfyUI backend)     │
                    │   model_management · samplers · sd · cldm     │
                    └──────────────────────────────────────────────┘
```

---

## 2. Architecture

Fooocus is structured in three layers:

1. **UI layer** (`webui.py`, `shared.py`, `modules/gradio_hijack.py`, `modules/ui_gradio_extensions.py`, `javascript/`, `css/`). Defines a single `gr.Blocks` interface and wires every control to a callback. The interface is queued (`.queue()`), so generation requests are serialized.

2. **Orchestration layer** (`modules/`). The Fooocus-specific logic: the async task model, prompt processing, style application, the diffusion pipeline orchestration, inpaint/upscale/enhance workflows, LoRA handling, metadata, and the extensive runtime patches applied to the backend.

3. **Backend layer** (`ldm_patched/`). A vendored fork of the ComfyUI diffusion engine providing model loading, memory management, samplers, schedulers, VAE, ControlNet (`cldm`), and the latent-diffusion model code.

### Request lifecycle

- The user clicks **Generate**. `webui.py:get_task()` packs every UI control value (in a fixed positional order) into a `worker.AsyncTask`.
- The task is appended to `async_worker.async_tasks`. A single background **worker thread** (started at import) picks it up.
- `AsyncTask.__init__` unpacks the positional args into named attributes (this fixed ordering is the contract between `webui.py` and `async_worker.py` — see [Code Quality](#15-code-quality-and-patterns)).
- The worker runs the pipeline and yields progress events (`preview`, `results`, `finish`) back to the UI through `task.yields`, which `generate_clicked()` consumes in a polling loop.

### Concurrency model

There is exactly **one** worker thread and the Gradio queue serializes requests. Generation is therefore effectively single-task. The `--multi-user` flag (inherited from the backend) affects storage scoping only, not parallel execution. Interruption (Stop/Skip) is implemented via a backend `interrupt_processing` mutex.

> [!IMPORTANT]
> Because generation is single-threaded and single-GPU per process, a busy instance blocks all users. To serve multiple concurrent users, run multiple instances (each pinned to a GPU with `--gpu-device-id`) behind a load balancer with sticky sessions.

---

## 3. The Vendored `ldm_patched` Backend and Monkey-Patching

This is the most important architectural fact for anyone maintaining or forking Fooocus.

`ldm_patched/` is a **vendored, renamed fork of the ComfyUI backend** (`comfy/`). It includes `model_management`, `samplers`, `sd`, `controlnet/cldm`, `k_diffusion`, `unipc`, the latent-diffusion model code (`ldm/`), and the engine's own argument parser (`ldm_patched/modules/args_parser.py`).

Fooocus does **not** modify the backend in place at the call site. Instead, at the moment `modules/async_worker.py` is imported, it calls `patch_all()` from `modules/patch.py`, which **monkey-patches** functions and methods inside `ldm_patched` (and a few other libraries) at runtime. The patch modules are:

| Module | What it patches |
|--------|-----------------|
| `modules/patch.py` | Core diffusion patches: weight calculation, UNet forward, ADM guidance, sharpness, CFG mimicking, sampler hooks. Defines `PatchSettings` (sharpness, ADM scales, controlnet softness, adaptive CFG). |
| `modules/patch_clip.py` | Patches CLIP text-encoder behavior. |
| `modules/patch_precision.py` | Patches numeric precision handling. |
| `modules/sample_hijack.py` | Replaces/extends the sampling loop (scheduler selection, etc.). |
| `modules/anisotropic.py` | Anisotropic filtering used by the sharpness patch. |

> [!WARNING]
> **Upgrading the vendored backend can silently break the patches.** Because the patches target specific functions/methods in `ldm_patched` by name and signature, replacing `ldm_patched/` with a newer ComfyUI snapshot — without re-validating every patch — can cause subtle, non-crashing quality regressions (wrong guidance, missing sharpness) rather than loud errors. Treat `ldm_patched/` as a pinned, co-versioned component. Re-test image output against known seeds after any backend change.

> [!NOTE]
> This is the same hazard class as AUTOMATIC1111's `sd_hijack` patches over k-diffusion/CLIP. If you maintain a fork, keep a fixed-seed regression suite that compares output images before and after touching the backend or the patch modules.

A practical consequence: **the CLI flag surface is split across two parsers.** Fooocus's UX flags are defined in `args_manager.py`; the diffusion-engine flags (VRAM mode, precision, attention implementation, networking) are defined in `ldm_patched/modules/args_parser.py`. `args_manager.py` imports the backend parser and adds its own arguments to it, so a single `--help` shows both. See [Command-Line Reference](#8-command-line-reference).

---

## 4. Requirements and Dependencies

### Runtime requirements

| Resource | Minimum | Notes |
|----------|---------|-------|
| GPU | 4 GB VRAM (NVIDIA) | AMD beta (ROCm/DirectML); Intel/Apple via fallbacks |
| RAM | 8 GB + swap | 16 GB+ recommended; ≥40 GB free disk per drive if `CPUAllocator` errors appear |
| Python | 3.10 | `environment.yaml` pins `python=3.10` |
| Disk | ~10–20 GB for default models, more per preset | No models are bundled |

### Pinned dependencies (`requirements_versions.txt`)

```text
torchsde==0.2.6                 einops==0.8.0
transformers==4.42.4            safetensors==0.4.3
accelerate==0.32.1              pyyaml==6.0.1
pillow==10.4.0                  scipy==1.14.0
tqdm==4.66.4                    psutil==6.0.0
pytorch_lightning==2.3.3        omegaconf==2.3.0
gradio==3.41.2                  pygit2==1.15.1
opencv-contrib-python-headless==4.10.0.84
httpx==0.27.0                   onnxruntime==1.18.1
timm==1.0.7                     numpy==1.26.4
tokenizers==0.19.1              packaging==24.1
rembg==2.0.57                   groundingdino-py==0.4.0
segment_anything==1.0
```

PyTorch itself is installed separately by `launch.py:prepare_environment()`, which defaults to:

```text
pip install torch==2.1.0 torchvision==0.16.0 --extra-index-url https://download.pytorch.org/whl/cu121
```

> [!CAUTION]
> **The PyTorch 2.1.0 / CUDA 12.1 pin is the #1 source of "won't run on new hardware" reports.** Newer GPUs (e.g. RTX 50-series, compute capability `sm_120`) are not supported by this build, producing `CUDA error: no kernel image is available`. Override with the `TORCH_COMMAND` / `TORCH_INDEX_URL` environment variables (below) or pre-install a compatible PyTorch before launch.

> [!NOTE]
> `numpy==1.26.4` is pinned deliberately. Allowing NumPy 2.x into the environment causes `numpy.core.multiarray failed to import`. Do not blanket-upgrade the environment.

### Environment variables that influence installation

| Variable | Default | Effect |
|----------|---------|--------|
| `TORCH_INDEX_URL` | `https://download.pytorch.org/whl/cu121` | PyTorch wheel index. |
| `TORCH_COMMAND` | `pip install torch==2.1.0 torchvision==0.16.0 --extra-index-url $TORCH_INDEX_URL` | Full torch install command. Override to change torch version. |
| `REQS_FILE` | `requirements_versions.txt` | Requirements file to install. |
| `XFORMERS_PACKAGE` | `xformers==0.0.23` | xformers build (only if xformers install is enabled). |
| `INDEX_URL` | *(empty)* | Extra pip index URL (`modules/launch_util.py`). |
| `HF_MIRROR` | `https://huggingface.co` | Hugging Face mirror for model downloads (also `--hf-mirror`). |
| `LAUNCH_LIVE_OUTPUT` | *(empty)* | Stream subprocess output during install. |

---

## 5. Startup and the Generation Pipeline

### Entry chain

```text
entry_with_update.py   → git fetch + (fast-forward) hard reset to origin, then `from launch import *`
   └─ launch.py         → prepare_environment() [pip installs], build_launcher() [writes run*.bat on Windows],
                          parse args, download_models(), then `from webui import *`
        └─ webui.py      → build gr.Blocks UI, start the worker thread, launch the Gradio server (port 7865)
```

- `entry_with_update.py` uses `pygit2` to fetch `origin` and fast-forward the working tree. If you modified files, it prints `Update failed - Did you modify any file?` and continues with your local code.
- `launch.py` sets `GRADIO_SERVER_PORT=7865` (if unset), enables the MPS fallback for Apple Silicon, and — notably — sets `ssl._create_default_https_context = ssl._create_unverified_context` (see [Security](#10-security-analysis)).
- `build_launcher.py` writes `run.bat`, `run_anime.bat`, and `run_realistic.bat` on Windows standalone builds.

### The generation pipeline (`async_worker.py` → `default_pipeline.py`)

Each `AsyncTask` is processed roughly as follows:

1. **`apply_patch_settings`** — installs per-process `PatchSettings` (sharpness, ADM, adaptive CFG) keyed by PID.
2. **Performance overrides** — for Extreme Speed / Lightning / Hyper-SD, the worker downloads the acceleration LoRA and forces sampler, scheduler, CFG, sharpness, ADM, and refiner-switch values (`set_lcm_defaults`, `set_lightning_defaults`, `set_hyper_sd_defaults`).
3. **`apply_image_input`** — inspects the active tab and appends "goals" (`vary`, `upscale`, `inpaint`, `cn`, `enhance`). Downloads ControlNet / IP-Adapter / inpaint / upscale models as needed.
4. **`process_prompt`** — splits multi-line prompts, applies wildcards (`__file__`) and arrays (`[[a,b,c]]`), applies styles, runs Fooocus V2 prompt expansion, encodes positive/negative conditioning via CLIP, and refreshes models/LoRAs.
5. **Diffusion** — `pipeline.process_diffusion(...)` runs the sampler with the chosen steps, switch point (refiner), and resolution.
6. **Post-process** — inpaint post-processing, optional NSFW censor (`extras/censor.py`), then `save_and_log` writes the image plus a metadata dictionary (prompt, model, seed, sampler, LoRAs, ADM guidance, version, …) to `outputs/` via `private_logger`.

The worker yields `preview`/`results`/`finish` events to the UI throughout.

> [!NOTE]
> "Goals" are additive. The Image Prompt tab can mix with Upscale/Variation or Inpaint via the `mixing_image_prompt_and_*` flags, which is why `apply_image_input` can append both `cn` and `inpaint`.

---

## 6. Configuration Mastery

Fooocus configuration is layered. Understanding the precedence is the single most useful operator skill.

### Precedence (highest wins)

```text
1. Environment variable matching the config key   (e.g. set `default_cfg_scale` in the env)
2. CLI argument                                    (for the subset exposed as flags, e.g. --output-path)
3. User config file: config.txt                    (JSON; created on first launch)
4. The active preset: presets/<name>.json
5. presets/default.json                            (loaded first as the base)
6. Hard-coded defaults in modules/config.py
```

`modules/config.py` loads `presets/default.json`, then merges `config.txt`, then merges the active preset, then resolves every key through `get_config_item_or_set_default()` (which also checks for an environment-variable override and validates the value/type).

### `config.txt`

A JSON file at the repo root (path overridable with the `config_path` env var). It is **created on first launch** with the currently-resolved values, and thereafter you edit it to change defaults. Fooocus also always writes **`config_modification_tutorial.txt`** — a non-effective tutorial/example file listing every key with its current value and formatting rules.

> [!TIP]
> Edit `config.txt`, never `config_modification_tutorial.txt`. On Windows paths, escape backslashes (`\\`) and ensure there is no trailing comma before the closing `}`.

### Path configuration

| Key | Default (relative to repo) | Purpose |
|-----|----------------------------|---------|
| `path_checkpoints` | `../models/checkpoints/` | Base models (list-valued; multiple folders allowed). |
| `path_loras` | `../models/loras/` | LoRA files (list-valued). |
| `path_embeddings` | `../models/embeddings/` | Textual-inversion embeddings. |
| `path_vae` | `../models/vae/` | Standalone VAEs. |
| `path_vae_approx` | `../models/vae_approx/` | Preview approximation VAEs. |
| `path_upscale_models` | `../models/upscale_models/` | Upscaler. |
| `path_inpaint` | `../models/inpaint/` | Inpaint head + patch models. |
| `path_controlnet` | `../models/controlnet/` | ControlNet / IP-Adapter. |
| `path_clip_vision` | `../models/clip_vision/` | CLIP-Vision for image prompt. |
| `path_fooocus_expansion` | `../models/prompt_expansion/fooocus_expansion` | GPT-2 expansion model. |
| `path_wildcards` | `../wildcards/` | Wildcard text files. |
| `path_safety_checker` | `../models/safety_checker/` | NSFW safety checker. |
| `path_sam` | `../models/sam/` | Segment Anything models. |
| `path_outputs` | `../outputs/` | Generated images + HTML logs (override with `--output-path`). |

> [!NOTE]
> A deprecated `user_path_config.txt` format is auto-migrated to the new `path_*` keys at startup (`try_load_deprecated_user_path_config`), backing up the old file. This is transparent but worth knowing if you inherit an old install.

### Generation defaults (selected — full set in `modules/config.py`)

| Key | Default | Validated range / values |
|-----|---------|--------------------------|
| `default_model` | `model.safetensors` (preset overrides) | string |
| `default_refiner` | `None` | string |
| `default_refiner_switch` | `0.8` | 0–1 |
| `default_cfg_scale` | `7.0` (presets lower it) | number |
| `default_sample_sharpness` | `2.0` | number |
| `default_sampler` | `dpmpp_2m_sde_gpu` | must be in `sampler_list` |
| `default_scheduler` | `karras` | must be in `scheduler_list` |
| `default_vae` | `Default (model)` | string |
| `default_styles` | `["Fooocus V2","Fooocus Enhance","Fooocus Sharp"]` | all in legal style names |
| `default_performance` | `Speed` | one of Performance values |
| `default_max_lora_number` | `5` | ≥1 |
| `default_loras_min_weight` / `max_weight` | `-2` / `2` | -10–10 |
| `default_aspect_ratio` | `1152*896` | in `available_aspect_ratios` |
| `default_max_image_number` | `32` | ≥1 |
| `default_image_number` | `2` | 1–max |
| `default_output_format` | `png` | png/jpeg/webp |
| `default_clip_skip` | `2` | 1–12 |
| `default_cfg_tsnr` | `7.0` | number |
| `default_inpaint_engine_version` | `v2.6` | None/v1/v2.5/v2.6 |
| `default_black_out_nsfw` | `False` | bool — forces NSFW censoring |
| `default_save_metadata_to_images` | `False` | bool |
| `default_metadata_scheme` | `fooocus` | fooocus/a1111 |
| `temp_path` | system temp `/fooocus` | string |
| `temp_path_cleanup_on_launch` | `True` | bool |

> [!IMPORTANT]
> Set `default_black_out_nsfw: true` in `config.txt` to force the safety checker on for every generation regardless of the per-task checkbox. This downloads and runs `stable-diffusion-safety-checker.bin` and is the recommended setting for any shared/public deployment.

---

## 7. Presets

A preset is a JSON file in `presets/` that overrides config keys. The mapping from config key → metadata parameter lives in `possible_preset_keys` in `modules/config.py`. Shipped presets:

| Preset | Base model | Refiner | CFG | Default styles | Extra |
|--------|-----------|---------|-----|----------------|-------|
| `default` | juggernautXL_v8Rundiffusion | None | 4.0 | V2 + Enhance + Sharp | + SDXL offset LoRA @0.1 |
| `anime` | animaPencilXL_v500 | None | 6.0 | V2 + Semi Realistic + Masterpiece | — |
| `realistic` | realisticStockPhoto_v20 | None | 3.0 | V2 + Photograph + Negative | + film LoRA @0.25, strong negative prompt |
| `lcm` | juggernautXL_v8 | None | 4.0 | V2 + Enhance + Sharp | Extreme Speed |
| `lightning` | juggernautXL_v8 | None | 4.0 | V2 + Enhance + Sharp | Lightning |
| `playground_v2.5` | playground-v2.5-1024px | None | 2.0 | V2 | `edm_playground_v2.5` scheduler |
| `pony_v6` | ponyDiffusionV6XL | None | 7.0 | Fooocus Pony | + dedicated VAE |
| `sai` | sd_xl_base_1.0 | sd_xl_refiner_1.0 @0.75 | 7.0 | V2 + Cinematic | + SDXL offset LoRA @0.5 |

Each preset declares `checkpoint_downloads`, `lora_downloads`, `vae_downloads`, `embeddings_downloads` (the Hugging Face URLs to fetch) and `previous_default_models` (fallbacks so a preset switch reuses a model you already have instead of downloading the newest).

> [!TIP]
> To create a custom edition, copy a preset JSON, point it at your models with their download URLs, and launch with `--preset yourname`. Setting `REWRITE_PRESET = True` in `config.py` (developer-only) makes Fooocus dump the resolved config back to the preset file and exit.

---

## 8. Command-Line Reference

Flags come from two parsers. Fooocus-specific flags (`args_manager.py`):

| Flag | Type | Default | Purpose |
|------|------|---------|---------|
| `--share` | bool | off | Public Gradio share link. |
| `--preset` | str | None | Apply a preset. |
| `--disable-preset-selection` | bool | off | Hide in-browser preset dropdown. |
| `--language` | str | `default` | Use `language/<x>.json` for UI translation. |
| `--disable-offload-from-vram` | bool | off | Keep models in VRAM (some Macs need this). |
| `--theme` | str | None | `light` or `dark`. |
| `--disable-image-log` | bool | off | Don't write images/logs to `outputs/`. |
| `--disable-analytics` | bool | off | Disable Gradio analytics. |
| `--disable-metadata` | bool | off | Don't embed metadata in images. |
| `--disable-preset-download` | bool | off | Skip preset model downloads. |
| `--disable-enhance-output-sorting` | bool | off | Don't reorder enhance gallery. |
| `--enable-auto-describe-image` | bool | off | Auto-describe when prompt is empty. |
| `--always-download-new-model` | bool | off | Download newest preset models (no fallback). |
| `--rebuild-hash-cache` | int | — | Regenerate model/LoRA hashes (optional thread count). |

Backend/engine flags (`ldm_patched/modules/args_parser.py`) — selected:

| Flag | Default | Purpose |
|------|---------|---------|
| `--listen` | `127.0.0.1` | Bind address (set to `0.0.0.0` to expose). |
| `--port` | `8188`* | Server port (*Fooocus sets the Gradio port to `7865` separately). |
| `--web-upload-size` | `100` | Max upload size (MB). |
| `--disable-header-check` | None | Disable host-header check. |
| `--hf-mirror` | None | Hugging Face mirror. |
| `--external-working-path` / `--output-path` / `--temp-path` / `--cache-path` | None | Path overrides. |
| `--in-browser` / `--disable-in-browser` | — | Auto-open browser. |
| `--gpu-device-id` | None | Select GPU (sets `CUDA_VISIBLE_DEVICES`). |
| `--all-in-fp32` / `--all-in-fp16` | — | Global precision. |
| `--unet-in-bf16` / `--unet-in-fp16` / `--unet-in-fp8-e4m3fn` / `--unet-in-fp8-e5m2` | — | UNet precision. |
| `--vae-in-fp16` / `--vae-in-fp32` / `--vae-in-bf16` / `--vae-in-cpu` | — | VAE precision/placement. |
| `--clip-in-fp8-e4m3fn` / `--clip-in-fp8-e5m2` / `--clip-in-fp16` / `--clip-in-fp32` | — | Text-encoder precision. |
| `--attention-split` / `--attention-quad` / `--attention-pytorch` | — | Attention implementation. |
| `--disable-xformers` | — | Disable xformers. |
| `--always-gpu` / `--always-high-vram` / `--always-normal-vram` / `--always-low-vram` / `--always-no-vram` / `--always-cpu` | — | VRAM strategy. |
| `--always-offload-from-vram` | — | Force offload (Fooocus enables this by default unless `--disable-offload-from-vram`). |
| `--directml` | — | Use DirectML (Windows AMD/Intel). |
| `--disable-ipex-hijack` | — | Disable Intel IPEX hijack. |
| `--pytorch-deterministic` | — | Deterministic mode. |
| `--multi-user` | — | Storage scoping only (not parallel execution). |
| `--debug-mode` / `--disable-server-log` / `--disable-server-info` | — | Logging/diagnostics. |

> [!NOTE]
> Fooocus sets `disable_cuda_malloc=True`, `in_browser=True`, and `port=None` as defaults (in `args_manager.py`), and computes `always_offload_from_vram = not --disable-offload-from-vram`. The Gradio server port is `7865` (env `GRADIO_SERVER_PORT`), distinct from the backend's `--port` default of `8188`.

---

## 9. Model Management and Auto-Download

Fooocus downloads models lazily via `modules/model_loader.py:load_file_from_url`. Triggers and sources:

| Trigger | Function | Source (Hugging Face) |
|---------|----------|------------------------|
| First run / preset model | `download_models` (launch.py) | per-preset `checkpoint_downloads` (e.g. `lllyasviel/fav_models`, `mashb1t/fav_models`, `stabilityai`) |
| Prompt expansion | `download_models` | `lllyasviel/misc` (`fooocus_expansion.bin`) |
| VAE approx (preview) | `download_models` | `lllyasviel/misc`, `mashb1t/misc` |
| Inpaint | `downloading_inpaint_models(v)` | `lllyasviel/fooocus_inpaint` (head + `inpaint_v{1,25,26}.fooocus.patch`) |
| ControlNet (Canny/CPDS) | `downloading_controlnet_*` | `lllyasviel/misc` |
| Image Prompt / FaceSwap | `downloading_ip_adapters(v)` | `lllyasviel/misc` (clip_vision, ip-adapter-plus) |
| Upscaler | `downloading_upscale_model` | `lllyasviel/misc` |
| Safety checker | `downloading_safety_checker_model` | `mashb1t/misc` |
| SAM masking | `download_sam_model` | `mashb1t/misc` (vit_b/l/h) |
| Performance LoRAs | `downloading_sdxl_{lcm,lightning,hyper_sd}_lora` | `lllyasviel/misc`, `mashb1t/misc` |

> [!CAUTION]
> **No checksum verification.** `load_file_from_url` downloads by URL into the model folder; there is no signature or hash check on the downloaded weights. Combined with the globally-disabled TLS verification (see Security), this means model integrity depends entirely on the Hugging Face source and transport. For air-gapped or high-assurance deployments, **pre-stage all models manually**, verify hashes out of band, and run with `--disable-preset-download`.

Model file extensions recognized: `.pth`, `.ckpt`, `.bin`, `.safetensors`, `.fooocus.patch`. A hash cache (`modules/hash_cache.py`) indexes models/LoRAs; rebuild it with `--rebuild-hash-cache`.

---

## 10. Security Analysis

Fooocus is designed as a **local, single-user, offline** tool. Its defaults are appropriate for `localhost` use. Exposing it to a network or the internet substantially changes the risk picture. The items below are factual, source-derived, and (where noted) reference public community reports.

### Network exposure

- By default the backend binds `127.0.0.1`. `--listen` (with `0.0.0.0`) and `--share` (a public Gradio tunnel) expose the app.
- There is **no host-header check** unless you consider `--disable-header-check`; Gradio's own protections apply.

### Authentication

- `modules/auth.py` implements a minimal scheme: an `auth.json` file (a list of `{user, pass}` or `{user, hash}` entries). Passwords are hashed with **SHA-256** (no salt, no key-stretching).
- Auth is only active if `auth.json` exists; it gates the Gradio app when sharing.
- The shipped `auth-example.json` contains the user `sitting-duck-1` / password `very-bad-publicly-known-password-change-it` — a deliberate placeholder.

> [!WARNING]
> If you expose Fooocus with `--share` or `--listen`, create a real `auth.json` with strong credentials. SHA-256 without salting is weak against offline cracking if the file leaks — keep `auth.json` off any world-readable path and never commit it.

### TLS verification disabled globally

`launch.py` sets:

```python
ssl._create_default_https_context = ssl._create_unverified_context
```

This disables certificate verification for **all** HTTPS in the process (model downloads, any outbound call). It exists to avoid corporate-proxy/cert headaches but means downloads are not protected against TLS man-in-the-middle.

> [!CAUTION]
> For any hardened deployment, patch this out and verify model integrity by hash. Combined with the no-checksum model download, the unverified TLS context is the most significant supply-chain weakness in the default configuration.

### Auto-update trust

`entry_with_update.py` fetches and hard-resets to `origin` on every launch. This means each run pulls and executes the latest upstream code. In a controlled environment, **launch `launch.py` directly** (not `entry_with_update.py`) to pin code to a reviewed commit, or run with the network restricted.

### Known community-reported issues

| Report | Summary | Operator action |
|--------|---------|-----------------|
| #4185 | Arbitrary code execution via `eval()`. | Audit any `eval`/`exec` paths before exposing; restrict the OS account Fooocus runs under. |
| #4156 | Path traversal in `get_annotated_filepath` allowing arbitrary file reads. | Do not expose an un-patched instance; run under a low-privilege account with a confined working directory. |

> [!IMPORTANT]
> These are publicly filed issues against a popular open-source project, not signs of malicious code. The mitigation is standard defense-in-depth: run Fooocus as an unprivileged user, in a container or jailed directory, never as root/Administrator, and never expose an instance directly to the internet without a reverse proxy, authentication, and the hardening above.

### Content safety

- An optional NSFW safety checker (`extras/censor.py` + `stable-diffusion-safety-checker.bin`) blacks out flagged images. Enable globally with `default_black_out_nsfw: true` or per task.

### Input handling

- The **Image Prompt**, **Inpaint**, **Describe**, and **Metadata** tabs all accept user-uploaded images and (for Metadata) parse embedded parameter strings. Treat uploads as untrusted; `--web-upload-size` caps upload size.

---

## 11. Deployment

### Single-instance (typical)

```bash
python launch.py --listen --port 7865 --always-normal-vram
```

Put it behind a reverse proxy (nginx/Traefik/Caddy) terminating TLS, and add authentication (`auth.json` plus, ideally, proxy-level auth).

> [!TIP]
> Prefer `launch.py` over `entry_with_update.py` in production so the code does not auto-update from upstream on every restart. Pin your checkout to a reviewed commit.

### Reverse proxy sketch (nginx)

```nginx
location / {
    proxy_pass http://127.0.0.1:7865;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;     # Gradio uses websockets
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 600s;                    # long generations
}
```

### Containerized / Colab

- The repo includes `entrypoint.sh` (used by container/Colab templates) that symlinks `models` and `outputs` to a persistent `DATADIR` so weights survive container restarts, then runs `launch.py`.
- `environment.yaml` defines a conda env (`python=3.10`) for reproducible builds.

### Multi-GPU / multi-user

Run N instances, one per GPU:

```bash
python launch.py --gpu-device-id 0 --listen --port 7865 &
python launch.py --gpu-device-id 1 --listen --port 7866 &
```

Front them with a load balancer using **sticky sessions** (a generation streams progress over a persistent connection, so a user must stay pinned to one instance).

### Deployment checklist

- [ ] Run as an unprivileged user, not root/Administrator.
- [ ] Confine the working directory; mount models read-only where possible.
- [ ] Create a strong `auth.json`; never commit it.
- [ ] Terminate TLS at a reverse proxy; do not rely on `--share` for anything permanent.
- [ ] Pre-stage and hash-verify models; consider `--disable-preset-download`.
- [ ] Launch `launch.py` (pinned commit), not `entry_with_update.py`.
- [ ] Set `default_black_out_nsfw: true` for shared instances.
- [ ] Ensure adequate swap and ≥40 GB free disk per drive.
- [ ] Confirm PyTorch matches your GPU's compute capability.

---

## 12. Operations

### Start / stop

- **Start:** `run.bat` (Windows) or `python entry_with_update.py` / `python launch.py`.
- **Stop:** Ctrl-C the process. The single worker thread and Gradio server terminate with it.

### Logs and outputs

- Generated images and an **HTML session log** are written under `outputs/` (date-stamped). The History Log link in the UI opens it.
- Console output is the primary diagnostic channel: it prints the resolved args (`[System ARGV]`), version, model download progress, per-step progress (`[Fooocus] ...`), and total generation time.
- `--debug-mode`, `--disable-server-log`, `--disable-server-info` tune verbosity.

### Temp management

- `temp_path` defaults to the system temp `/fooocus`. With `temp_path_cleanup_on_launch: true` (default), Fooocus deletes its temp contents on each launch.

### Backup

Back up these, none of which are auto-synced anywhere:

- `config.txt` and any custom `presets/*.json`
- `auth.json`
- `models/` (large — or just record the source URLs)
- `outputs/` (your generated work + logs)
- `wildcards/` and `sdxl_styles/` if customized

### Updating

- Default: `entry_with_update.py` pulls on launch.
- Manual: `git pull` (or pin to a tag). After updating, **re-test output on fixed seeds** because of the backend-patch coupling described in §3.

### Health check

A simple liveness check is an HTTP GET to the Gradio root on the configured port; a 200 means the server is up. There is no dedicated `/health` endpoint (Fooocus exposes no REST API — interaction is via Gradio's event protocol).

---

## 13. Repository Structure

```text
Fooocus/
├── entry_with_update.py     # Auto-update launcher (git fetch + reset → launch)
├── launch.py                # Environment prep, model download, → webui
├── webui.py                 # Gradio Blocks UI + event wiring (~1500 lines)
├── args_manager.py          # Fooocus CLI flags (extends backend parser)
├── shared.py                # Global gradio_root handle
├── build_launcher.py        # Writes run*.bat on Windows
├── fooocus_version.py       # version = '2.5.5'
├── requirements_versions.txt
├── environment.yaml         # conda env (python=3.10)
├── entrypoint.sh            # container/Colab persistence + launch
├── config.txt               # (generated) user config
├── modules/                 # Fooocus orchestration layer (~29 files)
│   ├── async_worker.py      #   AsyncTask + the worker pipeline
│   ├── default_pipeline.py  #   diffusion orchestration
│   ├── config.py            #   the entire config system
│   ├── flags.py             #   enums: Performance, samplers, schedulers, ratios
│   ├── patch.py             #   core backend monkey-patches
│   ├── patch_clip.py        #   CLIP patches
│   ├── patch_precision.py   #   precision patches
│   ├── sample_hijack.py     #   sampling-loop hijack
│   ├── sdxl_styles.py       #   style loading + application
│   ├── inpaint_worker.py    #   inpaint/outpaint engine
│   ├── upscaler.py          #   upscaling
│   ├── meta_parser.py       #   metadata read/write (fooocus + a1111)
│   ├── private_logger.py    #   image saving + HTML log
│   ├── auth.py              #   SHA-256 auth file
│   ├── model_loader.py      #   load_file_from_url (downloads)
│   ├── lora.py, core.py, util.py, html.py, localization.py, ...
├── ldm_patched/             # Vendored ComfyUI backend (monkey-patched)
│   ├── modules/             #   model_management, samplers, sd, args_parser, ...
│   ├── ldm/                 #   latent diffusion model
│   ├── k_diffusion/, unipc/, controlnet/, t2ia/, taesd/, pfn/, utils/
├── extras/                  # Auxiliary ML: BLIP, GroundingDINO, SAM, facexlib,
│                            #   censor, expansion, interrogate, ip_adapter, preprocessors
├── presets/                 # default/anime/realistic/lcm/lightning/pony_v6/sai/...
├── sdxl_styles/             # JSON style packs (fooocus, sai, mre, twri, diva, ...)
├── wildcards/               # Wildcard text files
├── language/                # UI translation JSON
├── models/                  # (populated at runtime; mostly empty placeholders)
├── javascript/  css/        # Frontend assets injected into Gradio
└── fooocus_colab.ipynb      # Colab notebook
```

---

## 14. Module Reference

### Orchestration (`modules/`)

| Module | Responsibility |
|--------|----------------|
| `async_worker.py` | Defines `AsyncTask` (unpacks ~80 positional UI args into named fields) and the background `worker()` that runs the full pipeline: prompt processing, goals (vary/upscale/inpaint/cn/enhance), diffusion, censor, save/log. Calls `patch_all()` at import. |
| `default_pipeline.py` | Loads/refreshes base+refiner+LoRA+VAE, CLIP encoding, `process_diffusion`, candidate-VAE selection, expansion. The Fooocus "brain" over the backend. |
| `config.py` | The complete config system: defaults, validators, env/CLI/file/preset precedence, path resolution, and all `downloading_*` model fetchers. |
| `flags.py` | Enums and lists: `Performance` (+ `Steps`, `StepsUOV`, `PerformanceLoRA`), sampler/scheduler names, aspect ratios, ControlNet types, inpaint options/engines, mask models, metadata schemes, output formats. |
| `patch.py` / `patch_clip.py` / `patch_precision.py` / `sample_hijack.py` | Runtime monkey-patches over `ldm_patched` and libraries. `PatchSettings` holds per-PID sharpness/ADM/CFG. |
| `sdxl_styles.py` | Loads style JSON packs, normalizes names, applies styles (`{prompt}` placeholder), wildcard arrays (`[[...]]`). |
| `inpaint_worker.py` | The Fooocus-specific inpaint/outpaint algorithm and latent patching. |
| `upscaler.py` | `perform_upscale` (ESRGAN-style upscaler). |
| `meta_parser.py` | Reads/writes generation metadata in `fooocus` (JSON) and `a1111` (plain-text) schemes. |
| `private_logger.py` | Saves images, embeds metadata, maintains the HTML history log. |
| `auth.py` | `auth.json` loading + SHA-256 password check. |
| `model_loader.py` | `load_file_from_url` — the download primitive (no checksum). |
| `launch_util.py` | pip/install helpers, `requirements_met`, subprocess `run`. |
| `hash_cache.py` | Model/LoRA hash index. |
| `localization.py` | `language/*.json` UI translation. |
| `gradio_hijack.py` / `ui_gradio_extensions.py` | Custom `gr.Image` component and JS/CSS injection. |

### Backend (`ldm_patched/`)

A vendored ComfyUI fork. Key subpackages: `modules/` (model_management, samplers, sd, model_patcher, args_parser, ops, sd1_clip), `ldm/` (latent diffusion + attention + diffusion modules), `k_diffusion/` (sampling), `unipc/` (UniPC sampler), `controlnet/cldm` (ControlNet), `t2ia/` (T2I-Adapter), `taesd/` (tiny autoencoder previews), `pfn/` (upscaler architectures). See §3 for the patching relationship.

### Extras (`extras/`)

Auxiliary ML used by specific features: `BLIP` + `wd14tagger`/`interrogate` (Describe), `GroundingDINO` + `sam` + `inpaint_mask` (text-prompted masking), `facexlib` + `face_crop` (FaceSwap), `ip_adapter` (Image Prompt), `preprocessors` (Canny/CPDS), `censor` (NSFW), `expansion` (Fooocus V2 GPT-2 prompt expansion).

---

## 15. Code Quality and Patterns

**Strengths**

- **Clear three-layer separation** (UI / orchestration / backend) keeps Fooocus logic out of the vendored engine.
- **Centralized, validated configuration.** Every config key passes through a validator with a typed default, and the precedence chain is consistent. The auto-generated `config_modification_tutorial.txt` is good operator UX.
- **Opinionated defaults** encode substantial domain knowledge (per-preset CFG, styles, ADM guidance) so users get good results without tuning.
- **Pinned dependencies** make environments reproducible.

**Patterns and risks**

- **Positional arg coupling (high-risk).** `webui.py` packs ~80 UI control values into a list in a fixed order, and `AsyncTask.__init__` pops them in exactly that order. There is no named-key contract. Any insertion/removal in either file that isn't mirrored in the other silently misaligns every downstream parameter. This is the most fragile seam in the codebase.
- **Monkey-patch coupling to the vendored backend (high-risk).** See §3. Quality regressions can be silent.
- **Module-import side effects.** Importing `async_worker` triggers `patch_all()`; importing `config` writes files and can prompt interactively (deprecated-config migration). Import order matters.
- **Disabled TLS verification and unchecked downloads** (see §10).
- **Large monolith files.** `webui.py` and `async_worker.py` are each ~1500 lines with deeply nested closures; readable but hard to unit-test in isolation.

> [!NOTE]
> The `extras/` ML helpers (BLIP, GroundingDINO, facexlib) are themselves vendored third-party code with their own licenses (the repo bundles many `LICENSE` files, mostly Apache-2.0). Track these for license compliance if you redistribute.

---

## 16. Potential Improvements

These are observations for maintainers/forkers, derived from the source:

1. **Replace positional `AsyncTask` packing with a dataclass / named dict.** Eliminates the §15 misalignment hazard and makes the parameter contract explicit and testable.
2. **Add checksum/signature verification to `load_file_from_url`.** Pair each download URL with an expected SHA-256 in the preset JSON and verify after download.
3. **Remove the global `ssl._create_unverified_context` override** or scope it narrowly; rely on proper CA handling with an opt-in escape hatch.
4. **Decouple from PyTorch 2.1.0.** Detect GPU compute capability at install time and select a compatible torch build automatically, reducing the dominant class of "won't start on new GPUs" issues.
5. **Provide a pinned-commit production launcher** as a first-class, documented path (today operators must know to avoid `entry_with_update.py`).
6. **A backend-patch regression harness** (fixed-seed image diffs) shipped in `tests/` would make backend upgrades safe.
7. **Salt the auth hashes** and document a secure credential workflow for exposed deployments.

---

## 17. Quick Reference

### Entry points

| File | Use |
|------|-----|
| `entry_with_update.py` | Default launcher; auto-updates from `origin`. |
| `launch.py` | Direct launcher; no auto-update (prefer in production). |
| `run.bat` / `run_anime.bat` / `run_realistic.bat` | Windows package launchers (preset editions). |

### Key paths

| Path | Contents |
|------|----------|
| `config.txt` | User config (JSON). |
| `presets/*.json` | Editions. |
| `auth.json` | Credentials (SHA-256). |
| `models/<type>/` | Weights (downloaded). |
| `outputs/` | Images + HTML logs. |
| `sdxl_styles/*.json` | Style packs. |
| `wildcards/*.txt` | Wildcards. |
| `language/*.json` | UI translations. |

### Critical environment variables

`TORCH_COMMAND`, `TORCH_INDEX_URL` (override torch), `HF_MIRROR` (model mirror), `GRADIO_SERVER_PORT` (default 7865), `config_path` (config location).

### Performance ↔ steps ↔ LoRA

| Performance | Steps | UOV steps | LoRA |
|-------------|-------|-----------|------|
| Quality | 60 | 36 | — |
| Speed | 30 | 18 | — |
| Extreme Speed | 8 | 8 | LCM |
| Lightning | 4 | 4 | SDXL-Lightning |
| Hyper-SD | 4 | 4 | Hyper-SD |

### Default ports

| Service | Port |
|---------|------|
| Gradio UI | 7865 (`GRADIO_SERVER_PORT`) |
| Backend `--port` default | 8188 |

### Hardening one-liner (exposed instance)

```bash
# unprivileged user, pinned code, real auth, NSFW filter on, no preset auto-download
python launch.py --listen --port 7865 --disable-preset-download
# + config.txt: "default_black_out_nsfw": true
# + auth.json with strong credentials, behind a TLS reverse proxy
```

---

_Generated June 2026 from lllyasviel/Fooocus at ae05379. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
