A deterministic, policy-driven CI/CD action executor
DDC replaces complex shell scripts, ad-hoc deployers, and CI YAML logic with a single, explicit, deterministic binary designed for real production environments.
- Single Binary: One executable, no dependencies
- CI Agnostic: Works with GitLab CI, GitHub Actions, Jenkins, or any CI system
- Policy-Driven: Explicit control over retries, fallbacks, and failure handling
- Deterministic: Same inputs always produce same outputs
- Production-Ready: Designed for unreliable infrastructure and partial failures
- Auditable: Machine-readable JSON results for every execution
Best-Effort Simplicity
As simple as possible. As complete as necessary. No hidden behavior.
DDC is not a CI system, workflow engine, or orchestrator. It is a deployment control tool that CI systems invoke to perform specific operational actions.
git clone https://github.com/dievilz/ddc.git
cd ddc
go build -o ddc ./cmd/ddc# Download the latest release
curl -L https://github.com/dievilz/ddc/releases/latest/download/ddc-linux-amd64 -o ddc
chmod +x ddc# Configure registry
export REGISTRY_PROD_URL=registry.example.com
export REGISTRY_PROD_USERNAME=myuser
export REGISTRY_PROD_PASSWORD=mypassword
# Configure image
export IMAGE_NAME=myapp
export IMAGE_TAG=v1.0.0
# Execute
ddc run publish-image# Configure SSH target
export SSH_PROD_HOST=server.example.com
export SSH_PROD_USER=deploy
export SSH_PROD_KEY=/path/to/ssh/key
# Configure deployment
export COMPOSE_FILE=docker-compose.yml
export PROJECT_NAME=myapp
export REMOTE_DIR=/opt/myapp
# Execute
ddc run deploy-composeAn Action represents a high-level operational intent:
publish-image— Publish Docker images to registriesdeploy-compose— Deploy Docker Compose stacks via SSH
Actions are explicit, validated, and deterministic.
A Capability is a concrete resource an action can use:
- Docker registries
- SSH hosts
- Docker daemons
- File system paths
Capabilities are discovered from environment variables and explicitly tested for availability.
A Policy defines how an action uses its capabilities:
- Minimum Success: How many successful executions are required
- Fail Fast: Stop after first failure or try all capabilities
- Retries: How many times to retry each capability
- Priority Order: Which capabilities to try first
Policy is data, not control flow.
The Executor orchestrates the entire process:
- Detects available capabilities
- Validates action inputs
- Executes the action according to policy
- Tracks successes and failures
- Produces logs and machine-readable results
Configure one or more registries using environment variables:
# Primary registry
export REGISTRY_PRIMARY_URL=registry.example.com
export REGISTRY_PRIMARY_USERNAME=user
export REGISTRY_PRIMARY_PASSWORD=pass
# Backup registry
export REGISTRY_BACKUP_URL=backup-registry.example.com
export REGISTRY_BACKUP_USERNAME=user
export REGISTRY_BACKUP_PASSWORD=passConfigure SSH targets:
export SSH_PROD_HOST=prod.example.com
export SSH_PROD_USER=deploy
export SSH_PROD_PORT=22
export SSH_PROD_KEY=/path/to/key
export SSH_STAGING_HOST=staging.example.com
export SSH_STAGING_USER=deployControl execution behavior:
# Require at least 2 successful executions
export DDC_MIN_SUCCESS=2
# Stop after first failure
export DDC_FAIL_FAST=true
# Retry failed attempts up to 3 times
export DDC_MAX_RETRIES=3
# Try capabilities in specific order
export DDC_PRIORITY_ORDER=registry-primary,registry-backup
# Custom result file location
export DDC_RESULT_FILE=./build/ddc-result.jsonexport IMAGE_NAME=myapp # Required: Image name
export IMAGE_TAG=v1.0.0 # Required: Image tagexport COMPOSE_FILE=docker-compose.yml # Required: Path to compose file
export PROJECT_NAME=myapp # Optional: Project name (default: app)
export REMOTE_DIR=/opt/myapp # Optional: Remote directory
export ENV_FILE=.env.production # Optional: Environment file to transfer| Code | Meaning |
|---|---|
| 0 | Success — Policy satisfied |
| 1 | Policy not met — Not enough successful executions |
| 2 | Invalid configuration — Missing required inputs |
| 3 | Capability failed — No available capabilities |
| 4 | Action failed — Execution error |
| 5 | Validation failed — Input validation error |
DDC produces human-readable, phase-based logs:
[+0.001s] PHASE: Initializing
[+0.002s] INFO: Action: publish-image
[+0.003s] PHASE: Detecting Capabilities
[+0.010s] INFO: Discovered 2 capabilities
[+0.011s] INFO: ✓ registry-primary [docker-registry] - available
[+0.012s] INFO: ✓ registry-backup [docker-registry] - available
[+0.013s] PHASE: Executing Action: publish-image
[+0.014s] INFO: Validation passed
[+0.015s] INFO: Found 2 available capabilities
[+0.016s] INFO: Attempting capability: registry-primary (type: docker-registry)
[+2.341s] INFO: ✓ Success with registry-primary (duration: 2.325s)
[+2.342s] INFO: Policy satisfied: 1/1 successful executions
[+2.343s] PHASE: Execution Complete: SUCCESS
Every execution produces a machine-readable JSON result:
{
"ActionName": "publish-image",
"StartTime": "2024-01-15T10:30:00Z",
"EndTime": "2024-01-15T10:30:02Z",
"TotalDuration": 2340000000,
"CapabilitiesEvaluated": ["registry-primary"],
"Attempts": [
{
"CapabilityName": "registry-primary",
"Success": true,
"Error": "",
"Attempt": 1,
"Duration": 2325000000,
"Metadata": {
"image_ref": "registry.example.com/myapp:v1.0.0",
"registry": "registry.example.com",
"pushed_at": "2024-01-15T10:30:02Z"
}
}
],
"SuccessCount": 1,
"FailureCount": 0,
"PolicySatisfied": true,
"Decision": "SUCCESS",
"Reason": "Policy satisfied: 1/1 successful executions",
"Artifacts": {
"image_ref": "registry.example.com/myapp:v1.0.0",
"registry": "registry.example.com"
}
}publish:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache docker-cli
- wget -O /usr/local/bin/ddc https://github.com/dievilz/ddc/releases/latest/download/ddc-linux-amd64
- chmod +x /usr/local/bin/ddc
script:
- ddc run publish-image
artifacts:
reports:
dotenv: ddc-result.json- name: Publish Image
env:
REGISTRY_PROD_URL: ${{ secrets.REGISTRY_URL }}
REGISTRY_PROD_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PROD_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
IMAGE_NAME: myapp
IMAGE_TAG: ${{ github.sha }}
run: |
curl -L https://github.com/dievilz/ddc/releases/latest/download/ddc-linux-amd64 -o ddc
chmod +x ddc
./ddc run publish-imagestage('Deploy') {
steps {
sh '''
curl -L https://github.com/dievilz/ddc/releases/latest/download/ddc-linux-amd64 -o ddc
chmod +x ddc
./ddc run deploy-compose
'''
}
}# Configure multiple registries
export REGISTRY_PRIMARY_URL=registry1.example.com
export REGISTRY_PRIMARY_USERNAME=user
export REGISTRY_PRIMARY_PASSWORD=pass
export REGISTRY_SECONDARY_URL=registry2.example.com
export REGISTRY_SECONDARY_USERNAME=user
export REGISTRY_SECONDARY_PASSWORD=pass
# Require at least one success
export DDC_MIN_SUCCESS=1
# Try primary first, fallback to secondary
export DDC_PRIORITY_ORDER=registry-primary,registry-secondary
# Execute
ddc run publish-image# Configure multiple hosts
export SSH_PROD1_HOST=prod1.example.com
export SSH_PROD1_USER=deploy
export SSH_PROD2_HOST=prod2.example.com
export SSH_PROD2_USER=deploy
# Require both to succeed
export DDC_MIN_SUCCESS=2
# Execute
ddc run deploy-composeddc run publish-image --verbose
# or
ddc run publish-image -vddc/
├── cmd/ddc/ # CLI entry point
├── internal/
│ ├── core/ # Core types and executor
│ ├── actions/ # Action implementations
│ ├── capabilities/ # Capability detection
│ └── logger/ # Logging system
├── go.mod
└── README.md
# Build for current platform
go build -o ddc ./cmd/ddc
# Build for multiple platforms
GOOS=linux GOARCH=amd64 go build -o ddc-linux-amd64 ./cmd/ddc
GOOS=darwin GOARCH=amd64 go build -o ddc-darwin-amd64 ./cmd/ddc
GOOS=windows GOARCH=amd64 go build -o ddc-windows-amd64.exe ./cmd/ddcgo test ./...- Explicit over Implicit: Every decision is visible in logs
- Simple over Clever: Readability over abstraction
- Complete over Perfect: Handle real-world failures
- Deterministic: Same inputs → Same outputs
- Auditable: Machine-readable results always
- ❌ A CI/CD system
- ❌ A workflow engine
- ❌ A YAML/JSON DSL interpreter
- ❌ An orchestrator
- ❌ Magic automation
DDC is a tool. CI systems call DDC. DDC performs actions.
- Core executor engine
- publish-image action
- deploy-compose action
- transfer-artifacts action
- validate-env action
- Zig implementation
- Windows support
- Plugin system (maybe)
Contributions are welcome! Please ensure:
- Code is explicit and readable
- No hidden behavior
- Comprehensive error handling
- Tests for new features
- Documentation updates
MIT License - See LICENSE file for details
Dievilz
For questions, issues, or contributions, visit: https://github.com/dievilz/ddc