Drupal Module Development Guide
Drupal Module Development Guide
Separation of Duties: See Separation of Duties - Drupal modules are responsible for Drupal-specific functionality. They do NOT own agent manifests, execution, or OSSA spec.
Comprehensive guide for developing custom Drupal modules in the LLM Platform ecosystem.
Table of Contents
Overview
The LLM Platform uses custom Drupal modules to provide AI-powered functionality, agent orchestration, and enterprise integrations. All modules follow Drupal coding standards and OSSA compliance requirements.
Key Principles
- OSSA Compliance: All AI agent modules must follow the Open Standard for Swarm Architecture
- Drupal Standards: Follow PHPCS and PHPStan standards (Drupal, DrupalPractice)
- Test Coverage: PHPUnit tests for all critical functionality
- API-First: REST, GraphQL, and JSON:API support
- Security: Input validation, access control, audit logging
Module Structure
Standard Drupal module structure with OSSA enhancements:
module_name/
.agents/ # OSSA agent manifests
agent-name/
manifest.json # OSSA manifest
README.md
tools/
.claude/ # Claude Code configuration
CLAUDE.md # Employment protection
config/
install/ # Default config
schema/ # Config schema
src/
Controller/ # Route controllers
Entity/ # Entity definitions
Form/ # Form classes
Plugin/ # Plugin definitions
Service/ # Services
tests/
src/
Unit/ # Unit tests
Kernel/ # Kernel tests
Functional/ # Functional tests
module_name.info.yml # Module metadata
module_name.module # Hooks
module_name.routing.yml # Routes
module_name.services.yml # Service definitions
module_name.permissions.yml # Permissions
composer.json # Composer dependencies
README.md # Documentation
Development Workflow
1. Module Location
Source Location (edit here):
$LLM_ROOT/all_drupal_custom/modules/MODULE_NAME/
Deployment Location (Composer-managed, DO NOT EDIT):
$LLM_ROOT/llm-platform/web/modules/custom/MODULE_NAME/
2. Sync Modules
After making changes, sync to deployment:
buildkit drupal sync --modules
Or with dry-run to preview:
buildkit drupal sync --modules --dry-run
3. Module Creation
Create a new module:
buildkit drupal module:create my_module_name
This scaffolds:
- Basic module structure
.info.ymlwith dependencies- Service definitions
- OSSA compliance files
- CLAUDE.md employment protection
4. Development Commands
# Clear cache buildkit drupal cache:clear # Export config buildkit drupal config:export # Run database updates buildkit drupal database:update # PHPCS validation buildkit drupal phpcs MODULE_PATH --fix # Design taste validation buildkit drupal taste MODULE_PATH
OSSA Compliance
All AI agent modules must be OSSA-compliant.
Manifest Structure
Every agent requires .agents/agent-name/manifest.json:
{ "name": "agent-name", "version": "0.4.9", "type": "worker", "description": "Agent description", "capabilities": [ "capability1", "capability2" ], "tools": [ { "name": "tool_name", "type": "function", "description": "Tool description", "parameters": { "type": "object", "properties": {}, "required": [] } } ], "dependencies": [], "security": { "isolation_level": "container", "permissions": [] } }
Validation
# Validate OSSA manifest ossa validate .agents/agent-name/manifest.json # Migrate old manifests ossa migrate .agents/old-agent/ --output .agents/new-agent/
Best Practices
1. Module Info File
name: 'Module Name' type: module description: 'Clear, concise description including OSSA compliance note' package: 'Package Name' core_version_requirement: ^10.3 || ^11 version: 0.1.1 dependencies: # Core dependencies only - drupal:system (>=10.3) - drupal:user suggests: # Optional enhancements - admin_toolbar:admin_toolbar configure: module_name.settings lifecycle: stable
2. Service Definitions
Use dependency injection:
# module_name.services.yml services: module_name.service_name: class: Drupal\module_name\Service\ServiceName arguments: - '@entity_type.manager' - '@logger.factory' - '@config.factory'
3. Entity Definitions
Use ECK (Entity Construction Kit) or custom entities:
<?php namespace Drupal\module_name\Entity; use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; /** * Defines the Example entity. * * @ContentEntityType( * id = "example_entity", * label = @Translation("Example Entity"), * base_table = "example_entity", * entity_keys = { * "id" = "id", * "uuid" = "uuid", * "label" = "name", * }, * ) */ class ExampleEntity extends ContentEntityBase { public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = parent::baseFieldDefinitions($entity_type); $fields['name'] = BaseFieldDefinition::create('string') ->setLabel(t('Name')) ->setRequired(TRUE); return $fields; } }
4. Plugin System
Use plugins for extensibility:
<?php namespace Drupal\module_name\Plugin\ActionType; use Drupal\Core\Plugin\PluginBase; /** * @ActionType( * id = "example_action", * label = @Translation("Example Action"), * description = @Translation("Description of action"), * ) */ class ExampleAction extends PluginBase { public function execute(array $context): array { // Implementation return ['success' => TRUE]; } }
5. API Endpoints
Provide REST/GraphQL endpoints:
# module_name.routing.yml module_name.api.endpoint: path: '/api/v1/module-name/{id}' defaults: _controller: '\Drupal\module_name\Controller\ApiController::getData' _format: 'json' requirements: _permission: 'access module name api' _method: 'GET'
6. Configuration Schema
Define configuration schema:
# config/schema/module_name.schema.yml module_name.settings: type: config_object label: 'Module Name settings' mapping: api_key: type: string label: 'API Key' timeout: type: integer label: 'Timeout (seconds)'
Testing
PHPUnit Setup
# Run all tests vendor/bin/phpunit modules/custom/module_name/tests # Run specific test suite vendor/bin/phpunit --testsuite Unit modules/custom/module_name
Unit Test Example
<?php namespace Drupal\Tests\module_name\Unit; use Drupal\Tests\UnitTestCase; use Drupal\module_name\Service\ExampleService; /** * @coversDefaultClass \Drupal\module_name\Service\ExampleService * @group module_name */ class ExampleServiceTest extends UnitTestCase { /** * @covers ::processData */ public function testProcessData() { $service = new ExampleService(); $result = $service->processData(['input' => 'test']); $this->assertEquals('expected', $result['output']); } }
Kernel Test Example
<?php namespace Drupal\Tests\module_name\Kernel; use Drupal\KernelTests\KernelTestBase; /** * Tests the Example entity. * * @group module_name */ class ExampleEntityTest extends KernelTestBase { protected static $modules = ['module_name', 'user', 'system']; protected function setUp(): void { parent::setUp(); $this->installEntitySchema('example_entity'); } public function testEntityCreation() { $entity = ExampleEntity::create(['name' => 'Test']); $entity->save(); $this->assertNotNull($entity->id()); $this->assertEquals('Test', $entity->label()); } }
Deployment
1. Pre-Deployment Checks
# Run tests buildkit golden test # Validate code buildkit drupal phpcs modules/custom/module_name --fix # Check design taste buildkit drupal taste modules/custom/module_name # Security audit buildkit golden audit
2. Sync and Deploy
# Sync to deployment location buildkit drupal sync --modules # Export configuration buildkit drupal config:export # Deploy to environment buildkit golden deploy --env dev
3. Post-Deployment
# Run database updates buildkit drupal database:update # Import configuration buildkit drupal config:import # Clear caches buildkit drupal cache:clear # Verify module status drush pm:list --type=module --status=enabled | grep module_name
Employment Protection
All modules include .claude/CLAUDE.md with employment protection:
# CLAUDE.md - module_name ## EMPLOYMENT PROTECTION ACTIVE - Claude Code BLOCKED from development branch - AI attribution BLOCKED in commits - Feature branch workflow ENFORCED ## TOKEN OPTIMIZATION MANDATORY Before writing ANY code > 500 tokens: - Check: buildkit agents list - Use: buildkit agents spawn --type worker Protected by Agent BuildKit v0.1.9
Common Patterns
AI Integration
// Use AI service $ai = \Drupal::service('ai.provider.manager'); $provider = $ai->createInstance('openai'); $result = $provider->chat($messages);
ECA Integration
# Workflow automation langcode: en status: true dependencies: module: - module_name id: example_workflow label: 'Example Workflow' modeller: bpmn events: - id: event_1 plugin: 'content:entity:save' conditions: [] actions: - id: action_1 plugin: 'module_name:custom_action'
Queue Processing
// Queue worker $queue = \Drupal::queue('module_name_tasks'); $queue->createItem(['data' => $data]); // Process in QueueWorker plugin
Resources
See Also
- Recipe Development
- AI Agents OSSA Module - OSSA compliance and validation
- Drupal Standards
- Module-Specific Guides