Manages DDEV local environments for Craft CMS: config.yaml (PHP/Node/DB/docroot), shorthand commands (composer/craft/npm), add-ons (Redis/Mailpit), DB import/export, Xdebug toggle, Vite exposure, sharing, troubleshooting (logs/poweroff/delete/port conflicts).
npx claudepluginhub michtio/craftcms-claude-skills --plugin craftcms-claude-skillsThis skill uses the workspace's default tool permissions.
When this skill triggers, also load:
Generates Docker Compose and Dockerfile configurations for local development via interactive Q&A. Supports PHP/Laravel, WordPress, Drupal, Node.js, Python stacks with Nginx, Supervisor/PM2, databases, Redis, email testing.
Scaffolds CLAUDE.md and .claude/rules for Craft CMS projects (plugin, site, module, hybrid, monorepo) by detecting type from composer.json, .ddev/config.yaml, templates, and modules.
Provides reference for docker-local Laravel dev environment including service credentials/ports, CLI commands (status/up/down/logs), file paths, project structure, and .env requirements. Use for setup, health checks, and troubleshooting.
Share bugs, ideas, or general feedback.
When this skill triggers, also load:
craftcms — Plugin/module development. Required when DDEV commands involve Craft CLI (ddev craft make, ddev craft migrate, ddev craft project-config).craft-php-guidelines — PHP coding standards. Required when DDEV commands involve code quality tooling (ddev composer check-cs, ddev composer phpstan, ddev craft pest/test).When unsure about a DDEV feature, WebFetch the relevant docs page.
ddev exec composer install instead of ddev composer install — DDEV shorthand commands handle path resolution and environment setup. Always use the shorthand.ddev craft up does both migrate/all and project-config/apply — no need to run them separately after pulls or deploys.ports instead of web_extra_exposed_ports — ports causes conflicts when running multiple DDEV projects. web_extra_exposed_ports routes through Traefik and works with HTTPS.ddev composer global require — global packages install inside the container and vanish on restart. Install project-level dependencies only.nodejs_version but running npm install on the host — Node must run inside the container via ddev npm to match the configured version..ddev/config.yaml while containers are running without restarting — changes to config require ddev restart to take effect.ddev import-db without --target-db=db on multi-database setups — the default target is db, but if you've configured additional databases, be explicit.#ddev-generated to custom commands you've customized — DDEV overwrites files with this comment during updates. Only use it for add-on-managed commands. Custom commands you maintain should omit it.composer install on the host then ddev composer check-cs/ddev composer phpstan — if the host PHP version differs from DDEV's (e.g., host PHP 8.4, DDEV PHP 8.3), vendor/composer/platform_check.php fails. Always run ddev composer install so vendor/ matches the container's PHP version.Always prefer Craft CLI commands over raw database queries:
ddev craft users/list-admins # not: ddev mysql -e "SELECT * FROM users WHERE admin=1"
ddev craft project-config/get system # not: reading project.yaml manually
ddev craft resave/entries # not: UPDATE queries on content tables
ddev craft elements/delete # not: DELETE FROM elements
Only fall back to ddev mysql when no CLI equivalent exists (e.g., checking table schemas, debugging specific rows, TRUNCATE cache for stuck mutex locks). Craft CLI commands handle project config, search index updates, and event firing that raw SQL skips.
Always use DDEV shorthand over ddev exec:
ddev composer install # not ddev exec composer install
ddev craft up # not ddev exec php craft up
ddev npm install # not ddev exec npm install
ddev craft make service # scaffolding
# .ddev/config.yaml
name: my-craft-site
type: craftcms
docroot: web
php_version: "8.3"
database:
type: mysql
version: "8.0"
nodejs_version: "20"
DDEV auto-injects: CRAFT_DB_SERVER, CRAFT_DB_USER, CRAFT_DB_PASSWORD, CRAFT_DB_DATABASE, PRIMARY_SITE_URL.
ddev start # Start the project
ddev stop # Stop the project
ddev restart # Restart containers
ddev ssh # SSH into web container
ddev describe # Show project info and URLs
ddev logs # View container logs
ddev import-db --file=dump.sql # Import database
ddev export-db --file=dump.sql # Export database
ddev xdebug on # Enable Xdebug
ddev craft db/backup # Craft database backup
Composer scripts auto-run craft up after install/update:
{
"scripts": {
"post-craft-update": [
"@php craft install/check && php craft up --interactive=0 || exit 0"
],
"post-update-cmd": "@post-craft-update",
"post-install-cmd": "@post-craft-update"
}
}
No need to manually run ddev craft migrate/all or ddev craft project-config/apply — ddev craft up does both, and it auto-runs after ddev composer install/update.
ddev add-on get ddev/ddev-redis # Install Redis
ddev add-on get ddev/ddev-mailpit # Install Mailpit
ddev add-on list # List installed add-ons
ddev add-on remove ddev/ddev-redis # Remove add-on
Place scripts in .ddev/commands/web/ (container) or .ddev/commands/host/ (host):
#!/usr/bin/env bash
## Description: Run ECS code style check
## Usage: check-cs
## Example: ddev check-cs
cd /var/www/html && composer check-cs
Note: omit #ddev-generated on custom commands you maintain — DDEV overwrites files with that comment during updates. Only add-on-managed commands should include it.
When developing plugins locally, Composer path repos symlink the plugin into vendor/. For this to work inside DDEV's Docker container, the host path must be volume-mounted so the symlink resolves.
{
"repositories": [
{
"type": "path",
"url": "/Users/Shared/dev/craft-plugins/v5/*"
}
]
}
.ddev/docker-compose.mounts.yaml:services:
web:
volumes:
- /Users/Shared/dev/craft-plugins:/Users/Shared/dev/craft-plugins
The mount path inside the container must match the host path exactly — Composer creates absolute symlinks that must resolve in both contexts. Replace /Users/Shared/dev/craft-plugins with your actual plugin directory path.
ddev composer require vendor/plugin-handle:@devcomposer.json url — the path must be the host filesystem path, not /var/www/...ddev composer install succeeds but the symlink points nowhere inside the container"platform": {"php": "8.3"} in composer.json config — don't. DDEV handles the PHP version via .ddev/config.yaml. Platform overrides cause dependency resolution mismatches between host and container, and prevent DDEV from managing version upgrades cleanly.The Chrome DevTools MCP server gives Claude Code direct browser access — inspect pages, read console logs, check network requests, capture screenshots, and interact with the DOM.
claude mcp add chrome-devtools -- npx @anthropic-ai/chrome-devtools-mcp@latest
Quit and reopen Claude Code to load the new MCP server. Requires Chrome or Chromium running — the MCP server handles the DevTools Protocol connection automatically.
| Capability | Use Case |
|---|---|
| Page inspection | Check rendered HTML, verify template output, inspect meta tags |
| Console logs | Catch Twig errors, JS exceptions, Garnish initialization failures |
| Network requests | Debug 404 assets, failed AJAX calls, Sprig/htmx swaps |
| DOM queries | Verify form markup, check field rendering, validate ARIA attributes |
| Screenshots | Visual verification of CP templates, responsive testing |
| Navigation & login | Authenticate into the CP, navigate to plugin settings/edit pages |
allowAdminChanges offDDEV sites are accessible at https://{project}.ddev.site. To inspect CP pages:
https://{project}.ddev.site/{cpTrigger}The craft-project-setup skill offers to install Chrome DevTools MCP during scaffolding. If installed later, run claude mcp add chrome-devtools -- npx @anthropic-ai/chrome-devtools-mcp@latest from the project root — this writes to the project's .claude.json, keeping it project-level.
ddev poweroff # Stop all DDEV projects
ddev debug router # Debug router configuration
ddev debug capabilities # Check Docker capabilities
ddev delete --omit-snapshot # Remove project without snapshot