Skip to content
Development
Skill

/composer-patch-generator

Generate and maintain patches for Composer-installed packages (Drupal contrib modules, WordPress packages, PHP libraries) using cweagans/composer-patches. Invoke when the user needs to modify a contrib or vendor package, mentions "composer patch", "patch a module", "patch a

From plugin
cms-cultivator
1728 skills1 agent

Claude Code

$ npx -y skills add kanopi/cms-cultivator --skill composer-patch-generator --agent claude-code

SKILL.md

composer-patch-generator.SKILL.md
name: composer-patch-generator
description: Generate and maintain patches for Composer-installed packages (Drupal contrib modules, WordPress packages, PHP libraries) using cweagans/composer-patches. Invoke when the user needs to modify a contrib or vendor package, mentions "composer patch", "patch a module", "patch a contrib module", "cweagans", "diff -ruN", "extra.patches", or needs a package change that applies cleanly in CI. Covers generating diff -ruN patches, handling new files, wiring composer.json, and verifying the patch applies.

Composer Patch Generator

Generate reliable, CI-safe patches for Composer-managed packages you cannot edit directly (Drupal contrib modules, WordPress plugins/packages, PHP libraries).

Philosophy

Contrib and vendor code is not yours to fork. Patches let you carry a change on top of an upstream release, re-apply it on every `composer install`, and drop it the moment upstream ships a fix.

Core Beliefs

1. **Patches are temporary by design** — always describe the change so it can be removed when upstream merges it. 2. **CI is the source of truth** — a patch that applies locally but fails in CI is a broken patch. Generate for how CI applies, not how your laptop does. 3. **Minimal surface** — a patch should contain only your delta, never build artifacts, `.git` metadata, or tooling files. 4. **Never edit `vendor/` or `web/modules/contrib/` directly** — those dirs are git-ignored and rebuilt on install. The patch is the only durable artifact.

When to Use This Skill

Activate when the user:

  • Wants to change a Composer-installed package (contrib module, plugin, library).
  • Mentions "composer patch", "patch this module", "cweagans", "extra.patches".
  • Says a change "needs to be a patch" or "applies in CI but not locally" (or vice versa).
  • Needs to create, update, or debug an entry under `extra.patches` in `composer.json`.

Do **not** use for changes to custom (first-party) modules/themes — edit those directly.

Critical Rules (why patches fail in CI)

These are the failure modes that cause "works locally, fails on CI":

1. **Use `diff -ruN`, NOT `git diff`.** `cweagans/composer-patches` tries `git apply` only when the install dir has a `.git` folder. CI installs with `--prefer-dist` (archives, no `.git`), so it falls back to the `patch` command — which cannot parse git headers (`diff --git`, `new file mode 100644`, `index abc..def`). `diff -ruN` is universally compatible. 2. **Base the diff on the dist archive, not a `git clone`.** Drupal.org dist `.zip`/`.tar.gz` files differ from the git repo: they add `LICENSE.txt` and packaging metadata (version/datestamp lines appended to `.info.yml`). CI uses the dist. If you diff against a clone, those files show up as spurious "new file" hunks that fail when `patch` finds them already present. 3. **Never pass `--exclude` to `diff -ruN`.** It leaks into the header lines (`diff -ruN --ex a/file b/file`) and breaks `patch` parsing. Delete unwanted dirs (`.git`, `node_modules`) *before* diffing instead. 4. **Exclude tool artifacts.** After a patched install, the package dir contains a `PATCHES.txt` written by composer-patches. Never let it into your diff.

Workflow

1. Identify the package, version, and prior patches

# Exact installed version (drives which dist archive to download).
grep -E "^version|datestamp" web/modules/contrib/<module>/<module>.info.yml
# Or from the lock file:
grep -A2 '"name": "drupal/<module>"' composer.lock | head -3

# Any patches already applied (yours must stack cleanly on top of these).
grep -A6 '"drupal/<module>"' composer.json

2. Snapshot a pristine base BEFORE editing

Edit the installed files in place (so you can test live), and diff them against a clean snapshot of the *same version*.

WORK=/tmp/patch_gen && rm -rf "$WORK" && mkdir -p "$WORK"
# Preferred base = the dist archive CI will use:
curl -sL "https://ftp.drupal.org/files/projects/<module>-<version>.zip" -o "$WORK/dist.zip"
unzip -q "$WORK/dist.zip" -d "$WORK/base_dl"     # -> $WORK/base_dl/<module>
cp -r "$WORK/base_dl/<module>" "$WORK/base"

# If earlier patches exist, apply them to the base first so your diff is a
# clean delta ON TOP of them (order matters — composer applies in listed order):
( cd "$WORK/base" && patch -p1 --no-backup-if-mismatch < /path/to/earlier-patch.patch )

If you cannot download the dist (no network, private package), snapshot the current installed dir *before* you edit as the base — acceptable as long as no uncommitted edits exist yet and no unpatched files you'll touch differ from dist.

3. Make your edits to the installed package

Edit files under `web/modules/contrib/<module>/` (or `vendor/<pkg>/`) directly. Run the project's checks on the changed files (e.g. `composer phpcs`, `composer phpstan`, unit tests) before generating the patch.

4. Generate the patch with `diff -ruN`

# Mirror the edited install into a clean "modified" tree (drop noise + artifacts).
rsync -a --exclude='.git' --exclude='node_modules' \
  web/modules/contrib/<module>/ "$WORK/modified/"
rm -f "$WORK/modified/PATCHES.txt"          # composer-patches artifact — never patch it
rm -rf "$WORK/base/.git" "$WORK/modified/.git"

# Confirm ONLY the files you intended changed:
diff -qr "$WORK/base" "$WORK/modified"

# Emit the patch, normalizing paths to a/ … b/ (what `patch -p1` expects):
( cd "$WORK" && diff -ruN base/ modified/ \
  | sed 's|^--- base/|--- a/|; s|^+++ modified/|+++ b/|; \
         s|^diff -ruN base/|diff -ruN a/|; s| modified/| b/|' \
  ) > patches/<module>-<short-description>.patch

New files are handled automatically by `diff -ruN` (uses an epoch timestamp on the `---` line), unlike `git diff`'s unparseable `new file mode` header.

5. Wire it into `composer.json`

"extra": {
    "patches": {
        "drupal/<module>": {
            "Short description of the change (link to upstre
Read more
@kanopi
Ships withcms-cultivator

Specialist agents and auto-invoked skills for Drupal/WordPress development. Works in Claude Code, Claude Desktop, and OpenAI Codex. Full documentation: What changed in 2.0? CMS Cultivator now focuses on CMS development workflows.

1728 skills1 agent
Get the whole plugin

Stars on GitHub

Momentum

stars in total
17
Star history of kanopi/cms-cultivator on GitHub, a chart by star-history.com

Other skills on cms-cultivator.

browser-validator

browser-validator

Automatically validate implementations in real browsers after code is written or when user says "test this", "test what you built…

coverage-analyzer

coverage-analyzer

Automatically analyze test coverage when user asks which code is tested, mentions coverage gaps, or shows code asking about…

ddev-docker-cleanup

ddev-docker-cleanup

Deterministic cleanup of DDEV and Docker disk usage on OrbStack, Docker Desktop, or any Docker provider. Safely reclaims space by…

ddev-workflow

ddev-workflow

Operate a Kanopi DDEV site day to day — get a fresh clone or worktree actually serving pages, pull a database from the hosting…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc11d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about composer-patch-generator.

Which coding agents can use composer-patch-generator?
composer-patch-generator installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.