Pipeline YAML is boilerplate-heavy, syntax-fussy, and perfectly suited to AI drafting — as long as you treat the draft as untrusted until it survives a dry run.
Tier: Foundation · Workflow area: CI/CD & release engineering
This playbook turns a plain-English description of your build into a working GitHub Actions or GitLab CI pipeline, with a validation loop that catches the hallucinated action versions and invented syntax that assistants routinely produce.
Skip AI for one-line changes to a working pipeline — editing directly is faster than reviewing a regenerated file.
actionlint for GitHub Actions, glab ci lint or the CI Lint API for GitLab.Write the spec before you prompt. List stages, triggers, secrets, and constraints as bullets. A vague prompt yields a generic pipeline you will rewrite anyway.
Prompt with your real constraints.
Write a GitHub Actions workflow for a Go 1.22 monorepo service in ./services/payments.
Requirements:
- Trigger: PRs touching services/payments/** and pushes to main.
- Jobs: lint (golangci-lint), test with race detector and coverage,
build a distroless image, push to ECR only on main.
- Cache Go modules and build cache between runs.
- Auth to AWS via OIDC (role arn passed as a repo variable) — no long-lived keys.
- Pin all third-party actions to a full commit SHA, not a tag.
- Add nothing I did not ask for. If a requirement is ambiguous, ask first.
Lint before you run. Hallucinated action inputs and bad needs: graphs surface here for free:
actionlint .github/workflows/payments.yml
Verify every third-party action exists at the pinned SHA. This is the top hallucination site — assistants invent plausible action names and versions. Open each uses: line on the marketplace or git ls-remote the repo.
Dry-run on a branch. Push to a test branch, let the pipeline execute against a no-op change, and read the logs for silent misbehavior: caches that never hit, jobs that skip when they should run, secrets referenced but empty.
Iterate in the same conversation. Paste failing run logs back to the assistant with "fix only the failing job, change nothing else" — scoped instructions prevent regenerate-the-world churn.
The assistant writes the YAML; the linter, the SHA check, and the branch run decide whether it ships. Never merge a pipeline whose first-ever execution happens on main.
Run the pipeline-flavored version of the standard gate chain before merge:
actionlint (or glab ci lint) passes with zero warnings.uses: pinned to SHAs; no pull_request_target with checkout of PR code; secrets scoped to the jobs that need them; OIDC instead of static keys.actions/setup-go@v6 may not exist. Verify every external reference by hand — the linter cannot know the marketplace.on: push for everything; you get a full build on every doc edit. Path filters are your job to demand.run: echo lines while "debugging." Grep the draft for secrets. before running it.Services-company delivery teams working in client repos: check the client's AI policy before pointing any assistant at their code. If public tools are prohibited, describe the pipeline abstractly (no client names, repo paths, or internal hostnames) to an approved assistant, or run a local model (Ollama + an 8B–14B coder model) for drafting and keep validation identical — actionlint and branch dry-runs work the same offline. Replace real registry URLs and role ARNs with placeholders in the prompt and substitute them locally.