This file provides guidance to AI agents when working with the DDEV core codebase.
DDEV is an open-source tool for running local web development environments for PHP and Node.js. It uses Docker containers to provide consistent, isolated development environments with minimal configuration.
For comprehensive developer documentation, see:
- Developer Documentation - Complete developer guide
- Building and Contributing - Local build setup and contribution workflow
make- Build for host OS/arch. Output:.gotmp/bin/<os>_<arch>/ddevmake clean- Remove build artifacts
go test -v ./pkg/[package]- Test specific package (5-30 seconds)make testpkg TESTARGS="-run TestName"- Run subset of package tests matching regex (30-120 seconds)make testcmd TESTARGS="-run TestName"- Run command testsmake quickstart-test- Build then run Bats docs tests indocs/tests
Testing Strategy:
- Use subset testing with regex patterns for faster iteration
- Test specific packages when making targeted changes
- Avoid full test suite unless absolutely necessary
- Set
DDEV_DEBUG=trueto see executed commands - Set
GOTEST_SHORT=trueto limit test matrix
make staticrequired- Run all required static analysis (golangci-lint, markdownlint, mkdocs, pyspelling)
- Never add trailing whitespace - Blank lines must be completely empty (no spaces or tabs)
- Match existing indentation style exactly (spaces vs tabs, indentation depth)
- Preserve the file's existing line ending style
- Run linting tools to catch whitespace issues before committing
make staticrequired- after changing docs
Main Binaries:
cmd/ddev/- Main DDEV CLI applicationcmd/ddev-hostname/- Hostname management utility
Core Packages:
pkg/ddevapp/- Core application logic, project management, Docker container orchestrationpkg/dockerutil/- Docker container utilities and Docker Compose managementpkg/globalconfig/- Global DDEV configuration managementpkg/fileutil/- File system utilitiespkg/netutil/- Network utilitiespkg/util/- General utilities
Container Definitions:
containers/ddev-webserver/- Web server container (Apache/Nginx + PHP)containers/ddev-dbserver/- Database server container (MySQL/MariaDB/PostgreSQL)containers/ddev-ssh-agent/- SSH agent container
The codebase follows standard Go project structure:
cmd/- CLI entrypoints (ddev,ddev-hostname)pkg/- Go packages (core app logic, Docker integration, config, utilities)containers/- Container images and Dockerfiles used by DDEVdocs/- MkDocs documentation source;docs/testsholds Bats testsscripts/- Helper scripts (installers, tooling)testing/- Performance/auxiliary test scriptsvendor/- Vendored Go dependencies
DDEV uses YAML configuration files:
.ddev/config.yaml- Per-project configuration- Global config stored in
~/.ddev/global_config.yaml - Container configs in
containers/*/directories
- Language: Go (modules + vendored deps). Use Go 1.23+
- Uses Go modules (go.mod)
- Requires Go 1.23.0+
- Uses vendored, checked-in dependencies
- CGO is disabled by default
- Formatting:
gofmt(enforced via golangci-lint). No trailing whitespace - Linters: configured in
.golangci.yml(errcheck, govet, revive, staticcheck, whitespace) - Naming: packages lower-case short names; exported identifiers
CamelCase; tests*_test.gowithTestXxx
- Tests are organized by package
- Integration tests in
pkg/ddevapp/test full workflows - Container tests validate Docker functionality
- Documentation tests use bats framework
- Prefer
requireoverassertin tests - Userequire.NoError()instead ofassert.NoError()for critical assertions that should stop test execution on failure
- Heavy use of docker-compose for orchestration
- Custom container images built from
containers/directory - Network management for inter-container communication
- Volume management for persistent data
- Uses golangci-lint with specific rules in
.golangci.yml - Static analysis is required for CI
- Markdown linting for documentation
- Spell checking on documentation
- Always run
make staticrequiredbefore committing changes to ensure code quality standards
- Do not commit secrets. Amplitude API keys are injected at build; never hardcode them
- Docker must be installed and able to access your home directory for tests
- Before committing, run
make staticrequiredto catch style and docs issues
- After editing markdown files: Run
markdownlint --fix $FILE && make markdownlintto auto-fix and validate markdown formatting - After editing Go files: Run
gofmt -w $FILEto format Go code according to standard conventions - Before committing: Run
make staticrequiredwhen user mentions "commit" to ensure all quality checks pass
- Temporary files: Use
~/tmpfor temporary directories and files - Command execution: For bash commands that don't start with a script or executable, wrap with
bash -c "..." - Working directories: Additional common directories include
~/workspace/d11,~/workspace/pantheon-*,~/workspace/ddev.com
Prerequisites:
- Go 1.25+ is required
- Docker must be installed and running
- PATH management is critical - include both
ddevandddev-hostnamein PATH for testing
Common Issues:
- Some tests require network access and may fail in restricted environments
- Use
DDEV_NO_INSTRUMENTATION=trueto disable analytics during testing
Important Notes:
- Vendored dependencies are checked into the repository
- Always use absolute paths when working with repository files
- Focus on surgical, minimal changes that maintain compatibility
- Cross-platform builds for macOS, Linux, Windows (x64 and ARM64)
- Code signing for macOS and Windows binaries
- Chocolatey packaging for Windows
- Container image building and publishing
Use descriptive branch names that include:
- Date in YYYYMMDD format
- Your GitHub username
- Brief description of the work
Format: YYYYMMDD_<username>_<short_description>
Examples:
20250719_rfay_vite_docs20250719_username_fix_networking20250719_contributor_update_tests
Branch Creation Strategy:
The recommended approach for creating branches is:
git fetch upstream && git checkout -b <branch_name> upstream/main --no-trackThis method:
- Fetches latest upstream changes
- Creates branch directly from upstream/main
- Doesn't require syncing local main branch
- Uses --no-track to avoid tracking upstream/main
When creating pull requests for DDEV, follow the PR template structure from .github/PULL_REQUEST_TEMPLATE.md:
Required Sections:
- The Issue: Reference issue number with
#<issue>and brief description - How This PR Solves The Issue: Technical explanation of the solution
- Manual Testing Instructions: Step-by-step guide for testing changes
- Automated Testing Overview: Description of tests or explanation why none needed
- Release/Deployment Notes: Impact assessment and deployment considerations
Commit Message Format:
Follow Conventional Commits: <type>[optional scope][optional !]: <description>[, fixes #<issue>]
Examples:
fix: handle container networking timeout, fixes #1234docs: clarify mkdocs setupfeat: add new container type support
For commits that will become PRs: Include the complete PR template content in commit messages. This ensures GitHub PRs are pre-populated and don't require additional editing.
MANDATORY: Always run make staticrequired before any commit
Critical Requirements Before Committing:
-
Run appropriate tests:
For targeted testing:
go test -v -run TestSpecificTestName ./pkg/...See Testing Documentation for detailed testing guidance.
-
Run static analysis (REQUIRED):
make staticrequired
This command runs golangci-lint, markdownlint, and mkdocs. All must pass before committing.
Complete Pre-Commit Checklist:
- Make your changes
- Run appropriate tests (
make testor targeted tests) - Run
make staticrequired - Fix any issues reported
- Stage changes with
git add - Commit with proper message format
- Push branch and create PR
Complete validation steps after making changes:
-
Build Validation:
make # Wait for completion .gotmp/bin/<platform>/ddev --version # Verify binary works
-
Unit Test Validation:
go test -v ./pkg/[changed-package] # Test your specific changes # Or run subset of tests matching a pattern: make testpkg TESTARGS="-run TestSpecificPattern"
-
CLI Validation:
.gotmp/bin/<platform>/ddev --help # Test CLI functionality .gotmp/bin/<platform>/ddev config --help # Test command help
-
Project Creation Validation:
# Create and configure a test project mkdir ~/tmp/validation-project && cd ~/tmp/validation-project PATH=".gotmp/bin/<platform>:$PATH" ddev config --project-type=php --docroot=web # Verify .ddev/config.yaml was created cat .ddev/config.yaml
For optimal performance with DDEV development, consider these configuration patterns:
File Exclusions (in .claude/settings.json):
{
"permissions": {
"deny": [
"Read(./vendor/**)",
"Read(./certfiles/**)",
"Read(./testing/**/artifacts/**)",
"Read(./.git/**)",
"Read(**/*.png)",
"Read(**/*.jpg)",
"Read(**/*.zip)",
"Read(**/*.tgz)"
]
}
}Common DDEV Command Allowlist:
Bash(make:*)Bash(go test:*)Bash(ddev:*)Bash(gofmt:*)mcp__task-master-ai__*
MCP Server Configuration (in .mcp.json):
- Enable
task-master-aifor project management - Enable
ddevfor local development operations - Enable
githubfor GitHub integration and workflow automation
Recommended GitHub MCP Setup:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "your_token_here"
}
}
}
}The web-based Claude Code environment has specific limitations compared to desktop environments:
Environment Limitations:
- Docker NOT Available: Docker is not installed and cannot be used in the web environment
- Integration Tests: Most DDEV integration tests require Docker and will fail in this environment
- Container Operations: No ability to build, run, or test Docker containers
SessionStart Hook Solution:
A .claude/hooks/session-start.sh hook automatically configures the environment for optimal development. The hook adapts to both desktop (with Docker) and web (without Docker) environments:
What the hook does:
- Installs
markdownlint-clivia npm (required formake staticrequired) - Detects Docker availability and adapts environment accordingly
- Sets
GOTEST_SHORT=trueONLY when Docker is not available (web environment) - Sets
DDEV_NO_INSTRUMENTATION=truein all environments - Displays environment status and context-appropriate guidance
- Uses
CLAUDE_ENV_FILEto persist environment variables across tool calls
Testing Strategy for Web Environment:
- ✅ Unit tests:
go test -short ./pkg/...(works without Docker) - ✅ Targeted tests:
make testpkg TESTARGS="-run TestName" - ✅ Linting:
make staticrequired(fully supported) - ✅ Building:
makeand all build targets work normally - ❌ Integration tests: Skip tests that require Docker
- ❌ Container tests: Cannot run in web environment
Recommended Workflow:
- Make code changes
- Run unit tests:
go test -short ./pkg/[package] - Run linting:
make staticrequired - Build and verify:
make && .gotmp/bin/linux_amd64/ddev --version - Commit and push changes
- Let CI/CD run full integration tests with Docker
Tool Availability:
- ✅
golangci-lint- Pre-installed in both environments - ✅
markdownlint- Installed by SessionStart hook ⚠️ mkdocs- Not available in web (gracefully skipped by Makefile)- ❌
docker- Not available in web environment - ✅
docker- Available in desktop environment
Environment Detection:
The SessionStart hook automatically detects Docker availability:
- Web Environment (no Docker): Sets
GOTEST_SHORT=true, shows Docker-free testing guidance - Desktop Environment (with Docker): Skips
GOTEST_SHORT, shows full testing capabilities
This ensures the hook works correctly in both environments without requiring manual configuration.
For standard DDEV organization patterns including communication style, branch naming, PR creation, and common development practices, see the organization-wide AGENTS.md.
Import Task Master's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file. @./.taskmaster/CLAUDE.md