Skip to content

Contribution Standards

This page is the source of truth for how contributions work on this project. The repo-root CONTRIBUTING.md is deliberately thin and points here for the mechanics; CLAUDE.md / AGENTS.md carry the same guardrails inline for AI coding tools. If any of those disagree with this page, this page wins.

Project specifics up front: the default branch is 1.x, all issue work happens in a shared issue fork, and we merge with GitLab-native squash-merge (not the classic drupal.org issue-page merge). See Developer Setup to get a working local environment first.

  1. Find or open an issue.
  2. Join the shared issue fork for that issue with /do:fork (or DrupalBot’s fork-management link).
  3. Branch off 1.x as <issue-number>-<short-slug>, commit, and push to the fork.
  4. Open a merge request targeting 1.x, with a Conventional-Commit title.
  5. A human with the Developer role reviews and squash-merges it.

This applies to everyone, including maintainers — see below.

Every change starts with an issue.

  • Title — descriptive but short. It appears in issue lists and feeds the branch slug, so make it specific and action-oriented (“Add…”, “Fix…”).
  • Category — pick one:
    • Bug report — something is broken.
    • Feature request — a new capability.
    • Task — a to-do that isn’t a bug or a feature (most of our docs and setup work).
    • Support request — help using the project.
    • Plan — roadmap or decision discussion.
  • PriorityNormal by default; Critical or Major for serious breakage, Minor for trivial items.
  • Fill in the issue summary template so the goal and scope are clear.

Follow Drupal’s issue etiquette: search before filing, keep one issue to one problem, stay constructive, and update the issue as work progresses so anyone can pick it up.

These fields — category, priority, component — and the issue’s workflow status are all set with scoped labels, not a status dropdown. See Issue Labels & Workflow for the full system, the old-status → label mapping, and how to set them.

Reference: List of issue fields, Issue Category, Issue Priority.

There are no personal forks on this project. Contributors work together on a single shared issue fork per issue, named issue/groupsdrupalorg-<issue-number>. This holds even though we’ve left the drupal.org issue queue for GitLab-native issues — the shared-fork model persists.

Create or join the fork with /do:fork posted as an issue comment (or use DrupalBot’s fork-management link). That gives you a fork whose SSH URL is git@git.drupal.org:issue/groupsdrupalorg-<issue-number>.git.

Applies to Everyone — No Maintainer Exception

Section titled “Applies to Everyone — No Maintainer Exception”

All issue work routes through the shared fork — maintainers included. A maintainer’s push access to the canonical repository is not a licence to skip the fork for routine issue work; that access exists for merging MRs and trunk/release operations only. The rule is simple: “if you’re on an issue, you’re on a fork.”

This binds AI agents too: in a maintainer’s session, an agent must never take the direct-push-to-canonical shortcut just because access allows it. The hard guard (protecting 1.x so nobody can push directly) is tracked separately as a drupal.org infra ask in #3578760; until then the rule is enforced by convention and by the self-check in CLAUDE.md.

  • Branch off 1.x inside the shared fork.
  • Branch names are <issue-number>-<short-slug> — for example 3578755-set-up-a-starlight-docs-instance-in-docs. No feature/ prefix (that idea was dropped in favor of the shared-fork model).
  • Commit to your branch inside the fork, not to the fork’s default branch.

Reference: Creating issue forks.

  • Open the MR from the fork branch against 1.x, in GitLab’s native UI (or via the API).
  • Reference the issue with Closes #NNNN in the description so it auto-closes on merge.
  • Assign the MR to yourself, and add the scoped labels (category::, component::, priority::) mirroring the linked issue. Set these when you open the MR — a bot opening an MR must set them at creation, not leave them blank.
  • Mark it Draft while it still needs work; set it Ready when it’s ready for review.
  • A human reviewer with merge rights reviews and merges — contributors don’t self-merge, and bots never self-merge.

Reference: Create a merge request, Merge request guidelines.

This is the part most different from the classic drupal.org flow, so read it carefully.

We merge with GitLab-native squash-merge. GitLab squashes the whole MR into a single commit on 1.x, and it uses the MR title as that squash commit’s subject. Therefore the MR title must itself be a valid Conventional Commit — it is not merely cosmetic.

Format:

<type>: #<issue-id> One-line summary of the change
  • Types: feat, fix, docs, ci, perf, refactor, test, task, revert.
  • #<issue-id> is the issue number (the last segment of the issue URL).
  • Example MR title: task: #3578754 Bootstrap the Drupal 11.4 module.

This replaces the classic Issue #NNNN: Summary style. That older style is only correct for the drupal.org issue-page merge path, which we are not using. Existing 1.x history still contains some Issue #NNNN: subjects; we use Conventional Commits going forward and leave that history as-is.

Put credit in the MR description (it becomes the squash-commit body):

By: alice
By: bob
  • Credit each contributor with a By: trailer using their drupal.org username — not a GitLab username, and without a leading @.
  • Maintainers may also use Co-authored-by:, Reported-by:, and Reviewed-by: trailers.

Because everything is squashed, commit as often as you like on the fork branch — only the MR title and description carry into 1.x. Write those well.

Reference: Drupal commit message standard, Conventional Commits.

Merging into canonical needs a merge-capable role on the project, which is separate from fork access:

  • drupal.org “Write to VCS” → GitLab Developer — can push and merge MRs into the unprotected 1.x branch. A fork contributor can push and open an MR, but cannot merge unless granted this role.
  • Adding “Administer maintainers” → GitLab Maintainer — project settings, protected branches, default-branch changes.

Roles are granted self-service on the drupal.org project’s Maintainers page and sync to GitLab. See GitLab Operations & Permissions for the full capability matrix.

  • The shared fork is not deleted when the MR merges — it persists per-issue and is eventually garbage-collected by drupal.org after the issue is closed.
  • Deleting the MR’s source branch (a merge option) does not delete the fork. The merged squash commit lives in 1.x regardless.
  • Local cleanup is on the contributor: remove the fork remote and any stale tracking branches when you’re done (git remote remove issue, then prune).
  • Follow the Drupal coding standards for PHP, JavaScript, CSS, and Twig.
  • Match the conventions already in the file you’re editing.
  • For the documentation site, keep pages plain Markdown so they stay editable in the visual editor — no MDX imports/expressions, no ::: directives, no unregistered JSX. See Editing These Docs and File Formats.
  • See Developer Setup to clone, install the docs toolchain, and enable the pre-push checks.
  • For docs changes, run npm run build from docs/ (astro check + internal link validation) before pushing — the pre-push hook and CI run the same checks.
  • Drupal-module test setup (DDEV, Playwright) will be documented as it lands, tracked in #3578754.

How to Submit a Merge Request (End to End)

Section titled “How to Submit a Merge Request (End to End)”
  1. Comment /do:fork on the issue and wait for DrupalBot to create/announce the fork.
  2. Add the fork remote: git remote add issue git@git.drupal.org:issue/groupsdrupalorg-<n>.git.
  3. Branch off 1.x: git switch -c <n>-<short-slug> 1.x.
  4. Commit your work, then push to the fork: git push issue <n>-<short-slug>.
  5. Open an MR from that branch to 1.x with a Conventional-Commit title and a By: trailer. Assign it to yourself, add the scoped labels, and tick the AI-assisted checkbox in the MR template if an AI tool assisted.
  6. Set it Ready and wait for a human reviewer to review and squash-merge.

AI-assisted contributions are welcome. Most of this project’s work is driven with AI tools (mostly Claude), and that is expected and fine.

Two rules are non-negotiable:

  1. Every merge request must be reviewed and pushed/merged by a human maintainer. No MR merges on the strength of automation alone — a human with merge rights is accountable for what lands in 1.x. Bots never self-merge.
  2. AI involvement must be disclosed on the merge request. When an AI tool materially assisted the change, add a clear disclosure naming the tool. (An MR template with an AI-assisted checkbox is coming in #3578766.) You’re also encouraged (not required) to add an Assisted-by: <tool>:<model> commit trailer. Human authorship and review are still required; disclosure is transparency, not an exemption.

All contributions, human- or AI-assisted, are held to the same review bar and the Drupal Code of Conduct.

Claude Code and similar agents auto-load CLAUDE.md / AGENTS.md from the repo root, so they pick up these guardrails automatically. For other tools (web chat, a different IDE), or to brief a session explicitly, paste this prompt:

You are contributing to the Drupal "groupsdrupalorg" project. Before writing any code, read
CLAUDE.md at the repo root and the Contribution Standards page
(https://project.pages.drupalcode.org/groupsdrupalorg/contribution-standards/).
Non-negotiables: (1) never push to canonical origin (project/groupsdrupalorg) — run /do:fork,
work in the shared issue fork, and open a merge request targeting 1.x; (2) the MR title must be
a Conventional Commit (e.g. `task: #NNNN Summary`) — it becomes the squash commit subject;
(3) assign the MR to yourself, add scoped labels (category::, component::, priority::), and set
workflow status with the state:: label (e.g. state::needsReview) — not GitLab's native Status field;
(4) disclose AI use via the MR-template checkbox and never self-merge — a human maintainer
reviews and merges. Confirm you have read the guidance before proceeding.