Plugins
Plugins are shell scripts that register custom commands in dde. They allow you to create project-specific or globally available shortcuts without modifying the dde codebase.
Plugin Directories
Section titled “Plugin Directories”Plugins are loaded from two locations:
| Location | Scope |
|---|---|
~/.dde/plugins/ | Global — available in all projects |
.dde/plugins/ | Project — available only in the current project |
If a project plugin defines the same @command name as a global plugin, the project plugin takes precedence.
Plugin Format
Section titled “Plugin Format”A plugin is a *.sh file with two required annotations in comments:
# @command <command-name># @description <human-readable description>Everything after the annotations is the script body, executed when the command is invoked.
Minimal Example
Section titled “Minimal Example”#!/usr/bin/env bash# @command hello# @description Say hello from the containerdde project:exec -s web echo "Hello from the web container"This registers as dde project:exec:hello.
With Arguments
Section titled “With Arguments”Arguments passed to the plugin command are forwarded as positional parameters ($1, $2, etc.):
#!/usr/bin/env bash# @command web:hash-pw# @description Generate a password hashdde project:exec -s web -- php bin/console security:hash-password "$1"Invoke with:
dde project:exec:web:hash-pw "my-secret-password"Namespace Convention
Section titled “Namespace Convention”Use colons in the @command name to create logical groupings:
# @command cache:clear# @description Clear all application cachesThis registers as dde project:exec:cache:clear.
Command Registration
Section titled “Command Registration”Plugins are registered under the project:exec: namespace. The full command name is project:exec:<@command-value>.
@command value | Registered as |
|---|---|
hello | dde project:exec:hello |
web:hash-pw | dde project:exec:web:hash-pw |
cache:clear | dde project:exec:cache:clear |
All plugin commands appear in dde list output with their @description text.
Execution
Section titled “Execution”Plugins run on the host machine via PluginProxyCommand. The plugin script is executed directly as a process with:
- A 300-second timeout
- TTY support when the terminal supports it (interactive commands work)
- Arguments appended to the script invocation
- Exit code forwarded to the caller
File Discovery
Section titled “File Discovery”- Only
*.shfiles are considered. - Files are sorted alphabetically by name within each directory.
- Files without a
@commandannotation are silently ignored. - The
@descriptionannotation is optional (defaults to an empty string).
Examples
Section titled “Examples”Run tests
Section titled “Run tests”#!/usr/bin/env bash# @command test# @description Run the test suitedde project:exec -s web php bin/phpunitDatabase reset
Section titled “Database reset”#!/usr/bin/env bash# @command db:reset# @description Drop and recreate database with fixturesset -euo pipefaildde project:exec -s web -- php bin/console doctrine:database:drop --force --if-existsdde project:exec -s web -- php bin/console doctrine:database:createdde project:exec -s web -- php bin/console doctrine:migrations:migrate --no-interactiondde project:exec -s web -- php bin/console doctrine:fixtures:load --no-interactionLint all files
Section titled “Lint all files”#!/usr/bin/env bash# @command lint# @description Run all lintersset -euo pipefaildde project:exec -s web php vendor/bin/ecs checkdde project:exec -s web php vendor/bin/phpstan analyseGlobal utility (in ~/.dde/plugins/)
Section titled “Global utility (in ~/.dde/plugins/)”#!/usr/bin/env bash# @command ports# @description Show all exposed ports for the current projectdocker compose ps --format "table {{.Name}}\t{{.Ports}}"Implementation Details
Section titled “Implementation Details”The plugin system consists of four classes:
PluginLoader— scans directories, parses annotations via regex (/^#\s*@(\w+)\s+(.+)$/m), returnsPluginDefinitioninstances.PluginDefinition— readonly DTO withcommand,description,scriptPath, andpluginDirproperties.PluginProxyCommand— Symfony Console command that wraps aPluginDefinitionand executes the script viaProcessFactory. Validates that the script path resolves within the plugin directory (symlink traversal protection).PluginCommandLoader— implementsCommandLoaderInterfaceto lazily resolve plugin commands for the Symfony Console application.
Related
Section titled “Related”- Hooks — event-driven scripts tied to project lifecycle
- Service Adapters — scripts that run inside containers at startup