К основному содержанию
скилл CX Codex

pre-push-gate — скилл для Claude Code: что делает и как установить

Скилл запускает локальный гейт проверок перед отправкой кода и помогает разобрать ошибки линтеров, тестов, DCO и манифестов.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add modelcontextprotocol/servers --skill pre-push-gate -a claude-code
Открыть на GitHub

Что делает pre-push-gate

Скилл управляет выполнением скрипта npm run local:gate в репозитории modelcontextprotocol/servers. Он инструктирует агента форматировать файлы через npm run format или uv run --frozen ruff format . для серверов на Python, запускать проверки и оценивать результат строго по коду возврата, а не по тексту в консоли.

Внутри заложены инструкции по диагностике упавших этапов. Скилл подсказывает, как устранить рассинхронизацию node_modules через npm install, восстановить подписи коммитов в verify:dco, закрепить версии GitHub Actions через SHA или исправить манифесты навыков в verify:skills. При падении любого шага гейт сразу останавливается, поэтому после исправления агент перезапускает цепочку целиком.

Проверка verify:skills:cli требует доступа к сети, поэтому в офлайне гейт упадёт из-за вызова npx для загрузки Claude Code CLI.

Какие задачи решает

  • проверить код командой npm run local:gate перед коммитом
  • исправить ошибки подписи коммитов DCO через git rebase
  • обновить устаревшие зависимости при падении verify:install-fresh
  • закрепить SHA для GitHub Actions в защищённых пайплайнах

Примеры запросов агенту

  • Запусти локальный гейт проверок перед пушем и проверь код завершения.
  • Гейт упал на этапе verify:dco, поправь подписи коммитов.
  • Разбери ошибку verify:skills:cli и почини описание навыка.

Как установить pre-push-gate

1Через Skills CLI (Vercel)

npx skills add modelcontextprotocol/servers --skill pre-push-gate -a claude-code

2Вручную: положить файлы

~/.claude/skills/pre-push-gate/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/pre-push-gate/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о pre-push-gate

Как установить pre-push-gate в Claude Code?

Выполните команду npx skills add modelcontextprotocol/servers --skill pre-push-gate -a claude-code. Также файл можно сохранить вручную по пути ~/.claude/skills/pre-push-gate/SKILL.md.

Что делает pre-push-gate?

Запускает локальный набор проверок репозитория перед отправкой изменений в Git и помогает агенту пошагово устранять сбои линтеров, тестов и манифестов.

Почему гейт нельзя проверить без интернета?

Шаг verify:skills:cli скачивает нужную версию Claude Code CLI через npx, если локальная версия отличается, поэтому без доступа к сети проверка завершится ошибкой.

Исходный текст

SKILL.md · Apache-2.0
---
name: pre-push-gate
description: "Run this repo's pre-push gate and fix it when it goes red. Use when npm run local:gate fails or a stage of it does (verify:install-fresh, a root guard, lint, typecheck, ruff, pyright, pytest, verify:skills:cli, the boot smoke); when the gate says it is waiting on the gate lease; or when checking whether a gate run really passed."
disable-model-invocation: false
---

# The pre-push gate

**The rule** (stated in [`AGENTS.md`](../../../AGENTS.md#before-pushing)): run
**`npm run local:gate`** before every push, and push only when it exits 0.
`npm run validate` is the inner-loop check and is **not** a substitute.

What each stage covers, and how the gate relates to CI, is
[`docs/quality-gate.md`](../../../docs/quality-gate.md). The stage list is
written out there and nowhere else, on purpose. This skill is how to run the
gate and what to do when it goes red.

## Run it

```sh
cd <repo root>
npm run format                       # TypeScript. It rewrites files; the gate only checks.
npm run local:gate; echo "EXIT=$?"
```

In a Python server you changed, format with `uv run --frozen ruff format .`
from that server's directory.

**Verify by exit code, not by grepping the output.** A Prettier failure is a
few `[warn]` lines that match no obvious failure pattern, and `validate:py`
prints `PASS` for two servers above the `FAIL` for the third.

⚠️ If you run it as a background task, the harness's "exit code 0"
notification describes the _wrapper_ (the trailing `echo`), not the gate. Read
the `EXIT=` line.

**Background it and wait for the notification.** Do not spend turns tailing
the log; see `AGENTS.md` **Waiting on long-running work**.

The gate stops at the first failing stage, so the last stage header in the
output is the one that failed. Fix it, then **re-run the whole gate**, not just
that stage: the stages after it have not run yet.

## Diagnosing a failing stage

Each heading is a stage or guard name as it appears in the output.

### `verify:install-fresh`

An installed package's version disagrees with `package-lock.json`
(`node_modules` is older than the tree you pulled), or a `package.json`
declares a dependency the lockfile does not record. **Run `npm install` at the
repo root**, commit the lockfile if it changed, and re-run. It is the first stage because a stale install otherwise
passes every static check and fails later as a test reporting the _old_
dependency's behavior. Do not "fix" that test.

### `verify:dco`

A commit in `origin/v2/main..HEAD` has no `Signed-off-by:` trailer, or one
whose name and email match neither its author nor its committer. The output
names each commit and the repair: `git rebase --signoff <merge-base>`, then
`git push --force-with-lease` if it was already pushed. Commit with
`git commit -s` from then on. The rule, and when a rewrite is safe, is
`pr-flow` step 3.

"cannot resolve origin/v2/main" means the ref is missing from this clone:
`git fetch origin v2/main`. On a stacked branch the gate also checks the lower
branch's commits; `npm run verify:dco -- --base <lower branch>` checks only
yours.

### `format:check` / `format:check:root`

Run `npm run format` at the **root**. It covers `scripts/`, the root configs
and every workspace; a single workspace's `format` does not.

### `verify:format-coverage`

A tracked source file is matched by no `format:check` glob, so nothing checks
its formatting. Put it where a glob reaches it, or extend the glob. Do not add
it to `.prettierignore` to make the guard pass.

### `verify:skills` / `verify:skills:cli`

A `.claude/skills` manifest does not parse, declares no
`disable-model-invocation`, a model-invoked skill lacks its eval cases, or the
listing is over budget. The message names the skill. The usual cause is an
unquoted `#` or `:` in a `description`.

`verify:skills:cli` is the authoritative validator. It fetches the pinned
Claude Code CLI with `npx` when the installed one is a different version, so it
**fails offline**. (`validate:py`'s `sync` step is the other stage that can:
`uv sync --locked` downloads when a server's environment is missing or stale.
`coverage:py` opens with the same sync, a no-op once `validate:py` has run.)

### `verify:typecheck-coverage`

A tracked `.ts` file lands in no `tsc` program. Usually a new test or config
file outside the server's `tsconfig.test.json` `include`. Add it there.

### `verify:dep-lockstep`

Two workspaces declare different ranges of a shared toolchain package
(`typescript`, `vitest`, `@vitest/coverage-v8`, `prettier`, `@types/node`).
Bump it in **every** workspace that declares it, then `npm install`.

### `verify:no-test-retries`

A test declares a retry: Vitest's `retry:` option or `--retry` flag, a pytest
rerun plugin, or a `flaky` marker. Remove it and fix why the test fails. A race
is fixed with fake timers or an awaited condition; a port collision with a port
the OS hands out.

The guard matches spellings, not semantics, so an unrelated `retry:` property
in server source trips it too. Rename the property, or restructure so the key
is not written as `retry:` at the start of an expression.

### `verify:action-pins`

A job that holds a credential, one whose artifact such a job downloads, or one
whose outputs such a job reads, uses an action by a tag (`actions/checkout@v6`) or by a SHA with no exact-version
comment. The finding names the workflow, the job and the `uses:` value. Pin it
as `owner/repo@<40-hex sha> # vX.Y.Z`, resolving both from one lookup:

```sh
ACTION=actions/checkout TAG=v6.1.0
echo "uses: $ACTION@$(gh api "repos/$ACTION/commits/$TAG" --jq .sha) # $TAG"
```

If the job should not have become credentialed, that is the real fix: the
guard counts `id-token: write` or `packages: write` (the job's own, or the
workflow's when the job declares none); any secret other than `GITHUB_TOKEN`;
an `upload-artifact` in a job that a credentialed downloader has anywhere in
its `needs` chain; a reusable-workflow call in that position; and any job
whose outputs a credentialed job reads (`needs.<job>.outputs`), which is why
`release.yml`'s `detect-packages` is pinned although it holds no credential
itself. A local `./…` action or workflow in such a job is reported as well. A YAML
alias in such a job is reported too; spell the ref out. The rule is in
`AGENTS.md` **Credentialed workflow jobs**.

### `test:scripts`

A guard's own unit test failed. Two of these are about the gate itself and
mean a change broke one of its invariants
(`scripts/lib/workflow-gate.test.mjs`):

- **"GitHub CI must not run a local-only script"**: a workflow invokes a
  `local:*` script. Call the underlying checks as their own steps instead.
- **"every CI job needs a timeout"**: a job was added without
  `timeout-minutes`.
- **"local:gate must run …"**: a stage was dropped from `local:gate:stages`,
  or `local:gate` is no longer exactly the lease wrapper.

Do not edit the guard to make these pass; the split they enforce is the design.

### `lint`

**There is no warning tier.** Every `lint` script runs `--max-warnings 0`, so
a warning fails exactly as an error does. Fix the finding. If a rule genuinely
must be waived on one line, use its inline disable comment **with a one-line
justification**; never widen an ignore list or turn the rule off.

### `typecheck` / `build`

`typecheck` runs `tsc -p tsconfig.test.json` (source and tests); `build` runs
the server's own `tsc`. An error in a test file only shows in `typecheck`.

### `test` (a TypeScript workspace)

Re-run just that suite to iterate: `npm test -w src/<server>`. Read the failure
before changing a timeout: an assertion that races is a bug in the test.

### `coverage`

A TypeScript file is below 90% on lines, statements, functions or branches.
Vitest names each file and dimension:

```
ERROR: Coverage for branches (71.42%) does not meet global threshold (90%) for roots-utils.ts
```

("global threshold" is Vitest's wording; with `perFile: true` it is checked
per file.) The root `npm run coverage` carries on into the remaining
workspaces after a failure, so **the failing report is not the last thing
printed**: find the `npm ERR!` block, which names the workspace
(`in workspace: @modelcontextprotocol/server-<name>`), and read the `ERROR:`
lines just above it.

1. Re-run that server alone: `npm run coverage -w src/<server>`.
2. Read its per-file table. The `Uncovered Line #s` column is where the
   missing tests go (a long list is truncated to `...`, and a long file name
   to `...-name.ts`; open `coverage/index.html` in the workspace, or narrow
   the run, for the full list). A branch shortfall with no uncovered lines is
   the untaken side of a condition, `??`, `?.` or default parameter.
3. **Write the tests.** Drive what a client sees through a `Client` over the
   in-memory transport; call a helper directly only for its logic (`testing`
   skill).
4. Only for code that genuinely cannot run, annotate it at the source with
   its reason, `/* v8 ignore next -- <reason> */` (or `start`/`stop` around a
   block). A branch that is merely awkward to reach is not unreachable.

**Never lower a threshold, drop `perFile`, or widen the coverage `exclude`**
to get green; the gate is the rule in `AGENTS.md` **Always test new or
modified code**. A failing _test_ in this stage is an ordinary test failure:
fix it as under `test`, above.

### `validate:py`

The summary at the end names the failing server, and the step that failed is
the last `[validate:py] <server>: <step>` line above it. Re-run one server with
`npm run validate:py -- <server>`.

| Step | Fix |
| --- | --- |
| `sync` | `uv.lock` no longer matches `pyproject.toml`. Run `uv lock` in that server and commit the lockfile |
| `ruff check` | Fix the finding; `uv run --frozen ruff check --fix .` handles the mechanical ones |
| `ruff format --check` | `uv run --frozen ruff format .` |
| `pyright` | A type error. Add the missing hint rather than an ignore |
| `pytest` | `uv run --frozen pytest -k <name>` in that server to iterate |
| `build` | A packaging error in `pyproject.toml` |

`uv: command not found` means `uv` is not installed. Never substitute `pip`.

### `coverage:py`

The Python per-file coverage gate: every file each server measures must reach
**90% on lines and 90% on branches**. The summary names the server, the step,
and for a shortfall each file and dimension below 90:

```
  FAIL  time — per-file check (2 below 90%)
          src/time/src/mcp_server_time/server.py: lines 84.2% (75/89) is below 90%
          src/time/src/mcp_server_time/server.py: branches 78.5% (11/14) is below 90%
```

Re-run one server with `npm run coverage:py -- <server>`. The per-file table
above the summary gives both figures for every file, and coverage.py's own
report above that (`term-missing`) lists the uncovered lines and partial
branches (`120->124` is the jump from line 120 to 124 never taken).

| Step | Fix |
| --- | --- |
| `sync` | As for `validate:py`: run `uv lock` in that server and commit the lockfile |
| `pytest --cov` | A test failed, so no verdict was reached; fix it as for `validate:py`'s `pytest`. `unrecognized arguments: --cov` means `pytest-cov` is missing from the server's dev dependencies |
| `per-file check`, "below 90%" | Write tests for the lines and branches the report lists. Drive the server in-process through a `ClientSession` where you can (`/testing`) |
| `per-file check`, "was not written" or "measured no files" | The run produced no usable `coverage.json`: check the server's `[tool.coverage.run]` (`branch = true`, `source` naming its package) |
| `per-file check`, "not measured with branch coverage" or "no covered_branches/num_branches" | `branch = true` is missing from `[tool.coverage.run]`. The check refuses such a report rather than counting every file's zero branches as 100% |

**Never lower the gate**, and never drop a file from `source` to clear it.
Code that genuinely cannot run (a guard the types already rule out, a branch
the SDK's input validation makes unreachable) is marked at the source with
`# pragma: no cover  # <reason>`; every pragma carries its reason
(`AGENTS.md` **Always test new or modified code**). A pragma on a line that is
merely awkward to test is not justified; write the test.

### `smoke`

`smoke — FAIL  <server> over <transport>` followed by the reason and the tail
of the server's stderr. Re-run a subset with
`node scripts/smoke-servers.mjs <server> [<server> …]`.

- **"dist/index.js does not exist — build first"**: you ran the smoke on its
  own before building. `npm run build -w src/<server>`. Inside the gate this
  cannot happen, since `validate` builds first.
- **".venv does not exist — sync first"**: the same for a Python server. The
  smoke never creates an environment; `npm run validate:py -- <server>` does.
- **The server exited before answering**: the stderr tail shows why. This is
  what the smoke is for: the unit tests import the source, so a wrong `bin`
  path, a file missing from `dist/`, or an import that only resolves under the
  test runner passes them and fails here.
- **"tools/list does not include …"**: a tool was renamed or removed. A
  published tool is never renamed (`AGENTS.md` **MCP protocol**); if the change
  is intended, update that server's entry in `SERVERS`.
- **A new server fails `test:scripts`** with "every server directory in the
  repo has a smoke entry": add it to `SERVERS` in `scripts/smoke-servers.mjs`.

### `interface-diff`

The last stage diffs the `everything` server's MCP interface (capabilities,
tools, prompts, resources, resource templates) in this checkout's build
against the same server built from the merge-base with `origin/v2/main`, and
prints the report. **A changed interface does not fail it**: the report is
what the PR's sticky comment will show, so read it, and if a change is not
one you meant, that is the finding. It fails only when the diff cannot run,
with `❌ The interface diff could not run` and the reason:

- **"origin/v2/main is not available"**: `git fetch origin v2/main`.
- **"src/everything/dist/index.js does not exist"**: you ran it on its own
  before building: `npm run build -w src/everything`.
- **An `npm ci` or `npm run build` failure**: the _base_ did not install or
  build. Offline with a cold npm cache is the usual cause; otherwise name a
  base that builds with `npm run interface-diff -- --base <ref>`.
- **"Base server probe failed" / "Target probe failed"**: a server did not
  answer the probe. A target failure is this checkout's server and is the
  real defect; the smoke stage before it usually fails first.

Re-run it on its own with `npm run interface-diff` (about ten seconds). What
it compares against in CI, and why it is a script rather than an action, is
in [`docs/quality-gate.md`](../../../docs/quality-gate.md) and the header of
`scripts/interface-diff.mjs`.

## Waiting on the lease

A gate that starts with

```
gate-lease: pid 12345 in /path/to/other-worktree, running for 40s holds the gate lease; waiting for its turn so the gates do not contend. SERVERS_SKIP_GATE_LEASE=1 runs anyway.
```

is queued behind another worktree's gate. That is normal: it starts once the
holder (and any gate that arrived before it) finishes. The line names the
holder's pid and worktree, so you can tell whether to wait or to stop that
gate.

- A holder that was **killed** stops refreshing its lock and is taken over
  after 30 seconds. Nothing needs cleaning up.
- A waiter that prints `gave up after 45m` names a lock path. Check whether
  the holder it names is alive and hung (stop it), or dead with a lock
  directory that could not be removed (remove that directory).
- Do **not** set `SERVERS_SKIP_GATE_LEASE=1` to get a result sooner. Two
  overlapping gates each take longer than one queued behind the other.
- Do **not** write your own "wait until no gate is running" loop. Two of them
  deadlock on each other, and a `pgrep` for the gate's command line matches the
  loop itself.

The details of the lease are in
[`docs/quality-gate.md`](../../../docs/quality-gate.md#the-gate-lease).

## Not part of the gate

`npm run skills:eval` (real model calls) and `npm run pack:verify` (installs
each package's publish artifact and boots it; needs the network, and belongs to
the release flow) are separate commands. Run the eval suite when you add a
skill or change a description.

© modelcontextprotocol · Apache-2.0 · modelcontextprotocol/servers

Похожие скиллы

Все скиллы по теме «Git и GitHub» →
pre-merge bobmatnyc Скилл-чеклист, который прогоняет типы, линтер и тесты до коммита, до PR и до мержа в main. Пригодится, когда не хочется ловить поломки уже в ревью. CX Codex +1 330установок husky davila7 Прогоняет линтер, сборку, типы и тесты по шагам и правит ошибки, пока репозиторий не станет рабочим. Полезно перед коммитом. 282установок no-mistakes kunchenguid Проверяет изменения через цепочку ревью, тестов, линтинга, документации и CI перед отправкой в настроенную ветку. Подходит для валидации задачи после её выполнения. CX Codex +1 5 600установок ce-commit-push-pr EveryInc Скилл ведёт изменения от коммита до pull request: проверяет состояние ветки, отправляет изменения и собирает описание PR. Нужен для публикации готовой работы. CX Codex +1 3 300установок fingerprint-ci-gate liarjsdev Останавливает сборку в CI при деградации браузерного отпечатка Chromium. Сравнивает текущий прогон с эталонным снимком или проверяет минимальный порог очков. CX Codex +1 102 500установок pre-trade-discipline-gate tradermonty Проверяет чек-лист перед ручным входом в сделку и блокирует входы без плана, с превышением риска или в период отката. CX Codex +1 2 700установок

Из того же набора11

testing Скилл объясняет, как писать и запускать тесты для серверов MCP: где лежит файл, какой раннер и как пройти порог покрытия. Пригодится, когда тест молча пропускается или проходит на устаревшей сборке. CX Codex +1 ★ 91 595звёзд репо security-advisory Ведёт процесс обработки приватных уязвимостей в GitHub Security Advisories: заводит карточки на доске, проверяет авторство кода и готовит исправления в приватном форке. CX Codex +1 ★ 91 595звёзд репо release Проводит один milestone-релиз от релизного issue до публикации GitHub Release: аудит, бампы версий, merge PR и release ledger. CX Codex +1 ★ 91 595звёзд репо project-structure Скилл разбирает устройство репозитория modelcontextprotocol/servers и подсказывает, в какой файл или каталог добавить новый код. CX Codex +1 ★ 91 595звёзд репо pr-flow Проводит задачу от issue до пул-реквеста и закрывает её после мержа: ветка, DCO-подпись, гейт, ревью Copilot. CX Codex +1 ★ 91 595звёзд репо local-dev Скилл для локальной разработки MCP-серверов: ставит зависимости, собирает TypeScript, запускает сервер по stdio, SSE или Streamable HTTP. CX Codex +1 ★ 91 595звёзд репо issue-triage Разбирает входящие issues и внешние PR в GitHub, переносит задачи на доску проекта, выставляет скоринг приоритета и закрывает оффтоп по шаблонам. CX Codex +1 ★ 91 595звёзд репо issue-create Проводит создание issue в репозитории от проверки дублей до карточки на доске с приоритетом. Пригодится, когда работа нашлась по ходу задачи и её нужно завести отдельно. CX Codex +1 ★ 91 595звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой