browser-validator
Automatically validate implementations in real browsers after code is written or when user says "test this", "test what you built…
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
Claude Code
$ npx -y skills add kanopi/cms-cultivator --skill composer-patch-generator --agent claude-code
Codex
$ npx skills add kanopi/cms-cultivator --skill composer-patch-generator -a codex -y
Cursor
$ npx skills add kanopi/cms-cultivator --skill composer-patch-generator -a cursor -y
Gemini CLI
$ npx skills add kanopi/cms-cultivator --skill composer-patch-generator -a gemini-cli -y
GitHub Copilot
$ npx skills add kanopi/cms-cultivator --skill composer-patch-generator -a github-copilot -y
OpenCode
$ npx skills add kanopi/cms-cultivator --skill composer-patch-generator -a opencode -y
Windsurf
$ npx skills add kanopi/cms-cultivator --skill composer-patch-generator -a windsurf -y
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.
Automatically validate implementations in real browsers after code is written or when user says "test this", "test what you built…
Run the right linting, formatting, and static-analysis commands after changing code, and check it against PHPCS, ESLint,…
Automatically generate conventional commit messages when user has staged changes and mentions committing. Analyzes git diff and…
Automatically analyze test coverage when user asks which code is tested, mentions coverage gaps, or shows code asking about…
Deterministic cleanup of DDEV and Docker disk usage on OrbStack, Docker Desktop, or any Docker provider. Safely reclaims space by…
Operate a Kanopi DDEV site day to day — get a fresh clone or worktree actually serving pages, pull a database from the hosting…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.