drupal-contribute-fix

REQUIRED when user mentions a Drupal module + error/bug/issue - even without stack traces. Trigger on: (1) "<module_name> module has an error/bug/issue", (2) "Acquia/Pantheon/Platform.sh" + module problem, (3) any contrib module name (metatag, webform, mcp, paragraphs, etc.) + problem description. Searches drupal.org BEFORE you write code changes. NOT just for upstream contributions - use for ALL local fixes to contrib/core.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "drupal-contribute-fix" with this command: npx skills add scottfalconer/drupal-contribute-fix/scottfalconer-drupal-contribute-fix-drupal-contribute-fix

drupal-contribute-fix

Use this skill for ANY Drupal contrib/core bug - even "local fixes".

Checks drupal.org before you write code, so you don't duplicate existing fixes.

Preferred Companion Skill: drupalorg-cli (Highly Recommended)

drupal-contribute-fix should focus on bug identification, triage quality, and report prep. Use drupalorg-cli for issue-fork, MR, and pipeline execution steps.

Recommended split:

  • This skill: detect bug ownership, search/match upstream issues, build clear reproduction + test steps, prepare submission-ready notes.
  • drupalorg-cli: fork/remote setup, branch checkout, MR inspection, pipeline status/log checks, iterative push loop.

Quick prerequisite check:

drupalorg --version
php -v

Use drupalorg-cli commands (0.8+ expected, PHP 8.1+):

drupalorg issue:show <nid> --format=llm
drupalorg issue:get-fork <nid> --format=llm
drupalorg issue:setup-remote <nid>
drupalorg issue:checkout <nid> <branch>
drupalorg mr:list <nid> --format=llm
drupalorg mr:status <nid> <mr-iid> --format=llm
drupalorg mr:logs <nid> <mr-iid>

If drupalorg-cli is unavailable, fall back to the manual Drupal.org/GitLab flow below.

Resolving Script Paths

All script paths below are relative to this skill's root directory — NOT your current working directory. Before running any command, resolve the skill root once:

for d in "$HOME/.agents/skills/drupal-contribute-fix" "$HOME/.codex/skills/drupal-contribute-fix"; do [ -f "$d/SKILL.md" ] && DCF_ROOT="$d" && break; done

All commands below use $DCF_ROOT. You only need to run the line above once per session.

FIRST STEP - Before Writing Any Code

If you are debugging an error in docroot/modules/contrib/* or web/modules/contrib/*, run preflight BEFORE editing any code - even if the user only asked for a local fix.

python3 "$DCF_ROOT/scripts/contribute_fix.py" preflight \
  --project <module-name> \
  --keywords "<error message>" \
  --out .drupal-contribute-fix

False-Positive Guard (Required)

preflight candidate matching is heuristic. Do not treat "already fixed" output as final without verification.

Before stopping work due to an "existing fix", you must verify all of the following:

  1. Open the referenced issue/commit and confirm its title/component matches the bug class and code area.
  2. Inspect the exact affected file/function in the target branch and confirm the bug condition is actually gone.
  3. Record file path + commit/issue evidence in your notes/report before closing/switching local tracking.

If any verification step fails, treat it as a false positive and continue triage/fix flow.

This takes 30 seconds and may save hours of duplicate work.

Important: Drupal.org's api-d7 endpoint does not support a full-text text= filter (it returns HTTP 412). If you need a manual keyword search link, use the Drupal.org UI search:

https://www.drupal.org/project/issues/search/<project>?text=<keywords>

Optional Companion Skill: drupal-issue-queue

If the drupal-issue-queue skill is also available, use it for deeper triage and clean issue summaries (still read-only, still api-d7):

  • Summarize the best-match issue:
    • python scripts/dorg.py issue <nid-or-url> --format md
  • Filter/search a project's issue queue (status/priority/category/version/component/tag):
    • python scripts/dorg.py search --project <machine_name> --status "needs review" --limit 20 --format json

(Run those commands from the drupal-issue-queue skill directory.)

If the tool isn’t in a standard location, set DRUPAL_ISSUE_QUEUE_DIR=/path/to/drupal-issue-queue.

LAST STEP - Produce a Handoff (Always)

This skill should always end with a clear handoff package for upstream contribution.

If you made local code changes, run package:

python3 "$DCF_ROOT/scripts/contribute_fix.py" package \
  --root /path/to/drupal/site \
  --changed-path docroot/modules/contrib/<module-name> \
  --keywords "<error message>" \
  --test-steps "<step 1>" "<step 2>" "<step 3>" \
  --out .drupal-contribute-fix

If you did triage-only (no local code change), preserve preflight evidence and provide:

  • The best-match issue(s)/MR(s)
  • Specific reproduction + expected behavior steps
  • Suggested drupalorg-cli commands to continue contribution work

Then tell the user where the artifacts are and what to run next.

NEVER DELETE Contribution Artifacts

DO NOT delete these files:

  • .drupal-contribute-fix/ directory
  • Diff files in diffs/
  • ISSUE_COMMENT.md
  • REPORT.md

Even if the user asks to "reset" or "undo" the local fix, preserve the contribution artifacts so the fix can be submitted upstream. The whole point is to help the Drupal community.

Complete Workflow

1. DETECT    → Error from contrib/core? Trigger activated.
2. PREFLIGHT → Search drupal.org BEFORE writing code
3. TRIAGE    → Verify/score candidates, avoid false positives
4. PREP      → Produce report-quality repro/test steps and recommendation
5. PACKAGE   → If code changed, run `package`; otherwise keep preflight evidence only
6. HANDOFF   → Prefer `drupalorg-cli` for fork/MR/pipeline execution
7. PRESERVE  → Keep .drupal-contribute-fix/ artifacts for follow-up

Steps 4-7 are MANDATORY. Don't stop at "issue found"; leave an actionable handoff.

When to Use This Skill

Early Conversational Triggers - Fire BEFORE Investigation

You don't need a stack trace to trigger this skill. Fire on high-level descriptions:

User SaysTrigger?Why
"The metatag module has an error"YESModule name + "error"
"mcp module isn't working with Acquia"YESModule + platform constraint
"I'm getting a bug in webform"YESModule name + "bug"
"paragraphs module throws an exception"YESModule + error indicator
"contrib module X has a problem"YESExplicit "contrib" mention
"my custom module has a bug"MaybeOnly if it triggers a contrib/core bug

Key insight: If the user mentions a Drupal module name (that isn't clearly custom) + any problem indicator (error, bug, issue, not working, exception, broken), trigger this skill FIRST. Don't wait until you've investigated and found a stack trace.

MANDATORY Triggers - You MUST Use This Skill When:

  1. Error/exception originates FROM contrib or core code

    • Stack trace shows modules/contrib/ or core/ as the source
    • Error message references a class in Drupal\<contrib_module>\ namespace
    • Fatal error, TypeError, exception thrown by contrib/core code
  2. You are about to edit files in contrib or core

    • docroot/modules/contrib/* or web/modules/contrib/*
    • docroot/core/* or web/core/*
    • docroot/themes/contrib/* or web/themes/contrib/*
  3. You are about to modify contrib/core code that should go upstream

    • Replacing ad-hoc Composer patching with a real MR contribution
    • Converting temporary local fixes into issue-fork/MR work
  4. Custom module encounters a bug in core/contrib

    • Custom code works correctly but triggers a bug in contrib/core
    • The fix would need to be in the contrib/core code, not the custom module
  5. Hosting platform constraints cause contrib/core issues

    • "Acquia best practices", "Pantheon", "Platform.sh" constraints
    • Core module disabled/unavailable causing contrib to fail

This Skill is NOT Just for "Upstream Contributions"

Common misconception: This skill is only for patch uploads to drupal.org.

Reality: Use it for ALL local fixes to contrib modules. Why?

  • The bug may already be fixed upstream (save yourself the work)
  • An existing MR or attachment may already solve it
  • Even if you need a local fix NOW, the preflight search is fast

How to Recognize Contrib/Core Errors

Look for these patterns in error messages or stack traces:

# Error ORIGINATES from contrib - USE THIS SKILL
Drupal\metatag\MetatagManager->build()
docroot/modules/contrib/mcp/src/Plugin/Mcp/General.php
web/modules/contrib/webform/src/...
core/lib/Drupal/Core/...

# Error in CUSTOM module - skill may not apply
# (unless the custom code is triggering a bug in contrib/core)
modules/custom/mymodule/src/...

Path Triggers:

  • web/core/, web/modules/contrib/, web/themes/contrib/
  • docroot/core/, docroot/modules/contrib/, docroot/themes/contrib/
  • patches/ directory (especially patches/drupal-*)

What To Do

  1. FIRST: Run preflight to search drupal.org (even for "local fixes")
  2. TRIAGE: Verify candidate quality (issue title/component/file/function match)
  3. DOCUMENT: Write precise reproduction, before/after behavior, and test steps
  4. IF CODE CHANGED: Run package to generate artifacts; otherwise keep preflight outputs
  5. HANDOFF TO CLI: Recommend drupalorg-cli commands for fork/MR/pipeline flow
  6. PRESERVE: Keep .drupal-contribute-fix/ directory - NEVER delete it
  7. GUIDE USER: Tell them the exact next command(s) to run

What This Skill Does

  1. Identifies contrib/core bug ownership from symptoms, paths, and stack traces
  2. Searches drupal.org for existing issues/MRs/attachments matching the bug
  3. Validates candidate relevance before declaring "already fixed"
  4. Builds report-quality issue content (repro steps, expected/actual behavior, rationale)
  5. Generates contribution artifacts when local code changes exist:
    • Paste-ready issue comment
    • Properly-named local .diff file
    • Validation results (php lint, phpcs if available)
  6. Hands off execution to drupalorg-cli for branch/MR/pipeline actions

Mandatory Gatekeeper Behavior

No new local diff artifact may be generated until upstream search + "already fixed?" checks are complete. No "STOP existing fix found" decision may be accepted until the file-level verification steps above are completed.

The skill ends in exactly one of these outcomes:

Exit CodeOutcomeMeaning
0PROCEEDMR artifacts + local diff generated
10STOPExisting upstream fix found (MR-based, historical patch attachments, or closed-fixed)
20STOPFixed upstream in newer version (reserved for future use)
30STOPAnalysis-only recommended (change would be hacky/broad)
40ERRORCouldn't determine project/baseline, network failure
50STOPSecurity-related issue detected (follow security team process)

Workflow modes: When an existing fix is found (exit 10), the skill reports whether the issue has an active MR or only historical patch attachments to guide contributor workflow.

Workflow Hygiene (MR-first)

Drupal contributions should be handled through Merge Requests (MRs). To reduce maintainer back-and-forth, this skill records workflow context but defaults to MR-only contributions for new work. When available, drive execution with drupalorg-cli instead of manual UI/Git steps.

Outputs (in every issue directory):

  • WORKFLOW.md - at-a-glance workflow decision + links + MR-first guidance
  • REPORT.md - includes a Workflow section near the top
  • ISSUE_COMMENT.md - template is workflow-aware:
    • MR-based: comment template points to the existing MR(s)
    • Historical patch attachments: comment template still directs follow-up via MR workflow

Rule of thumb:

  • MR-based issues: contribute via GitLab MR/issue fork branch; don't upload new patches to the Drupal.org issue unless maintainers request it.
  • Issues with only historical patch attachments: use MR workflow for new work; use old attachments as context.

Commands

Preflight (search only)

Search drupal.org for existing issues without generating local artifacts:

python3 "$DCF_ROOT/scripts/contribute_fix.py" preflight \
  --project metatag \
  --keywords "TypeError MetatagManager::build" \
  --paths "src/MetatagManager.php" \
  --out .drupal-contribute-fix

drupalorg-cli handoff (preferred execution path)

After triage identifies the target issue/MR, use drupalorg-cli for issue-fork and MR execution:

drupalorg issue:show <nid> --format=llm
drupalorg issue:get-fork <nid> --format=llm
drupalorg issue:setup-remote <nid>
drupalorg issue:checkout <nid> <branch>
drupalorg mr:list <nid> --format=llm
drupalorg mr:status <nid> <mr-iid> --format=llm
drupalorg mr:logs <nid> <mr-iid>

Package (search + generate)

Search upstream AND generate contribution artifacts if appropriate:

# For web/ docroot layout:
python3 "$DCF_ROOT/scripts/contribute_fix.py" package \
  --root /path/to/drupal/site \
  --changed-path web/modules/contrib/metatag \
  --keywords "TypeError MetatagManager::build" \
  --test-steps "Enable metatag" "Visit affected page" "Confirm fixed behavior" \
  --out .drupal-contribute-fix

# For docroot/ layout (common in Acquia/BLT projects):
python3 "$DCF_ROOT/scripts/contribute_fix.py" package \
  --root /path/to/drupal/site \
  --changed-path docroot/modules/contrib/mcp \
  --keywords "module not installed" "update_get_available" \
  --test-steps "Set up failing config" "Trigger failing code path" "Confirm expected post-fix result" \
  --out .drupal-contribute-fix

Note: package always runs preflight first and refuses to generate local artifacts if an existing fix is found (unless --force is provided).

Test (generate RTBC comment)

Generate a Tested-by/RTBC comment for an existing MR or diff artifact you've tested:

python3 "$DCF_ROOT/scripts/contribute_fix.py" test \
  --issue 3345678 \
  --tested-on "Drupal 10.2, PHP 8.2" \
  --result pass \
  --out .drupal-contribute-fix

Options: --result can be pass, fail, or partial. Use --mr or --patch to specify which artifact you tested.

Reroll (legacy patch-only issues)

Legacy fallback only: reroll an existing patch attachment when maintainers explicitly request patch workflow:

python3 "$DCF_ROOT/scripts/contribute_fix.py" reroll \
  --issue 3345678 \
  --patch-url "https://www.drupal.org/files/issues/metatag-fix-3345678-15.patch" \
  --target-ref 2.0.x \
  --out .drupal-contribute-fix

This downloads the patch, attempts to apply it to your target branch, and generates a rerolled patch if needed (or confirms it applies cleanly). Prefer MR workflow for new contributions.

Common Options

OptionDescription
--projectDrupal project machine name (e.g., metatag, drupal)
--keywordsError message fragments or search terms (space-separated)
--pathsRelevant file paths (space-separated)
--outOutput directory for artifacts
--offlineUse cached data only, don't hit API
--forceOverride gatekeeper and generate local diff artifact anyway
--issueKnown issue number (runs gatekeeper check against this issue)
--detect-deletionsInclude deleted files in diff (risky with Composer trees)
--test-stepsREQUIRED Specific test steps for the issue (agent must provide)

Test Steps (MANDATORY)

Agents MUST provide specific test steps via --test-steps. Generic placeholders are not acceptable.

python3 "$DCF_ROOT/scripts/contribute_fix.py" package \
  --changed-path docroot/modules/contrib/mcp \
  --keywords "update module not installed" \
  --test-steps \
    "Enable MCP module with Update module disabled" \
    "Call the general:status tool via MCP endpoint" \
    "Before fix: Fatal error - undefined function update_get_available()" \
    "After fix: JSON response with status unavailable" \
  --out .drupal-contribute-fix

Test steps should:

  1. Describe how to set up the environment to reproduce the bug
  2. Describe the action that triggers the bug
  3. Describe the expected behavior BEFORE the fix (the bug)
  4. Describe the expected behavior AFTER the fix (the fix)

Output Files

.drupal-contribute-fix/
├── UPSTREAM_CANDIDATES.json              # Search results cache (shared)
├── 3541839-fix-metatag-build/            # Known issue
│   ├── REPORT.md                         # Analysis & next steps
│   ├── ISSUE_COMMENT.md                  # Paste-ready drupal.org comment
│   └── diffs/
│       └── project-fix-3541839.diff
├── 3573571-component-context/            # Optional local CI evidence
│   ├── LOCAL_CI_PARITY_2026-02-16.md     # Job/result summary + commands
│   └── ci/
│       ├── canvas-ci-local-full-20260216.log
│       └── canvas-ci-local-rerun-20260216.log
└── unfiled-update-module-check/          # New issue needed
    ├── REPORT.md
    ├── ISSUE_COMMENT.md
    └── diffs/
        └── project-fix-new.diff

Directory naming:

  • {issue_nid}-{slug}/ - Existing issue matched or specified
  • unfiled-{slug}/ - No existing issue found

Preflight vs Package: preflight only updates UPSTREAM_CANDIDATES.json. Issue directories are created by package when generating artifacts.

Local CI Evidence Artifacts (Recommended)

If local CI parity tooling is available (for example gitlab-ci-local), keep evidence under the issue directory in .drupal-contribute-fix/:

  • LOCAL_CI_PARITY_YYYY-MM-DD.md: concise summary with exact commands, exit codes, pass/fail/incomplete jobs, and blocker details.
  • ci/*.log: raw logs for audit/debug follow-up.
  • drupal-contribute-fix package now auto-creates LOCAL_CI_PARITY_YYYY-MM-DD.md when ci/*.log exists in that issue directory and no parity summary file exists yet.

Rules:

  • These are local review artifacts, not upstream contribution artifacts.
  • Keep them out of MR diffs.
  • If local CI tooling mutates tracked files, restore tracked files before preparing the final MR diff.
  • If the tooling is unavailable, record not run and why.

Security Issue Handling

If the fix appears security-related, the skill will STOP with exit code 50.

Security indicators:

  • Access bypass patterns
  • User input reaching dangerous sinks (SQL, shell, eval)
  • Authentication/session handling changes
  • File system access control modifications

Do NOT post security issues publicly. Follow the Drupal Security Team process: https://www.drupal.org/drupal-security-team/security-team-procedures

Minimal + Upstream Acceptable

The skill enforces contribution best practices:

  • Warns if a change touches >3 files or has large LOC changes
  • Separates "must fix" from "nice-to-haves" (nice-to-haves excluded from submitted change)
  • Detects patterns likely to be rejected:
    • Broad cache disables/bypasses
    • Swallowed exceptions
    • Access check bypasses
    • Environment-specific hacks

See references/hack-patterns.md for details.

Validation

The skill runs validation and reports results honestly:

  • Always runs: php -l on changed PHP files
  • Runs if available: PHPCS with Drupal standard
  • Never claims tests passed if they weren't run

After Completion - What To Tell The User

When triage/fix is complete, you MUST inform the user about the contribution artifacts and provide a CLI-first handoff:

I completed contrib/core bug triage and prepared contribution artifacts:

📁 .drupal-contribute-fix/<nid>-<slug>/
  - REPORT.md - Triage findings and next steps
  - ISSUE_COMMENT.md - Copy/paste issue or MR comment text
  - WORKFLOW.md - MR/patch workflow recommendation
  - diffs/<diff-file>.diff - Present only when code changed (local artifact)

**Recommended next commands (drupalorg-cli):**
drupalorg issue:show <nid> --format=llm
drupalorg issue:get-fork <nid> --format=llm
drupalorg issue:setup-remote <nid>
drupalorg issue:checkout <nid> <branch>
drupalorg mr:list <nid> --format=llm

For unfiled issues (no existing drupal.org issue found):

📁 .drupal-contribute-fix/unfiled-<slug>/
  - Create a new issue at https://www.drupal.org/project/issues/<project> first
  - Use ISSUE_COMMENT.md as the issue description template
  - Then continue with drupalorg-cli using the new issue NID

DO NOT skip this step. The user may not know about the contribution workflow.

Drupal.org GitLab Workflow (CLI-first)

All Drupal core and contrib contributions use GitLab merge requests. Patch uploads are exception-only when explicitly requested by maintainers.

Reference: https://www.drupal.org/docs/develop/git/using-gitlab-to-contribute-to-drupal

Preferred command sequence

drupalorg issue:show <nid> --format=llm
drupalorg issue:get-fork <nid> --format=llm
drupalorg issue:setup-remote <nid>
drupalorg issue:checkout <nid> <branch>
drupalorg mr:list <nid> --format=llm
drupalorg mr:status <nid> <mr-iid> --format=llm
drupalorg mr:logs <nid> <mr-iid>

Iteration loop (after triage)

git add <changed-files>
git commit -m "Issue #<nid> by <username>: <short description>"
git push
drupalorg mr:status <nid> <mr-iid> --format=llm
drupalorg mr:logs <nid> <mr-iid>   # only if failing

Rebase when needed

git fetch origin
git checkout BASE_BRANCH_NAME
git pull
git checkout ISSUE_BRANCH_NAME
git rebase BASE_BRANCH_NAME
git push --force-with-lease

GitLab CI Automated Testing

GitLab CI runs automatically on all merge requests. You cannot test patch files—contributions must be merge requests to be tested.

What runs automatically:

  • Compatibility testing across Drupal Core versions
  • PHP and database configuration testing
  • PHPCS, PHPStan, and cspell linting
  • Project-specific PHPUnit tests

Interpreting results:

  1. Check pipeline status with drupalorg mr:status <nid> <mr-iid> --format=llm
  2. If failing, inspect logs with drupalorg mr:logs <nid> <mr-iid>
  3. Apply fixes, push again, and re-check status

Triggering test re-runs:

  • Push additional commits to the branch

Important: GitLab CI uses phpunit.xml.dist, phpstan.neon.dist and other .dist files. Review these files as they may cause unexpected test failures.

Manual fallback (only when drupalorg-cli is unavailable)

If drupalorg-cli cannot run in the environment, use the issue page's Issue fork controls and standard Git/GitLab UI as a fallback.

Local CI Parity (Best Effort)

If local CI tooling exists in the contributor environment, run parity checks and archive evidence under .drupal-contribute-fix/<issue>/:

  1. Save the exact command line(s) and exit status.
  2. Save raw logs in ci/.
  3. Summarize outcomes in LOCAL_CI_PARITY_YYYY-MM-DD.md (auto-scaffolded by package when ci/*.log is present).

If local parity tooling is not installed or blocked by environment constraints, state that clearly and do not claim full local parity.

Drupal Core Contributions

Drupal core requires test coverage for all changes. Contrib modules don't require tests (though they're encouraged).

For core contributions, you MUST:

  1. Include test coverage for changes
  2. Ensure all existing tests pass
  3. Update tests if behavior changes

See references/core-testing.md for:

  • Choosing the right test type (Unit vs Kernel vs Functional)
  • Test file locations and class structure
  • Example test classes
  • Running tests locally (DDEV/Lando commands)
  • Test coverage checklist

Contribution Workflow Summary

1. Detect + triage bug with `preflight`
2. Prepare report-quality reproduction and test steps
3. Identify target issue/MR (or file a new issue)
4. Use `drupalorg-cli` to set up fork remote + checkout branch
5. Make changes with test coverage (required for core)
6. Push commits and monitor MR pipeline
7. Iterate until pipeline is green and review feedback is addressed

Key Command Reference

TaskCommand
Show issue detailsdrupalorg issue:show <nid> --format=llm
Inspect fork + branchesdrupalorg issue:get-fork <nid> --format=llm
Set up issue fork remotedrupalorg issue:setup-remote <nid>
Check out issue branchdrupalorg issue:checkout <nid> <branch>
List MRsdrupalorg mr:list <nid> --format=llm
Check MR pipelinedrupalorg mr:status <nid> <mr-iid> --format=llm
Read failing job logsdrupalorg mr:logs <nid> <mr-iid>
Push latest commit(s)git push

References

Example Output

See examples/sample-report.md for a complete example.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

self-learning-skills

No summary provided by upstream source.

Repository SourceNeeds Review
General

drupal-issue-queue

No summary provided by upstream source.

Repository SourceNeeds Review
General

drupal-intent-testing

No summary provided by upstream source.

Repository SourceNeeds Review