browser-validator
Automatically validate implementations in real browsers after code is written or when user says "test this", "test what you built in the browser", "check it in…
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
$ npx -y skills add kanopi/cms-cultivator --skill composer-patch-generator --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/composer-patch-generatorContext preview
The summary Claude sees to decide when to auto-load this skill.
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
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.
Generate reliable, CI-safe patches for Composer-managed packages you cannot edit directly (Drupal contrib modules, WordPress plugins/packages, PHP libraries).
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.
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.
Activate when the user:
Do **not** use for changes to custom (first-party) modules/themes — edit those directly.
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.
# 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
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.
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.
# 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>.patchNew files are handled automatically by `diff -ruN` (uses an epoch timestamp on the `---` line), unlike `git diff`'s unparseable `new file mode` header.
"extra": {
"patches": {
"drupal/<module>": {
"Short description of the change (link to upstreSpecialist 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.
Repo: kanopi/cms-cultivator
Automatically validate implementations in real browsers after code is written or when user says "test this", "test what you built in the browser", "check it in…
Run the right linting, formatting, and static-analysis commands after changing code, and check it against PHPCS, ESLint, WordPress Coding Standards, or Drupal…
Automatically generate conventional commit messages when user has staged changes and mentions committing. Analyzes git diff and status to create properly…
Automatically analyze test coverage when user asks which code is tested, mentions coverage gaps, or shows code asking about testing. Identifies untested code…
Deterministic cleanup of DDEV and Docker disk usage on OrbStack, Docker Desktop, or any Docker provider. Safely reclaims space by removing orphaned Docker…
Operate a Kanopi DDEV site day to day — get a fresh clone or worktree actually serving pages, pull a database from the hosting provider, compile the front-end…