build-ci
This skill should be used when the user asks to "set up CI", "set up GitLab CI", "set up GitHub Actions CI", "write our .gitlab-ci.yml", "only run pipelines…
Skill by pmvanev
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/pmvanev-build-ci
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: devops, data, writing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Python package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/build-ci
What's inside
- Skill name
build-ci- Description
- This skill should be used when the user asks to "set up CI", "set up GitLab CI", "set up GitHub Actions CI", "write our .gitlab-ci.yml", "only run pipelines for MRs", "make the pipeline match our CI policy", "tell the team when main breaks", "notify us when the main pipeline fails", "tell the author when their pipeline fails", "comment on the MR when CI fails", "add a deploy job", "deploy to staging and production", "promote to production", "roll back a deploy", "speed up the pipeline", "why is CI slow", "find what CI builds twice", or runs /phil:build-ci. It declares the CI policy, builds the pipeline to it, lints it, wires a red-main alert, names whoever started a failed pipeline, deploys, by digest, the one image built after its gates pass, and asks before changing a forge setting; --speed ranks speed-ups on the measured critical path, and --rework finds artifacts built twice.
- License
- MIT
- Instructions
- 317 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Agent Skills spec issues
- files: referenced but missing: scripts/ci/run.sh
Files (109)
- SKILL.md
- run.sh · examples/
- alerts.md · references/
- rework-pass.md · references/
- speed-pass.md · references/
- pipeline-timings.py · scripts/
- expected-matrix.md · self-test/01-empty-project/
- expected.md · self-test/01-empty-project/
- manifest.json · self-test/01-empty-project/
- AGENTS.md · self-test/01-empty-project/project/
- README.md · self-test/01-empty-project/project/
- usage.md · self-test/01-empty-project/project/docs/
- eslint.config.js · self-test/01-empty-project/project/
- package-lock.json · self-test/01-empty-project/project/
- package.json · self-test/01-empty-project/project/
- cli.ts · self-test/01-empty-project/project/src/
- tally.ts · self-test/01-empty-project/project/src/
- stryker.config.json · self-test/01-empty-project/project/
- ledger.ts · self-test/01-empty-project/project/test/support/
- setup.ts · self-test/01-empty-project/project/test/support/
- tally.test.ts · self-test/01-empty-project/project/test/
- tsconfig.json · self-test/01-empty-project/project/
- vitest.config.ts · self-test/01-empty-project/project/
- expected-producers.md · self-test/02-rework/
- expected.md · self-test/02-rework/
- manifest.json · self-test/02-rework/
- .gitlab-ci.yml · self-test/02-rework/project/
- Dockerfile · self-test/02-rework/project/
- package-lock.json · self-test/02-rework/project/
- package.json · self-test/02-rework/project/
- run.sh · self-test/02-rework/project/scripts/ci/
- deploy.sh · self-test/02-rework/project/scripts/
- greet.js · self-test/02-rework/project/src/
- expected.md · self-test/03-speed/
- manifest.json · self-test/03-speed/
- .gitlab-ci.yml · self-test/03-speed/project/
- pipeline-000000009010.json · self-test/03-speed/project/history/
- pipeline-000000009020.json · self-test/03-speed/project/history/
- pipeline-000000009030.json · self-test/03-speed/project/history/
- pipeline-000000009040.json · self-test/03-speed/project/history/
- pipeline-000000009050.json · self-test/03-speed/project/history/
- build.log · self-test/03-speed/project/logs/
- lint.log · self-test/03-speed/project/logs/
- package.log · self-test/03-speed/project/logs/
- test.log · self-test/03-speed/project/logs/
- package-lock.json · self-test/03-speed/project/
- package.json · self-test/03-speed/project/
- run.sh · self-test/03-speed/project/scripts/ci/
- ledger.ts · self-test/03-speed/project/src/
- ledger.test.ts · self-test/03-speed/project/test/
- vitest.config.ts · self-test/03-speed/project/
- expected-matrix.md · self-test/04-github-project/
- expected.md · self-test/04-github-project/
- manifest.json · self-test/04-github-project/
- AGENTS.md · self-test/04-github-project/project/
- README.md · self-test/04-github-project/project/
- usage.md · self-test/04-github-project/project/docs/
- eslint.config.js · self-test/04-github-project/project/
- package-lock.json · self-test/04-github-project/project/
- package.json · self-test/04-github-project/project/
- …and 49 more
SKILL.md (first lines)
# Build CI
Build a project's pipeline to a declared policy, then prove it with the trigger matrix. Read
`${CLAUDE_PLUGIN_ROOT}/rules/ci-pipelines.md` whole on every run: its Principles say how to shape the
pipeline, its declared-policy section gives the default block, and its Always-flag rows say what a built
pipeline must never be. Read from `${CLAUDE_PLUGIN_ROOT}/rules/security.md` the **Supply chain and
build** table, the privilege row and the credential-literal row: a built pipeline pins what it runs,
installs from the lockfile, grants the narrowest token and holds no credential.
**This skill writes repository files and reads the forge.** It writes the CI files, `scripts/ci/run.sh`,
the project's instruction file, a hash-pinned lockfile for the tools CI installs where the project has
none, and `.gitignore` entries for what the jobs leave behind; the speed pass also writes the forge's job
lists under the session's scratch directory; and nothing else.
**Write no forge setting without an answer** — the merge gate, branch protection, auto-cancel, a pipeline
schedule. `glab api` and `gh api` can write as well as read: send a `POST`, `PUT` or `PATCH` only after a
yes, and never one that starts a pipeline. `python3` runs the speed pass's timing script and nothing else.
**Never push**, and never start a pipeline: a lint's dry run
creates none, and a push to find out is a guess sent to a runner. **Write no digest or SHA you did not
read** from a registry or the forge. Every ask follows `${CLAUDE_PLUGIN_ROOT}/skills/shared/decision-request.md`;
load it before the first `AskUserQuestion` call.
## Parse the Argument
| Argument | Runs |
|---|---|
| none, or a directory | Steps 1–9: declare the policy and build the pipeline to it |
| `--speed` | the speed pass alone, over the pipeline already there |
| `--rework` | the rework pass alone, over the pipeline already there |
A directory names the project; without one, the repository root.
## Step 1: Survey the Project
Read before proposing anything; the project may already have decided.
- **The forge and its default branch.** GitLab or GitHub, from `git remote get-url origin` and any CI
file present. The default branch from `git symbolic-ref --short refs/remotes/origin/HEAD`; failing
that, the one of `main` and `master` that `git rev-parse --verify -q refs/heads/<name>` finds; failing
both, ask.
- **The pipeline already there.** With a CI file present this run edits; gather the whole pipeline as
`${CLAUDE_PLUGIN_ROOT}/skills/review-ci/SKILL.md` Step 1 does, and keep every job a recorded decision
explains.
- **Recorded decisions.** ADRs, and dated decisions in `CLAUDE.md` or `AGENTS.md` about CI, mutation,
schedules, deploys, releases and runners. A recorded decision outranks the default block.
- **What each job would run.** The project's own commands: the test runner, linter, type checker, build,
mutation tool and deploy, from its task runner (`package.json` scripts, a `Makefile`, a `justfile`, a
repository CLI) and its manifests. Name what is missing; never invent a command. Call each check so its
failure fails the job: a wrapper that reports and exits 0 gates nothing, however useful it is
elsewhere. Where the tools CI installs have no lockfile, write one with hashes — `uv pip compile
--generate-hashes`, `npm install --package-lock-only` — and install from it, `pip` with
`--require-hashes`. A project with no
secret scanner gets gitleaks, in its own job and image: the policy's secret scan needs one.
- **Deploys.** Each environment the project deploys to, in the order a change reaches them; the command
that deploys and whether it takes the artifact it ships; and where each environment's settings come
from. This run writes neither the Dockerfile nor the deploy script, so where the build bakes an
environment's settings in (PIPE-29) or the deploy cannot be handed the artifact by digest (PIPE-30),
write no deploy job around it: report the row it breaks and the change that would clear it.
- **Change classes.** The areas a change can touch — packages, apps, services — and the selector's own
inputs: the lockfile and manifest, the CI configuration, `scripts/ci/`, shared test files, the build,
lint and mutation configuration.
- **Documentation paths.** Where the docs live — and a path the suite or a check reads is never docs,
whatever its folder is called: grep the tests and check scripts for each candidate path. In a
repository whose product is prose — skills, rules, specifications in markdown — ask which markdown is
product before calling any of it docs.
## Step 2: Declare the Policy
- **A `## CI policy` block exists:** use it. Raise a question only where the survey contradicts a field.
- **None exists:** propose the default block `ci-pipelines.md` gives, with its Docs-only paths taken from
the survey and every field a recorded decision changes rewritten to that decision, naming it. Ask once
whether to adopt it as shown or change a field.
- A field the project cannot yet keep — mutation where no mutation tool is installed — is the user's
call: ask, and write what they decide. The policy has no field for releases; where the project tags
releases, ask what a tag pipeline runs.
- **Name in the Andon field where the team hears a red main.** Where the field names no channel, ask for
one in the same request as the policy. The build wires two: on GitLab an email list, through the Pipeline
status emails integration; on GitHub an issue labelled `andon`, which the repository's watchers are
emailed about. Write any other answer — a chat app, a webhook — into the field, and report it as not
wired.
- **On GitLab, wire the Notify field through a token the user creates**, since the job token cannot
write a comment. Ask, in the same request, whether the user will create `NOTIFY_TOKEN` as
`references/alerts.md` describes. The user creates it, so a token's value never passes through this
run; on a yes, report the field as not wired until the user says the variable exists. On a no, leave
the Notify field out of the block, write no `tell-author` job, and keep each job meant only to inform
under `allow_failure`, with a comment that says it gates nothing.
Write the block under `## CI policy` in the project's instruction file, in the rule's shape: its
`CLAUDE.md`, or its `AGENTS.md` where that is the file it keeps; with neither, create `CLAUDE.md`.
## Step 3: Map Each Change to Its Jobs
Write a table for the report: each change class against the jobs it starts and their scope. Choose the
selection the project's tools already offer, in this order:
1. **The build tool's dependency graph** — Nx `affected`, Bazel reverse dependencies, Turborepo filters.
2. **The test runner's own** — Vitest `--changed`, Jest `--changedSince`.
3. **Path lists per area**, with a guard that fails closed: a changed path no list names, outside the
docs allow-list, runs the full suite (PIPE-22).
A change-scoped task scopes where its tool can and runs whole where it cannot; a type check and a build
run whole. A changed selector input widens the tests only (PIPE-20): mutation stays on the MR's changed
source files, and the schedule mutates the whole codebase (PIPE-23). Pass the changed files to the
mutation tool's own filter — StrykerJS `--mutate`, Stryker.NET `--since`, cargo-mutants `--in-diff` —
and exit 0 when no source file changed. Shard the scheduled run with GitLab `parallel:` or a GitHub
matrix, into no more shards than there are source files; a tool with no shard flag, such as StrykerJS,
gets its file list split by shard index in the script, which `./scripts/ci/run.sh shard` prints.
## Step 4: Write the Entry-Point Script
**Every job calls the entry-point script, one task per job; the CI file holds triggers, stages and
wiring.** Write `scripts/ci/run.sh` in POSIX `sh` from `${CLAUDE_PLUGIN_ROOT}/skills/build-ci/examples/run.sh`,
whose decision `tests/test_build_ci.py` pins. Keep its decision and its broad patterns
(`vitest.config.*`, not `vitest.config.ts`); add this project's own paths, drop only another forge's CI
paths, and point each task at the project's own task runner. On GitLab, drop the `andon` and `promote`
tasks, which only GitHub runs. For a project that deploys nothing, drop the `image`, `deploy` and `promote`
tasks; otherwise list in `.gitignore` the `image.env` and `image.ref` the `image` task leaves. Mark it
executable with `chmod +x scripts/ci/run.sh`.
The decision, which `./scripts/ci/run.sh scope` prints as `docs-only`, `scoped` or `full`:From pmvanev/phil-claude-plugin, MIT.
More from pmvanev/phil-claude-plugin
- 0.570score
issue-board
pmvanev
Use when driving a GitLab or GitHub issue tracker or board from the command line with `glab` or `gh` — moving a card between board columns, reordering a…
SkillAFreshness: AClaude Code +9 - 0.570score
board-snapshot
pmvanev
Use when asked where an issue board stands right now rather than what is wrong with it — "summarise my board", "what's on the board", "where does the board…
SkillAFreshness: AClaude Code +9 - 0.570score
board-setup
pmvanev
Use when recording a repo's issue-board constants in its `CLAUDE.md` — the forge and repo, the project and Status field ids, every option id, the enabled…
SkillAFreshness: AClaude Code +9 - 0.570score
nwave-slice-status
pmvanev
Use when the user asks where an nWave feature stands — "how many steps are in this slice", "which ones are done", "which one are we on", "what's next", "is…
SkillAFreshness: AClaude Code +9 - 0.566score
nwave-wave-summary
pmvanev
Use when asked what finished work decided, rather than where it stands or what you were doing — "what did DISCUSS decide", "what did that stage settle"…
SkillAFreshness: AClaude Code +9 - 0.566score
groom-issues
pmvanev
Skill bundle for the phil:groom-issues, phil:groom-fix, phil:groom-set and phil:groom-ask commands — reads a whole issue board in one list call per forge —…
SkillAFreshness: AClaude Code +9 - 0.566score
nwave-issue-board
pmvanev
Use for any GitLab or GitHub board or tracker work in an nWave repo — one holding `.nwave/` or `docs/feature/` — including putting a feature on the tracker as…
SkillAFreshness: AClaude Code +9 - 0.565score
adversarial-review
pmvanev
Skill bundle for phil:adversarial-review command — a general-purpose independent adversarial critic.
SkillAFreshness: AClaude Code +9 - 0.565score
edd
pmvanev
Skill bundle for phil:edd command — Expectation-Driven Development front-door.
SkillAFreshness: AClaude Code +9 - 0.565score
red-team-prose
pmvanev
Skill bundle for phil:red-team-prose command — reviews a doc, README, or release note for AI-generated tells, Elements of Style clarity, and fitness for its…
SkillAFreshness: AClaude Code +9 - 0.561score
ai-eos
pmvanev
Skill bundle for phil:ai-eos command — detects the stylistic tells that mark technical prose as AI-generated, with a density verdict and ranked findings.
SkillAFreshness: AClaude Code +9 - 0.561score
redesign-tests
pmvanev
Skill bundle for phil:redesign-tests command — human-approved, behaviour-changing test redesign loop with a coverage-equivalence claim per rewrite
SkillAFreshness: AClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 10
- Last commit (this folder)
- Oct 23, 2026 (6 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/pmvanev/phil-claude-plugin
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from pmvanev
- 0.570score
nwave-slice-status
pmvanev
Use when the user asks where an nWave feature stands — "how many steps are in this slice", "which ones are done", "which one are we on", "what's next", "is…
SkillAFreshness: AClaude Code +9 - 0.570score
board-snapshot
pmvanev
Use when asked where an issue board stands right now rather than what is wrong with it — "summarise my board", "what's on the board", "where does the board…
SkillAFreshness: AClaude Code +9 - 0.570score
board-setup
pmvanev
Use when recording a repo's issue-board constants in its `CLAUDE.md` — the forge and repo, the project and Status field ids, every option id, the enabled…
SkillAFreshness: AClaude Code +9 - 0.570score
issue-board
pmvanev
Use when driving a GitLab or GitHub issue tracker or board from the command line with `glab` or `gh` — moving a card between board columns, reordering a…
SkillAFreshness: AClaude Code +9 - 0.566score
groom-issues
pmvanev
Skill bundle for the phil:groom-issues, phil:groom-fix, phil:groom-set and phil:groom-ask commands — reads a whole issue board in one list call per forge —…
SkillAFreshness: AClaude Code +9 - 0.566score
nwave-issue-board
pmvanev
Use for any GitLab or GitHub board or tracker work in an nWave repo — one holding `.nwave/` or `docs/feature/` — including putting a feature on the tracker as…
SkillAFreshness: AClaude Code +9
Cite this page
build-ci skill. Agent Mart. https://agentmart.dev/skills/pmvanev-build-ci (last updated 2026-10-24)