skills/aif-ci/SKILL.md
Generate CI/CD pipeline (GitHub Actions / GitLab CI) with linting, static analysis, tests, security. Use when user says "ci", "setup ci", "github actions", "gitlab ci", "pipeline".
npx skillsauth add lee-to/ai-factory aif-ciInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Analyze a project and generate production-grade CI/CD pipeline configuration for GitHub Actions or GitLab CI. Generates separate jobs for linting, static analysis, tests, and security scanning — adapted to the project's language, framework, and existing tooling.
Three modes based on what exists:
| What exists | Mode | Action |
|-------------|------|--------|
| No CI config | generate | Create pipeline from scratch with interactive setup |
| CI config exists but incomplete | enhance | Audit & improve, add missing jobs |
| Full CI config | audit | Audit against best practices, fix gaps |
Read the project description if available:
Read .ai-factory/DESCRIPTION.md
Store project context for later steps. If absent, Step 2 detects everything.
Read .ai-factory/skill-context/aif-ci/SKILL.md — MANDATORY if the file exists.
This file contains project-specific rules accumulated by /aif-evolve from patches,
codebase conventions, and tech-stack analysis. These rules are tailored to the current project.
How to apply skill-context rules:
Enforcement: After generating any output artifact, verify it against all skill-context rules. If any rule is violated — fix the output before presenting it to the user.
Glob: .github/workflows/*.yml, .github/workflows/*.yaml, .gitlab-ci.yml, .circleci/config.yml, Jenkinsfile, .travis.yml, bitbucket-pipelines.yml
Classify found files:
HAS_GITHUB_ACTIONS: .github/workflows/ contains YAML filesHAS_GITLAB_CI: .gitlab-ci.yml existsHAS_OTHER_CI: CircleCI, Jenkins, Travis, or Bitbucket detectedIf $ARGUMENTS contains --enhance -> set MODE = "enhance" regardless.
Path A: No CI config exists (!HAS_GITHUB_ACTIONS && !HAS_GITLAB_CI && !HAS_OTHER_CI):
MODE = "generate"Path B: CI config exists but is incomplete (e.g., has only tests, no linting):
MODE = "enhance"EXISTING_CONTENTPath C: Full CI setup (has linting + tests + static analysis):
MODE = "audit"EXISTING_CONTENTDetermine CI platform from $ARGUMENTS or ask:
If $ARGUMENTS contains github -> set PLATFORM = "github"
If $ARGUMENTS contains gitlab -> set PLATFORM = "gitlab"
Otherwise:
AskUserQuestion: Which CI/CD platform do you use?
Options:
1. GitHub Actions (Recommended) — .github/workflows/*.yml
2. GitLab CI — .gitlab-ci.yml
Ask about optional features:
AskUserQuestion: Which additional CI features do you need?
Options (multiSelect):
1. Security scanning — Dependency audit, SAST
2. Coverage reporting — Upload test coverage
3. Matrix builds — Test across multiple language versions
4. None — Just linting, static analysis, and tests
Store choices:
PLATFORM: github | gitlabWANT_SECURITY: booleanWANT_COVERAGE: booleanWANT_MATRIX: booleanRead all existing CI files and store as EXISTING_CONTENT:
.github/workflows/*.yml files.gitlab-ci.ymlinclude: directives)Determine PLATFORM from existing files.
Scan the project thoroughly — every decision in the generated pipeline depends on this profile.
| File | Language |
|------|----------|
| composer.json | PHP |
| package.json | Node.js / TypeScript |
| pyproject.toml / setup.py / setup.cfg | Python |
| go.mod | Go |
| Cargo.toml | Rust |
| pom.xml | Java (Maven) |
| build.gradle / build.gradle.kts | Java/Kotlin (Gradle) |
Detect the project's language version to use in CI:
| Language | Version Source | Example |
|----------|---------------|---------|
| PHP | composer.json -> require.php | >=8.2 -> ['8.2', '8.3', '8.4'] |
| Node.js | package.json -> engines.node, .nvmrc, .node-version | >=18 -> [18, 20, 22] |
| Python | pyproject.toml -> requires-python, .python-version | >=3.11 -> ['3.11', '3.12', '3.13'] |
| Go | go.mod -> go directive | go 1.23 -> '1.23' |
| Rust | Cargo.toml -> rust-version, rust-toolchain.toml | 1.82 -> '1.82' |
| Java | pom.xml -> maven.compiler.source, build.gradle -> sourceCompatibility | 17 -> [17, 21] |
For matrix builds: use the minimum version from the project config as the lowest, and include the latest stable version. For non-matrix builds: use the latest version that satisfies the constraint.
| File | Package Manager | Install Command |
|------|-----------------|-----------------|
| composer.lock | Composer | composer install --no-interaction --prefer-dist |
| bun.lockb | Bun | bun install --frozen-lockfile |
| pnpm-lock.yaml | pnpm | pnpm install --frozen-lockfile |
| yarn.lock | Yarn | yarn install --frozen-lockfile |
| package-lock.json | npm | npm ci |
| uv.lock | uv | uv sync --all-extras --dev |
| poetry.lock | Poetry | poetry install |
| Pipfile.lock | Pipenv | pipenv install --dev |
| requirements.txt | pip | pip install -r requirements.txt |
| go.sum | Go modules | go mod download |
| Cargo.lock | Cargo | (built-in) |
Store: PACKAGE_MANAGER, LOCK_FILE, INSTALL_CMD.
Detect project tools by scanning config files and dependencies. For the complete tool-to-command mapping → read references/TOOL-COMMANDS.md
Categories: Linters & Formatters (PHP-CS-Fixer, ESLint, Prettier, Biome, Ruff, golangci-lint, clippy, Checkstyle), Static Analysis (PHPStan, Psalm, Rector, mypy, tsc), Test Frameworks (PHPUnit, Pest, Jest, Vitest, pytest, go test, cargo test) with coverage flags, Security Audit (composer audit, npm audit, pip-audit, govulncheck, cargo audit).
Check if tests require external services (database, Redis, etc.):
Grep in tests/: postgres|mysql|redis|mongo|rabbitmq|elasticsearch
Glob: docker-compose.test.yml, docker-compose.ci.yml
If services are needed, they will be configured in the CI pipeline as service containers.
Does the project have a build step?
| Language | Has Build | Build Command |
|----------|-----------|---------------|
| Node.js (with build script) | Yes | npm run build / pnpm build |
| Go | Yes | go build ./... |
| Rust | Yes | cargo build --release |
| Java | Yes | mvn package -DskipTests -B / ./gradlew assemble |
| PHP | Usually no | — |
| Python | Usually no | — |
Build PROJECT_PROFILE:
language, language_version, language_versions (for matrix)package_manager, lock_file, install_cmdlinters: list of {name, command, config_file}static_analyzers: list of {name, command}test_framework, test_cmd, coverage_cmdsecurity_tools: list of {name, command}has_build_step, build_cmdhas_typescript: boolean (for typecheck job)services_needed: list of services for CIsource_dir: main source directory (src/, app/, lib/)Read skills/ci/references/BEST-PRACTICES.md
Select templates matching the platform and language:
GitHub Actions:
| Language | Template |
|----------|----------|
| PHP | templates/github/php.yml |
| Node.js | templates/github/node.yml |
| Python | templates/github/python.yml |
| Go | templates/github/go.yml |
| Rust | templates/github/rust.yml |
| Java | templates/github/java.yml |
GitLab CI:
| Language | Template |
|----------|----------|
| PHP | templates/gitlab/php.yml |
| Node.js | templates/gitlab/node.yml |
| Python | templates/gitlab/python.yml |
| Go | templates/gitlab/go.yml |
| Rust | templates/gitlab/rust.yml |
| Java | templates/gitlab/java.yml |
Read the selected template:
Read skills/ci/templates/<platform>/<language>.yml
Using the PROJECT_PROFILE, best practices, and template as a base, generate a customized CI pipeline.
One workflow per concern — each file has its own triggers, permissions, concurrency:
| File | Name | Jobs | When to create |
|------|------|------|----------------|
| lint.yml | Lint | code-style, static-analysis, rector | Linters or SA detected |
| tests.yml | Tests | tests (+ service containers) | Always |
| build.yml | Build | build | has_build_step |
| security.yml | Security | dependency-audit, dependency-review | WANT_SECURITY |
Why one file per concern:
security-events: writetests but not security)When to keep single file: Only for very small projects with just lint + tests (2 jobs). As soon as there are 3+ concerns — split.
Every workflow gets the same header pattern:
name: <Name>
on:
push:
branches: [main]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
Per-file job organization:
lint.yml — all code quality checks in parallel:
| Job | Purpose | When to include |
|-----|---------|-----------------|
| code-style | Formatting (CS-Fixer, Prettier, Ruff format, rustfmt) | Formatter detected |
| lint | Linting (ESLint, Ruff check, Clippy, golangci-lint) | Linter detected |
| static-analysis | Type checking / SA (PHPStan, Psalm, mypy, tsc) | SA tools detected |
| rector | Rector dry-run (PHP only) | Rector detected |
All jobs run in parallel (no needs). If only one tool detected (e.g. Go with just golangci-lint) — single job in the file is fine.
tests.yml — test suite:
| Job | Purpose | When to include |
|-----|---------|-----------------|
| tests | Unit/integration tests | Always |
| tests-<service> | Tests requiring service containers | services_needed detected |
Matrix builds (multiple language versions) only in this file.
build.yml — build verification:
| Job | Purpose | Notes |
|-----|---------|-------|
| build | Verify compilation/bundling | Can depend on external workflow via workflow_run or just run independently |
security.yml — security scanning:
| Job | Purpose | Extra triggers |
|-----|---------|---------------|
| dependency-audit | Vulnerability scan | schedule: cron '0 6 * * 1' (weekly) |
| dependency-review | PR dependency diff | Only on pull_request |
Per-job rules:
shivammathur/setup-php@v2 with tools: parameteractions/setup-node@v4 with cache: parameterastral-sh/setup-uv@v5 (if uv) or actions/setup-python@v5 (if pip)actions/setup-go@v5 (auto-caches)dtolnay/rust-toolchain@stable + Swatinem/rust-cache@v2actions/setup-java@v4 with cache: parameterfail-fast: false in matrix buildsWANT_COVERAGEMatrix builds (when WANT_MATRIX):
Only the tests job uses a matrix. Lint/SA jobs run on the latest version only.
tests:
name: Tests (${{ matrix.<language>-version }})
strategy:
fail-fast: false
matrix:
<language>-version: <language_versions from PROJECT_PROFILE>
Combining linter jobs:
If the project has both a formatter AND a linter from the same ecosystem, combine them into one job:
php-cs-fixer check + other lint -> code-style jobeslint + prettier -> lint job. Biome replaces BOTH ESLint and Prettier — if Biome is detected, use only npx biome check . in a single lint jobruff check + ruff format --check -> lint job (Ruff handles both)cargo fmt + cargo clippy -> can be separate (fmt is fast, clippy needs compilation)Do NOT combine lint/SA with tests — they should fail independently with clear feedback.
Use the templates in templates/github/ and templates/gitlab/ as a base for generating workflow files. Follow the header pattern (name, on, concurrency, permissions) and per-file job organization described above.
Output file: .gitlab-ci.yml
For GitLab-specific pipeline structure, cache strategy, report format integration, and language-specific patterns → read references/GITLAB-PATTERNS.md
Pipeline stages: install → lint → test → build → security
If services_needed is not empty, add service containers to the test job.
For GitHub Actions and GitLab CI service container syntax → read references/SERVICE-CONTAINERS.md
Verify generated pipeline before writing:
Correctness:
Best practices:
concurrency group set (GitHub Actions)permissions: contents: read set (GitHub Actions)interruptible: true set (GitLab CI)workflow.rules defined (GitLab CI)needs)fail-fast: false on matrix buildsNo over-engineering:
When MODE = "enhance" or MODE = "audit", analyze EXISTING_CONTENT against the project profile and best practices.
Compare existing pipeline against PROJECT_PROFILE:
Missing jobs:
Configuration issues:
actions-rs instead of dtolnay/rust-toolchain)?fail-fast: false on matrix?policy: pull-push on all GitLab jobs instead of pull on non-install jobs?Missing features:
workflow_dispatch trigger (GitHub Actions)?For audit report format, fix flow options, and display templates → read references/AUDIT-REPORT.md
Present results as tables with ✅/❌/⚠️ per check. Categorize recommendations by severity (CRITICAL, HIGH, MEDIUM, LOW). Ask user to choose: fix all, fix critical only, or show details first.
If fixing: preserve existing structure, job names, and ordering conventions.
GitHub Actions:
Bash: mkdir -p .github/workflows
Write .github/workflows/lint.yml # If linters/SA detected
Write .github/workflows/tests.yml # Always
Write .github/workflows/build.yml # If has_build_step
Write .github/workflows/security.yml # If WANT_SECURITY
Only create files for detected concerns. If only lint + tests — two files. If the project is trivially small (single lint + single test job) — a single ci.yml is acceptable.
GitLab CI:
Write .gitlab-ci.yml
GitLab CI uses a single .gitlab-ci.yml — stages and DAG (needs:) handle separation.
Edit existing files using the Edit tool. Preserve the original structure and only add/modify what's needed.
Display summary using format from references/AUDIT-REPORT.md (Summary Display Template section). Show platform, files created, features, and quick start commands.
Suggest: /aif-build-automation for CI targets in Makefile/Taskfile, /aif-dockerize for containerization.
.github/workflows/* and .gitlab-ci.yml.config.yaml.data-ai
Archive completed plans and roadmap milestones. Moves finished plans to the archive directory and optionally trims closed milestones from ROADMAP.md. Use when user says "archive plans", "clean up plans", "archive completed", or "trim roadmap".
tools
Set up agent context for a project. Analyzes tech stack, installs relevant skills from skills.sh, generates custom skills, and configures MCP servers. Use when starting new project, setting up AI context, or asking "set up project", "configure AI", "what skills do I need".
development
Verify completed implementation against the plan. Checks that all tasks were fully implemented, nothing was forgotten, code compiles, tests pass, and quality standards are met. Use after "/aif-implement" completes, or when user says "verify", "check work", "did we miss anything".
data-ai
Plan implementation for a feature or task. Two modes — fast (single quick plan) or full (richer plan with optional git branch/worktree flow). Use when user says "plan", "new feature", "start feature", "create tasks".