| name | deploy |
| description | [Internal pipeline stage — run by /build; invoke directly only as a power user.] Generate Docker Compose stack, Dockerfiles, environment config, and init.sh bootstrap script. |
| argument-hint | [--up] |
| context | fork |
| agent | planner |
Deploy Skill — Docker Compose Stack and Bootstrap
Usage
/deploy
/deploy --up
/deploy — generate all deployment files without starting services.
/deploy --up — generate files and immediately run bash init.sh to start the stack.
Prerequisites
The following must exist before running this skill:
backend/ and/or frontend/ — source code with known runtimes and entry points.
specs/design/deployment.md — deployment architecture decisions (DB engine, port assignments, service names).
project-manifest.json — for service names, port config, and environment variable inventory.
If any of these are missing, stop and report what is absent.
Steps
Step 1 — Read Project Manifest
Read project-manifest.json. Extract:
- Service names and their roles (backend API, frontend SPA, worker, etc.)
- Port assignments for each service.
- Database engine and version.
- Any declared environment variable names.
Step 2 — Read Deployment Architecture
Read specs/design/deployment.md. Extract:
- Service dependencies and startup order.
- Health check endpoints for each service.
- Volume requirements (DB data, uploads, etc.).
- Any explicit constraints (network mode, resource limits).
Step 3 — Generate docker-compose.yml
Generate docker-compose.yml at the project root from the deployment template.
Requirements:
- Every service that another service depends on must use
depends_on with a condition: service_healthy entry.
- Define named volumes for all persistent data (DB data directory, upload storage).
- No hardcoded passwords — all secrets come from environment variables.
- Each service must have a
healthcheck block with a realistic test, interval, timeout, and retries.
- Use specific image tags (e.g.,
postgres:16-alpine), never latest.
- Observability (G9): when
project-manifest.json#observability.enabled is true, add Prometheus scrape-discovery labels to the backend service so any Prometheus can scrape it — prometheus.io/scrape: "true", prometheus.io/path: "<observability.metrics_path>", prometheus.io/port: "<backend port>". Do not modify application source here; deploy only wires the service so the app's existing /metrics endpoint is discoverable.
Step 4 — Generate Dockerfiles
backend/Dockerfile
- Multi-stage build:
builder stage installs dependencies, runtime stage copies only the built artefact.
- Run as non-root user.
EXPOSE the port declared in the manifest.
HEALTHCHECK instruction matching the health check endpoint.
frontend/Dockerfile (if frontend exists)
- Build stage: install deps, run build.
- Serve stage: NGINX or equivalent static server.
EXPOSE the frontend port.
Step 5 — Generate .env.example
Generate .env.example at the project root.
Every environment variable referenced in docker-compose.yml or either Dockerfile must have an entry. Each entry must include a comment explaining what it is and what format it expects:
# Database connection string
DATABASE_URL=postgresql://user:pass@db:5432/appdb
# JWT signing secret — generate with: openssl rand -hex 32
JWT_SECRET=change-me-in-production
No variable may appear in compose or Dockerfiles without a corresponding .env.example entry.
Step 6 — Generate init.sh
Generate init.sh at the project root from the init template.
The script must:
- Check that Docker and Docker Compose are available.
- Copy
.env.example to .env if .env does not already exist.
- Run
docker compose build.
- Run
docker compose up -d.
- Poll each service health check URL until it responds or a timeout is reached (30s per service).
- Print a summary: which services are up, which URLs are accessible.
Make init.sh executable (chmod +x init.sh).
Step 7 — Phase Evaluation Gate
This gate runs BEFORE the stack is started — it exists to catch invalid compose syntax, port conflicts, and missing health checks before they become runtime failures.
First, validate syntax deterministically:
docker compose config
Fix any errors before spawning the evaluator.
Then spawn the evaluator agent (artifact mode) to validate deploy artifacts.
Agent invocation:
Spawn Agent with subagent_type="evaluator" and prompt:
- Phase: deploy
- Artifacts: docker-compose.yml, all Dockerfile* files, .env.example, init.sh
- Upstream: specs/design/architecture.md (if exists)
- Rubric: Read .claude/templates/phase-eval-rubrics.json, key "deploy"
- Iteration: 1 (increment on retry)
- Previous score: null (or previous iteration's weighted_average)
- Check: Every service in architecture.md has a compose entry. No port conflicts. Health checks defined. YAML syntax valid.
- Write result to specs/reviews/phase-deploy-eval.json
Ratchet loop (max 2 iterations):
- If verdict is PASS — proceed to Step 8.
- If verdict is FAIL — fix config issues based on findings. Re-run evaluator.
- Ratchet rule: weighted_average must be >= previous iteration. Revert on regression.
- After 2 iterations — proceed to Step 8 with findings attached as warnings, but do NOT run
--up on an unresolved FAIL — report the failure instead.
Step 8 — If --up Flag
Only after the gate above has passed (or warnings were explicitly accepted), run:
bash init.sh
Report the output. If any service fails its health check, print the service logs and stop.
Output
| Path | Purpose |
|---|
docker-compose.yml | Full service stack definition |
backend/Dockerfile | Backend container build |
frontend/Dockerfile | Frontend container build (if applicable) |
.env.example | All required environment variables documented |
init.sh | Bootstrap script: build, start, health check |
Gotchas
- Missing
depends_on with health conditions. Services that start before their dependencies are ready cause intermittent failures. Always use condition: service_healthy.
- No bind mount volumes. Named volumes persist across
docker compose down. Bind mounts to host paths break in CI and on other machines.
- Hardcoded passwords. Never put credentials directly in
docker-compose.yml. All secrets go in .env.
- Missing
.env.example entries. New variables added to compose but not documented leave other developers with silent failures.
latest image tags. Tags like postgres:latest break reproducibility. Pin to a specific version.
- Root user in containers. Run application processes as a non-root user to limit blast radius on compromise.