From 6c210a75e67aee147340925cac4fe34c64ff2f1f Mon Sep 17 00:00:00 2001 From: "yiyi@huggingface.co" Date: Tue, 28 Apr 2026 00:51:46 +0000 Subject: [PATCH 1/3] [agents docs] pipelines.md: be deliberate about pipeline methods Adds a gotcha covering when a pipeline method should be public (a step in __call__'s lifecycle) vs private/module-level (only used by another method), and the preference to absorb single-use helpers when small. Co-Authored-By: Claude Opus 4.7 (1M context) --- .ai/pipelines.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.ai/pipelines.md b/.ai/pipelines.md index e107639cb24b..ecd2dfe40978 100644 --- a/.ai/pipelines.md +++ b/.ai/pipelines.md @@ -60,3 +60,7 @@ When adding a new pipeline (or reviewing one), skim `pipeline_flux.py`, `pipelin 4. **Subclassing an existing pipeline for a variant.** Don't use an existing pipeline class (e.g. `FluxPipeline`) to override another (e.g. `FluxImg2ImgPipeline`) inside the core `src/` codebase. Each pipeline lives in its own file with its own class, even if it shares 90% of `__call__` with a sibling. Convention across diffusers — flux, sdxl, wan, qwenimage — is duplicated `__call__` between img2img / text2img / inpaint variants, not subclassing. Reuse private utilities (shared schedulers, prep functions) but not the pipeline class itself. 5. **Copying a method from another pipeline without `# Copied from`.** When you reuse a method like `encode_prompt`, `prepare_latents`, `check_inputs`, or `_prepare_latent_image_ids` from another pipeline, add a `# Copied from` annotation so `make fix-copies` keeps the two in sync. Forgetting it means future refactors to the source drift away from your copy silently — and reviewers waste time spotting near-identical code that should have been linked. The annotation grammar (decorator placement, rename syntax with `with old->new`, etc.) is implemented in [`utils/check_copies.py`](../utils/check_copies.py) — read it for the exact rules. + +6. **Be deliberate about methods on the pipeline.** `__call__` is the user's mental model of the pipeline, and the methods on the class are how they navigate it. Diffusers convention (flux, sdxl, wan, qwenimage) is a flat class body of public lifecycle methods (`__init__`, `check_inputs`, `encode_prompt`, `prepare_latents`, `__call__`), each invoked from `__call__`. Two principles, not strict rules — use judgment: + - **If a method is called from `__call__`, and it's a step in the pipeline lifecycle, make it public.** Each call from `__call__` should correspond to a step a user can identify: either a standard one (`encode_prompt`, `prepare_latents`, `set_timesteps`, …) or a pipeline-specific one (`prepare_src_latents`, `prepare_reference_audio_latents`, …). Don't gate these behind a `_`; they're part of the pipeline's API surface alongside their standard siblings. + - **If a method is only used by another method, make it private (`_foo`) or lift it to a module-level function — and keep the count down.** Before adding one, see if the logic can be absorbed into its caller. Unless you expect the helper to be reused by another method (or another task pipeline), absorbing is usually the better call — especially when the body is small. What we want to avoid is a pipeline class littered with private helpers that bury the lifecycle. From 8c42ec642b2cddf4c206ef7905b0a0a64ffe83d0 Mon Sep 17 00:00:00 2001 From: YiYi Xu Date: Tue, 28 Apr 2026 09:20:15 -1000 Subject: [PATCH 2/3] Update .ai/pipelines.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> --- .ai/pipelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ai/pipelines.md b/.ai/pipelines.md index ecd2dfe40978..9e7eaa8305c9 100644 --- a/.ai/pipelines.md +++ b/.ai/pipelines.md @@ -61,6 +61,6 @@ When adding a new pipeline (or reviewing one), skim `pipeline_flux.py`, `pipelin 5. **Copying a method from another pipeline without `# Copied from`.** When you reuse a method like `encode_prompt`, `prepare_latents`, `check_inputs`, or `_prepare_latent_image_ids` from another pipeline, add a `# Copied from` annotation so `make fix-copies` keeps the two in sync. Forgetting it means future refactors to the source drift away from your copy silently — and reviewers waste time spotting near-identical code that should have been linked. The annotation grammar (decorator placement, rename syntax with `with old->new`, etc.) is implemented in [`utils/check_copies.py`](../utils/check_copies.py) — read it for the exact rules. -6. **Be deliberate about methods on the pipeline.** `__call__` is the user's mental model of the pipeline, and the methods on the class are how they navigate it. Diffusers convention (flux, sdxl, wan, qwenimage) is a flat class body of public lifecycle methods (`__init__`, `check_inputs`, `encode_prompt`, `prepare_latents`, `__call__`), each invoked from `__call__`. Two principles, not strict rules — use judgment: +6. **Be deliberate about methods on the pipeline.** `__call__` is the user's mental model. The methods on the class are how they navigate it. Diffusers convention (flux, sdxl, wan, qwenimage) is a flat class body of public lifecycle methods (`__init__`, `check_inputs`, `encode_prompt`, `prepare_latents`, `__call__`). Two principles, not strict rules — use judgment: - **If a method is called from `__call__`, and it's a step in the pipeline lifecycle, make it public.** Each call from `__call__` should correspond to a step a user can identify: either a standard one (`encode_prompt`, `prepare_latents`, `set_timesteps`, …) or a pipeline-specific one (`prepare_src_latents`, `prepare_reference_audio_latents`, …). Don't gate these behind a `_`; they're part of the pipeline's API surface alongside their standard siblings. - **If a method is only used by another method, make it private (`_foo`) or lift it to a module-level function — and keep the count down.** Before adding one, see if the logic can be absorbed into its caller. Unless you expect the helper to be reused by another method (or another task pipeline), absorbing is usually the better call — especially when the body is small. What we want to avoid is a pipeline class littered with private helpers that bury the lifecycle. From 893bf275b8cd23c45e675ba18c9426e247b6b634 Mon Sep 17 00:00:00 2001 From: YiYi Xu Date: Tue, 28 Apr 2026 09:20:24 -1000 Subject: [PATCH 3/3] Update .ai/pipelines.md Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> --- .ai/pipelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ai/pipelines.md b/.ai/pipelines.md index 9e7eaa8305c9..e6db54a7f7de 100644 --- a/.ai/pipelines.md +++ b/.ai/pipelines.md @@ -63,4 +63,4 @@ When adding a new pipeline (or reviewing one), skim `pipeline_flux.py`, `pipelin 6. **Be deliberate about methods on the pipeline.** `__call__` is the user's mental model. The methods on the class are how they navigate it. Diffusers convention (flux, sdxl, wan, qwenimage) is a flat class body of public lifecycle methods (`__init__`, `check_inputs`, `encode_prompt`, `prepare_latents`, `__call__`). Two principles, not strict rules — use judgment: - **If a method is called from `__call__`, and it's a step in the pipeline lifecycle, make it public.** Each call from `__call__` should correspond to a step a user can identify: either a standard one (`encode_prompt`, `prepare_latents`, `set_timesteps`, …) or a pipeline-specific one (`prepare_src_latents`, `prepare_reference_audio_latents`, …). Don't gate these behind a `_`; they're part of the pipeline's API surface alongside their standard siblings. - - **If a method is only used by another method, make it private (`_foo`) or lift it to a module-level function — and keep the count down.** Before adding one, see if the logic can be absorbed into its caller. Unless you expect the helper to be reused by another method (or another task pipeline), absorbing is usually the better call — especially when the body is small. What we want to avoid is a pipeline class littered with private helpers that bury the lifecycle. + - **If a method is only used by another method, make it private (`_foo`) or lift it to a module-level function — and keep the count down.** Before adding one, see if the logic can be absorbed into its caller. Unless you expect the helper to be reused by another method (or another task pipeline), absorbing is usually the better call — especially when the body is small. Avoid a pipeline class littered with private helpers that bury the lifecycle..