From 4f0721893345023f508775d86fdabf56faae0895 Mon Sep 17 00:00:00 2001 From: DN6 Date: Wed, 12 Aug 2026 13:21:53 +0530 Subject: [PATCH 1/5] restructure guides as skill references --- .ai/.claude-plugin/plugin.json | 15 ++++++++++++ .ai/.codex-plugin/plugin.json | 6 +++++ .ai/AGENTS.md | 34 +++++++++++++++++++++------ .ai/plugin.json | 16 +++++++++++++ .ai/{ => references}/models.md | 2 +- .ai/{ => references}/modular.md | 0 .ai/{ => references}/pipelines.md | 2 +- .ai/{ => references}/review-rules.md | 8 +++---- .ai/{ => references}/testing.md | 0 .ai/skills/custom-blocks/SKILL.md | 7 +++--- .ai/skills/model-integration/SKILL.md | 16 ++++++------- .ai/skills/self-review/SKILL.md | 8 +++---- .claude-plugin/marketplace.json | 14 +++++++++++ 13 files changed, 99 insertions(+), 29 deletions(-) create mode 100644 .ai/.claude-plugin/plugin.json create mode 100644 .ai/.codex-plugin/plugin.json create mode 100644 .ai/plugin.json rename .ai/{ => references}/models.md (99%) rename .ai/{ => references}/modular.md (100%) rename .ai/{ => references}/pipelines.md (99%) rename .ai/{ => references}/review-rules.md (77%) rename .ai/{ => references}/testing.md (100%) create mode 100644 .claude-plugin/marketplace.json diff --git a/.ai/.claude-plugin/plugin.json b/.ai/.claude-plugin/plugin.json new file mode 100644 index 000000000000..6195e465f66b --- /dev/null +++ b/.ai/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "diffusers", + "description": "Conventions and task skills for contributing to diffusers", + "author": { + "name": "The Hugging Face team" + }, + "homepage": "https://huggingface.co/docs/diffusers/main/en/conceptual/contribution#coding-with-ai-agents", + "repository": "https://github.com/huggingface/diffusers", + "license": "Apache-2.0", + "keywords": [ + "diffusers", + "diffusion-models", + "contributing" + ] +} diff --git a/.ai/.codex-plugin/plugin.json b/.ai/.codex-plugin/plugin.json new file mode 100644 index 000000000000..ac038c440f77 --- /dev/null +++ b/.ai/.codex-plugin/plugin.json @@ -0,0 +1,6 @@ +{ + "name": "diffusers", + "version": "0.1.0", + "description": "Conventions and task skills for contributing to diffusers", + "skills": "./skills/" +} diff --git a/.ai/AGENTS.md b/.ai/AGENTS.md index ae611feb4bb6..c7a0d3eb0aa1 100644 --- a/.ai/AGENTS.md +++ b/.ai/AGENTS.md @@ -2,8 +2,28 @@ ## Setup -- Local Claude Code agents: run `make claude` after cloning to wire the [skills](#skills) under `.claude/`. -- Local OpenAI Codex agents: run `make codex` after cloning to wire the [skills](#skills) under `.agents/`. +This file is loaded automatically in a checkout, through the root `AGENTS.md` / `CLAUDE.md` symlinks. The +[skills](#skills) are not — install them once, by whichever route fits the agent: + +```bash +# Claude Code — installs every skill, namespaced as /diffusers: +claude plugin marketplace add huggingface/diffusers +claude plugin install diffusers@diffusers-skills --scope project + +# Codex — register the catalog, then install from the Plugins Directory in the ChatGPT desktop app +codex plugin marketplace add huggingface/diffusers + +# Any agent, no marketplace needed +diffusers-cli skills add --all # or: skills add , and --claude / --codex / --cursor to pick a target +``` + +Installing a skill copies the [reference guides](#reference-guides) it cites into its own `references/` subdirectory, +so it is self-contained wherever it lands. A skill gets a guide by citing it as `references/.md`; the guides +themselves live once at `.ai/references/`. `diffusers-cli skills list` shows what is available, and `diffusers-cli +skills update` refreshes what you installed. + +When editing the skills in this repo, load them from the working tree instead of installing: `claude --plugin-dir .ai` +for one session, or `make codex` to symlink `.agents/skills` at `.ai/skills` (`make clean-ai` to undo). ## Coding style @@ -27,10 +47,10 @@ Strive to write code as simple and explicit as possible. ## Reference guides -- **Models** — see [models.md](models.md) for model conventions, attention pattern, implementation rules, dependencies, and gotchas. For adding or converting a model, use the [model-integration](./skills/model-integration/SKILL.md) skill. -- **Pipelines** — see [pipelines.md](pipelines.md) for pipeline conventions, patterns, and gotchas. -- **Modular pipelines** — see [modular.md](modular.md) for modular pipeline conventions, patterns, and gotchas. -- **Tests** — see [testing.md](testing.md) for test conventions: required test layers, tester mixins, and dummy-component rules. +- **Models** — see [models.md](references/models.md) for model conventions, attention pattern, implementation rules, dependencies, and gotchas. For adding or converting a model, use the [model-integration](./skills/model-integration/SKILL.md) skill. +- **Pipelines** — see [pipelines.md](references/pipelines.md) for pipeline conventions, patterns, and gotchas. +- **Modular pipelines** — see [modular.md](references/modular.md) for modular pipeline conventions, patterns, and gotchas. +- **Tests** — see [testing.md](references/testing.md) for test conventions: required test layers, tester mixins, and dummy-component rules. ## Skills @@ -43,4 +63,4 @@ Task-specific guides live in `.ai/skills/` and are loaded on demand by AI agents ## Self-review before a PR -Before opening a PR, run self-review against [review-rules.md](review-rules.md). The [self-review skill](skills/self-review/SKILL.md) runs this as the same pass the `@claude` CI reviewer uses. Share the final report on the PR (description or comment) — see the skill for details. +Before opening a PR, run self-review against [review-rules.md](references/review-rules.md). The [self-review skill](skills/self-review/SKILL.md) runs this as the same pass the `@claude` CI reviewer uses. Share the final report on the PR (description or comment) — see the skill for details. diff --git a/.ai/plugin.json b/.ai/plugin.json new file mode 100644 index 000000000000..93c863f7931f --- /dev/null +++ b/.ai/plugin.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "diffusers", + "description": "Conventions and task skills for contributing to diffusers", + "author": { + "name": "The Hugging Face team" + }, + "homepage": "https://huggingface.co/docs/diffusers/main/en/conceptual/contribution#coding-with-ai-agents", + "repository": "https://github.com/huggingface/diffusers", + "license": "Apache-2.0", + "keywords": [ + "diffusers", + "diffusion-models", + "contributing" + ] +} diff --git a/.ai/models.md b/.ai/references/models.md similarity index 99% rename from .ai/models.md rename to .ai/references/models.md index bdc6464c9aec..b99ff18e2334 100644 --- a/.ai/models.md +++ b/.ai/references/models.md @@ -1,7 +1,7 @@ # Model conventions and rules Shared reference for model-related conventions, patterns, and gotchas. -Linked from `AGENTS.md`, `skills/model-integration/SKILL.md`, and `review-rules.md`. +Linked from `../AGENTS.md`, `../skills/model-integration/SKILL.md`, and `review-rules.md`. ## Coding style diff --git a/.ai/modular.md b/.ai/references/modular.md similarity index 100% rename from .ai/modular.md rename to .ai/references/modular.md diff --git a/.ai/pipelines.md b/.ai/references/pipelines.md similarity index 99% rename from .ai/pipelines.md rename to .ai/references/pipelines.md index 7384808a1cda..005c4d544255 100644 --- a/.ai/pipelines.md +++ b/.ai/references/pipelines.md @@ -1,7 +1,7 @@ # Pipeline conventions and rules Shared reference for pipeline-related conventions, patterns, and gotchas. -Linked from `AGENTS.md`, `skills/model-integration/SKILL.md`, and `review-rules.md`. +Linked from `../AGENTS.md`, `../skills/model-integration/SKILL.md`, and `review-rules.md`. > **Prefer modular for new pipelines.** [Modular Diffusers](modular.md) is the preferred way to add a new pipeline; the standard `DiffusionPipeline` covered below is still supported but is no longer the default. We prefer modular especially for models that don't fit a fixed task-based structure (e.g. modality baked into the checkpoint) or that are actively evolving. The conventions below apply when you do build or review a standard pipeline. diff --git a/.ai/review-rules.md b/.ai/references/review-rules.md similarity index 77% rename from .ai/review-rules.md rename to .ai/references/review-rules.md index f554e4e5caaf..90be1ab1301f 100644 --- a/.ai/review-rules.md +++ b/.ai/references/review-rules.md @@ -3,16 +3,16 @@ Review-specific rules for Claude. Focus on correctness — style is handled by ruff. Before reviewing, read and apply the guidelines in: -- [AGENTS.md](AGENTS.md) — coding style, copied code +- [AGENTS.md](../AGENTS.md) — coding style, copied code - [models.md](models.md) — model conventions, attention pattern, implementation rules, dependencies, gotchas - [pipelines.md](pipelines.md) — pipeline conventions, coding style, gotchas - [modular.md](modular.md) — modular pipeline conventions, patterns, common mistakes - [testing.md](testing.md) — test conventions: required test layers, tester mixins, dummy-component rules. When a PR adds or changes tests, check them against this guide. -- [skills/model-integration/pitfalls.md](skills/model-integration/pitfalls.md) — known pitfalls causing numerical discrepancies between the reference implementation and the diffusers port (dtype mismatches, config assumptions, etc.) +- [skills/model-integration/pitfalls.md](../skills/model-integration/pitfalls.md) — known pitfalls causing numerical discrepancies between the reference implementation and the diffusers port (dtype mismatches, config assumptions, etc.) ## Common mistakes -Common mistakes are covered in the common-mistakes / gotcha sections in [AGENTS.md](AGENTS.md), [models.md](models.md), [pipelines.md](pipelines.md), and [modular.md](modular.md). Additionally, watch for below patterns that aren't covered there: +Common mistakes are covered in the common-mistakes / gotcha sections in [AGENTS.md](../AGENTS.md), [models.md](models.md), [pipelines.md](pipelines.md), and [modular.md](modular.md). Additionally, watch for below patterns that aren't covered there: - **Ephemeral context.** Comments, docstrings, and files that only made sense to the current PR's author or reviewer don't help a future reader/user/developer. Examples: `# per reviewer comment on PR #NNNN`, `# as discussed in review`, `# TODO from offline chat`, debug printouts. Same for files: parity harnesses, comparison scripts, anything in `scripts/` with hardcoded developer paths or imports from the reference repo. State the *reason* so the comment stands alone, or drop it. @@ -21,7 +21,7 @@ Common mistakes are covered in the common-mistakes / gotcha sections in [AGENTS. A PR can leave existing docs stale or surface a pattern worth recording. Scan the docs related to what the PR touches and flag updates as a **suggestions / additional info** section (not blocking): - **Usage docs.** New or changed public behavior — a new pipeline/model, a new argument, changed defaults, a renamed API — should have matching updates in `docs/`, docstrings, and examples. Flag any that now describe outdated behavior or that are missing for the new surface. -- **Agent docs.** If the review turns up a rule, pattern, or common gotcha that isn't written down yet — especially one the author got wrong or that you had to reason out — propose adding it to the relevant agent guide ([AGENTS.md](AGENTS.md), [models.md](models.md), [pipelines.md](pipelines.md), [modular.md](modular.md), a skill, or this file) so the next contributor/agent gets it for free instead of repeating the mistake. Human review comments on the PR are a good source for these: if a human reviewer pointed something out and your review missed it, that usually indicates a doc gap — figure out what's missing and propose the addition. +- **Agent docs.** If the review turns up a rule, pattern, or common gotcha that isn't written down yet — especially one the author got wrong or that you had to reason out — propose adding it to the relevant agent guide ([AGENTS.md](../AGENTS.md), [models.md](models.md), [pipelines.md](pipelines.md), [modular.md](modular.md), a skill, or this file) so the next contributor/agent gets it for free instead of repeating the mistake. Human review comments on the PR are a good source for these: if a human reviewer pointed something out and your review missed it, that usually indicates a doc gap — figure out what's missing and propose the addition. ## Dead code analysis (new models) diff --git a/.ai/testing.md b/.ai/references/testing.md similarity index 100% rename from .ai/testing.md rename to .ai/references/testing.md diff --git a/.ai/skills/custom-blocks/SKILL.md b/.ai/skills/custom-blocks/SKILL.md index 09ac19ddb21d..734fa7823a21 100644 --- a/.ai/skills/custom-blocks/SKILL.md +++ b/.ai/skills/custom-blocks/SKILL.md @@ -146,12 +146,11 @@ diffusers-cli run --model my-user/my-denoise-block --trust-remote-code \ ## Verifying the install -If `diffusers-cli` isn't on PATH, see the install verification section of -[`../diffusers-cli/SKILL.md`](../diffusers-cli/SKILL.md#verifying-the-cli-is-installed). +If `diffusers-cli` isn't on PATH, see the install verification section of the `diffusers-cli` skill. ## Related -- [`diffusers-cli` skill](../diffusers-cli/SKILL.md) — once your block is uploaded, `schema`/`run` +- the `diffusers-cli` skill — once your block is uploaded, `schema`/`run` let you call it from the terminal without writing Python. -- diffusers' [modular pipelines docs](../../../docs/source/en/modular_diffusers) — for writing the block +- diffusers' [modular pipelines docs](https://huggingface.co/docs/diffusers/main/en/modular_diffusers/overview) — for writing the block class itself. diff --git a/.ai/skills/model-integration/SKILL.md b/.ai/skills/model-integration/SKILL.md index 856549085899..287a8973e8b8 100644 --- a/.ai/skills/model-integration/SKILL.md +++ b/.ai/skills/model-integration/SKILL.md @@ -1,5 +1,5 @@ --- -name: integrating-models +name: model-integration description: > Use when adding a new model or pipeline to diffusers, setting up file structure for a new model, converting a pipeline to modular format, or @@ -16,7 +16,7 @@ Before writing any code, gather info in this order: 1. **Reference repo** — ask for the github link. If they've already set it up locally, ask for the path. Otherwise, ask what setup steps are needed (install deps, download checkpoints, set env vars, etc.) and run through them before proceeding. 2. **Inference script** — ask for a runnable end-to-end script for a basic workflow first (e.g. T2V). Then ask what other workflows they want to support (I2V, V2V, etc.) and agree on the full implementation order together. -3. **Standard vs modular** — **default to modular.** [Modular Diffusers](../../modular.md) is the preferred implementation for new pipelines; the standard `DiffusionPipeline` is still supported but no longer the default. We prefer modular especially for models that don't fit a fixed task-based structure (modality baked into the checkpoint) or that are actively evolving. +3. **Standard vs modular** — **default to modular.** [Modular Diffusers](references/modular.md) is the preferred implementation for new pipelines; the standard `DiffusionPipeline` is still supported but no longer the default. We prefer modular especially for models that don't fit a fixed task-based structure (modality baked into the checkpoint) or that are actively evolving. Ask step 3 as an `AskUserQuestion`, with modular marked as the recommended default. @@ -29,7 +29,7 @@ Then work through the **Integration checklist** below A pipeline in Diffusers (be it standard or modular) will have multiple components. These components can be models, schedulers, processors, etc. - [ ] **Transformer model** - - [ ] Implement the model with `from_pretrained` support (conventions: [models.md](../../models.md)) + - [ ] Implement the model with `from_pretrained` support (conventions: [models.md](references/models.md)) - [ ] Convert weights (see **Weight / Checkpoint Conversion**) - [ ] Parity test against the reference (internal, not shipped — see **Model parity test**) - [ ] Register in the relevant `__init__.py` files (lazy imports) @@ -37,7 +37,7 @@ A pipeline in Diffusers (be it standard or modular) will have multiple component - [ ] **VAE** (if applicable) — reuse an existing `AutoencoderKL*` if possible; if a new one is needed, follow the same sub-steps as the transformer - [ ] **Scheduler** — reuse an existing scheduler, or add a custom one - [ ] **Pipeline** - - [ ] Implement the pipeline — see [modular.md](../../modular.md) for modular pipeline, or [pipelines.md](../../pipelines.md) for standard pipeline + - [ ] Implement the pipeline — see [modular.md](references/modular.md) for modular pipeline, or [pipelines.md](references/pipelines.md) for standard pipeline - [ ] Add a LoRA mixin if applicable - [ ] Register in the relevant `__init__.py` files (lazy imports) - [ ] Pipeline-level tests (see **Testing**) @@ -66,7 +66,7 @@ docs/source/en/ ## Model integration specific rules -**Match the reference's numerical logic.** Restructuring code to fit diffusers APIs (`ModelMixin`, `ConfigMixin`, blocks for modular, etc.) is expected, and required diffusers conventions (e.g. the attention pattern in [models.md](../../models.md)) take precedence. Beyond those, keep the actual computation as close to the reference as possible — don't reorder operations, change the math, or rename internals for aesthetics, even if it looks unclean. Small deviations make output mismatches very hard to track down. +**Match the reference's numerical logic.** Restructuring code to fit diffusers APIs (`ModelMixin`, `ConfigMixin`, blocks for modular, etc.) is expected, and required diffusers conventions (e.g. the attention pattern in [models.md](references/models.md)) take precedence. Beyond those, keep the actual computation as close to the reference as possible — don't reorder operations, change the math, or rename internals for aesthetics, even if it looks unclean. Small deviations make output mismatches very hard to track down. ## Weight / Checkpoint Conversion @@ -76,7 +76,7 @@ Convert the original checkpoint into diffusers format with a standalone script u 2. Instantiate the diffusers model from its config and load the converted state dict. 3. `save_pretrained(...)` to a local path, then load it back with `from_pretrained` to confirm it round-trips. -All weights load through the standard paths — `from_pretrained`, or `from_single_file` (add `FromSingleFileMixin` + a weight-mapping) for an original-format single checkpoint. No custom `from_pretrained`, no manual runtime loading. See the loading rule in [models.md](../../models.md). +All weights load through the standard paths — `from_pretrained`, or `from_single_file` (add `FromSingleFileMixin` + a weight-mapping) for an original-format single checkpoint. No custom `from_pretrained`, no manual runtime loading. See the loading rule in [models.md](references/models.md). Common conversion patterns to watch for model-level components: - Fused QKV weights that need splitting into separate Q, K, V @@ -87,13 +87,13 @@ Common conversion patterns to watch for model-level components: ## Testing -Two test layers must be added for any new pipeline: pipeline-level tests, and (if a new model is introduced) model-level tests. Conventions for both layers — file locations, tester mixins, dummy-component rules — live in [testing.md](../../testing.md); follow it when writing the tests. +Two test layers must be added for any new pipeline: pipeline-level tests, and (if a new model is introduced) model-level tests. Conventions for both layers — file locations, tester mixins, dummy-component rules — live in [testing.md](references/testing.md); follow it when writing the tests. ## Model parity test Confirm the diffusers implementation matches the reference. Test each component on **CPU/float32** with a strict tolerance (`max_diff < 1e-3`), comparing the **freshly converted** weights against the reference in a single script — both sides side by side, nothing saved to disk in between. See [pitfalls.md](pitfalls.md) for the common sources of numerical discrepancy. -This is an **internal verification tool for integration — it should not be shipped in the PR** (it imports the reference repo). The tests that ship with the PR are the model-level and pipeline-level tests in [testing.md](../../testing.md). +This is an **internal verification tool for integration — it should not be shipped in the PR** (it imports the reference repo). The tests that ship with the PR are the model-level and pipeline-level tests in [testing.md](references/testing.md). The example below is schematic (placeholder names). `ReferenceModel` is the component **imported from the original repo**, and `convert_my_component` is **the same conversion function you wrote for the conversion script for the component**. You should make sure both load the *same* checkpoint weights and run the *same* input, so any difference is a conversion or implementation bug — not a difference in inputs. diff --git a/.ai/skills/self-review/SKILL.md b/.ai/skills/self-review/SKILL.md index 7a8536d32e54..088b2649c368 100644 --- a/.ai/skills/self-review/SKILL.md +++ b/.ai/skills/self-review/SKILL.md @@ -3,7 +3,7 @@ name: self-review description: > Use before opening a PR, or whenever asked to self-review a diffusers contribution. Applies the same rubric as the `@claude` CI (checks the diff - against .ai/review-rules.md, traces call paths for dead code). Reports findings grouped by + against references/review-rules.md, traces call paths for dead code). Reports findings grouped by severity, flagging what to fix before submitting (blocking issues + dead code) vs what to leave for the actual review. Report-only — does not edit files. --- @@ -30,14 +30,14 @@ files, scope to your own commits: `git log main..HEAD --oneline`, then ## 2. Read the rubric -`.ai/review-rules.md` is the canonical rubric (the CI pins it from `main`) — read +`references/review-rules.md` is the canonical rubric (the CI pins it from `main`) — read it and review against it; don't rely on a remembered copy. For the areas you -touched, also read `.ai/models.md`, `.ai/pipelines.md`, or `.ai/modular.md`. +touched, also read `references/models.md`, `references/pipelines.md`, `references/modular.md`, or `references/testing.md`. ## 3. Report - **Blocking issues** — numbered. Each: title → explanation → `file.py:line` → - impact. Cite the rule, e.g. *Per `.ai/models.md`: "…only keep the inference path."* + impact. Cite the rule, e.g. *Per `references/models.md`: "…only keep the inference path."* - **Non-blocking issues** — same format, lower severity. - **Dead code (advisory)** — a table: `path:line` · Likely-dead / Used · reason. - **Summary** — short synthesis and a verdict (**READY** / **NEEDS CHANGES**), diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 000000000000..2aa81aa24f55 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,14 @@ +{ + "name": "diffusers-skills", + "description": "Agent plugins published from the diffusers repository", + "owner": { + "name": "The Hugging Face team" + }, + "plugins": [ + { + "name": "diffusers", + "source": "./.ai", + "description": "Conventions and task skills for contributing to diffusers" + } + ] +} From 83b2efc971aef38b1eaa55c03838afb0ec0a65d7 Mon Sep 17 00:00:00 2001 From: DN6 Date: Wed, 12 Aug 2026 18:39:52 +0530 Subject: [PATCH 2/5] reorganize AGENTS.md and references --- .ai/AGENTS.md | 66 ----------- .ai/references/models.md | 1 - .ai/references/pipelines.md | 1 - .ai/references/review-rules.md | 6 +- .github/workflows/claude_review.yml | 4 +- AGENTS.md | 76 ++++++++++++- CLAUDE.md | 2 +- README.md | 2 +- docs/source/en/conceptual/contribution.md | 81 ++++++++++--- docs/source/en/using-diffusers/cli.md | 9 +- src/diffusers/commands/skills.py | 132 ++++++++++++++++++++-- tests/others/test_cli_skills.py | 64 ++++++++++- 12 files changed, 339 insertions(+), 105 deletions(-) delete mode 100644 .ai/AGENTS.md mode change 120000 => 100644 AGENTS.md mode change 120000 => 100644 CLAUDE.md diff --git a/.ai/AGENTS.md b/.ai/AGENTS.md deleted file mode 100644 index c7a0d3eb0aa1..000000000000 --- a/.ai/AGENTS.md +++ /dev/null @@ -1,66 +0,0 @@ -# Diffusers — Agent Guide - -## Setup - -This file is loaded automatically in a checkout, through the root `AGENTS.md` / `CLAUDE.md` symlinks. The -[skills](#skills) are not — install them once, by whichever route fits the agent: - -```bash -# Claude Code — installs every skill, namespaced as /diffusers: -claude plugin marketplace add huggingface/diffusers -claude plugin install diffusers@diffusers-skills --scope project - -# Codex — register the catalog, then install from the Plugins Directory in the ChatGPT desktop app -codex plugin marketplace add huggingface/diffusers - -# Any agent, no marketplace needed -diffusers-cli skills add --all # or: skills add , and --claude / --codex / --cursor to pick a target -``` - -Installing a skill copies the [reference guides](#reference-guides) it cites into its own `references/` subdirectory, -so it is self-contained wherever it lands. A skill gets a guide by citing it as `references/.md`; the guides -themselves live once at `.ai/references/`. `diffusers-cli skills list` shows what is available, and `diffusers-cli -skills update` refreshes what you installed. - -When editing the skills in this repo, load them from the working tree instead of installing: `claude --plugin-dir .ai` -for one session, or `make codex` to symlink `.agents/skills` at `.ai/skills` (`make clean-ai` to undo). - -## Coding style - -Strive to write code as simple and explicit as possible. - -- Prefer inlining small helper/utility functions over factoring them out — a reader should be able to follow the full flow without jumping between functions. If a private helper has only one caller, inlining it at the call site is usually the cleaner choice. -- No defensive code, unused code paths, or legacy stubs — do not add fallback paths, safety checks, or configuration options "just in case"; do not carry unused method parameters "for API consistency", backwards-compatibility aliases for names that never shipped, or deprecation shims for code that was never released. When porting from a research repo, delete training-time code paths, experimental flags, and ablation branches entirely — only keep the inference path you are actually integrating. -- Do not guess user intent and silently correct behavior. Make the expected inputs clear in the docstring, and raise a concise error for unsupported cases rather than adding complex fallback logic. - ---- - -## Code formatting - -- `make style` and `make fix-copies` should be run before opening a PR - -### Copied Code - -- Many classes are kept in sync with a source via a `# Copied from ...` header comment -- Do not edit a `# Copied from` block directly — run `make fix-copies` to propagate changes from the source -- Remove the header to intentionally break the link - -## Reference guides - -- **Models** — see [models.md](references/models.md) for model conventions, attention pattern, implementation rules, dependencies, and gotchas. For adding or converting a model, use the [model-integration](./skills/model-integration/SKILL.md) skill. -- **Pipelines** — see [pipelines.md](references/pipelines.md) for pipeline conventions, patterns, and gotchas. -- **Modular pipelines** — see [modular.md](references/modular.md) for modular pipeline conventions, patterns, and gotchas. -- **Tests** — see [testing.md](references/testing.md) for test conventions: required test layers, tester mixins, and dummy-component rules. - -## Skills - -Task-specific guides live in `.ai/skills/` and are loaded on demand by AI agents. Available skills include: - -- [model-integration](./skills/model-integration/SKILL.md) (adding/converting pipelines) -- [custom-blocks](./skills/custom-blocks/SKILL.md) (packaging a `ModularPipelineBlocks` subclass for the Hub) -- [diffusers-cli](./skills/diffusers-cli/SKILL.md) (running pipelines, inspecting schemas, and using the Diffusers CLI) -- [self-review](./skills/self-review/SKILL.md) (pre-PR self-review against the project rules) - -## Self-review before a PR - -Before opening a PR, run self-review against [review-rules.md](references/review-rules.md). The [self-review skill](skills/self-review/SKILL.md) runs this as the same pass the `@claude` CI reviewer uses. Share the final report on the PR (description or comment) — see the skill for details. diff --git a/.ai/references/models.md b/.ai/references/models.md index b99ff18e2334..01396a8ca8fb 100644 --- a/.ai/references/models.md +++ b/.ai/references/models.md @@ -1,7 +1,6 @@ # Model conventions and rules Shared reference for model-related conventions, patterns, and gotchas. -Linked from `../AGENTS.md`, `../skills/model-integration/SKILL.md`, and `review-rules.md`. ## Coding style diff --git a/.ai/references/pipelines.md b/.ai/references/pipelines.md index 005c4d544255..84d4e8b2b525 100644 --- a/.ai/references/pipelines.md +++ b/.ai/references/pipelines.md @@ -1,7 +1,6 @@ # Pipeline conventions and rules Shared reference for pipeline-related conventions, patterns, and gotchas. -Linked from `../AGENTS.md`, `../skills/model-integration/SKILL.md`, and `review-rules.md`. > **Prefer modular for new pipelines.** [Modular Diffusers](modular.md) is the preferred way to add a new pipeline; the standard `DiffusionPipeline` covered below is still supported but is no longer the default. We prefer modular especially for models that don't fit a fixed task-based structure (e.g. modality baked into the checkpoint) or that are actively evolving. The conventions below apply when you do build or review a standard pipeline. diff --git a/.ai/references/review-rules.md b/.ai/references/review-rules.md index 90be1ab1301f..e04a8de81433 100644 --- a/.ai/references/review-rules.md +++ b/.ai/references/review-rules.md @@ -3,7 +3,7 @@ Review-specific rules for Claude. Focus on correctness — style is handled by ruff. Before reviewing, read and apply the guidelines in: -- [AGENTS.md](../AGENTS.md) — coding style, copied code +- the repo's `AGENTS.md` — coding style, copied code - [models.md](models.md) — model conventions, attention pattern, implementation rules, dependencies, gotchas - [pipelines.md](pipelines.md) — pipeline conventions, coding style, gotchas - [modular.md](modular.md) — modular pipeline conventions, patterns, common mistakes @@ -12,7 +12,7 @@ Before reviewing, read and apply the guidelines in: ## Common mistakes -Common mistakes are covered in the common-mistakes / gotcha sections in [AGENTS.md](../AGENTS.md), [models.md](models.md), [pipelines.md](pipelines.md), and [modular.md](modular.md). Additionally, watch for below patterns that aren't covered there: +Common mistakes are covered in the common-mistakes / gotcha sections in `AGENTS.md`, [models.md](models.md), [pipelines.md](pipelines.md), and [modular.md](modular.md). Additionally, watch for below patterns that aren't covered there: - **Ephemeral context.** Comments, docstrings, and files that only made sense to the current PR's author or reviewer don't help a future reader/user/developer. Examples: `# per reviewer comment on PR #NNNN`, `# as discussed in review`, `# TODO from offline chat`, debug printouts. Same for files: parity harnesses, comparison scripts, anything in `scripts/` with hardcoded developer paths or imports from the reference repo. State the *reason* so the comment stands alone, or drop it. @@ -21,7 +21,7 @@ Common mistakes are covered in the common-mistakes / gotcha sections in [AGENTS. A PR can leave existing docs stale or surface a pattern worth recording. Scan the docs related to what the PR touches and flag updates as a **suggestions / additional info** section (not blocking): - **Usage docs.** New or changed public behavior — a new pipeline/model, a new argument, changed defaults, a renamed API — should have matching updates in `docs/`, docstrings, and examples. Flag any that now describe outdated behavior or that are missing for the new surface. -- **Agent docs.** If the review turns up a rule, pattern, or common gotcha that isn't written down yet — especially one the author got wrong or that you had to reason out — propose adding it to the relevant agent guide ([AGENTS.md](../AGENTS.md), [models.md](models.md), [pipelines.md](pipelines.md), [modular.md](modular.md), a skill, or this file) so the next contributor/agent gets it for free instead of repeating the mistake. Human review comments on the PR are a good source for these: if a human reviewer pointed something out and your review missed it, that usually indicates a doc gap — figure out what's missing and propose the addition. +- **Agent docs.** If the review turns up a rule, pattern, or common gotcha that isn't written down yet — especially one the author got wrong or that you had to reason out — propose adding it to the relevant agent guide (`AGENTS.md`, [models.md](models.md), [pipelines.md](pipelines.md), [modular.md](modular.md), a skill, or this file) so the next contributor/agent gets it for free instead of repeating the mistake. Human review comments on the PR are a good source for these: if a human reviewer pointed something out and your review missed it, that usually indicates a doc gap — figure out what's missing and propose the addition. ## Dead code analysis (new models) diff --git a/.github/workflows/claude_review.yml b/.github/workflows/claude_review.yml index 6f0510c923d1..5baf3a378dbf 100644 --- a/.github/workflows/claude_review.yml +++ b/.github/workflows/claude_review.yml @@ -62,8 +62,8 @@ jobs: EOF_DELIMITER="GITHUB_ENV_$(openssl rand -hex 8)" { echo "REVIEW_RULES<<${EOF_DELIMITER}" - git show "origin/${DEFAULT_BRANCH}:.ai/review-rules.md" 2>/dev/null \ - || echo "No .ai/review-rules.md found. Apply Python correctness standards." + git show "origin/${DEFAULT_BRANCH}:.ai/references/review-rules.md" 2>/dev/null \ + || echo "No .ai/references/review-rules.md found. Apply Python correctness standards." echo "${EOF_DELIMITER}" } >> "$GITHUB_ENV" diff --git a/AGENTS.md b/AGENTS.md deleted file mode 120000 index b28461c924a4..000000000000 --- a/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -.ai/AGENTS.md \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000000..92473dffbdc5 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,75 @@ +# Diffusers — Agent Guide + +## Setup + +We recommend developing in a virtual environment managed by [uv](https://docs.astral.sh/uv/): + +```bash +uv venv && source .venv/bin/activate +uv pip install -e . # provides diffusers-cli +``` + +List the available skills, and what each one is for, with: + +```bash +diffusers-cli skills list +``` + +Install them with: + +```bash +diffusers-cli skills add # install one, or --all for every skill + # --claude / --codex / --cursor to pick one target +``` + +`diffusers-cli skills update` refreshes what you installed. + +Claude Code and Codex can also install via plugins + +```bash +claude plugin marketplace add huggingface/diffusers +claude plugin install diffusers@diffusers-skills --scope project + +codex plugin marketplace add huggingface/diffusers # then install from the Plugins Directory +``` + + +## Coding style + +Strive to write code as simple and explicit as possible. + +- Prefer inlining small helper/utility functions over factoring them out — a reader should be able to follow the full flow without jumping between functions. If a private helper has only one caller, inlining it at the call site is usually the cleaner choice. +- No defensive code, unused code paths, or legacy stubs — do not add fallback paths, safety checks, or configuration options "just in case"; do not carry unused method parameters "for API consistency", backwards-compatibility aliases for names that never shipped, or deprecation shims for code that was never released. When porting from a research repo, delete training-time code paths, experimental flags, and ablation branches entirely — only keep the inference path you are actually integrating. +- Do not guess user intent and silently correct behavior. Make the expected inputs clear in the docstring, and raise a concise error for unsupported cases rather than adding complex fallback logic. + +--- + +## Code formatting + +- `make style` and `make fix-copies` should be run before opening a PR + +### Copied Code + +- Many classes are kept in sync with a source via a `# Copied from ...` header comment +- Do not edit a `# Copied from` block directly — run `make fix-copies` to propagate changes from the source +- Remove the header to intentionally break the link + +## Reference guides + +- **Models** — see [models.md](.ai/references/models.md) for model conventions, attention pattern, implementation rules, dependencies, and gotchas. For adding or converting a model, use the [model-integration](.ai/skills/model-integration/SKILL.md) skill. +- **Pipelines** — see [pipelines.md](.ai/references/pipelines.md) for pipeline conventions, patterns, and gotchas. +- **Modular pipelines** — see [modular.md](.ai/references/modular.md) for modular pipeline conventions, patterns, and gotchas. +- **Tests** — see [testing.md](.ai/references/testing.md) for test conventions: required test layers, tester mixins, and dummy-component rules. + +## Skills + +Task-specific guides live in `.ai/skills/` and are loaded on demand by AI agents. Available skills include: + +- [model-integration](.ai/skills/model-integration/SKILL.md) (adding/converting pipelines) +- [custom-blocks](.ai/skills/custom-blocks/SKILL.md) (packaging a `ModularPipelineBlocks` subclass for the Hub) +- [diffusers-cli](.ai/skills/diffusers-cli/SKILL.md) (running pipelines, inspecting schemas, and using the Diffusers CLI) +- [self-review](.ai/skills/self-review/SKILL.md) (pre-PR self-review against the project rules) + +## Self-review before a PR + +Before opening a PR, run self-review against [review-rules.md](.ai/references/review-rules.md). The [self-review skill](.ai/skills/self-review/SKILL.md) runs this as the same pass the `@claude` CI reviewer uses. Share the final report on the PR (description or comment) — see the skill for details. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 120000 index b28461c924a4..000000000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -.ai/AGENTS.md \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000000..43c994c2d361 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md index f9f494e393c6..88e32673b39a 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Check out the [Quickstart](https://huggingface.co/docs/diffusers/quicktour) to l We ❤️ contributions from the open-source community! If you want to contribute to this library, please check out our [Contribution guide](https://huggingface.co/docs/diffusers/main/en/conceptual/contribution). -If you are using an AI agent, please point it at the project conventions in [`.ai/`](https://github.com/huggingface/diffusers/tree/main/.ai) first (run `make claude` or `make codex`) — see [Coding with AI agents](https://huggingface.co/docs/diffusers/main/en/conceptual/contribution#coding-with-ai-agents). +If you are using an AI agent, please point it at the project conventions in [`AGENTS.md`](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) and [`.ai/`](https://github.com/huggingface/diffusers/tree/main/.ai) first (install them as a plugin with `claude plugin marketplace add huggingface/diffusers`, or a skill at a time with `diffusers-cli skills add `) — see [Coding with AI agents](https://huggingface.co/docs/diffusers/main/en/conceptual/contribution#coding-with-ai-agents). You can look out for [issues](https://github.com/huggingface/diffusers/issues) you'd like to tackle to contribute to the library. - See [Good first issues](https://github.com/huggingface/diffusers/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) for general opportunities to contribute - See [New model/pipeline](https://github.com/huggingface/diffusers/issues?q=is%3Aopen+is%3Aissue+label%3A%22New+pipeline%2Fmodel%22) to contribute exciting new diffusion models / diffusion pipelines diff --git a/docs/source/en/conceptual/contribution.md b/docs/source/en/conceptual/contribution.md index 2eb3275fa95a..db27ec00c7c6 100644 --- a/docs/source/en/conceptual/contribution.md +++ b/docs/source/en/conceptual/contribution.md @@ -578,36 +578,85 @@ For documentation strings, 🧨 Diffusers follows the [Google style](https://goo ## Coding with AI agents -The repository keeps AI-agent configuration in [`.ai/`](https://github.com/huggingface/diffusers/tree/main/.ai). Run `make claude` / `make codex` to additionally wire up the on-demand task skills for your tool. - -- **Read-only for contributors** — `.ai/` is maintained by the core maintainers. Please do not edit files under `.ai/` (or the root-level `AGENTS.md` / `CLAUDE.md` symlinks, or the generated `.agents/skills` / `.claude/skills`) in your PR. If you find something missing or wrong, open an issue or flag it on the PR and a maintainer will update it. -- **Guidelines** (loaded into every agent session): - - [`.ai/AGENTS.md`](https://github.com/huggingface/diffusers/blob/main/.ai/AGENTS.md) — top-level coding guidelines - - [`.ai/models.md`](https://github.com/huggingface/diffusers/blob/main/.ai/models.md) — attention pattern, model implementation rules, common conventions - - [`.ai/pipelines.md`](https://github.com/huggingface/diffusers/blob/main/.ai/pipelines.md) — pipeline conventions - - [`.ai/modular.md`](https://github.com/huggingface/diffusers/blob/main/.ai/modular.md) — modular pipeline conventions and conversion checklist - - [`.ai/review-rules.md`](https://github.com/huggingface/diffusers/blob/main/.ai/review-rules.md) — what reviewers look for +The repository keeps AI-agent configuration in [`.ai/`](https://github.com/huggingface/diffusers/tree/main/.ai), which is also published as an agent plugin so the on-demand task skills install in one step. + +- **Read-only for contributors** — `AGENTS.md` and `.ai/` are maintained by the core maintainers. Please do not edit them (or the root `CLAUDE.md`, or the installed `.agents/skills` / `.claude/skills`) in your PR. If you find something missing or wrong, open an issue or flag it on the PR and a maintainer will update it. +- **Guidelines** — `AGENTS.md` at the repo root is loaded into every agent session; Codex and Cursor read it + directly, and the root `CLAUDE.md` imports it for Claude Code. The reference guides under `.ai/references/` are read + on demand when a link is followed: + - [`AGENTS.md`](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) — top-level coding guidelines + - [`.ai/references/models.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/models.md) — attention pattern, model implementation rules, common conventions + - [`.ai/references/pipelines.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/pipelines.md) — pipeline conventions + - [`.ai/references/modular.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/modular.md) — modular pipeline conventions and conversion checklist + - [`.ai/references/testing.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/testing.md) — required test layers, tester mixins, dummy-component rules + - [`.ai/references/review-rules.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/review-rules.md) — what reviewers look for - **Skills** (under [`.ai/skills/`](https://github.com/huggingface/diffusers/tree/main/.ai/skills), loaded on demand for specific tasks): - `model-integration` — adding a new model or pipeline to diffusers end-to-end (file structure, integration checklist, testing layout, weight conversion) - `self-review` — review your changes against the project rules before opening a PR -- **Setup commands**: - - `make codex` — wire up skills for OpenAI Codex (under `.agents/`) - - `make claude` — wire up skills for Claude Code (under `.claude/`) - - `make clean-ai` — remove the generated skills symlinks + - `diffusers-cli` — running pipelines and inspecting schemas from the terminal + - `custom-blocks` — packaging a `ModularPipelineBlocks` subclass for the Hub + +### Installing the skills + +All four skills are the same whichever route you take. Pick one — installing through more than one leaves you with two +copies of every skill. + +**Claude Code, from the marketplace.** The usual route. Run these in your shell, or the same commands as `/plugin ...` +inside a session: + +```bash +claude plugin marketplace add huggingface/diffusers +claude plugin install diffusers@diffusers-skills --scope project +``` + +`--scope project` records the plugin in `.claude/settings.json`, so everyone working in the clone is prompted to install +it; `--scope local` installs it for you in this repository only, and `--scope user` for you across all projects. In a +running session, activate it with `/reload-plugins`. + +**Claude Code, for one session.** Loads the plugin straight from your checkout without installing anything — useful for +trying a change to a skill: + +```bash +claude --plugin-dir .ai +``` + +**Codex.** Register the same catalog, then install from the Plugins Directory in the ChatGPT desktop app: + +```bash +codex plugin marketplace add huggingface/diffusers +``` + +**Any agent, without a marketplace.** The [`skills`](../using-diffusers/cli#skills) CLI command downloads skills from +`main` and writes them where your agent looks: + +```bash +diffusers-cli skills add --all # detects the agent from the environment +diffusers-cli skills add --all --claude # or --codex / --cursor to pick one +diffusers-cli skills add self-review # a single skill +``` + +For Claude Code this writes a plugin bundle at `.claude/skills/diffusers/`, which loads once you trust the workspace and +gives the same `/diffusers:` namespace as the marketplace. Codex and Cursor get `.agents/skills//`, the +layout their discovery expects, where skills are invoked by their bare name. Installing a skill also copies the guides +it cites from [`.ai/references/`](https://github.com/huggingface/diffusers/tree/main/.ai/references) into its own +`references/` subdirectory, so an installed skill is self-contained outside a checkout. Add `--global` to install for +every project instead of the current one, and `diffusers-cli skills update` to refresh both the skills and their +references. + ### AI-assisted and agentic contributions -AI agents are welcome for contributing to Diffusers. We encourage you to set up your agent with the Diffusers [agent guide](https://github.com/huggingface/diffusers/blob/main/.ai/AGENTS.md) and use the relevant task-specific skills, such as `model-integration` and `self-review`. Run `make codex` or `make claude` to use the skills with your agent, then follow the guide to scope, implement, test, and review your contribution. You remain responsible for understanding, testing, and maintaining the changes in your PR. +AI agents are welcome for contributing to Diffusers. We encourage you to set up your agent with the Diffusers [agent guide](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) and use the relevant task-specific skills, such as `model-integration` and `self-review`. Install the plugin (or the individual skills) as described above, then follow the guide to scope, implement, test, and review your contribution. You remain responsible for understanding, testing, and maintaining the changes in your PR. AI-assisted contributions are welcome, but they must be coordinated, scoped, and verified to keep review load manageable. PRs that do not follow these guidelines may be closed without detailed review. - **Coordinate before opening a PR.** Find or open an issue, review similar PRs (open and recently closed), and wait for an explicit acknowledgment from a maintainer on that issue before opening a PR. This gives us a chance to discuss scope, avoid duplicate work, and confirm the approach. - **Fix patterns, not one-offs.** If you spot an recurring issue, search the codebase for similar instances and open a *single* issue with a clear, systematic scope (e.g. "fix mutable defaults across all schedulers") rather than many issues or PRs for individual instances. -- **Self-review before opening.** Run the [`self-review`](https://github.com/huggingface/diffusers/blob/main/.ai/skills/self-review/SKILL.md) skill — it reviews your diff against [`.ai/review-rules.md`](https://github.com/huggingface/diffusers/blob/main/.ai/review-rules.md), the same rubric the `@claude` CI reviewer uses — and address what it reports — it's a helper, not authoritative, and can be wrong. Focus on the blocking issues that make sense to you, and clean up dead/unused code as much as possible. If you disagree with a suggestion, it's fine to leave it for the reviewer to discuss after the PR is opened — the notes you share (see below) tell the reviewer it was a deliberate call. +- **Self-review before opening.** Run the [`self-review`](https://github.com/huggingface/diffusers/blob/main/.ai/skills/self-review/SKILL.md) skill — it reviews your diff against [`.ai/references/review-rules.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/review-rules.md), the same rubric the `@claude` CI reviewer uses — and address what it reports — it's a helper, not authoritative, and can be wrong. Focus on the blocking issues that make sense to you, and clean up dead/unused code as much as possible. If you disagree with a suggestion, it's fine to leave it for the reviewer to discuss after the PR is opened — the notes you share (see below) tell the reviewer it was a deliberate call. - **Share your self-review notes.** Please post the final self-review report — the round that reflects the diff you're submitting — on the PR, in the description or as a comment, including findings you intentionally did not fix and why. It helps the reviewer see what has already been checked and which calls were deliberate, and usually saves a few rounds of back-and-forth. - **Include in the PR description:** - A **coordination link** to the issue or discussion where a maintainer acknowledged the work. - The **test commands you ran** and their results (paste relevant output, not just "tests pass"). - Your **self-review notes** (or a link to the PR comment containing them), as described above. -If you are a model author or part of a team that officially maintains a model, we encourage you to use agents for a new model integration. Follow the repository's [recommended setup](https://github.com/huggingface/diffusers/blob/main/.ai/AGENTS.md) and use the [`model-integration`](https://github.com/huggingface/diffusers/blob/main/.ai/skills/model-integration/SKILL.md) skill. Coordinate the scope with maintainers before opening a PR — see [Adding pipelines, models, schedulers](#9-adding-pipelines-models-schedulers). +If you are a model author or part of a team that officially maintains a model, we encourage you to use agents for a new model integration. Follow the repository's [recommended setup](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) and use the [`model-integration`](https://github.com/huggingface/diffusers/blob/main/.ai/skills/model-integration/SKILL.md) skill. Coordinate the scope with maintainers before opening a PR — see [Adding pipelines, models, schedulers](#9-adding-pipelines-models-schedulers). diff --git a/docs/source/en/using-diffusers/cli.md b/docs/source/en/using-diffusers/cli.md index 4a8127888c73..5cefc9376b75 100644 --- a/docs/source/en/using-diffusers/cli.md +++ b/docs/source/en/using-diffusers/cli.md @@ -276,7 +276,7 @@ diffusers-cli skills add "" # Install every skill in the registry diffusers-cli skills add --all -# List available skills +# List available skills with a one-line summary of each diffusers-cli skills list # Preview a skill's SKILL.md without installing @@ -287,6 +287,13 @@ diffusers-cli skills update # Install to the user-level directory instead of the current project diffusers-cli skills add diffusers-cli --global + +# Install for one agent instead of detecting it from the environment +diffusers-cli skills add --all --claude # or --codex / --cursor ``` +Without a target flag, the CLI installs for whichever agent launched it, or for every agent when it can't tell. +For Claude Code the skills are written as a plugin bundle at `.claude/skills/diffusers/`, so they are namespaced +as `/diffusers:`; Codex and Cursor get `.agents/skills//`. + diff --git a/src/diffusers/commands/skills.py b/src/diffusers/commands/skills.py index 60d2e40e883f..455c1f0eee0a 100644 --- a/src/diffusers/commands/skills.py +++ b/src/diffusers/commands/skills.py @@ -14,14 +14,17 @@ """`diffusers-cli skills` — install Agent Skills bundles. Skill bundles live under `.ai/skills//` in the diffusers repo and follow the Agent Skills standard: a directory -containing `SKILL.md` (plus optional resources). Installs to `.agents/skills//` which Claude, Codex, and Cursor -all discover. +containing `SKILL.md` (plus optional resources), including the `references/` copies of the guides it cites. Claude Code +gets a plugin bundle under `.claude/skills/`; Codex and Cursor get `.agents/skills//`. """ from __future__ import annotations +import json import os +import re import shutil +import textwrap from argparse import ArgumentParser, Namespace, _SubParsersAction from pathlib import Path @@ -37,8 +40,13 @@ _REGISTRY_BASE = "https://api.github.com/repos/huggingface/diffusers/contents/.ai/skills" +_RAW_BASE = "https://raw.githubusercontent.com/huggingface/diffusers" _REGISTRY_REF = "main" +# How a skill cites a guide, e.g. `](references/models.md)` or `` `references/testing.md` ``. The install copies exactly +# the guides named this way, so a skill only has to cite one to get it. +_CITATION = re.compile(r"(?` and matches what the +# published plugin gives contributors. Codex and Cursor have no equivalent, so they keep the plain +# one-skill-per-directory layout their discovery expects. +_PLUGIN_NAME = "diffusers" +_PLUGIN_MANIFEST = { + "name": _PLUGIN_NAME, + "description": "Conventions and task skills for contributing to diffusers", +} + # --------------------------------------------------------------------------- # Registry fetch @@ -72,6 +90,11 @@ def _registry_url(name: str = "") -> str: return f"{_REGISTRY_BASE}{path}?ref={_REGISTRY_REF}" +def _skill_md_url(name: str) -> str: + """Raw URL of a skill's SKILL.md, so `list` can read descriptions without walking each bundle.""" + return f"{_RAW_BASE}/{_REGISTRY_REF}/.ai/skills/{name}/SKILL.md" + + def _fetch_json(url: str) -> list[dict]: try: resp = httpx.get(url, timeout=DIFFUSERS_REQUEST_TIMEOUT) @@ -99,6 +122,32 @@ def _walk(api_url: str, prefix: str) -> None: return files +def _skill_description(skill_md: str) -> str: + """The `description` from a SKILL.md YAML frontmatter, collapsed onto one line. + + Handles both `description: text` and the folded `description: >` form the skills in this repo use. Returns an empty + string when the file has no frontmatter or no description. + """ + lines = skill_md.splitlines() + if not lines or lines[0].strip() != "---": + return "" + for index, line in enumerate(lines[1:], start=1): + if line.strip() == "---": + return "" + if not line.startswith("description:"): + continue + value = line[len("description:") :].strip() + if value and value not in (">", "|", ">-", "|-"): + return value + folded = [] + for continuation in lines[index + 1 :]: + if continuation.strip() == "---" or not continuation.startswith((" ", "\t")): + break + folded.append(continuation.strip()) + return " ".join(folded) + return "" + + def _download_skill_bundle(name: str) -> dict[str, bytes]: files = _walk_skill_files(name) if not files: @@ -128,8 +177,30 @@ def _detect_install_dirs() -> tuple[Path, ...]: return _ALL_INSTALL_DIRS +def _skill_dir(root: Path, skills_dir: Path, name: str) -> Path: + """Where a single skill lands, which differs by target: a plugin bundle for Claude Code, a bare + directory for Codex and Cursor.""" + if skills_dir == _CLAUDE_SKILLS_DIR: + return root / skills_dir / _PLUGIN_NAME / "skills" / name + return root / skills_dir / name + + +def _install_references(skill_dir: Path, skill_md: bytes) -> None: + """Copy the guides a skill cites into its own `references/` directory. + + A skill cites a guide as `references/.md`, so the guides it needs are exactly the ones its SKILL.md names. + The repo keeps one copy of each under `.ai/references/`; an install gets its own so the skill is self-contained. + """ + references_dir = skill_dir / "references" + for guide in sorted(set(_CITATION.findall(skill_md.decode()))): + resp = httpx.get(f"{_RAW_BASE}/{_REGISTRY_REF}/.ai/references/{guide}", timeout=DIFFUSERS_REQUEST_TIMEOUT) + resp.raise_for_status() + references_dir.mkdir(parents=True, exist_ok=True) + (references_dir / guide).write_bytes(resp.content) + + def _install_skill(name: str, bundle: dict[str, bytes], root: Path, skills_dir: Path, force: bool) -> Path: - skill_dir = root / skills_dir / name + skill_dir = _skill_dir(root, skills_dir, name) if skill_dir.exists(): if not force: raise SystemExit(f"Skill already installed at {skill_dir}. Use --force to reinstall.") @@ -140,19 +211,29 @@ def _install_skill(name: str, bundle: dict[str, bytes], root: Path, skills_dir: target.parent.mkdir(parents=True, exist_ok=True) target.write_bytes(data) (skill_dir / _MANAGED_MARKER_FILE).touch() + _install_references(skill_dir, bundle["SKILL.md"]) + + if skills_dir == _CLAUDE_SKILLS_DIR: + manifest = root / skills_dir / _PLUGIN_NAME / ".claude-plugin" / "plugin.json" + manifest.parent.mkdir(parents=True, exist_ok=True) + manifest.write_text(json.dumps(_PLUGIN_MANIFEST, indent=2) + "\n") + return skill_dir def _has_local_changes(skill_dir: Path, bundle: dict[str, bytes]) -> bool: """True if the installed skill has any file that differs from `bundle` or has extra files. - The marker file is ignored. Compares raw bytes so a whitespace-only edit still counts as dirty. + The marker file and the copied `references/` guides are ignored — neither comes from the skill bundle. Compares raw + bytes so a whitespace-only edit still counts as dirty. """ on_disk: dict[str, bytes] = {} for path in skill_dir.rglob("*"): if not path.is_file(): continue rel = str(path.relative_to(skill_dir)) + if rel.startswith("references/"): + continue if rel == _MANAGED_MARKER_FILE: continue on_disk[rel] = path.read_bytes() @@ -164,6 +245,8 @@ def _discover_installed(root: Path) -> list[tuple[Path, str]]: found: list[tuple[Path, str]] = [] for skills_dir in _ALL_INSTALL_DIRS: skills_root = root / skills_dir + if skills_dir == _CLAUDE_SKILLS_DIR: + skills_root = skills_root / _PLUGIN_NAME / "skills" if not skills_root.exists(): continue for d in sorted(skills_root.iterdir()): @@ -196,6 +279,28 @@ def register_subcommand(subparsers: _SubParsersAction) -> None: action="store_true", help="Install every skill in the registry. Mutually exclusive with a positional name.", ) + target = add.add_mutually_exclusive_group() + target.add_argument( + "--claude", + dest="install_dirs", + action="store_const", + const=(_CLAUDE_SKILLS_DIR,), + help="Install for Claude Code only, instead of detecting the agent from the environment.", + ) + target.add_argument( + "--codex", + dest="install_dirs", + action="store_const", + const=(_AGENTS_SKILLS_DIR,), + help="Install for Codex only.", + ) + target.add_argument( + "--cursor", + dest="install_dirs", + action="store_const", + const=(_AGENTS_SKILLS_DIR,), + help="Install for Cursor only.", + ) add.add_argument( "--global", "-g", @@ -254,7 +359,7 @@ def _add(self) -> None: raise SystemExit("Pass a skill name (e.g. diffusers-cli) or --all to install every skill.") root = Path.home() if self.args.install_global else Path.cwd() - install_dirs = _detect_install_dirs() + install_dirs = self.args.install_dirs or _detect_install_dirs() names = self._resolve_names() installed: list[str] = [] @@ -272,6 +377,7 @@ def _add(self) -> None: if not installed: raise SystemExit(f"No skills installed. Failed: {failed}") + out.result( f"Installed {len(installed)} skill(s)", installed=", ".join(installed), @@ -302,7 +408,7 @@ def _update(self) -> None: try: bundle = _download_skill_bundle(name) for skills_dir in dirs: - skill_dir = root / skills_dir / name + skill_dir = _skill_dir(root, skills_dir, name) if not self.args.force and _has_local_changes(skill_dir, bundle): logger.warning( f"Skill {name!r} at {skill_dir} has local modifications; " @@ -332,10 +438,18 @@ def _preview(self) -> None: def _list(self) -> None: entries = _fetch_json(_registry_url()) - skills = [{"name": e["name"]} for e in entries if e["type"] == "dir" and not e["name"].startswith(".")] - if not skills: + names = sorted(e["name"] for e in entries if e["type"] == "dir" and not e["name"].startswith(".")) + if not names: raise SystemExit("No skills found in registry.") - out.table(skills, headers=["name"]) + + # Descriptions run several sentences, so they get a wrapped block under each name rather than a table cell. + width = min(shutil.get_terminal_size().columns, 100) + for name in names: + resp = httpx.get(_skill_md_url(name), timeout=DIFFUSERS_REQUEST_TIMEOUT) + resp.raise_for_status() + description = _skill_description(resp.text) + print(f"\n{name}") + print(textwrap.fill(description, width=width, initial_indent=" ", subsequent_indent=" ")) def _resolve_names(self) -> list[str]: if self.args.install_all: diff --git a/tests/others/test_cli_skills.py b/tests/others/test_cli_skills.py index d5e87ed61d44..645e416d2ef8 100644 --- a/tests/others/test_cli_skills.py +++ b/tests/others/test_cli_skills.py @@ -17,6 +17,9 @@ (``_fetch_json`` / ``_download_skill_bundle``) is left out — it needs the network. """ +import json +from argparse import ArgumentParser + import pytest from diffusers.commands.skills import ( @@ -25,12 +28,21 @@ _ALL_INSTALL_DIRS, _CLAUDE_SKILLS_DIR, _MANAGED_MARKER_FILE, + _PLUGIN_NAME, + SkillsCommand, _detect_install_dirs, _discover_installed, _install_skill, + _skill_description, ) +def _parse_skills_args(argv): + parser = ArgumentParser() + SkillsCommand.register_subcommand(parser.add_subparsers()) + return parser.parse_args(argv) + + SAMPLE_BUNDLE = { "SKILL.md": b"---\nname: example-skill\ndescription: An example skill.\n---\n\n# Example\n", "extra.md": b"# Extra reference file\n", @@ -41,13 +53,23 @@ class TestInstallSkill: def test_writes_bundle_and_marker(self, tmp_path): location = _install_skill("example-skill", SAMPLE_BUNDLE, tmp_path, _CLAUDE_SKILLS_DIR, force=False) - skill_dir = tmp_path / _CLAUDE_SKILLS_DIR / "example-skill" + skill_dir = tmp_path / _CLAUDE_SKILLS_DIR / _PLUGIN_NAME / "skills" / "example-skill" assert location == skill_dir assert (skill_dir / "SKILL.md").read_bytes() == SAMPLE_BUNDLE["SKILL.md"] assert (skill_dir / "extra.md").read_bytes() == SAMPLE_BUNDLE["extra.md"] assert (skill_dir / "reference" / "script.py").read_bytes() == SAMPLE_BUNDLE["reference/script.py"] assert (skill_dir / _MANAGED_MARKER_FILE).exists() + def test_claude_install_writes_plugin_manifest(self, tmp_path): + _install_skill("example-skill", SAMPLE_BUNDLE, tmp_path, _CLAUDE_SKILLS_DIR, force=False) + manifest = tmp_path / _CLAUDE_SKILLS_DIR / _PLUGIN_NAME / ".claude-plugin" / "plugin.json" + assert json.loads(manifest.read_text())["name"] == _PLUGIN_NAME + + def test_agents_install_stays_flat(self, tmp_path): + location = _install_skill("example-skill", SAMPLE_BUNDLE, tmp_path, _AGENTS_SKILLS_DIR, force=False) + assert location == tmp_path / _AGENTS_SKILLS_DIR / "example-skill" + assert not (tmp_path / _AGENTS_SKILLS_DIR / _PLUGIN_NAME).exists() + def test_errors_without_force_on_existing_dir(self, tmp_path): _install_skill("example-skill", SAMPLE_BUNDLE, tmp_path, _CLAUDE_SKILLS_DIR, force=False) with pytest.raises(SystemExit, match="Use --force to reinstall"): @@ -57,7 +79,7 @@ def test_force_replaces_existing(self, tmp_path): _install_skill("example-skill", SAMPLE_BUNDLE, tmp_path, _CLAUDE_SKILLS_DIR, force=False) new_bundle = {"SKILL.md": b"different content"} _install_skill("example-skill", new_bundle, tmp_path, _CLAUDE_SKILLS_DIR, force=True) - skill_dir = tmp_path / _CLAUDE_SKILLS_DIR / "example-skill" + skill_dir = tmp_path / _CLAUDE_SKILLS_DIR / _PLUGIN_NAME / "skills" / "example-skill" assert (skill_dir / "SKILL.md").read_bytes() == b"different content" assert not (skill_dir / "extra.md").exists() assert (skill_dir / _MANAGED_MARKER_FILE).exists() @@ -85,12 +107,48 @@ def test_env_var_picks_specific_target(self, monkeypatch, env_var, expected): assert _detect_install_dirs() == (expected,) +class TestSkillDescription: + def test_reads_folded_block(self): + skill_md = "---\nname: demo\ndescription: >\n First line\n second line.\n---\n\n# Body\n" + assert _skill_description(skill_md) == "First line second line." + + def test_reads_single_line(self): + assert _skill_description("---\nname: demo\ndescription: Does a thing.\n---\n") == "Does a thing." + + def test_returns_empty_without_frontmatter(self): + assert _skill_description("# Just a heading\n") == "" + + def test_returns_empty_without_description(self): + assert _skill_description("---\nname: demo\n---\n") == "" + + +class TestTargetFlags: + @pytest.mark.parametrize( + ("flag", "expected"), + [ + ("--claude", (_CLAUDE_SKILLS_DIR,)), + ("--codex", (_AGENTS_SKILLS_DIR,)), + ("--cursor", (_AGENTS_SKILLS_DIR,)), + ], + ) + def test_flag_pins_install_dirs(self, flag, expected): + args = _parse_skills_args(["skills", "add", "self-review", flag]) + assert args.install_dirs == expected + + def test_no_flag_defers_to_detection(self): + assert _parse_skills_args(["skills", "add", "self-review"]).install_dirs is None + + def test_flags_are_mutually_exclusive(self): + with pytest.raises(SystemExit): + _parse_skills_args(["skills", "add", "self-review", "--claude", "--codex"]) + + class TestDiscoverInstalled: def test_returns_managed_installs_from_all_paths(self, tmp_path): _install_skill("skill-a", SAMPLE_BUNDLE, tmp_path, _CLAUDE_SKILLS_DIR, force=False) _install_skill("skill-b", SAMPLE_BUNDLE, tmp_path, _AGENTS_SKILLS_DIR, force=False) # User-placed skill without our marker — should be ignored. - unmanaged = tmp_path / _CLAUDE_SKILLS_DIR / "user-placed" + unmanaged = tmp_path / _CLAUDE_SKILLS_DIR / _PLUGIN_NAME / "skills" / "user-placed" unmanaged.mkdir(parents=True) (unmanaged / "SKILL.md").write_bytes(b"user content") From 5791767bbcbf913395314b70884c5f7029953087 Mon Sep 17 00:00:00 2001 From: DN6 Date: Wed, 12 Aug 2026 19:01:20 +0530 Subject: [PATCH 3/5] clean up --- AGENTS.md | 76 +---------------------- CLAUDE.md | 2 +- README.md | 2 +- docs/source/en/conceptual/contribution.md | 61 ++---------------- 4 files changed, 9 insertions(+), 132 deletions(-) mode change 100644 => 120000 AGENTS.md mode change 100644 => 120000 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 92473dffbdc5..000000000000 --- a/AGENTS.md +++ /dev/null @@ -1,75 +0,0 @@ -# Diffusers — Agent Guide - -## Setup - -We recommend developing in a virtual environment managed by [uv](https://docs.astral.sh/uv/): - -```bash -uv venv && source .venv/bin/activate -uv pip install -e . # provides diffusers-cli -``` - -List the available skills, and what each one is for, with: - -```bash -diffusers-cli skills list -``` - -Install them with: - -```bash -diffusers-cli skills add # install one, or --all for every skill - # --claude / --codex / --cursor to pick one target -``` - -`diffusers-cli skills update` refreshes what you installed. - -Claude Code and Codex can also install via plugins - -```bash -claude plugin marketplace add huggingface/diffusers -claude plugin install diffusers@diffusers-skills --scope project - -codex plugin marketplace add huggingface/diffusers # then install from the Plugins Directory -``` - - -## Coding style - -Strive to write code as simple and explicit as possible. - -- Prefer inlining small helper/utility functions over factoring them out — a reader should be able to follow the full flow without jumping between functions. If a private helper has only one caller, inlining it at the call site is usually the cleaner choice. -- No defensive code, unused code paths, or legacy stubs — do not add fallback paths, safety checks, or configuration options "just in case"; do not carry unused method parameters "for API consistency", backwards-compatibility aliases for names that never shipped, or deprecation shims for code that was never released. When porting from a research repo, delete training-time code paths, experimental flags, and ablation branches entirely — only keep the inference path you are actually integrating. -- Do not guess user intent and silently correct behavior. Make the expected inputs clear in the docstring, and raise a concise error for unsupported cases rather than adding complex fallback logic. - ---- - -## Code formatting - -- `make style` and `make fix-copies` should be run before opening a PR - -### Copied Code - -- Many classes are kept in sync with a source via a `# Copied from ...` header comment -- Do not edit a `# Copied from` block directly — run `make fix-copies` to propagate changes from the source -- Remove the header to intentionally break the link - -## Reference guides - -- **Models** — see [models.md](.ai/references/models.md) for model conventions, attention pattern, implementation rules, dependencies, and gotchas. For adding or converting a model, use the [model-integration](.ai/skills/model-integration/SKILL.md) skill. -- **Pipelines** — see [pipelines.md](.ai/references/pipelines.md) for pipeline conventions, patterns, and gotchas. -- **Modular pipelines** — see [modular.md](.ai/references/modular.md) for modular pipeline conventions, patterns, and gotchas. -- **Tests** — see [testing.md](.ai/references/testing.md) for test conventions: required test layers, tester mixins, and dummy-component rules. - -## Skills - -Task-specific guides live in `.ai/skills/` and are loaded on demand by AI agents. Available skills include: - -- [model-integration](.ai/skills/model-integration/SKILL.md) (adding/converting pipelines) -- [custom-blocks](.ai/skills/custom-blocks/SKILL.md) (packaging a `ModularPipelineBlocks` subclass for the Hub) -- [diffusers-cli](.ai/skills/diffusers-cli/SKILL.md) (running pipelines, inspecting schemas, and using the Diffusers CLI) -- [self-review](.ai/skills/self-review/SKILL.md) (pre-PR self-review against the project rules) - -## Self-review before a PR - -Before opening a PR, run self-review against [review-rules.md](.ai/references/review-rules.md). The [self-review skill](.ai/skills/self-review/SKILL.md) runs this as the same pass the `@claude` CI reviewer uses. Share the final report on the PR (description or comment) — see the skill for details. diff --git a/AGENTS.md b/AGENTS.md new file mode 120000 index 000000000000..b28461c924a4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +.ai/AGENTS.md \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 43c994c2d361..000000000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -@AGENTS.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 000000000000..b28461c924a4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +.ai/AGENTS.md \ No newline at end of file diff --git a/README.md b/README.md index 88e32673b39a..9d6a086d6492 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Check out the [Quickstart](https://huggingface.co/docs/diffusers/quicktour) to l We ❤️ contributions from the open-source community! If you want to contribute to this library, please check out our [Contribution guide](https://huggingface.co/docs/diffusers/main/en/conceptual/contribution). -If you are using an AI agent, please point it at the project conventions in [`AGENTS.md`](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) and [`.ai/`](https://github.com/huggingface/diffusers/tree/main/.ai) first (install them as a plugin with `claude plugin marketplace add huggingface/diffusers`, or a skill at a time with `diffusers-cli skills add `) — see [Coding with AI agents](https://huggingface.co/docs/diffusers/main/en/conceptual/contribution#coding-with-ai-agents). +If you are using an AI agent, please point it at the project conventions in [`.ai/`](https://github.com/huggingface/diffusers/tree/main/.ai) first (install them as a plugin with `claude plugin marketplace add huggingface/diffusers`, or a skill at a time with `diffusers-cli skills add `) — see [Coding with AI agents](https://huggingface.co/docs/diffusers/main/en/conceptual/contribution#coding-with-ai-agents). You can look out for [issues](https://github.com/huggingface/diffusers/issues) you'd like to tackle to contribute to the library. - See [Good first issues](https://github.com/huggingface/diffusers/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) for general opportunities to contribute - See [New model/pipeline](https://github.com/huggingface/diffusers/issues?q=is%3Aopen+is%3Aissue+label%3A%22New+pipeline%2Fmodel%22) to contribute exciting new diffusion models / diffusion pipelines diff --git a/docs/source/en/conceptual/contribution.md b/docs/source/en/conceptual/contribution.md index db27ec00c7c6..5e56afe1e68c 100644 --- a/docs/source/en/conceptual/contribution.md +++ b/docs/source/en/conceptual/contribution.md @@ -580,11 +580,10 @@ For documentation strings, 🧨 Diffusers follows the [Google style](https://goo The repository keeps AI-agent configuration in [`.ai/`](https://github.com/huggingface/diffusers/tree/main/.ai), which is also published as an agent plugin so the on-demand task skills install in one step. -- **Read-only for contributors** — `AGENTS.md` and `.ai/` are maintained by the core maintainers. Please do not edit them (or the root `CLAUDE.md`, or the installed `.agents/skills` / `.claude/skills`) in your PR. If you find something missing or wrong, open an issue or flag it on the PR and a maintainer will update it. -- **Guidelines** — `AGENTS.md` at the repo root is loaded into every agent session; Codex and Cursor read it - directly, and the root `CLAUDE.md` imports it for Claude Code. The reference guides under `.ai/references/` are read - on demand when a link is followed: - - [`AGENTS.md`](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) — top-level coding guidelines +- **Read-only for contributors** — `.ai/` is maintained by the core maintainers. Please do not edit files under `.ai/` (or the root-level `AGENTS.md` / `CLAUDE.md` symlinks, or the installed `.agents/skills` / `.claude/skills`) in your PR. If you find something missing or wrong, open an issue or flag it on the PR and a maintainer will update it. +- **Guidelines** — `.ai/AGENTS.md` is loaded into every agent session through the root `AGENTS.md` / `CLAUDE.md` + symlinks; the reference guides under `.ai/references/` are read on demand when a link is followed: + - [`.ai/AGENTS.md`](https://github.com/huggingface/diffusers/blob/main/.ai/AGENTS.md) — top-level coding guidelines - [`.ai/references/models.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/models.md) — attention pattern, model implementation rules, common conventions - [`.ai/references/pipelines.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/pipelines.md) — pipeline conventions - [`.ai/references/modular.md`](https://github.com/huggingface/diffusers/blob/main/.ai/references/modular.md) — modular pipeline conventions and conversion checklist @@ -596,57 +595,9 @@ The repository keeps AI-agent configuration in [`.ai/`](https://github.com/huggi - `diffusers-cli` — running pipelines and inspecting schemas from the terminal - `custom-blocks` — packaging a `ModularPipelineBlocks` subclass for the Hub -### Installing the skills - -All four skills are the same whichever route you take. Pick one — installing through more than one leaves you with two -copies of every skill. - -**Claude Code, from the marketplace.** The usual route. Run these in your shell, or the same commands as `/plugin ...` -inside a session: - -```bash -claude plugin marketplace add huggingface/diffusers -claude plugin install diffusers@diffusers-skills --scope project -``` - -`--scope project` records the plugin in `.claude/settings.json`, so everyone working in the clone is prompted to install -it; `--scope local` installs it for you in this repository only, and `--scope user` for you across all projects. In a -running session, activate it with `/reload-plugins`. - -**Claude Code, for one session.** Loads the plugin straight from your checkout without installing anything — useful for -trying a change to a skill: - -```bash -claude --plugin-dir .ai -``` - -**Codex.** Register the same catalog, then install from the Plugins Directory in the ChatGPT desktop app: - -```bash -codex plugin marketplace add huggingface/diffusers -``` - -**Any agent, without a marketplace.** The [`skills`](../using-diffusers/cli#skills) CLI command downloads skills from -`main` and writes them where your agent looks: - -```bash -diffusers-cli skills add --all # detects the agent from the environment -diffusers-cli skills add --all --claude # or --codex / --cursor to pick one -diffusers-cli skills add self-review # a single skill -``` - -For Claude Code this writes a plugin bundle at `.claude/skills/diffusers/`, which loads once you trust the workspace and -gives the same `/diffusers:` namespace as the marketplace. Codex and Cursor get `.agents/skills//`, the -layout their discovery expects, where skills are invoked by their bare name. Installing a skill also copies the guides -it cites from [`.ai/references/`](https://github.com/huggingface/diffusers/tree/main/.ai/references) into its own -`references/` subdirectory, so an installed skill is self-contained outside a checkout. Add `--global` to install for -every project instead of the current one, and `diffusers-cli skills update` to refresh both the skills and their -references. - - ### AI-assisted and agentic contributions -AI agents are welcome for contributing to Diffusers. We encourage you to set up your agent with the Diffusers [agent guide](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) and use the relevant task-specific skills, such as `model-integration` and `self-review`. Install the plugin (or the individual skills) as described above, then follow the guide to scope, implement, test, and review your contribution. You remain responsible for understanding, testing, and maintaining the changes in your PR. +AI agents are welcome for contributing to Diffusers. We encourage you to set up your agent with the Diffusers [agent guide](https://github.com/huggingface/diffusers/blob/main/.ai/AGENTS.md) and use the relevant task-specific skills, such as `model-integration` and `self-review`. Install the plugin (or the individual skills) as described above, then follow the guide to scope, implement, test, and review your contribution. You remain responsible for understanding, testing, and maintaining the changes in your PR. AI-assisted contributions are welcome, but they must be coordinated, scoped, and verified to keep review load manageable. PRs that do not follow these guidelines may be closed without detailed review. @@ -659,4 +610,4 @@ AI-assisted contributions are welcome, but they must be coordinated, scoped, and - The **test commands you ran** and their results (paste relevant output, not just "tests pass"). - Your **self-review notes** (or a link to the PR comment containing them), as described above. -If you are a model author or part of a team that officially maintains a model, we encourage you to use agents for a new model integration. Follow the repository's [recommended setup](https://github.com/huggingface/diffusers/blob/main/AGENTS.md) and use the [`model-integration`](https://github.com/huggingface/diffusers/blob/main/.ai/skills/model-integration/SKILL.md) skill. Coordinate the scope with maintainers before opening a PR — see [Adding pipelines, models, schedulers](#9-adding-pipelines-models-schedulers). +If you are a model author or part of a team that officially maintains a model, we encourage you to use agents for a new model integration. Follow the repository's [recommended setup](https://github.com/huggingface/diffusers/blob/main/.ai/AGENTS.md) and use the [`model-integration`](https://github.com/huggingface/diffusers/blob/main/.ai/skills/model-integration/SKILL.md) skill. Coordinate the scope with maintainers before opening a PR — see [Adding pipelines, models, schedulers](#9-adding-pipelines-models-schedulers). From 28c08475b8838a2898d5cfd3fa80f145f7a0c8ec Mon Sep 17 00:00:00 2001 From: DN6 Date: Wed, 12 Aug 2026 19:06:11 +0530 Subject: [PATCH 4/5] clean up --- .ai/AGENTS.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .ai/AGENTS.md diff --git a/.ai/AGENTS.md b/.ai/AGENTS.md new file mode 100644 index 000000000000..4208609c64c6 --- /dev/null +++ b/.ai/AGENTS.md @@ -0,0 +1,75 @@ +# Diffusers — Agent Guide + +## Setup + +We recommend developing in a virtual environment managed by [uv](https://docs.astral.sh/uv/): + +```bash +uv venv && source .venv/bin/activate +uv pip install -e . # provides diffusers-cli +``` + +List the available skills, and what each one is for, with: + +```bash +diffusers-cli skills list +``` + +Install them with: + +```bash +diffusers-cli skills add # install one, or --all for every skill + # --claude / --codex / --cursor to pick one target +``` + +`diffusers-cli skills update` refreshes what you installed. + +Claude Code and Codex can also install via plugins + +```bash +claude plugin marketplace add huggingface/diffusers +claude plugin install diffusers@diffusers-skills --scope project + +codex plugin marketplace add huggingface/diffusers # then install from the Plugins Directory +``` + + +## Coding style + +Strive to write code as simple and explicit as possible. + +- Prefer inlining small helper/utility functions over factoring them out — a reader should be able to follow the full flow without jumping between functions. If a private helper has only one caller, inlining it at the call site is usually the cleaner choice. +- No defensive code, unused code paths, or legacy stubs — do not add fallback paths, safety checks, or configuration options "just in case"; do not carry unused method parameters "for API consistency", backwards-compatibility aliases for names that never shipped, or deprecation shims for code that was never released. When porting from a research repo, delete training-time code paths, experimental flags, and ablation branches entirely — only keep the inference path you are actually integrating. +- Do not guess user intent and silently correct behavior. Make the expected inputs clear in the docstring, and raise a concise error for unsupported cases rather than adding complex fallback logic. + +--- + +## Code formatting + +- `make style` and `make fix-copies` should be run before opening a PR + +### Copied Code + +- Many classes are kept in sync with a source via a `# Copied from ...` header comment +- Do not edit a `# Copied from` block directly — run `make fix-copies` to propagate changes from the source +- Remove the header to intentionally break the link + +## Reference guides + +- **Models** — see [models.md](references/models.md) for model conventions, attention pattern, implementation rules, dependencies, and gotchas. For adding or converting a model, use the [model-integration](./skills/model-integration/SKILL.md) skill. +- **Pipelines** — see [pipelines.md](references/pipelines.md) for pipeline conventions, patterns, and gotchas. +- **Modular pipelines** — see [modular.md](references/modular.md) for modular pipeline conventions, patterns, and gotchas. +- **Tests** — see [testing.md](references/testing.md) for test conventions: required test layers, tester mixins, and dummy-component rules. + +## Skills + +Task-specific guides live in `.ai/skills/` and are loaded on demand by AI agents. Available skills include: + +- [model-integration](./skills/model-integration/SKILL.md) (adding/converting pipelines) +- [custom-blocks](./skills/custom-blocks/SKILL.md) (packaging a `ModularPipelineBlocks` subclass for the Hub) +- [diffusers-cli](./skills/diffusers-cli/SKILL.md) (running pipelines, inspecting schemas, and using the Diffusers CLI) +- [self-review](./skills/self-review/SKILL.md) (pre-PR self-review against the project rules) + +## Self-review before a PR + +Before opening a PR, run self-review against [review-rules.md](references/review-rules.md). The [self-review skill](./skills/self-review/SKILL.md) runs this as the same pass the `@claude` CI reviewer uses. Share the final report on the PR (description or comment) — see the skill for details. From f9427505065866da5485d4855669cbf2fcb7a97a Mon Sep 17 00:00:00 2001 From: DN6 Date: Thu, 13 Aug 2026 22:31:49 +0530 Subject: [PATCH 5/5] clean up --- .ai/AGENTS.md | 7 +++ .ai/references/modular.md | 2 +- .ai/references/pipelines.md | 2 +- .ai/references/review-rules.md | 2 +- .ai/references/testing.md | 2 +- Makefile | 16 +------ utils/check_ai.py | 83 ++++++++++++++++++++++++++++++++++ 7 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 utils/check_ai.py diff --git a/.ai/AGENTS.md b/.ai/AGENTS.md index 4208609c64c6..311061ee5eb1 100644 --- a/.ai/AGENTS.md +++ b/.ai/AGENTS.md @@ -24,6 +24,13 @@ diffusers-cli skills add # install one, or --all for every ski `diffusers-cli skills update` refreshes what you installed. +`make claude` and `make codex` used to symlink `.claude/skills` and `.agents/skills` at `.ai/skills`. If those symlinks +are still around, remove them before installing — otherwise the install writes through them into `.ai/` itself: + +```bash +rm .claude/skills .agents/skills +``` + Claude Code and Codex can also install via plugins ```bash diff --git a/.ai/references/modular.md b/.ai/references/modular.md index b68129d08536..bcbd501d5ab7 100644 --- a/.ai/references/modular.md +++ b/.ai/references/modular.md @@ -211,7 +211,7 @@ Prefer flat sequences over nested compositions. Put the `Auto` / `Conditional` s ## InputParam / OutputParam -Use `.template("")` for params with a canonical meaning (`prompt`, `negative_prompt`, `image`, `generator`, `num_inference_steps`, `latents`, `prompt_embeds`, `images`, `videos`, etc.) — the template carries a vetted description and type hint. The full registry lives in [`src/diffusers/modular_pipelines/modular_pipeline_utils.py`](../src/diffusers/modular_pipelines/modular_pipeline_utils.py) (`INPUT_PARAM_TEMPLATES`, `OUTPUT_PARAM_TEMPLATES`); read that file rather than relying on a hardcoded list here, since names get added. +Use `.template("")` for params with a canonical meaning (`prompt`, `negative_prompt`, `image`, `generator`, `num_inference_steps`, `latents`, `prompt_embeds`, `images`, `videos`, etc.) — the template carries a vetted description and type hint. The full registry lives in [`src/diffusers/modular_pipelines/modular_pipeline_utils.py`](https://github.com/huggingface/diffusers/blob/main/src/diffusers/modular_pipelines/modular_pipeline_utils.py) (`INPUT_PARAM_TEMPLATES`, `OUTPUT_PARAM_TEMPLATES`); read that file rather than relying on a hardcoded list here, since names get added. For params that don't match a template (model-specific names, custom semantics), declare the field directly: diff --git a/.ai/references/pipelines.md b/.ai/references/pipelines.md index 84d4e8b2b525..fdf6b56ad862 100644 --- a/.ai/references/pipelines.md +++ b/.ai/references/pipelines.md @@ -70,7 +70,7 @@ src/diffusers/pipelines// 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. +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`](https://github.com/huggingface/diffusers/blob/main/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. 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. diff --git a/.ai/references/review-rules.md b/.ai/references/review-rules.md index e04a8de81433..03a2a9d972b4 100644 --- a/.ai/references/review-rules.md +++ b/.ai/references/review-rules.md @@ -8,7 +8,7 @@ Before reviewing, read and apply the guidelines in: - [pipelines.md](pipelines.md) — pipeline conventions, coding style, gotchas - [modular.md](modular.md) — modular pipeline conventions, patterns, common mistakes - [testing.md](testing.md) — test conventions: required test layers, tester mixins, dummy-component rules. When a PR adds or changes tests, check them against this guide. -- [skills/model-integration/pitfalls.md](../skills/model-integration/pitfalls.md) — known pitfalls causing numerical discrepancies between the reference implementation and the diffusers port (dtype mismatches, config assumptions, etc.) +- [skills/model-integration/pitfalls.md](https://github.com/huggingface/diffusers/blob/main/.ai/skills/model-integration/pitfalls.md) — known pitfalls causing numerical discrepancies between the reference implementation and the diffusers port (dtype mismatches, config assumptions, etc.) ## Common mistakes diff --git a/.ai/references/testing.md b/.ai/references/testing.md index 24d39da3bd68..03df2520a42c 100644 --- a/.ai/references/testing.md +++ b/.ai/references/testing.md @@ -36,7 +36,7 @@ Follow the style introduced in [#14113](https://github.com/huggingface/diffusers - Location: `tests/modular_pipelines//test_modular_pipeline_.py` (one test class per blockset / pipeline variant). - Subclass `ModularPipelineTesterMixin` (from `..test_modular_pipelines_common`) — it runs the pipeline end-to-end (call signature, batch consistency, float16, device placement) against a tiny checkpoint. -- Set `pipeline_class`, `pipeline_blocks_class`, `pretrained_model_name_or_path`, `params` / `batch_params`, and implement `get_dummy_inputs(seed=0)`. Set `expected_workflow_blocks` to pin the block name → class ordering per workflow. +- Set `pipeline_class`, `pipeline_blocks_class`, `pretrained_model_name_or_path`, `params` / `batch_params`, and implement `get_dummy_inputs(seed=0)`. Set `expected_workflow_blocks` to pin the block name → class ordering per workflow (only for blocksets with a `_workflow_map` — with a single workflow the list would just restate the class definition), and `expected_workflow_defaults` to pin each workflow's components, pipeline configs, and inputs — required ones by name, optional ones with their defaults. A pipeline without workflows pins its full blockset under the `None` key. An optional `component_configs` entry pins config values of `from_config` components against their creating spec (e.g. the guider scale that tells a base and a distilled preset apart); pretrained components take their config from the repo, so there is nothing block-level to pin. - `pretrained_model_name_or_path` is a tiny repo with real components (tiny transformer, real scheduler / VAE / tokenizer configs). Develop against a personal repo; tiny repos ultimately live under `hf-internal-testing/` — not merge-blocking, a maintainer moves it before or after merge. - **The tiny repo must mirror the real checkpoint's shape** — same index file type, same pipeline-level config keys, a scheduler configured like the real one. A fixture that doesn't look like the published repos tests a loading/config path no user will ever hit, while the path users *do* hit stays uncovered. If the model ships variants with different configs (base/distilled, different schedules), make one tiny repo and test class per variant — see the flux2 klein base/distilled split. - **Bespoke tests go on the tester class as methods**, not as module-level functions — the mixin is pytest-style, so fixtures (`tmp_path`, `pytest.raises`, parametrize) all work in methods. diff --git a/Makefile b/Makefile index ebf6b202b24c..1d92e692f0d8 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: deps_table_update modified_only_fixup extra_style_checks quality style fixup fix-copies test test-examples codex claude clean-ai +.PHONY: deps_table_update modified_only_fixup extra_style_checks quality style fixup fix-copies test test-examples # make sure to test the local checkout in scripts and not the pre-installed one (don't use quotes!) export PYTHONPATH = src @@ -104,17 +104,3 @@ post-release: post-patch: python utils/release.py --post_release --patch -# AI agent symlinks - -codex: - mkdir -p .agents - rm -rf .agents/skills - ln -snf ../.ai/skills .agents/skills - -claude: - mkdir -p .claude - rm -rf .claude/skills - ln -snf ../.ai/skills .claude/skills - -clean-ai: - rm -rf .agents/skills .claude/skills diff --git a/utils/check_ai.py b/utils/check_ai.py new file mode 100644 index 000000000000..4d116617fc53 --- /dev/null +++ b/utils/check_ai.py @@ -0,0 +1,83 @@ +# Copyright 2026 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Check that the agent guides and skills under `.ai/` still hold together. + +Skills are installed outside a checkout, so a link that only resolves in the repo is a link an installed skill cannot +follow. This checks the three things that break when files move: + +1. No relative link escapes its own directory — those cannot resolve once a skill is installed, so link to a stable URL + instead. +2. A guide a skill cites as `references/.md` exists in `.ai/references/`, since that is where the installer + copies it from. +3. Every other relative link resolves on disk, and each skill's frontmatter `name` matches its directory. + +Run `python utils/check_ai.py`. +""" + +import re +import sys +from pathlib import Path + + +AI_DIR = Path(__file__).parent.parent / ".ai" +REFERENCES_DIR = AI_DIR / "references" +LINK = re.compile(r"\]\(([^)]+)\)") +# Fenced code is prose to us — Python like `attn.to_out[0](hidden_states)` otherwise reads as a link. +CODE_FENCE = re.compile(r"^```.*?^```", re.M | re.S) +# Matches how the installer finds the guides a skill needs, so this checks exactly what gets copied. +CITATION = re.compile(r"(? int: + problems: list[str] = [] + + for path in sorted(AI_DIR.rglob("*.md")): + where = path.relative_to(AI_DIR.parent) + prose = CODE_FENCE.sub("", path.read_text()) + + for link in LINK.findall(prose): + target = link.split("#")[0] + if not target or target.startswith(("http://", "https://")): + continue + if ".." in Path(target).parts: + problems.append(f"{where}: '{link}' escapes its directory — link to a stable URL instead") + elif path.name == "SKILL.md" and target.startswith("references/"): + continue # covered below, which also catches guides cited outside a markdown link + elif not (path.parent / target).exists(): + problems.append(f"{where}: '{link}' does not exist") + + if path.name == "SKILL.md": + for guide in sorted(set(CITATION.findall(prose))): + if not (REFERENCES_DIR / guide).exists(): + problems.append(f"{where}: cites 'references/{guide}', which is not in {REFERENCES_DIR.name}/") + + for skill_md in sorted(AI_DIR.glob("skills/*/SKILL.md")): + declared = FRONTMATTER_NAME.search(skill_md.read_text()) + if declared is None: + problems.append(f"{skill_md.relative_to(AI_DIR.parent)}: no 'name' in frontmatter") + elif declared.group(1) != skill_md.parent.name: + problems.append( + f"{skill_md.relative_to(AI_DIR.parent)}: frontmatter name '{declared.group(1)}' " + f"does not match directory '{skill_md.parent.name}'" + ) + + if problems: + print("\n".join(problems), file=sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main())