-
Notifications
You must be signed in to change notification settings - Fork 11
Add AI helper assets for Drupal best practices #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
theodorosploumis
wants to merge
1
commit into
master
Choose a base branch
from
codex/generate-ai-guides-and-instructions-0bwy90
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # AI contribution guide | ||
|
|
||
| These instructions summarize the Drupal 10+ best practices from `README.md` for any AI-assisted changes inside the `ai/` folder. | ||
|
|
||
| - Prioritize the guidance from **2. Site building** and **3. Theming, templates**. Avoid any Drupal 7.x-only rules. | ||
| - Use clear machine names and avoid multi-word theme names; keep everything human-readable and concise. | ||
| - Keep recommendations aligned with current Drupal core tooling (composer, drush, ddev) and avoid deprecated workflows. | ||
| - Ensure scripts and prompts reinforce configuration over content, avoid hardcoded UUIDs, and respect configuration sync. | ||
| - Keep the output concise and actionable so it can be applied from CLI tools or code editors. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # AI Helpers for Drupal Best Practices | ||
|
|
||
| This folder provides AI-friendly outputs derived from `README.md` sections **2. Site building** and **3. Theming, templates** for Drupal 10+ projects. | ||
|
|
||
| - `AGENTS.md` – scope rules for AI-written assets in this folder. | ||
| - `claude-code-skills.md` – per-subsection skills for Claude Code. | ||
| - `rules.md` – generic rules for any CLI/editor AI. | ||
| - `commands.md` – slash commands mapping to the relevant README sections. | ||
| - `scripts/*.sh` – drush-based validators for subsections (nodes, blocks, taxonomy, fields, views, text formats, theming). | ||
|
|
||
| Run validators from a bootstrapped Drupal site, e.g. | ||
|
|
||
| ```bash | ||
| ./ai/scripts/validate-nodes.sh | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # Claude Code Skills for Drupal Best Practices | ||
|
|
||
| Use these skills to guide Claude Code when assisting Drupal 10+ work. Each skill maps to README sections. | ||
|
|
||
| ## 2.1 Nodes | ||
| - Ensure content types use singular names and human-friendly machine names without special characters. | ||
| - Create bundles only when display or functionality differs; keep revisions only where workflows require them. | ||
| - Prefer shared, generic view modes and document each bundle with a description. | ||
|
|
||
| ## 2.2 Blocks | ||
| - Create custom block types or plugins in code with clean machine names (no region info, no `block_` prefix). | ||
| - Treat block fields and view modes like node bundles and avoid hardcoded UUID-driven blocks. | ||
|
|
||
| ## 2.3 Taxonomy | ||
| - Keep vocabulary names singular; use taxonomy for categorization pages, not simple filtering. | ||
| - Consider entity references when authorization, fields, or displays exceed taxonomy needs. | ||
|
|
||
| ## 2.4 Other content entities | ||
| - Apply node conventions to media, paragraphs, and comments; watch translation handling for paragraphs. | ||
| - Use concise, reusable image style names that describe intent rather than dimensions. | ||
|
|
||
| ## 2.5 Fields | ||
| - Name shared fields generically and specific fields with entity context using `field_[bundle]_[short]`. | ||
| - Add descriptions, reuse fields only when invariant, and set meaningful file directories; drop `gif` unless required. | ||
|
|
||
| ## 2.6 Views | ||
| - Normalize machine names (remove `_1` suffix), titles, tags, and admin descriptions for every display. | ||
| - Favor separate Views per display, render entities via view modes, avoid blanket CSS classes and default Ajax. | ||
| - Require permission-based access controls and clear "No results" text. | ||
|
|
||
| ## 2.7 Forms | ||
| - Default to the Webform module for custom forms; reserve core Contact only for simple single-form cases. | ||
|
|
||
| ## 2.8 Text formats and editors | ||
| - Standardize on a single HTML format using CKEditor; align buttons with allowed tags and limit format switching. | ||
| - Keep insecure content out of WYSIWYG and ensure admin formats mirror author access when possible. | ||
|
|
||
| ## 3. Theming, templates | ||
| - Use one-word theme machine names without `theme` or base-theme prefixes; favor twig and atomic design patterns. | ||
| - Add classes via preprocess in `.theme`, cover special templates (404/403/maintenance/login), and keep overrides minimal. | ||
| - Prefer Classy as a base; if using contrib themes, decouple machine names. Use SCSS, meaningful breakpoints, and semantic class prefixes (`twig-`, `js-`). | ||
| - Avoid styling by path aliases, comment mixins/functions, and split SCSS by responsibility (entities, variables, etc.). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # AI Commands for Drupal Best Practices | ||
|
|
||
| Use these slash commands in chat-based tools to pull focused guidance from README sections 2 and 3. | ||
|
|
||
| - `/drupal-best-practices-nodes` → Section 2.1 Nodes: singular bundles, minimal revisions, generic view modes, human-readable machine names. | ||
| - `/drupal-best-practices-blocks` → Section 2.2 Blocks: code-driven block types/plugins, clean machine names, no UUID-bound blocks. | ||
| - `/drupal-best-practices-taxonomy` → Section 2.3 Taxonomy: singular vocabularies, use for categorization pages, prefer lists or references for filtering/authorization needs. | ||
| - `/drupal-best-practices-entities` → Section 2.4 Other content entities: reuse node conventions for media/paragraphs/comments; translation awareness. | ||
| - `/drupal-best-practices-fields` → Section 2.5 Fields: `field_[bundle]_[short]` naming, descriptions, reuse rules, image directory conventions, avoid `gif`. | ||
| - `/drupal-best-practices-views` → Section 2.6 Views: display-per-view, admin metadata, view modes, permission access, no default Ajax, empty-state text. | ||
| - `/drupal-best-practices-forms` → Section 2.7 Forms: default to Webform, reserve core Contact for single lightweight forms. | ||
| - `/drupal-best-practices-text-formats` → Section 2.8 Text formats and editors: single HTML format, CKEditor, aligned buttons/tags, limited switching. | ||
| - `/drupal-best-practices-theming` → Section 3 Theming, templates: one-word theme names, twig-first, preprocess classes, minimal overrides, SCSS with shared breakpoints, semantic class prefixes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # AI-Agnostic Rules for Drupal Best Practices | ||
|
|
||
| Apply these Drupal 10+ rules across any CLI/editor tooling. They mirror README sections 2 and 3. | ||
|
|
||
| - **Machine names:** Use single words without prefixes or suffixes tied to regions/themes; avoid collisions and keep them human-readable. | ||
| - **Content modeling (2.1–2.5):** Favor fewer bundles, singular labels, documented descriptions, and reusable fields with clear `field_[bundle]_[short]` naming. Treat blocks, taxonomies, media, and paragraphs with the same discipline and avoid hardcoded UUID content. | ||
| - **Views (2.6):** One view per display when possible, explicit admin metadata, permission-based access, entity view mode rendering, non-Ajax by default, and clear empty states. | ||
| - **Forms (2.7):** Default to Webform; core Contact only for trivial single-form needs. | ||
| - **Text formats (2.8):** Standardize on one HTML format using CKEditor; align toolbar buttons with allowed tags and restrict switching formats. | ||
| - **Theming (3):** One-word theme machine names without `theme` suffixes or base-theme coupling, atomic/twig-first approach, preprocess for classes, minimal overrides, SCSS with shared breakpoints, semantic class prefixes (`twig-`, `js-`), and avoid styling by path aliases. | ||
| - **Tooling:** Prefer composer, drush, and ddev for automation; keep guidance compatible with config synchronization and current Drupal core support. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Validate README section 2.2 Blocks rules. | ||
|
|
||
| command -v drush >/dev/null 2>&1 || { echo "drush is required" >&2; exit 1; } | ||
|
|
||
| drush php:eval ' | ||
| use Drupal\block_content\Entity\BlockContentType; | ||
| $fail = 0; | ||
| $storage = \Drupal::entityTypeManager()->getStorage("block_content_type"); | ||
| foreach ($storage->loadMultiple() as $type) { | ||
| $id = $type->id(); | ||
| $desc = trim((string) $type->getDescription()); | ||
| if (preg_match("/\s/", $id) || preg_match("/[^a-z0-9_]/", $id) || preg_match("/[A-Z]/", $id)) { | ||
| echo "[blocks] Machine name needs cleanup: $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if (strpos($id, 'block_') === 0) { | ||
| echo "[blocks] Remove redundant block_ prefix from $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if ($desc === '') { | ||
| echo "[blocks] Missing description for $id\n"; | ||
| $fail = 1; | ||
| } | ||
| } | ||
| if ($fail) { | ||
| exit(1); | ||
| } | ||
| ' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Validate README section 2.5 Fields rules. | ||
|
|
||
| command -v drush >/dev/null 2>&1 || { echo "drush is required" >&2; exit 1; } | ||
|
|
||
| drush php:eval ' | ||
| use Drupal\field\Entity\FieldStorageConfig; | ||
| $fail = 0; | ||
| $storage = \Drupal::entityTypeManager()->getStorage("field_storage_config"); | ||
| foreach ($storage->loadMultiple() as $field) { | ||
| $id = $field->getName(); | ||
| $desc = trim((string) $field->getDescription()); | ||
| if (strpos($id, "field_") !== 0) { | ||
| echo "[fields] Field name should start with field_: $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if (preg_match("/\s/", $id) || preg_match("/[^a-z0-9_]/", $id) || preg_match("/[A-Z]/", $id)) { | ||
| echo "[fields] Machine name needs cleanup: $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if ($desc === '') { | ||
| echo "[fields] Missing description for $id\n"; | ||
| $fail = 1; | ||
| } | ||
| } | ||
| if ($fail) { | ||
| exit(1); | ||
| } | ||
| ' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Validate README section 2.1 Nodes rules against a Drupal 10+ site. | ||
| # Requires: drush, Drupal bootstrap. | ||
|
|
||
| command -v drush >/dev/null 2>&1 || { echo "drush is required" >&2; exit 1; } | ||
|
|
||
| drush php:eval ' | ||
| use Drupal\node\Entity\NodeType; | ||
| $fail = 0; | ||
| $storage = \Drupal::entityTypeManager()->getStorage("node_type"); | ||
| foreach ($storage->loadMultiple() as $type) { | ||
| $id = $type->id(); | ||
| $label = $type->label(); | ||
| $desc = trim((string) $type->getDescription()); | ||
| if (preg_match("/\s/", $id) || preg_match("/[^a-z0-9_]/", $id) || preg_match("/[A-Z]/", $id)) { | ||
| echo "[nodes] Machine name needs cleanup: $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if (preg_match("/s$/", $label)) { | ||
| echo "[nodes] Label looks plural; prefer singular: $label ($id)\n"; | ||
| $fail = 1; | ||
| } | ||
| if ($desc === '') { | ||
| echo "[nodes] Missing description for $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if ($type->isNewRevision()) { | ||
| echo "[nodes] Revisions enabled by default; confirm workflow need: $id\n"; | ||
| } | ||
| } | ||
| if ($fail) { | ||
| exit(1); | ||
| } | ||
| ' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Validate README section 2.3 Taxonomy rules. | ||
|
|
||
| command -v drush >/dev/null 2>&1 || { echo "drush is required" >&2; exit 1; } | ||
|
|
||
| drush php:eval ' | ||
| use Drupal\taxonomy\Entity\Vocabulary; | ||
| $fail = 0; | ||
| $storage = \Drupal::entityTypeManager()->getStorage("taxonomy_vocabulary"); | ||
| foreach ($storage->loadMultiple() as $vocab) { | ||
| $id = $vocab->id(); | ||
| $label = $vocab->label(); | ||
| if (preg_match("/\s/", $id) || preg_match("/[^a-z0-9_]/", $id) || preg_match("/[A-Z]/", $id)) { | ||
| echo "[taxonomy] Machine name needs cleanup: $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if (preg_match("/s$/", $label)) { | ||
| echo "[taxonomy] Label looks plural; prefer singular: $label ($id)\n"; | ||
| $fail = 1; | ||
| } | ||
| } | ||
| if ($fail) { | ||
| exit(1); | ||
| } | ||
| ' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Validate README section 2.8 Text formats and editors rules. | ||
|
|
||
| command -v drush >/dev/null 2>&1 || { echo "drush is required" >&2; exit 1; } | ||
|
|
||
| drush php:eval ' | ||
| use Drupal\filter\Entity\FilterFormat; | ||
| $formats = FilterFormat::loadMultiple(); | ||
| if (count($formats) > 2) { | ||
| echo "[text formats] More than one HTML-capable format detected; aim for a single HTML format.\n"; | ||
| } | ||
| foreach ($formats as $format) { | ||
| $name = $format->id(); | ||
| $filters = $format->filters(); | ||
| if (strpos($name, "html") !== false && empty($format->getRoles())) { | ||
| echo "[text formats] Ensure access to $name is scoped to roles, not open to all.\n"; | ||
| } | ||
| if ($filters->has('filter_html')) { | ||
| $allowed = $filters->get('filter_html')->getConfiguration()['allowed_html'] ?? ''; | ||
| if ($allowed === '') { | ||
| echo "[text formats] Allowed HTML empty for $name; align toolbar buttons with allowed tags.\n"; | ||
| } | ||
| } | ||
| } | ||
| ' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Validate README section 3 Theming rules. | ||
|
|
||
| command -v drush >/dev/null 2>&1 || { echo "drush is required" >&2; exit 1; } | ||
|
|
||
| drush php:eval ' | ||
| use Drupal\system\Entity\Theme; | ||
| $fail = 0; | ||
| $themes = Theme::loadMultiple(); | ||
| foreach ($themes as $theme) { | ||
| $id = $theme->id(); | ||
| if (preg_match("/\s/", $id) || preg_match("/[^a-z0-9_]/", $id) || preg_match("/[A-Z]/", $id)) { | ||
| echo "[theming] Theme machine name should be one word lowercase: $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if (strpos($id, 'theme') !== false) { | ||
| echo "[theming] Remove redundant 'theme' substring from $id\n"; | ||
| $fail = 1; | ||
| } | ||
| $base = $theme->getBaseTheme(); | ||
| if ($base && strpos($id, $base) !== false) { | ||
| echo "[theming] Subtheme machine name should not include base theme ($base): $id\n"; | ||
| $fail = 1; | ||
| } | ||
| } | ||
| if ($fail) { | ||
| exit(1); | ||
| } | ||
| ' | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Validate README section 2.6 Views rules. | ||
|
|
||
| command -v drush >/dev/null 2>&1 || { echo "drush is required" >&2; exit 1; } | ||
|
|
||
| drush php:eval ' | ||
| use Drupal\views\Views; | ||
| $fail = 0; | ||
| $storage = \Drupal::entityTypeManager()->getStorage("view"); | ||
| foreach ($storage->loadMultiple() as $view) { | ||
| $id = $view->id(); | ||
| $human = $view->label(); | ||
| if (preg_match("/\s/", $id) || preg_match("/[^a-z0-9_]/", $id) || preg_match("/[A-Z]/", $id)) { | ||
| echo "[views] Machine name needs cleanup: $id\n"; | ||
| $fail = 1; | ||
| } | ||
| if ($human === $id || $human === '') { | ||
| echo "[views] Missing descriptive label for $id\n"; | ||
| $fail = 1; | ||
| } | ||
| foreach ($view->get('display') as $display_id => $display) { | ||
| if (substr($display_id, -2) === '_1') { | ||
| echo "[views] Rename default _1 display id in $id ($display_id)\n"; | ||
| $fail = 1; | ||
| } | ||
| if (empty($display['display_title'])) { | ||
| echo "[views] Missing display title for $id::$display_id\n"; | ||
| $fail = 1; | ||
| } | ||
| } | ||
| } | ||
| if ($fail) { | ||
| exit(1); | ||
| } | ||
| ' |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The theming script imports
Drupal\system\Entity\Themeand callsTheme::loadMultiple(), but Drupal themes are extensions exposed through the theme handler, not config entities. On Drupal 10 thisusestatement causes drush php:eval to fatally error (Class "Drupal\system\Entity\Theme" not found), so none of the validation logic can run. Please switch to the theme handler (e.g.,\Drupal::service('theme_handler')->listInfo()) or another supported API so the script can execute.Useful? React with 👍 / 👎.