CodeVetter · Repo Unpack · Extension points
AUTOMATIC1111/stable-diffusion-webui
This repo is primarily an extension host. Four plug-in surfaces exist: (1) extensions in extensions/ and extensions-builtin/ — directories with optional preload.py (argparse), install.py (setup), scripts/*.py (Script subclasses), metadata.ini (ordering/deps), and javascript/*.js; (2) the Script base class lifecycle with ~20 hooks from before_process to postprocess; (3) the script_callbacks.py registry with ~20 named callback categories including CFG denoiser per-step hooks; (4) registries for extra networks, samplers, upscalers, optimizers, and UNET patches.
- Extension discovery: extensions.list_extensions() scans extensions-builtin/ then extensions/, building Extension objects gated by --disable-all-extensions/--disable-extra-extensions and opts.disabled_extensions; ExtensionMetadata reads metadata.ini for canonical Name and [Extension] Requires plus per-script Requires/Before/After ordering fields.
- Script loading: scripts.load_scripts() runs list_scripts('scripts','.py') + list_scripts('modules/processing_scripts','.py') over the base dir and every active extension, orders files by topological_sort of metadata dependencies, load_module() exec's each file, and registers every Script or ScriptPostprocessing subclass found into scripts_data/postprocessing_scripts_data.
- Script API: subclass modules.scripts.Script, implement title()/ui(is_img2img)/show()/run(p,*args); AlwaysVisible return from show() makes it always-on; lifecycle hooks include setup, before_process, process, before_process_batch, after_extra_networks_activate, process_batch, postprocess_batch, postprocess_batch_list, on_mask_blend, post_sample, postprocess_image, postprocess_image_after_composite, postprocess, before_hr — each documented in the class.
- script_callbacks.py exposes registration functions on_app_started, on_before_reload, on_model_loaded, on_ui_tabs, on_ui_train_tabs, on_ui_settings, on_before_image_saved, on_image_saved, on_extra_noise, on_cfg_denoiser, on_cfg_denoised, on_cfg_after_cfg, on_before_component, on_after_component, on_image_grid, on_infotext_pasted, on_script_unloaded, on_before_ui, on_list_optimizers, on_list_unets, on_before_token_counter — backed by callback_map lists with ordered sorting and per-extension callback naming.
- on_ui_tabs is how extensions add top-level Gradio tabs: callback returns [(blocks, label, elem_id)] tuples appended to interfaces in create_ui(); on_before_component/after_component (or Script.on_before_component(elem_id=...)) lets scripts inject/modify any Gradio component by elem_id.
- Extra networks: call extra_networks.register_extra_network(obj) (name matches <name:...> in prompts) and register_extra_network_alias; obj implements activate(p, params_list)/deactivate(p). extensions-builtin/Lora registers ExtraNetworkLora with alias 'lyco' in its scripts/lora_script.py before_ui callback.
- preload.py hook: any extension dir containing preload.py gets load_module'd and its preload(parser) called during shared_cmd_options import, letting extensions add CLI args before cmd_opts is parsed (Lora uses it for --lora-dir/--lyco-dir-backcompat).
- Settings extension: update shared.options_templates with shared.options_section(...) dicts of OptionInfo — Lora adds 'sd_lora', 'lora_*' options this way; each OptionInfo can carry an onchange callback and restrict_api flag.
- Extra Networks pages: ui_extra_networks.register_page(ExtraNetworksPage subclass) adds browsable card tabs; ui_extra_networks_user_metadata.py shows per-file .json sidecar editing — pages are served to the browser via add_pages_to_demo.
- Sampler/scheduler/upscaler registration: append SamplerData to sd_samplers_*.py lists consumed by all_samplers; sd_schedulers.schedulers; upscaler.Upscaler subclasses discovered by modelloader.load_upscalers() scanning models dirs; optimizers via on_list_optimizers into sd_hijack_optimizations; UNET patches via on_list_unets into sd_unet.
- API surface for scripts is automatic: Api.__init__ initializes scripts_txt2img/img2img runners if empty, builds default_script_arg arrays from each script's ui() default component values, and get_script_info exposes Script.api_info — scripts appear in /sdapi/v1/scripts and are addressable by name in requests' script_name/alwayson_scripts.
- Built-in extensions in extensions-builtin/ (canvas-zoom-and-pan, extra-options-section, hypertile, LDSR, Lora, mobile, postprocessing-for-training, prompt-bracket-checker, ScuNET, soft-inpainting, SwinIR) are the reference implementations for each extension pattern — is_builtin=True keeps them loaded even under --disable-extra-extensions.
- Frontend extension: every .js file under javascript/ (and extension javascript dirs) is bundled into the Gradio page; they hook DOM lifecycle (onUiLoaded/onOptionsChanged/onAfterUiUpdate etc. defined in script.js/ui.js) — e.g. edit-attention.js, extraNetworks.js, contextMenus.js. (inferred)