Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate and optimize CI/CD pipelines for GitLab CI and CircleCI. Use when a user asks to set up GitLab CI, create a CircleCI pipeline, build a CI pipeline for GitLab, automate deployments with CircleCI, add test automation to GitLab, or configure continuous integration on non-GitHub platforms. For GitHub Actions pipelines, use the github-actions skill instead.
.claude/skills/terminalskills-cicd-pipeline/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 85% | 0% |
| case-10 | ✓→✓ | = Same ✓ | 55% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 178% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 81% | 0% |
| case-08 | ✓→✓ | = Same ✓ | 126% | 0% |
Generate production-ready CI/CD pipeline configurations for automated testing, building, and deploying applications on GitLab CI and CircleCI. This skill creates well-structured workflows with proper caching, matrix testing, environment separation, and deployment strategies. For GitHub Actions pipelines, use the github-actions skill.
When a user asks to create or improve a CI/CD pipeline, follow these steps:
Detect the project type and requirements:
bash# Determine language and framework ls package.json pyproject.toml Gemfile go.mod Cargo.toml pom.xml build.gradle 2>/dev/null # Check for existing CI config ls .gitlab-ci.yml .circleci/config.yml 2>/dev/null # Detect test commands cat package.json | grep -A5 '"scripts"' 2>/dev/null cat Makefile 2>/dev/null | grep -E "^test|^lint|^build"
Identify:
Default to GitLab CI if the repo is on GitLab. Use CircleCI if specified or if the project already has a .circleci/ directory.
GitLab CI — Node.js example:
yaml# .gitlab-ci.yml stages: - lint - test - build - deploy variables: NODE_VERSION: "20" .node-cache: cache: key: ${CI_COMMIT_REF_SLUG} paths: - node_modules/ lint: stage: lint extends: .node-cache image: node:${NODE_VERSION} script: - npm ci - npm run lint test: stage: test extends: .node-cache image: node:${NODE_VERSION} script: - npm ci - npm test -- --coverage coverage: '/All files.*\|.*\s+([\d\.]+)/' artifacts: reports: coverage_report: coverage_format: cobertura path: coverage/cobertura-coverage.xml build: stage: build extends: .node-cache image: node:${NODE_VERSION} script: - npm ci - npm run build artifacts: paths: - dist/ only: - main
GitLab CI — Docker build and deploy:
yamlbuild-image: stage: build image: docker:24 services: - docker:24-dind variables: DOCKER_TLS_CERTDIR: "/certs" script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA only: - main deploy: stage: deploy image: alpine:latest before_script: - apk add --no-cache openssh-client - eval $(ssh-agent -s) - echo "$SSH_PRIVATE_KEY" | ssh-add - script: - ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$DEPLOY_HOST "docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA && docker-compose up -d" when: manual only: - main
CircleCI — Node.js example:
yaml# .circleci/config.yml version: 2.1 orbs: node: circleci/node@5 jobs: lint-and-test: docker: - image: cimg/node:20.11 steps: - checkout - node/install-packages - run: npm run lint - run: npm test -- --coverage - store_test_results: path: test-results - store_artifacts: path: coverage build: docker: - image: cimg/node:20.11 steps: - checkout - node/install-packages - run: npm run build - persist_to_workspace: root: . paths: [dist] deploy: docker: - image: cimg/node:20.11 steps: - attach_workspace: at: . - run: npx vercel deploy --prod --token $VERCEL_TOKEN workflows: build-and-deploy: jobs: - lint-and-test - build: requires: [lint-and-test] - deploy: requires: [build] filters: branches: only: main
User request: "Create a GitLab CI pipeline for my Django app with Docker deployment"
Actions taken:
.gitlab-ci.yml with lint, test (with Postgres service), build, deploy stagesResult:
Created: .gitlab-ci.yml
Stages: lint -> test -> build -> deploy
- lint: ruff + mypy type checking
- test: pytest with PostgreSQL 16 service container
- build: Docker image build, pushed to $CI_REGISTRY_IMAGE
- deploy: SSH deploy to production (manual trigger)
Required variables: DEPLOY_HOST, DEPLOY_USER, SSH_PRIVATE_KEYUser request: "Set up CircleCI for my monorepo with separate test jobs per package"
Actions taken:
.circleci/config.yml with parallel test jobs per packageResult:
Created: .circleci/config.yml
Jobs: test-api, test-web, test-shared, build-web, deploy-web
- Uses path filtering: only tests changed packages
- Shared dependency caching across jobs
- Deploy to Vercel on main branch only
Required env vars: VERCEL_TOKEN
Estimated run time: ~4 minutes (parallel jobs)cache: blocks; CircleCI uses orbs or save_cache/restore_cache.only/rules in GitLab CI or filters in CircleCI to control when jobs run.extends and YAML anchors for DRY configs — use them for shared job configurations.when: manual in GitLab CI or approval jobs in CircleCI for production deploys to prevent accidental releases.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-10 | pass→pass | 9,796 | 5,826 | -41% | 1 | 1 | 0% | 1,891 | 2,937 | +55% | 0 | 0 | — |
case-01 | fail→fail | 11,455 | 3,775 | -67% | 1 | 1 | 0% | 2,438 | 2,050 | -16% | 0 | 0 | — |
case-02 | fail→fail | 6,680 | 6,985 | +5% | 1 | 1 | 0% | 1,343 | 3,292 | +145% | 0 | 0 | — |
case-03 | fail→fail | 10,916 | 11,553 | +6% | 1 | 1 | 0% | 2,129 | 4,117 | +93% | 0 | 0 | — |
case-04 | fail→fail | 10,230 | 23,857 | +133% | 1 | 1 | 0% | 2,062 | 3,739 | +81% | 0 | 0 | — |
case-05 | pass→pass | 4,935 | 3,711 | -25% | 1 | 1 | 0% | 913 | 2,536 | +178% | 0 | 0 | — |
case-06 | pass→pass | 9,234 | 27,120 | +194% | 1 | 1 | 0% | 1,887 | 3,411 | +81% | 0 | 0 | — |
case-07 | fail→pass | 9,857 | 7,345 | -25% | 1 | 1 | 0% | 1,717 | 3,171 | +85% | 0 | 0 | — |
case-08 | pass→pass | 8,080 | 9,655 | +19% | 1 | 1 | 0% | 1,682 | 3,800 | +126% | 0 | 0 | — |
case-09 | pass→pass | 9,235 | 7,642 | -17% | 1 | 1 | 0% | 1,639 | 3,319 | +103% | 0 | 0 | — |
case-11 | pass→pass | 9,613 | 8,444 | -12% | 1 | 1 | 0% | 1,777 | 3,469 | +95% | 0 | 0 | — |
case-12 | pass→pass | 11,411 | 8,942 | -22% | 1 | 1 | 0% | 2,164 | 3,499 | +62% | 0 | 0 | — |
case-13 | pass→pass | 5,226 | 5,168 | -1% | 1 | 1 | 0% | 1,073 | 2,879 | +168% | 0 | 0 | — |
case-14 | pass→pass | 11,567 | 10,688 | -8% | 1 | 1 | 0% | 2,403 | 4,121 | +71% | 0 | 0 | — |
case-15 | pass→pass | 12,418 | 11,828 | -5% | 1 | 1 | 0% | 2,339 | 4,196 | +79% | 0 | 0 | — |
case-16 | pass→pass | 5,623 | 4,454 | -21% | 1 | 1 | 0% | 1,039 | 2,609 | +151% | 0 | 0 | — |
case-17 | pass→pass | 10,963 | 10,332 | -6% | 1 | 1 | 0% | 2,200 | 3,566 | +62% | 0 | 0 | — |
case-18 | pass→pass | 12,628 | 10,574 | -16% | 1 | 1 | 0% | 2,328 | 3,775 | +62% | 0 | 0 | — |
case-19 | pass→pass | 8,109 | 7,123 | -12% | 1 | 1 | 0% | 1,389 | 3,002 | +116% | 0 | 0 | — |
case-20 | pass→pass | 10,416 | 6,547 | -37% | 1 | 1 | 0% | 1,616 | 3,052 | +89% | 0 | 0 | — |
case-21 | pass→pass | 10,510 | 6,940 | -34% | 1 | 1 | 0% | 1,845 | 3,276 | +78% | 0 | 0 | — |
case-22 | pass→pass | 9,742 | 6,417 | -34% | 1 | 1 | 0% | 1,696 | 2,919 | +72% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +5 percentage points is the difference between those two pass rates over the 21 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.