module-development
Skill4 starsChanged 4 months agoMITView on GitHub
Scaffold a custom Drupal module — the .info.yml manifest, .services.yml service definitions with dependency injection, and hook implementations in the .module file. Use when the user wants to implement a Drupal hook such as hook_form_alter or hook_theme in a custom module .module file; the user wants to scaffold a new custom Drupal module with an .info.yml manifest and a service or hook; the user needs to register a service in a Drupal module .services.yml and inject dependencies into it. Keywords: drupal, module, info-yml, services-yml, hooks, dependency-injection, scaffold, php81.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- microsoft/amplifier-module-tool-skillstheir own version, first seen Oct 13, 2026
- microsoft/amplifier-bundle-skillstheir own version, first seen Oct 13, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- microsoft/amplifier-bundle-skills★ 12same name
- microsoft/amplifier-module-tool-skills★ 8same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository119 other files it gives its agents.
- strategy-bitrix-d7-incrementalSkill
- strategy-explicit-over-magicSkill
- strategy-framework-conventionsSkill
- strategy-legacy-safe-editsSkill
- strategy-minimal-diffSkill
- strategy-no-untested-refactorSkill
- strategy-preserve-public-apiSkill
- strategy-readonly-immutabilitySkill
- strategy-security-firstSkill
- strategy-test-drivenSkill
- openapiSkill
- paginationSkill
- rest-designSkill
- versioningSkill
- cqrsSkill
- dependency-inversionSkill
- hexagonalSkill
- repository-patternSkill
- service-layerSkill
- bitrixSkill
- findings-reportSkill
- laravelSkill
- performanceSkill
- phpSkill
- project-analysisSkill
- refactoringSkill
- roi-prioritizationSkill
- securitySkill
- stack-detectionSkill
- cache-layersSkill
- component-engineSkill
- d7-eventsSkill
- d7-loaderSkill
- d7-orm-queriesSkill
- iblock-elementsSkill
- kernel-main-moduleSkill
- localizationSkill
- controllersSkill
- ormSkill
- validationSkill
- controllersSkill
- query-builderSkill
- routingSkill
- autoload-psr4Skill
- dependency-managementSkill
- scriptsSkill
- connection-poolingSkill
- mysql-indexingSkill
- redisSkill
- transactionsSkill
- ci-github-actionsSkill
- deployment-strategiesSkill
- docker-phpSkill
- env-configSkill
- associationsSkill
- entities-mappingSkill
- orm-basicsSkill
- entity-apiSkill
- routing-controllersSkill
- formsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 3 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 65
Do not build a custom Drupal module when a maintained contrib module on drupal.org already covers the requirement.
- Distinctive: line 66
Do not use a module when the task is purely Twig templates, CSS, or JavaScript.
- Very specific: line 75
Create modules/custom/my_module/my_module.info.yml with name, type: module, and core_version_requirement: ^10 || ^11.
- Very specific: line 76
Add my_module.services.yml defining a service class under Drupal\my_module\ with its dependencies listed in arguments.
- Very specific: line 77
Add a my_module_HOOK() implementation to my_module.module, then run drush cr so Drupal discovers it.
- Distinctive: line 107
Not applicable — no I/O, auth, or untrusted input.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- generated: do not edit — source: knowledge/atoms/drupal/module-development/ --><!-- schema: atomVersion=3 skillVersion=2 graphVersion=1 --><!-- compile: @php-skills/compiler v1.0.0 (deterministic build) -->Drupal Module Development
When to use
- The user wants to implement a Drupal hook such as hook_form_alter or hook_theme in a custom module .module file.
- The user wants to scaffold a new custom Drupal module with an .info.yml manifest and a service or hook.
- The user needs to register a service in a Drupal module .services.yml and inject dependencies into it.
When NOT to use
- Do not build a custom Drupal module when a maintained contrib module on drupal.org already covers the requirement.
- Do not use a module when the task is purely Twig templates, CSS, or JavaScript; that belongs in a Drupal theme.
Core guidance
- Declare type, core_version_requirement, and dependencies in .info.yml — In
my_module.info.ymlsettype: module,core_version_requirement: ^10 || ^11, and list each module dependency asdrupal:nodeorproject:module. - Match the machine name across file names and namespace — Use one lowercase, underscore machine name (e.g.
my_module) for the directory, the.info.yml, the.modulefile, and map it to theDrupal\my_modulePSR-4 namespace undersrc/.
Quick recipe
- Create
modules/custom/my_module/my_module.info.ymlwithname,type: module, andcore_version_requirement: ^10 || ^11. (verify: The module appears at /admin/modules under its declared name.) - Add
my_module.services.ymldefining a service class underDrupal\my_module\with its dependencies listed inarguments. (verify:drush evcan resolve the service from the container without error.) - Add a
my_module_HOOK()implementation tomy_module.module, then rundrush crso Drupal discovers it. (verify: The hook fires on the expected event after the cache rebuild.)
Best practices
- For controllers, forms, and plugins that Drupal instantiates, implement
create(ContainerInterface $container)and pull dependencies from the container there rather than declaring them in a .services.yml file - Implement hooks as functions named
MACHINENAME_hookname(e.g - Define services in
my_module.services.ymlwith explicitargumentsand inject them via the constructor; call\Drupal::service()only inside hooks and other procedural code that cannot receive injection
Anti-patterns
| Anti-pattern | Why it fails | Do instead |
| Heavy business logic in the .module file | Procedural .module code is untestable and cannot use dependency injection, so it accretes into an unmaintainable tangle. | Keep the .module file to thin hook stubs that delegate to injected services holding the real logic. |
| Editing contrib or core files directly | Direct edits are overwritten on the next update and silently reintroduce the original behavior or bugs. | Alter behavior from your own module via hooks, event subscribers, or service decoration, and track upstream fixes as composer patches. |
| Using \Drupal::service() inside injectable classes | The static accessor hides dependencies, prevents unit testing, and couples the class to the global container. | Declare the dependency as a constructor argument in .services.yml or resolve it in create(). |
See references/anti-patterns.md.
Common mistakes
- New services or hooks not picked up until cache rebuild — A newly added service, route, or hook appears to have no effect because Drupal caches its discovery data. Fix: Run
drush cache:rebuild(ordrush cr) after adding or renaming services, routes, or hooks. - Module refuses to install on unsupported core — The module is missing from the extend list or errors on install because core_version_requirement is absent or too narrow. Fix: Set
core_version_requirement: ^10 || ^11(or the range you actually support) and remove the legacycore: 8.xkey. - Class not found due to PSR-4 namespace mismatch — A service class fails to load with a ClassNotFound error even though the file exists under
src/. Fix: Ensure the namespace is exactlyDrupal\MACHINENAME\...and the file path undersrc/mirrors the sub-namespace.
Version notes
- core_version_requirement replaced core key in Drupal 9 (PHP >=8.1) — From Drupal 9,
.info.ymlmust usecore_version_requirementwith a semver constraint; the oldcore: 8.xkey is removed in Drupal 10.
Security
- Not applicable — no I/O, auth, or untrusted input.
Testing
- Activation and decision behavior are verified in
eval/scenarios/drupal/module-development.yaml.
Additional resources
- references/anti-patterns.md
- references/core.md
- references/examples.md
- references/pitfalls.md
- references/recipes.md
- references/version-differences.md
Knowledge graph
Related: drupal/entity-api, php/typed-properties
<!-- graph-fragment: graph/fragments/drupal/module-development.yaml -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

