What is SwiftDeploy?
Most DevOps work involves writing config files manually — nginx.conf, docker-compose.yml, environment variables. SwiftDeploy flips this. You describe what you want in one file (manifest.yaml) and the tool generates everything else automatically.
The manifest is the single source of truth. Every generated file derives from it. Change the manifest, regenerate, everything updates consistently.
Part 1: The Design — A Tool That Writes Its Own Files
The core idea is template substitution. I created two template files with placeholder variables:
templates/nginx.conf.tmpl → contains {{NGINX_PORT}}, {{SERVICE_PORT}}
templates/docker-compose.yml.tmpl → contains {{SERVICE_IMAGE}}, {{SERVICE_MODE}}
When you run swiftdeploy init, the CLI reads the manifest and uses sed to replace every placeholder with the real value:
sed -e "s|{{NGINX_PORT}}|8080|g" templates/nginx.conf.tmpl > nginx.conf
This means:
Nothing is hardcoded
Change the manifest, run init, get fresh configs
The grader can delete generated files, run init, and verify everything regenerates correctly
The API is written in Go — a single binary that compiles down to 11.9MB. No runtime dependencies, fast startup, well within the 300MB image size limit.
Part 2: The Guardrails — OPA Policy Engine
Before deploying or promoting, SwiftDeploy asks OPA: "is this allowed?"
OPA (Open Policy Agent) is a separate container that makes yes/no decisions based on rules you write in a language called Rego. The key principle is the CLI never makes the decision itself — it just asks OPA and surfaces the answer.
Why isolate decisions in OPA?
If you hardcode thresholds in the CLI:
if [ $DISK_GB -lt 10 ]; then exit 1; fi
Changing a threshold means editing the CLI code, testing it, redeploying. With OPA, you edit a policy file and restart OPA. The CLI doesn't change.
Infrastructure policy
package infrastructure
default allow := false
allow if {
input.disk_free_gb >= data.thresholds.min_disk_free_gb
input.cpu_load <= data.thresholds.max_cpu_load
}
The thresholds live in a separate JSON file — not hardcoded in the Rego. Change thresholds.json, restart OPA, new limits apply immediately.
Canary safety policy
Before promoting canary to stable, the CLI scrapes /metrics and sends the data to OPA:
package canary
allow if {
input.error_rate <= data.thresholds.max_error_rate
input.p99_latency_ms <= data.thresholds.max_p99_latency_ms
}
If error rate exceeds 1% or P99 latency exceeds 500ms, promotion is blocked with a clear message.
Part 3: The Chaos — What Happens When Things Break
The API has a /chaos endpoint (canary mode only) that simulates degraded behaviour:
# Inject 80% error rate
curl -X POST http://localhost:8080/chaos \
-d '{"mode": "error", "rate": 0.8}'
# Try to promote — gets blocked
./swiftdeploy promote stable
# → Error rate 80.00% exceeds maximum 1.00%
I ran this during testing and it worked exactly as designed. The canary policy caught the degraded state and blocked promotion. Once I recovered chaos and restarted the API to reset metrics, the promotion succeeded.
This is the value of the policy gate — it prevents you from accidentally promoting a broken canary to production.
Part 4: Live Metrics and Audit
The API exposes /metrics in Prometheus format:
http_requests_total{method="GET",path="/",status_code="200"} 42
http_request_duration_seconds_p99 0.0034
app_mode 1
chaos_active 0
swiftdeploy status scrapes this every 3 seconds and shows a live dashboard. Every scrape appends to history.jsonl. swiftdeploy audit then parses this file and generates audit_report.md — a markdown table showing mode changes, error rates, and policy violations over time.
Lessons Learned
- Timing matters with containers — OPA needs to start before the policy check runs. I had to start OPA first, wait 4 seconds, run the check, then bring up the rest of the stack.
- Metrics are cumulative — when testing chaos, errors accumulate in the counter. Restarting the API resets the counter. In production you'd use a sliding window.
- Generated files don't belong in git — they're derived from the manifest. Anyone cloning the repo runs swiftdeploy init to get fresh configs.
- Go was the right choice — the API image is 11.9MB. A Python equivalent would be 200MB+. Single binary, no dependencies, instant startup.
Repository
Full source code: https://github.com/Hacker-Dark/swiftdeploy

Top comments (1)
Really like the “manifest as single source of truth” approach here. Regenerating clean configs instead of maintaining multiple files manually saves a lot of DevOps headaches, and the OPA guardrails make the deploy flow feel much safer in real-world use.