Skip to content

An Agent Skill to turn local Drupal fixes into effortless, maintainer-friendly contributions without the noise, duplicates, or churn.

License

Notifications You must be signed in to change notification settings

zivtech/drupal-contribute-fix

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

drupal-contribute-fix

Drupal Agent Skill License Python

Turn local Drupal fixes into effortless, maintainer-friendly contributions.

AI scales code generation, but it shouldn't scale noise.

We want to empower AI Agents to fix Drupal bugs, while protecting maintainers from a flood of duplicate or low-quality contributions. This tool bridges the gap, transforming the Agent from a "local hacker" into a responsible open-source contributor.

Our Mission: High Signal, Zero Noise

To ensure contributions are helpful rather than overwhelming, this skill enforces three strict rules:

  1. Targeted: Searches Drupal.org first. If a fix exists, we stop and recommend using it. No duplicate effort.
  2. High-Quality: Runs PHP lint by default; runs PHPCS if available; flags hack patterns.
  3. Maintainer-First: Never auto-posts. Generates clean artifacts for you to review.

πŸ“– Table of Contents


Why Use This?

Stop your AI from "hacking" core.

❌ Without this Skill βœ… With drupal-contribute-fix
Duplicate Work: Agent ignores existing MRs/patches. Upstream-aware: Searches Drupal.org and surfaces existing fixes.
Tech Debt: Fixes are buried in vendor/ or core/. Standardized: Generates patches in patches/.
Maintainer Burnout: Spammy, low-quality issues. Maintainer-friendly: Warns on risky patterns and keeps human review in the loop.
Lost Fixes: Local patches vanish on composer update. Preserved Work: Artifacts are saved for future rerolls.
No Validation: Errors slip through. Quality Gates: Runs PHP lint and PHPCS (if available).

What This Will NOT Do

This skill is designed to be helpful without creating churn.

🚫 Never βœ… Instead
Auto-post to Drupal.org Generates files for you to review and paste
Create issues automatically Searches existing issues; you decide what to file
Push to git.drupalcode.org Outputs local patch files only
Bypass your review Every artifact requires human approval before submission
Spam maintainers Stops when existing MR/patch found; encourages testing over duplicating

The "No Noise" Guarantee

This tool never auto-posts to Drupal.org or pushes code automatically. It only generates local artifacts for you to review and submit.

The --force flag should be rare. Use it only when:

  • You've reviewed the existing MR/patch and confirmed your fix is meaningfully different
  • You're providing a reroll for a different version
  • The existing fix doesn't apply to your Drupal version

When using --force, always explain in your issue comment why a new patch was needed.


How It Works

graph TD
    A[πŸ” Local Fix Detected] --> B{Search Drupal.org}
    B -- MR/Patch Exists --> C[πŸ›‘ STOP & DOWNLOAD]
    C --> D[Test Existing Fix]
    B -- No Fix Found --> E{Check Dev Branch}
    E -- Fixed in Dev --> F[πŸ›‘ STOP & UPGRADE]
    E -- Bug Exists in Dev --> H{Hack Detection}
    H -- Clean Fix --> I[βœ… GENERATE PATCH]
    H -- Hacky Fix --> K[⚠️ WARN USER]
Loading

Note: Dev-branch checks are currently a manual step; the tool does not auto-verify them yet.


What You Get

.drupal-contribute-fix/
β”œβ”€β”€ UPSTREAM_CANDIDATES.json           # Search results cache (shared)
β”œβ”€β”€ 3345678-fix-metatag-build/         # Known issue with slug
β”‚   β”œβ”€β”€ REPORT.md                      # Analysis & next steps
β”‚   β”œβ”€β”€ ISSUE_COMMENT.md               # Copy/paste this to drupal.org
β”‚   └── patches/
β”‚       └── metatag-fix-3345678.patch  # Upload this to the issue
└── unfiled-update-module-check/       # New issue needed
    β”œβ”€β”€ REPORT.md
    β”œβ”€β”€ ISSUE_COMMENT.md
    └── patches/
        └── project-fix-new.patch

Directory naming: {nid}-{slug}/ for existing issues, unfiled-{slug}/ for new issues.


Quick Start

Prerequisites

  • Python 3.8+
  • Git
  • Internet access to drupal.org API

Installation

# Clone from your preferred location
git clone <repository-url>
cd drupal-contribute-fix

Usage

Search only (preflight):

python3 scripts/contribute_fix.py preflight \
  --project metatag \
  --keywords "TypeError MetatagManager" \
  --out .drupal-contribute-fix

Search + generate patch:

python3 scripts/contribute_fix.py package \
  --changed-path /path/to/drupal/web/modules/contrib/metatag \
  --keywords "TypeError MetatagManager" \
  --test-steps \
    "Enable Metatag module" \
    "Trigger the error in the UI" \
    "Before patch: TypeError in MetatagManager" \
    "After patch: Page renders without error" \
  --out .drupal-contribute-fix

Test an existing MR/patch (generate RTBC comment):

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

Reroll an existing patch for your version:

python3 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

Workflow Modes

The skill understands Drupal's contribution workflow:

Mode What It Means Your Action
MR-based Issue has active Merge Request Review/update the existing MR
Patch-based Issue uses patch workflow Reroll/update existing patches
New No existing fixes Submit your patch

Options

Option Description
--project Drupal project machine name (e.g., metatag, drupal)
--keywords Error message fragments or search terms
--changed-path Path to modified module/theme/core directory
--issue Known issue number (runs gatekeeper against this issue)
--force Override gatekeeper and generate patch anyway
--offline Use cached data only
--detect-deletions Include deleted files (risky with Composer trees)
--test-steps Required for package. Specific reproduction/verification steps

Exit Codes (Gatekeeper Behavior)

The skill refuses to generate patches when existing upstream fixes are found:

Outcome Action Exit
βœ… PROCEED Patch generated. Ready to contribute. 0
πŸ›‘ REDIRECT Existing fix found. Use the upstream MR/patch. 10
⚠️ REVIEW Fix deemed too broad/hacky. Post analysis first. 30
β›” ERROR Network or detection failure. 40
πŸ”’ SECURITY Security issue detected. Follow security team process. 50

For AI Agent Developers

This skill follows the Agent Skills specification. The main skill definition is in SKILL.md.

MANDATORY Activation Rules

You MUST use this skill when ANY of these conditions are true:

Early Triggers (no stack trace needed):

  1. User mentions module name + problem - "metatag has an error", "mcp isn't working", "webform bug"
  2. Platform + module issue - "Acquia best practices" + any module problem
  3. Explicit contrib mention - "contrib module", "drupal module"

Technical Triggers (after investigation):

  1. Error originates FROM contrib/core - stack trace shows modules/contrib/, core/
  2. About to edit contrib/core files - */modules/contrib/* or */core/*
  3. About to create Composer patch for any drupal/* package

Key: Don't wait for a stack trace. If user says "[module] has an error", trigger immediately.

Run preflight BEFORE writing any code - even for "local fixes".

This is NOT Just for "Upstream Contributions"

Common mistake: Treating this as an "optional" skill for when users want to contribute to drupal.org.

Correct usage: Use for ALL contrib/core fixes because:

  • The fix may already exist (don't duplicate work)
  • Preflight takes 30 seconds; writing a patch takes 30 minutes
  • Even "local fixes" should check upstream first

How to Recognize Contrib/Core Errors

# Error FROM contrib/core - USE THIS SKILL:
Drupal\metatag\MetatagManager->build()
docroot/modules/contrib/mcp/src/Plugin/...
web/core/lib/Drupal/Core/...

# Error in custom module - may not apply:
modules/custom/mymodule/src/...
(unless custom code triggers a bug in contrib/core)

Path Triggers

web/core/             docroot/core/
web/modules/contrib/  docroot/modules/contrib/
web/themes/contrib/   docroot/themes/contrib/
patches/drupal-*      patches/*/

Example: Correct Agent Behavior

User says: "I have the mcp module installed but it has an error with the update module not being installed, but Acquia best practices are for that to not be installed."

Agent should IMMEDIATELY recognize triggers:

  • "mcp module" β†’ Drupal module name
  • "has an error" β†’ problem indicator
  • "Acquia best practices" β†’ platform constraint

This is THREE triggers in one sentence. Fire the skill FIRST, before investigating.

Agent should:

  1. IMMEDIATELY invoke drupal-contribute-fix skill (don't investigate first!)
  2. Run preflight --project mcp --keywords "update module not installed"
  3. Check if fix already exists upstream
  4. THEN proceed with local fix if needed
  5. AFTER fixing: Run package to generate contribution artifacts
  6. Tell user about .drupal-contribute-fix/ files and how to submit upstream

WRONG behavior: Reading code first, finding the bug, fixing it, THEN thinking "oh maybe I should check upstream". By then you've already duplicated work.

MANDATORY: After Fixing, Complete the Workflow

DO NOT just fix locally and move on. After making a local fix:

  1. Run package to generate contribution artifacts
  2. Preserve the .drupal-contribute-fix/ directory - NEVER delete it
  3. Guide user through the submission process

Even if user asks to "reset" or "undo": Keep the contribution artifacts. The whole point is to help the Drupal community.

What To Tell Users When Done

I've fixed the bug locally. Here's how to contribute it upstream:

πŸ“ .drupal-contribute-fix/<nid>-<slug>/
  - ISSUE_COMMENT.md - Copy/paste this to drupal.org
  - patches/<file>.patch - Upload to the issue

Steps:
1. Go to https://www.drupal.org/node/<nid>
2. Paste content from ISSUE_COMMENT.md
3. Attach the patch file
4. Set status to "Needs review"

For unfiled issues (unfiled-<slug>/):

  1. Create a new issue at https://www.drupal.org/project/issues/
  2. Use ISSUE_COMMENT.md as the description template
  3. Attach the patch file

Project Structure

drupal-contribute-fix/
β”œβ”€β”€ SKILL.md              # Agent skill definition
β”œβ”€β”€ README.md             # This file
β”œβ”€β”€ LICENSE               # GPL-2.0-or-later
β”œβ”€β”€ lib/                  # Python modules
β”‚   β”œβ”€β”€ drupalorg_api.py  # Drupal.org API client
β”‚   β”œβ”€β”€ issue_matcher.py  # Issue search and scoring
β”‚   β”œβ”€β”€ baseline_repo.py  # Git baseline resolution
β”‚   β”œβ”€β”€ patch_packager.py # Patch generation
β”‚   β”œβ”€β”€ report_writer.py  # Output file generation
β”‚   β”œβ”€β”€ security_detector.py
β”‚   └── validator.py
β”œβ”€β”€ scripts/
β”‚   └── contribute_fix.py # CLI entry point
β”œβ”€β”€ references/           # Reference documentation
└── examples/             # Sample outputs

Contributing

Contributions are welcome! This skill is for the Drupal community.

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run syntax checks: python3 -m py_compile scripts/contribute_fix.py lib/*.py
  5. Submit a pull request

License

GPL-2.0-or-later - Compatible with Drupal's licensing.


Acknowledgments


Built for the Drupal community to encourage proper upstream contribution.

About

An Agent Skill to turn local Drupal fixes into effortless, maintainer-friendly contributions without the noise, duplicates, or churn.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%