Gate 1 of the development cycle. Creates/updates Docker configuration, docker-compose setup, and environment variables for local development and deployment readiness.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
name: dev-devops description: | Gate 1 of the development cycle. Creates/updates Docker configuration, docker-compose setup, and environment variables for local development and deployment readiness.
trigger: |
skip_when: |
sequence: after: [dev-implementation] before: [dev-sre]
related: complementary: [dev-implementation, dev-testing]
verification: automated: - command: "docker-compose build" description: "Docker images build successfully" success_pattern: "Successfully built|successfully" failure_pattern: "error|failed|Error" - command: "docker-compose up -d && sleep 10 && docker-compose ps" description: "All services start and are healthy" success_pattern: "Up|running|healthy" failure_pattern: "Exit|exited|unhealthy" - command: "docker-compose logs app | head -5 | jq -e '.level'" description: "Structured JSON logging works" success_pattern: "info|debug|warn|error" manual: - "Verify docker-compose ps shows all services as 'Up (healthy)'" - "Verify .env.example documents all required environment variables"
examples:
See CLAUDE.md and dev-team/docs/standards/devops.md for canonical DevOps requirements. This skill orchestrates Gate 1 execution.
This skill configures the development and deployment infrastructure:
See shared-patterns/shared-pressure-resistance.md for universal pressure scenarios.
Gate 1-specific note: If the application can run in a container, it MUST be containerized. docker-compose ensures reproducibility.
See shared-patterns/shared-anti-rationalization.md for universal anti-rationalizations.
Gate 1-specific rationalizations:
| Excuse | Reality |
|---|---|
| "Works fine locally" | Your machine ≠ production. Docker = consistency. |
| "Docker is overkill for this" | Docker is baseline, not overkill. Complexity is hidden, not added. |
| "Just need docker run" | docker-compose is reproducible. docker run is not documented. |
| "Build system will handle Docker" | Build system uses your Dockerfile. No Dockerfile = no reproducible builds. |
| "Works on demo machine" | Demo machine ≠ production. Docker ensures consistency. |
| "Quick demo setup, proper later" | Quick setup becomes permanent. Proper setup now or never. |
See shared-patterns/shared-red-flags.md for universal red flags.
If you catch yourself thinking ANY of those patterns, STOP immediately. Proceed with containerization.
Different deployment targets still require containerization for development parity:
| Deployment Target | Development Requirement | Why |
|---|---|---|
| Traditional VM/Server | Dockerfile + docker-compose | Standard containerization |
| Helm Deployment | Dockerfile + docker-compose + Helm chart | Helm uses container images |
| AWS Lambda/Serverless | Dockerfile OR SAM template | Local testing needs container |
| Vercel/Netlify | Dockerfile for local dev | Platform builds ≠ local builds |
| Static Site (CDN) | Optional (nginx container for parity) | Recommended but not required |
Lambda/Cloud Functions still need local containerization:
# For AWS Lambda - use SAM or serverless framework
# sam local invoke uses Docker under the hood
# docker-compose.yml for serverless local dev
services:
lambda-local:
build: .
command: sam local start-api
ports:
- "3000:3000"
volumes:
- .:/var/task
Serverless does NOT exempt from Gate 1. It changes the containerization approach.
Even when platform handles production containers:
| Platform Handles | You Still Need | Why |
|---|---|---|
| Production build | Dockerfile for local | Parity between local and prod |
| Scaling | docker-compose | Team onboarding consistency |
| SSL/CDN | .env.example | Environment documentation |
Anti-Rationalization for Serverless/Platform:
| Rationalization | Why It's WRONG | Required Action |
|---|---|---|
| "Lambda doesn't need Docker" | SAM uses Docker locally. Container is hidden, not absent. | Use SAM/serverless containers |
| "Vercel handles everything" | Vercel deploys. Local dev is YOUR problem. | Dockerfile for local dev |
| "Platform builds from source" | Platform build ≠ your local. Parity matters. | Match platform build locally |
| "Static site has no runtime" | Build process has runtime. Containerize the build. | nginx or build container |
Demos do NOT justify skipping containerization:
| Demo Scenario | Correct Response |
|---|---|
| "Demo tomorrow, no time for Docker" | Docker takes 30 min. 30 min now > environment crash during demo. |
| "Demo machine already configured" | Demo machine config will be lost. Docker is documentation. |
| "Just need to show it works" | Showing it works requires it to work. Docker ensures that. |
| "Will containerize after demo" | After demo = never. Containerize now. |
Demo-specific guidance:
.env.demo with demo-safe valuesMANDATORY unless ALL skip_when conditions apply:
INVALID Skip Reasons:
VALID Skip Reasons:
Before starting Gate 1:
From Gate 0: New dependencies, env vars, services needed
Check existing: Dockerfile (EXISTS/MISSING), docker-compose.yml (EXISTS/MISSING), .env.example (EXISTS/MISSING)
Determine actions: Create/Update each file as needed based on gaps
MANDATORY: Task(subagent_type: "devops-engineer", model: "opus")
Prompt includes: Gate 0 handoff summary, existing config files, requirements for Dockerfile/compose/.env/docs
| Component | Requirements |
|---|---|
| Dockerfile | Multi-stage build, non-root USER, specific versions (no :latest), health check, layer caching |
| docker-compose.yml | App service, DB/cache services, volumes, networks, depends_on with health checks |
| .env.example | All vars with placeholders, comments, grouped by service, marked required vs optional |
| docs/LOCAL_SETUP.md | Prerequisites, setup steps, run commands, troubleshooting |
Agent returns: Complete files + verification commands
Pattern: Multi-stage build → builder stage (deps first, then source) → production stage (non-root user, only artifacts)
Required elements: WORKDIR /app, USER appuser (non-root), EXPOSE {port}, HEALTHCHECK (30s interval, 3s timeout)
| Language | Builder | Runtime | Build Command | Notes |
|---|---|---|---|---|
| Go | golang:1.21-alpine | alpine:3.19 | CGO_ENABLED=0 go build | Add ca-certificates, tzdata |
| TypeScript | node:20-alpine | node:20-alpine | npm ci && npm run build | npm ci --only=production in prod |
| Python | python:3.11-slim | python:3.11-slim | venv + pip install | Copy /opt/venv to prod |
Version: 3.8 | Network: app-network (bridge) | Restart: unless-stopped
| Service | Image | Ports | Volumes | Healthcheck | Key Config |
|---|---|---|---|---|---|
| app | Build from Dockerfile | ${APP_PORT:-8080}:8080 | .:/app:ro | - | depends_on with condition: service_healthy |
| db | postgres:15-alpine | ${DB_PORT:-5432}:5432 | postgres-data:/var/lib/postgresql/data | pg_isready -U $DB_USER | POSTGRES_USER/PASSWORD/DB env vars |
| redis | redis:7-alpine | ${REDIS_PORT:-6379}:6379 | redis-data:/data | redis-cli ping | 10s interval, 5s timeout, 5 retries |
Named volumes: postgres-data, redis-data
Format: Grouped by service, comments explaining each, defaults shown with :- syntax
| Group | Variables | Format/Notes |
|---|---|---|
| Application | APP_PORT=8080, APP_ENV=development, LOG_LEVEL=info | Standard app config |
| Database | DATABASE_URL=postgres://user:pass@host:port/db | Or individual: DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME |
| Redis | REDIS_URL=redis://redis:6379 | Connection string |
| Auth | JWT_SECRET=..., JWT_EXPIRATION=1h | Generate secret: openssl rand -hex 32 |
| External | Commented placeholders | # STRIPE_API_KEY=sk_test_... |
Create docs/LOCAL_SETUP.md with these sections:
| Section | Content |
|---|---|
| Prerequisites | Docker ≥24.0, Docker Compose ≥2.20, Make (optional) |
| Quick Start | 1. Clone → 2. cp .env.example .env → 3. docker-compose up -d → 4. Verify docker-compose ps |
| Services | Table: Service, URL, Description (App/DB/Cache) |
| Commands | up -d, down, build, logs -f, exec app [cmd], exec db psql, exec redis redis-cli |
| Troubleshooting | Port in use (lsof -i), DB refused (check ps, logs), Permissions (down -v, up -d) |
Commands: docker-compose build → docker-compose up -d → docker-compose ps → docker-compose logs app | grep -i error
Checklist: Build succeeds ✓ | Services start ✓ | All healthy ✓ | No errors ✓ | DB connects ✓ | Redis connects ✓
Handoff format: DevOps status (COMPLETE/PARTIAL) | Files changed (Dockerfile, compose, .env, docs) | Services configured (App:port, DB:type/port, Cache:type/port) | Env vars added | Verification results (build/startup/connectivity: PASS/FAIL) | Ready for testing: YES/NO
| Pattern | File | Key Config |
|---|---|---|
| Multi-env | docker-compose.override.yml (dev) / .prod.yml | target: development/production, volumes, memory limits |
| Migrations | Separate service in compose | command: ["./migrate", "up"], depends_on: db: condition: service_healthy |
| Hot Reload | Override compose | Go: air -c .air.toml, Node: npm run dev with volume mounts |
Base metrics per shared-patterns/output-execution-report.md.
| Metric | Value |
|---|---|
| Duration | Xm Ys |
| Iterations | N |
| Result | PASS/FAIL/PARTIAL |