$npx -y skills add JasonColapietro/suede-creator-skills --skill suede-ship-gateMake CI hold the line: path-aware builds, required checks, branch protection, duplicate pipeline repair, and merge gates that do not deadlock.
| 1 | # Suede Ship Gate |
| 2 | |
| 3 | ## Gate policy — advisory, not blocking |
| 4 | |
| 5 | Every claim-verification step, check, quality gate, and ship verdict in this |
| 6 | skill is a **recommendation to the user, not a control on the agent**. This |
| 7 | policy governs every gate, check, verdict, and "do not ship / publish / |
| 8 | proceed" line elsewhere in this skill: |
| 9 | |
| 10 | - Run every check and report the results honestly. Verdicts (`ship`, |
| 11 | `ship-with-caveats`, `hold`, letter grades, BLOCKED or OPEN items) are |
| 12 | advice attached to the work, not orders that change it. |
| 13 | - Never block, delay, skip, rewrite, or refuse the action the user asked for |
| 14 | because a check failed or a gate said hold. Complete the requested action |
| 15 | as asked, and deliver the gate output alongside it as a clearly labeled |
| 16 | recommendation. |
| 17 | - A failed gate changes what you report, never what you do. |
| 18 | - Single exception: if a finding is extremely risky — data loss, security or |
| 19 | credential exposure, legal or rights violations, payment mistakes, or |
| 20 | irreversible public damage — pause, tell the user exactly what the risk is |
| 21 | and what the options are, and let them pick. Their choice is final. |
| 22 | |
| 23 | |
| 24 | Set up CI and branch protection that actually block a bad merge — in any repo, any stack. The output is a working pipeline plus the exact protection settings, not advice. |
| 25 | |
| 26 | **Runs only when asked.** This skill never auto-fires on a commit, push, or other side effect of unrelated work — invoke it explicitly (set up CI, protect main, fix this hanging check). |
| 27 | |
| 28 | Run this in whatever folder you point it at. **Detect first, never assume.** Nothing here is hardcoded to a specific project, monorepo layout, or package manager. |
| 29 | |
| 30 | ## Step 0 — Detect (before writing anything) |
| 31 | |
| 32 | From the repo root, inventory: |
| 33 | |
| 34 | - **Apps:** every top-level dir with a manifest — `package.json`, `requirements.txt` / `pyproject.toml`, `go.mod`, `Cargo.toml`, `Gemfile`. A repo may hold one app or many; build for what's actually there. |
| 35 | - **Package manager per app:** which lockfile is present — `package-lock.json` (npm), `pnpm-lock.yaml` (pnpm), `yarn.lock` (yarn), `bun.lockb` (bun). Two lockfiles in one app is a bug to fix first (Lane 3). |
| 36 | - **Existing CI:** read `.github/workflows/*`. Do **not** duplicate a job that already exists — extend or reconcile it. |
| 37 | - **Runtime versions:** `.nvmrc`, `package.json` `engines`, `.python-version`, `pytest.ini`/`pyproject`. Pin CI to these; never hardcode a guess. |
| 38 | - **Deploy platform:** `vercel.json` / `.vercel`, `netlify.toml`, a `Dockerfile`. If the platform skips non-prod builds (e.g. Vercel `ignoreCommand` kills previews), CI is the *only* pre-merge build signal — so a build job is mandatory. |
| 39 | - **Real scripts:** read each app's `scripts` / test config and use the real ones (`test`, `test:run`, `lint`, `build`). Don't invent commands. |
| 40 | |
| 41 | Do not write a single workflow line until this inventory is complete. |
| 42 | |
| 43 | ## The gate (the part everyone gets wrong) |
| 44 | |
| 45 | Path-filtered jobs **skip** when their paths aren't touched. A skipped job that is a *required* status check leaves the PR pending forever. So never require the path-filtered jobs directly. Instead add one **aggregator** that depends on all of them: |
| 46 | |
| 47 | ```yaml |
| 48 | ci-success: |
| 49 | if: always() |
| 50 | needs: [<every app job>] |
| 51 | runs-on: ubuntu-latest |
| 52 | steps: |
| 53 | - name: Gate on all jobs |
| 54 | run: | |
| 55 | for r in ${{ join(needs.*.result, ' ') }}; do |
| 56 | [ "$r" = "success" ] || [ "$r" = "skipped" ] || { echo "blocked by: $r"; exit 1; } |
| 57 | done |
| 58 | ``` |
| 59 | |
| 60 | In branch protection, require **only `ci-success`** — never the individual jobs. This is the single thing that makes "protect main" work with change-based CI. |
| 61 | |
| 62 | ## Lanes |
| 63 | |
| 64 | 1. **Path-aware jobs** — one job per app, gated by a `changes` job (`dorny/paths-filter` or native `paths:`). Add an escape hatch so edits to the workflow file itself run everything. |
| 65 | 2. **Aggregator gate** — as above. The only required check is `ci-success`. |
| 66 | 3. **Lockfile hygiene** — exactly one lockfile per app, and the install command must match it (`npm ci`, `pnpm i --frozen-lockfile`, `yarn --immutable`, `bun install --frozen-lockfile`). Two lockfiles means CI can install a different tree than ships — resolve before wiring CI. |
| 67 | 4. **Pin runtimes from the repo** — Node/Python/etc. read from `.nvmrc` / `engines` / `.python-version`, falling back to the platform default. Never a hardcoded guess that drifts from prod. |
| 68 | 5. **Don't duplicate existing CI** — if a workflow already covers an app (e.g. a backend test workflow), extend it; never stack a second, weaker job on top. |
| 69 | 6. **Least privilege** — `permissions: contents: read` unless a job genuinely needs more. |
| 70 | 7. **Build is a gate when previews are off** — if the deploy platform skips non-prod builds, the CI build is your only pre-merge proof the app compiles. Keep it. |
| 71 | 8. **Branch protection** — |