# CI Standard

> Use when the user asks to create, edit, or review a GitHub Actions workflow or CI under .github/workflows/.

- Skill: `painhardcore/ci-standard` (Agent Skill, multi-file: 14 files)
- Install (CLI): `npx skillmds@latest add painhardcore/ci-standard`
- Raw SKILL.md: https://api.skillmd.com/api/skills/painhardcore/ci-standard/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: painhardcore (https://skillmd.com/u/painhardcore)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/painhardcore/ci-standard

---


# ci-standard

Lean GitHub Actions that call the project's Make targets. GitHub Actions only in v1, and not a multi-vendor CI catalog.

## Scope

Not here: Make target vocabulary (`makefile-standard`), Dockerfile content (`dockerfile-standard`), Compose topology (`compose-standard`), Go layout and golangci (`go-project-standard`). Circle, GitLab, and Jenkins are out of scope, as is deploying to production from CI unless it is already evidenced.

## Workflow

### 1. Inspect needs

Inventory: existing workflows, `Makefile` targets (`check`, `ci`, `test`, `lint`, `build`), language and tool caches, a Dockerfile (image build only if one exists and is requested), path-sensitive trees, secrets already in use.

Prefer `make check`. Use `make ci` when the Makefile defines a fuller non-interactive target. **Do not invent CI steps that duplicate what Make already does.** That includes reaching for a lint action because it bundles its own install.

If the Makefile has neither `check` nor `ci`, fix the naming through `makefile-standard` first, then wire CI.

### 2. Shape the workflow

Greenfield: start from [`assets/ci.yml.template`](assets/ci.yml.template). Where an image build is evidenced: [`assets/ci-with-image.yml.template`](assets/ci-with-image.yml.template), building **after** `make check`, never instead of it.

Full rules: [`references/ci-standard.md`](references/ci-standard.md).

| Rule | Expectation |
|------|-------------|
| Make entry | The primary validation job runs `make check` or `make ci` |
| Concurrency | A `concurrency` group with cancel-in-progress on PRs |
| Permissions | Least privilege, `contents: read` by default, preferably workflow-level |
| Actions | Pinned to a tag or commit SHA, never `@main` / `@master` / `@latest` |
| Cache | A language or tool cache when installing is non-trivial |
| Paths | `paths` / `paths-ignore` for a monorepo or obvious noise |
| Images | `docker build` only when a Dockerfile and a need are both evidenced |
| Deploy | No production deploy or push from CI unless evidenced and excepted |

### 3. YAGNI

One validation workflow beats a matrix of unused jobs. No separate lint, test, or format job when `make check` covers them. No OIDC or registry login without an evidenced push.

### 4. Validate

```bash
python3 scripts/validate_workflow.py /path/to/.github/workflows/ci.yml
python3 scripts/validate_workflow.py /path/to/.github/workflows
```

Errors = fix. Warnings = human review.

### 5. Report

Workflows touched; the Make target used, or the exception; concurrency, permissions, cache, and path filters; image and deploy steps, or why you skipped them; validation result.

## Hard rules

- CI consumes Make. It does not redefine `makefile-standard` vocabulary.
- Apps must not depend on this repo at CI runtime. Commit the workflow YAML into the app.

## Exceptions

```yaml
# ci-standard: except <rule-id> — <reason>
```

Put it on its own line near what it exempts, at the workflow top or on the step. Every ignored MUST needs an exception line with a reason.

