.claude/skills/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 YaroslavKomarov/ShedulerBot ai-factory.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.
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 existing tools by scanning config files and dependency files:
PHP (scan composer.json -> require-dev):
| Tool | Config File | CI Command |
|------|-------------|------------|
| PHP-CS-Fixer | .php-cs-fixer.php, .php-cs-fixer.dist.php | vendor/bin/php-cs-fixer fix --dry-run --diff |
| PHP_CodeSniffer | phpcs.xml, phpcs.xml.dist | vendor/bin/phpcs |
| Pint | pint.json | vendor/bin/pint --test |
Node.js (scan package.json -> devDependencies):
| Tool | Config File | CI Command |
|------|-------------|------------|
| ESLint | eslint.config.*, .eslintrc.* | npx eslint . |
| Prettier | .prettierrc*, prettier.config.* | npx prettier --check . |
| Biome | biome.json, biome.jsonc | npx biome check . |
Python (scan pyproject.toml -> [tool.*] sections, requirements-dev.txt):
| Tool | Config File | CI Command |
|------|-------------|------------|
| Ruff | ruff.toml, pyproject.toml [tool.ruff] | ruff check . / ruff format --check . |
| Black | pyproject.toml [tool.black] | black --check . |
| isort | pyproject.toml [tool.isort] | isort --check-only . |
| Flake8 | .flake8, setup.cfg [flake8] | flake8 . |
| Pylint | .pylintrc, pyproject.toml [tool.pylint] | pylint src/ |
Go:
| Tool | Config File | CI Command |
|------|-------------|------------|
| golangci-lint | .golangci.yml, .golangci.yaml | golangci-lint run |
Rust (built-in):
| Tool | CI Command |
|------|------------|
| clippy | cargo clippy --all-targets --all-features -- -D warnings |
| rustfmt | cargo fmt --all -- --check |
Java:
| Tool | Config File | CI Command (Maven) | CI Command (Gradle) |
|------|-------------|-------------------|---------------------|
| Checkstyle | checkstyle.xml | mvn checkstyle:check -B | ./gradlew checkstyleMain |
| PMD | pmd-ruleset.xml | mvn pmd:check -B | ./gradlew pmdMain |
| SpotBugs | — | mvn compile spotbugs:check -B | ./gradlew spotbugsMain |
PHP (scan composer.json -> require-dev):
| Tool | Config File | CI Command |
|------|-------------|------------|
| PHPStan | phpstan.neon, phpstan.neon.dist | vendor/bin/phpstan analyse --memory-limit=512M |
| Psalm | psalm.xml, psalm.xml.dist | vendor/bin/psalm --no-cache |
| Rector | rector.php | vendor/bin/rector process --dry-run |
Python:
| Tool | CI Command |
|------|------------|
| mypy | mypy src/ |
| pyright | pyright |
Node.js (TypeScript):
| Tool | CI Command |
|------|------------|
| tsc | npx tsc --noEmit |
Go:
golangci-lint includes static analysis (go vet, staticcheck, etc.)Rust:
cargo clippy covers static analysis| Language | Detect By | Test Command |
|----------|-----------|--------------|
| PHP | phpunit/phpunit in composer.json | vendor/bin/phpunit |
| PHP | pestphp/pest in composer.json | vendor/bin/pest --ci |
| Node.js | jest in package.json | npx jest --ci |
| Node.js | vitest in package.json | npx vitest run |
| Python | pytest in pyproject.toml | pytest -v |
| Go | Built-in | go test -race -v ./... |
| Rust | Built-in | cargo test --all-features |
| Java | Built-in (JUnit) | mvn verify -B / ./gradlew test |
Also detect coverage tools:
| Language | Coverage Flag |
|----------|--------------|
| PHP | --coverage-clover coverage.xml |
| Node.js (Jest) | --coverage |
| Node.js (Vitest) | --coverage |
| Python | --cov=src --cov-report=xml |
| Go | -coverprofile=coverage.out -covermode=atomic |
| Rust | cargo tarpaulin --ignore-tests --out xml |
| Java | mvn jacoco:report / ./gradlew jacocoTestReport |
| Language | Tool | CI Command |
|----------|------|------------|
| PHP | Composer audit | composer audit |
| Node.js | npm audit | npm audit --audit-level=high |
| Python | pip-audit | pip-audit or uv run pip-audit (dependency vulnerabilities) |
| Python | bandit | bandit -r src/ or uv run bandit -r src/ (code security) |
| Go | govulncheck | govulncheck ./... |
| Rust | cargo audit | cargo audit |
| Rust | cargo deny | cargo deny check |
| Java | OWASP | mvn dependency-check:check -B |
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.
security.yml example (when WANT_SECURITY):
name: Security
on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 6 * * 1' # Weekly on Monday
permissions:
contents: read
jobs:
dependency-audit:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Language-specific: composer audit / govulncheck / npm audit / cargo deny
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
tests.yml example:
name: Tests
on:
push:
branches: [main]
pull_request:
concurrency:
group: tests-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Language-specific setup + test command
Output file: .gitlab-ci.yml
Pipeline structure:
stages:
- install
- lint
- test
- build
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
default:
interruptible: true
Job organization:
| Stage | Jobs | Notes |
|-------|------|-------|
| install | install | Install dependencies, cache + artifact for downstream |
| lint | code-style, lint, static-analysis, rector | All needs: [install], run in parallel |
| test | tests | needs: [install] |
| build | build | needs: [tests, lint, ...] |
| security | security | needs: [install], allow_failure: true |
GitLab-specific features:
policy: pull-push on install job, policy: pull on all otherskey: files: with lock file for automatic invalidationvendor//node_modules/ via artifacts from install job (faster than cache for same-pipeline)artifacts.reports.junit for test results, artifacts.reports.codequality for lint outputneeds: keyword for parallel execution within stages.setup anchors for shared before_script and cache configcoverage: regex for test jobsPHP-specific GitLab patterns:
image: php:8.3-cli
variables:
COMPOSER_HOME: $CI_PROJECT_DIR/.composer
.composer-setup:
before_script:
- apt-get update && apt-get install -y git unzip
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
Report formats for GitLab integration:
| Tool | Flag | Report Type |
|------|------|-------------|
| PHPStan | --error-format=gitlab | codequality |
| ESLint | --format json | codequality |
| Ruff | --output-format=gitlab | codequality |
| golangci-lint | --out-format code-climate | codequality |
| PHPUnit | --log-junit report.xml | junit |
| Jest | --reporters=jest-junit | junit |
| pytest | --junitxml=report.xml | junit |
If services_needed is not empty, add service containers to the test job:
GitHub Actions:
tests:
services:
postgres:
image: postgres:17
env:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
GitLab CI:
tests:
services:
- name: postgres:17
alias: db
variables:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
DATABASE_URL: "postgresql://test:test@db:5432/test"
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)?## CI Pipeline Audit
### Jobs
| Check | Status | Detail |
|-------|--------|--------|
| Code style job | ✅ | php-cs-fixer dry-run |
| Static analysis | ❌ | PHPStan installed but no CI job |
| Rector check | ❌ | rector.php exists but no CI job |
| Tests | ✅ | PHPUnit with coverage |
| Security audit | ❌ | No dependency scanning |
### Configuration
| Check | Status | Detail |
|-------|--------|--------|
| Caching | ⚠️ | Missing composer cache |
| Concurrency | ❌ | No concurrency group |
| Permissions | ❌ | No explicit permissions |
| Matrix builds | ⚠️ | Only PHP 8.3, missing 8.2 |
### Recommendations
1. CRITICAL: Add PHPStan job — phpstan.neon exists
2. CRITICAL: Add Rector dry-run job — rector.php exists
3. HIGH: Add concurrency group to cancel redundant runs
4. HIGH: Add composer cache for faster installs
5. MEDIUM: Add security audit job (composer audit)
6. LOW: Add PHP 8.2 to test matrix
AskUserQuestion: CI audit found issues. What should we do?
Options:
1. Fix all — Apply all recommendations
2. Fix critical only — Add missing jobs, skip configuration improvements
3. Show details — Explain each issue before deciding
If fixing:
.gitlab-ci.yml in-placeGitHub 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.
## CI Pipeline Generated
### Platform
GitHub Actions
### Files Created
| File | Purpose |
|------|---------|
| .github/workflows/lint.yml | code-style, static-analysis, rector |
| .github/workflows/tests.yml | phpunit (PHP 8.2, 8.3, 8.4) |
| .github/workflows/security.yml | composer audit |
### Features
- Composer caching via shivammathur/setup-php
- Concurrency groups (cancel redundant runs)
- Matrix builds for PHP 8.2, 8.3, 8.4
- Coverage upload as artifact
### Quick Start
# Trigger manually
gh workflow run ci.yml
# View runs
gh run list --workflow=ci.yml
AskUserQuestion: CI pipeline is ready. What's next?
Options:
1. Build automation — Run /ai-factory.build-automation to add CI targets to Makefile/Taskfile
2. Docker setup — Run /ai-factory.dockerize to containerize the project
3. Both
4. Done — Skip follow-ups
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 "/ai-factory.implement" completes, or when user says "verify", "check work", "did we miss anything".
data-ai
Create a step-by-step implementation plan for a feature or task. Breaks down work into actionable tasks tracked via the task system. Use when user says "plan", "create tasks", "break down", or "make a plan for".
tools
# Supabase TypeScript Patterns Patterns for using Supabase with TypeScript in this project. Uses **service role key** (server-side only). Tables are prefixed `sch_`. ## Client Setup ```typescript // src/db/client.ts import { createClient } from "@supabase/supabase-js"; import type { Database } from "./types"; // generated types export const supabase = createClient<Database>( process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!, // server-side only, bypasses RLS { auth:
development
Generate professional Agent Skills for Claude Code and other AI agents. Creates complete skill packages with SKILL.md, references, scripts, and templates. Use when creating new skills, generating custom slash commands, or building reusable AI capabilities. Validates against Agent Skills specification.