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.
The Workflow at a Glance
Section titled “The Workflow at a Glance”- Find or open an issue.
- Join the shared issue fork for that issue with
/do:fork(or DrupalBot’s fork-management link). - Branch off
1.xas<issue-number>-<short-slug>, commit, and push to the fork. - Open a merge request targeting
1.x, with a Conventional-Commit title. - A human with the Developer role reviews and squash-merges it.
This applies to everyone, including maintainers — see below.
Issues
Section titled “Issues”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.
- Priority — Normal 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.
The Shared Issue-Fork Model
Section titled “The Shared Issue-Fork Model”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.
Branches
Section titled “Branches”- Branch off
1.xinside the shared fork. - Branch names are
<issue-number>-<short-slug>— for example3578755-set-up-a-starlight-docs-instance-in-docs. Nofeature/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.
Merge Requests
Section titled “Merge Requests”- Open the MR from the fork branch against
1.x, in GitLab’s native UI (or via the API). - Reference the issue with
Closes #NNNNin 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.
Commit and MR-Title Conventions
Section titled “Commit and MR-Title Conventions”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.
Credit Trailers
Section titled “Credit Trailers”Put credit in the MR description (it becomes the squash-commit body):
By: aliceBy: 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:, andReviewed-by:trailers.
You Don’t Need to Curate Branch Commits
Section titled “You Don’t Need to Curate Branch Commits”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.
Merge Authority and Roles
Section titled “Merge Authority and Roles”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.xbranch. 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.
Fork Lifecycle
Section titled “Fork Lifecycle”- 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.xregardless. - 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).
Coding Standards
Section titled “Coding Standards”- 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.
Local Setup and Testing
Section titled “Local Setup and Testing”- See Developer Setup to clone, install the docs toolchain, and enable the pre-push checks.
- For docs changes, run
npm run buildfromdocs/(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)”- Comment
/do:forkon the issue and wait for DrupalBot to create/announce the fork. - Add the fork remote:
git remote add issue git@git.drupal.org:issue/groupsdrupalorg-<n>.git. - Branch off
1.x:git switch -c <n>-<short-slug> 1.x. - Commit your work, then push to the fork:
git push issue <n>-<short-slug>. - Open an MR from that branch to
1.xwith a Conventional-Commit title and aBy:trailer. Assign it to yourself, add the scoped labels, and tick the AI-assisted checkbox in the MR template if an AI tool assisted. - Set it Ready and wait for a human reviewer to review and squash-merge.
Human and AI Policy
Section titled “Human and AI Policy”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:
- 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. - 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.
Briefing Your AI Tool
Section titled “Briefing Your AI Tool”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, readCLAUDE.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 bea 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 setworkflow 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 maintainerreviews and merges. Confirm you have read the guidance before proceeding.