CodeVetter · Repo Unpack · Contributor handoff
AUTOMATIC1111/stable-diffusion-webui
Read webui.py, modules/initialize.py, modules/processing.py, modules/scripts.py, modules/shared.py, and modules/paths_internal.py first — they define the boot order, the p-object pipeline, and the global-state conventions everything else hangs off. Safe edit zones: scripts/ and extensions-builtin/ for new features; modules/api/api.py + modules/api/models.py for new endpoints; shared_options.py for new settings. Traps: import-order sensitivity (paths_internal before torch), the single queue_lock serialization, opts restore semantics, and test mode requiring --test-server conventions.
- Import-order discipline matters: modules/paths_internal.py and modules/cmd_args.py parse sys.argv at import time and inject COMMANDLINE_ARGS; shared_cmd_options imports launch.py and runs extension preload.py files at import — never import torch-dependent modules before initialize.imports(), and set IGNORE_CMD_ARGS_ERRORS=1 when running pytest/other tools.
- Follow the 'p' convention: generation features should be implemented as Script subclasses (scripts/ or extension scripts/) mutating the StableDiffusionProcessing object via the documented hook lifecycle, not by editing process_images_inner directly — the base class docstrings define exactly when each hook fires.
- Adding a REST endpoint: add a pydantic model in modules/api/models.py, register with self.add_api_route in Api.__init__ (auto-wraps Depends(auth) when --api-auth is set), reuse init_script_args/apply_infotext for generation endpoints, and wrap generation calls in self.queue_lock.
- Adding a setting: add an OptionInfo entry to the right options_section in modules/shared_options.py (or shared.options_templates.update from an extension); set restrict_api=True to hide it from /sdapi/v1/options; onchange callbacks run via opts.set(); do_not_save entries never persist.
- Code style is ruff-governed (pyproject.toml: target py39, select B/C/I/W, E501/E721/E731/C901 ignored, extensions/ excluded); run 'ruff .' and 'npm run lint' before committing; CI also requires PRs from forks (lint/test jobs skip same-repo PRs).
- To run tests locally you must boot the app first: 'python launch.py --test-server --skip-prepare-environment --skip-torch-cuda-test --use-cpu all --api-server-stop' then 'pytest test' — tests hit a live server on :7860, there is no offline unit-test path for the pipeline.
- Beware mutable module globals: shared.sd_model may be swapped mid-generation by refiner/override_settings (reload_model_weights is called inside the batch loop); shared.opts changes during a job are restored by process_images' finally block only if override_settings_restore_afterwards — keep new opts writes inside that contract.
- Infotext is the cross-cutting serialization format: paste_fields in modules/infotext_utils.py map infotext labels ↔ gradio components ↔ API fields; any new generation parameter must be added there (and to create_infotext's generation_params dict) to roundtrip through PNG metadata and 'Send to' buttons.
- File-not-found and extension errors should go through modules/errors.py report()/display() (they render in UI and log), not bare exceptions; scripts' callback failures are individually caught by script_callbacks report_exception so one bad extension doesn't kill the run.
- Device/memory plumbing is centralized in modules/devices.py (autocast, torch_gc, test_for_nans, dtype selection via --no-half/--precision/--use-cpu) and modules/lowvram.py (--lowvram/--medvram model shuffling) — new GPU work should reuse devices.get_optimal_device/autocast/without_autocast contexts rather than raw torch calls.