Audits and sets up .github/dependabot.yml: recommends a grouping mode (low-noise, balanced, fine-grained) from the repo's use-case, gates setup on pinned dependency versions, wires CODEOWNERS over the deprecated reviewers key, groups security updates. Use when asked to set up, review, fix, or audit Dependabot / automated dependency updates / dependency grouping.
Analyzes .github/dependabot.yml — creating it if missing, repairing it if it deviates — and works collaboratively: gather evidence first, present findings and a recommended mode with reasons, let the user decide via AskUserQuestion, then write. Never overwrite an existing config without showing what's wrong with it. Pinned versions are the entry ticket: a Dependabot config over floating versions is theater, so the pin gate (Phase 3, delegating to the pin-node-dependencies / pin-github-actions siblings) must resolve before anything is written.
Run this when asked to "set up dependabot", review an existing config, or as the dependency-automation slice of a supply-chain audit (sibling skill release-audit).
The three modes
The core decision is how much review attention dependency PRs deserve. Ready-to-adapt templates ship in reference/ next to this SKILL.md.
Mode
Grouping
Cadence starting point
Right for
Template
low-noise
Everything (patch+minor+major) in one PR per ecosystem; optionally ONE repo-wide PR via multi-ecosystem groups
monthly
Solution templates, examples, internal tooling — minimal review capacity, CI is the gate
mode-low-noise.yml, mode-low-noise-single-pr.yml
balanced(default)
minor+patch grouped per ecosystem; each major = own PR
weekly
Open-source projects, production code, anything with external users — breaking changes get individual review
mode-balanced.yml
fine-grained
balanced + family groups (framework / testing / linting / …) + monorepo consolidation
weekly
Large dependency trees (≈40+ direct deps in one ecosystem), grouped PRs that repeatedly conflict or fail CI, monorepos
mode-fine-grained.yml
"Cadence starting point" is the mode's default before per-ecosystem tuning — see Per-ecosystem cadence in Phase 1 and the confirmation step in Phase 4. Security updates are never affected by schedule.interval (Dependabot opens those the moment a vulnerability is detected regardless of cadence), so the interval only trades off routine-update noise vs. staleness.
Within low-noise, one PR per ecosystem is the default: a single-tech repo is simply one fully-grouped block, and unrelated stacks (npm frontend + gradle backend) stay in separate PRs so a broken gradle major never blocks frontend updates. The repo-wide single PR is the escalation for when even one PR per ecosystem is too many — never for unrelated stacks.
The mode may differ per ecosystem: even in balanced mode, github-actions is commonly fully grouped (majors are mostly mechanical when actions are SHA-pinned and CI gates); keep actions majors separate only when workflows are the release pipeline.
Stack-groups variants — width follows repo type. When Phase 1d finds coupling (dependencies across ecosystems tracking the same underlying software), two widths can bundle it, both orthogonal to the mode. The choice is driven by what the repo is (Phase 1b), not by how many dependencies happen to be coupled:
Wide (mode-stack-groups.yml) — bundle each coupled ecosystem whole into one PR per stack (all gradle + all docker/compose as one backend group; backend & client in lockstep; terraform + infra images). Right for solution templates, examples, internal repos not consumed by other projects: nobody reviews these PRs individually, CI is the gate, and consolidation beats precision.
Narrow (mode-fine-grained-stack-groups.yml) — only the coupled dependency pair joins a multi-ecosystem group; the rest of each ecosystem keeps normal per-ecosystem handling. Right for libraries/OSS consumed elsewhere, or a large dependency tree, where unrelated majors still deserve individual review. Two blocks per coupled ecosystem, same directory: a "regular" block with the ecosystem's normal groups that ignores the coupled dependency, and a "stack" block scoped via patterns to just that dependency, joining the shared multi-ecosystem-group — ignore only suppresses updates within the block that declares it, so the stack block still gets version and security updates for the coupled dependency.
Trade-offs to state for either width when proposing a stack group: the stack shares one CI gate; everything the patterns match rides together, majors included; and a member block that joins a multi-ecosystem group carries only package-ecosystem, directory, patterns, and multi-ecosystem-group — schedule/labels live on the group, and cooldown, commit-message, and groups cannot sit on members. So every ecosystem pulled into a stack loses its per-block cooldown, commit-message prefix, and forced applies-to: security-updates grouping. Keep an ecosystem whose majors (or those knobs) need individual handling out of the stack, in a normal balanced/fine-grained block (mixing is fine).
Phase 1 — Discover
a) Ecosystems. Find every manifest Dependabot can watch, including nested ones (each distinct directory needs its own directory, or one block with a directories glob list):
b) Repo identity — the primary evidence. The mode follows from what the repo is and who it serves — not from how updates were handled so far:
gh repo view --json isTemplate,isFork,isArchived,visibility,stargazerCount,description,licenseInfo
head -50 README.md # what is this, who consumes it?
gh release list --limit 5 2>/dev/null # does it actually publish?
ls .github/workflows/ # is there a CI test job that gates PRs?
jq '(.dependencies//{}|length) + (.devDependencies//{}|length)' package.json 2>/dev/null # dep count per ecosystem
Answer these explicitly before recommending anything:
Purpose — product people depend on, library/package others consume, solution template, example/demo, internal tooling?
Audience — open-source with external users, or closed/internal where the team is the only consumer?
What it ships — how many artifacts does it deploy or publish (npm packages, container images, marketplace extensions)? Every published artifact raises the cost of a silently-broken major.
Safety net — CI tests that actually gate merges; release automation.
Scale & shape — dep count per ecosystem, number of packages/workspaces. (Cross-ecosystem coupling is its own mandatory step — see d below.)
Per-ecosystem cadence. The mode sets a starting point, but schedule.interval is decided per ecosystem, not once for the whole config — different ecosystems in the same repo release at different speeds:
Ecosystem tendency
Typical starting interval
Fast-moving app deps (npm, pip, gradle/maven app libs) in an actively developed repo
weekly — patches land often and cooldown already absorbs the risk of a too-fresh tag
Any ecosystem in a low-activity or maintenance-mode repo, regardless of mode
monthly (or slower) — matches actual review bandwidth
Treat this table as a heuristic to seed the Phase 4 question, not a rule to apply silently — always confirm the actual interval per ecosystem with the user rather than defaulting to the mode's starting point.
c) Update history — calibration only, never the basis. The existing config and past habits may be exactly what needs to change; deriving the target from the status quo would just ratify it. Use history to tune within the recommended mode:
gh pr list --author 'app/dependabot' --state all --limit 100 --json state,createdAt,closedAt,mergedAt,title
Many closed-without-merge / PRs open 30+ days → noise exceeded capacity → slower cadence or higher cooldown inside the chosen mode.
Grouped PRs repeatedly superseded, conflicting, or red → groups too broad → corroborates fine-grained.
d) Cross-ecosystem coupling — mandatory, explicit. Coupling is not a judgement call to leave to prose — run it as an explicit step. After collecting the pinned version of every dependency in every ecosystem (you read these anyway for the Phase 3 pin gate), identify dependencies in different ecosystems that track the same underlying software or release train, and flag each such pair as a coupled candidate — manifests that must bump together. Two signals surface a pair, don't rely on only the first: an identical version string shared across manifests (the strongest and easiest to grep — e.g. one library pinned in two places), anddifferent version strings that nonetheless track one product — a server and the client library that talks to it version their releases independently, so a literal-value match would miss them; recognise the shared software by name, not by number.
Stay general — flag any shared software, not just the familiar shapes. Illustrative pairs only:
a server image in docker/docker-compose and its client SDK or driver in npm/gradle/pip — e.g. the postgres image (tag 16) and the org.postgresql:postgresql driver (42.7.x): different version numbers, same server, must move together
a backend library and the client's pinned copy of the same library — usually an identical version string (backend & client released in lockstep)
a provider/tool and the deployed image tag it manages — e.g. a terraform provider and the infra image it provisions (typically different numbers)
Every coupled pair becomes a candidate carried into Phase 4, where the width of the bundle is chosen by repo type. If nothing across ecosystems tracks the same software, record "no coupling found" and skip the stack-group variants.
Phase 2 — Analyze the existing config (if present)
Check each update block:
Coverage — a block (or directories entry) for every ecosystem/directory from Phase 1; no orphan blocks for manifests that no longer exist.
Mode coherence — which mode does the config resemble, and is it consistent across blocks? A "balanced" repo with one all-types group hides breaking majors inside routine PRs — finding.
target-branch: — a block with target-branchno longer applies to security updates, even when it names the default branch. Flag redundant target-branch: main for removal.
Reviewer wiring — for a repo owned by a small group, prefer one CODEOWNERS* rule over per-block assignees: it covers all PRs (not just Dependabot's) and doesn't rot in N places. Keep assignees only where a dedicated person triages dependency PRs separately from code ownership (larger orgs).
Groups correct:
Group order matters — first match wins; specific families must precede the catch-all.
A group only affects version updates unless it says otherwise: without an applies-to: security-updates group, every CVE opens its own PR.
Noise controls — cooldown present (supply-chain guard: new releases mature before a PR opens); open-pull-requests-limit sized to the expected PR count (default 5 — too low for balanced mode where majors arrive individually).
Clutter — labels that don't exist in the repo or are typo'd (gh label list; e.g. "Technical Dept"), schedule.time without timezone (runs UTC), restated defaults, versioning-strategy that fights an exact-pin policy (widen vs pinned versions).
Right-sizing & dead fields — the config must match the ecosystem's actual dependency shape (dep count, prod-vs-dev split), not a template's worst case. Flag:
update-types on a group that restates the default set — a version-updates group with no update-types already covers all of patch+minor+major, so update-types: ['patch','minor','major'] is a no-op; write update-typesonly when genuinely narrowing (e.g. ['minor','patch'] in balanced mode to hold majors out). (Security-updates groups take no update-types at all.)
A commit-message.prefix that can never fire for that ecosystem's dependency class. prefix-development applies only to updates in the development group and only for the ecosystems that have that concept (bundler, composer, mix, maven, npm, pip, uv); prefix covers everything else. So a prefix/prefix-development split in an ecosystem whose deps are alldevDependencies leaves prefix dead (only prefix-development ever fires) — and all-prod leaves prefix-development dead. Collapse to a single prefix unless the ecosystem actually has both classes.
Group count out of proportion to dep count — a handful of named family groups over an ecosystem with only 2–3 direct deps is over-engineering; one grouped block (+ the security group) is enough. Reserve fine-grained family groups for genuinely large trees (see the mode table).
Phase 3 — Precondition: versions must be pinned
Dependabot PRs only reflect reality when manifests state exact versions — on floating specs the resolved dependency drifts on every install and the whole setup is theater. Treat pinning as a gate, not a finding: do not write a config while versions float.
Check per ecosystem, report with file:line evidence:
npm — no ^/~/>=/*/latest/mutable git refs; lockfile committed → fix via sibling skill pin-node-dependencies
github-actions — every uses: pinned to a full 40-char commit SHA → fix via sibling skill pin-github-actions
docker / docker-compose — exact tag, ideally tag + @sha256: digest, never latest
maven / gradle — no dynamic versions (1.+, [1.0,), latest.release)
pip — == pins or a committed lockfile (uv / poetry / pip-tools)
If anything floats, resolve the gate before Phase 5 via AskUserQuestion: fix pins now (recommended — invoke the sibling skills for npm and actions, patch the other ecosystems directly) or proceed anyway, with the user explicitly accepting that Dependabot PRs for the floating ecosystems won't match what actually runs. Record the choice in the Phase 4 report.
Phase 4 — Report, recommend, decide
Post the findings as a normal message first — table of Phase 2/3 checks plus the mode recommendation. The recommendation derives from the repo's use-case (Phase 1b); update history (Phase 1c) only tunes cadence, cooldown, and group breadth within it. If the recommendation contradicts the current setup, say so and explain the delta — matching the status quo is not a goal:
Use-case
Recommend
Solution template, example/demo, internal tooling with no external consumers
low-noise
Open-source project or product with external users; publishes artifacts — the more it deploys, the stronger the case
balanced
Large dependency tree (≈40+ direct deps in one ecosystem), many packages/workspaces, monorepo with shared deps
fine-grained
Coupling found (Phase 1d) and the repo is a solution template / example / internal tool not consumed by other projects
wide stack groups on top — bundle each coupled ecosystem whole into one PR (mode-stack-groups); CI is the gate, consolidation beats precision
Coupling found (Phase 1d) and the repo is a library/OSS consumed elsewhere, or has a large dependency tree
narrow targeted pairing on top — only the coupled pair joins a multi-ecosystem group, the rest of each ecosystem stays per-ecosystem (mode-fine-grained-stack-groups) so unrelated majors keep individual review
No CI test job
never low-noise — grouped majors would merge blind; recommend balanced and adding CI
Then confirm via AskUserQuestion — recommendation first, marked "(recommended)", every option stating its consequence. Ask only what the evidence can't answer, max 4 questions:
Mode — the three modes with one-line trade-offs. Include the single-PR multi-ecosystem variant only for clear low-noise repos. Whenever Phase 1d found coupling, surface both stack-group widths in the same question and mark the one matching the Phase-1b use-case "(recommended)":
wide — whole coupled ecosystems bundled (mode-stack-groups), recommended for solution-template/example/internal repos not consumed elsewhere (e.g. "all gradle + all docker/compose as one backend PR");
narrow — only the coupled pair joins the group, the rest stays per-ecosystem (mode-fine-grained-stack-groups), recommended for libraries/OSS consumed elsewhere or large dependency trees (e.g. "postgres image + postgres driver as one PR, rest of gradle/docker stays fine-grained").
Name the concrete coupled manifests/pair. State the stack-group trade-off in the option text: bundled member blocks lose their per-block cooldown, commit-message prefix, and forced applies-to: security-updates grouping (schedule/labels live on the group; cooldown/commit-message/groups can't sit on members).
Cadence per ecosystem — always confirm, never silently apply the mode's starting point. Propose an interval per detected ecosystem from the Per-ecosystem cadence heuristic (Phase 1) adjusted by PR history (Phase 1c) and repo activity level, and let the user override any of them.
Review wiring — CODEOWNERS-only (recommended for small teams) vs keep assignees, only if the existing config has assignees/reviewers.
Existing customizations (multiSelect) — which ignore: rules, labels, or schedule quirks to carry over vs drop.
Phase 5 — Create or update
Enter this phase only once the Phase 3 pin gate is resolved — pins fixed (sibling skills run, other ecosystems patched) or floating versions explicitly accepted by the user.
Update > replace. Fix the specific gaps; carry over confirmed customizations (especially ignore: rules) verbatim, including comments.
Strip teaching comments — never emit them. The reference/mode-*.yml files carry long explanatory prose comments for agent context only; they must not appear in the generated .github/dependabot.yml. Copy the config shape, not the rationale. The written file keeps at most brief one-line section labels in the host repo's existing comment style (or none at all). This does not conflict with update > replace above: comments already present in the repo's own config (e.g. a rationale line on an ignore: rule) are still carried over verbatim.
Start from the chosen reference/mode-*.yml, one block per detected ecosystem/directory. Templates show weekly/monthly as illustrative placeholders only — write the interval confirmed per ecosystem in Phase 4, not the template's literal value. For fine-grained: derive family groups from the actual manifests, never ship template families the repo doesn't use, and confirm the families with the user.
Every mode keeps: labels: ['dependencies'], commit-message prefix chore + include: scope, cooldown, and an applies-to: security-updates group per ecosystem.
Right-size to the ecosystem, don't emit dead fields (mirror the Phase 2 Right-sizing & dead fields check when writing, not just when auditing):
Omit update-types unless it genuinely narrows the set — a version-updates group without it already means all of patch+minor+major, so update-types: ['patch','minor','major'] is a no-op that reads as intent. In balanced mode the minor+patch group does carry update-types: ['minor','patch'] (that's the narrowing that keeps majors out); low-noise's all-in-one group carries none.
Emit a single commit-message.prefix unless the ecosystem actually mixes prod and dev deps. Don't add prefix-development for an ecosystem whose deps are all devDependencies (only it would fire, prefix is dead) or all prod (the reverse). prefix-development is meaningful only for bundler/composer/mix/maven/npm/pip/uv and only when both classes are present.
Scale groups to dep count: for a small ecosystem (a handful of direct deps) one grouped block plus the security group is the whole config — don't manufacture family groups the mode table reserves for large trees.
Grouped-PR prefix caveat: for a grouped update the PR title and branch come from the group's IDENTIFIER, not the commit-message prefix; the prefix still lands on the underlying commit, and prefix-development only applies when every member of that group is a dev dependency (a group mixing prod + dev deps falls back to prefix). So a dev-only ecosystem grouped into one PR consistently uses one prefix anyway — another reason not to split it.
If no CODEOWNERS exists, create .github/CODEOWNERS with a default owner (suggest from gh api repos/{owner}/{repo} --jq .owner.login):
# Default owners — requested as reviewers on every PR, including Dependabot's
* @<owner-or-team>
Ensure referenced labels exist: gh label create dependencies --description "Dependency updates" --color 0366d6 for any missing one.
Optional companion — patch/minor auto-merge
Auto-merge is owned by the sibling skill automerge-setup (the single source of truth for the workflow, its native-setting and required-check preconditions, and the scope gate). After the dependabot.yml is written, offer (never impose) to set up patch/minor auto-merge and hand off to automerge-setup — don't write .github/workflows/dependabot-automerge.yml from here. Auto-merge is only safe when a branch ruleset with a required status check gates the default branch (branch-ruleset-setup) and a CI test job runs on PRs (Phase 1b); automerge-setup enforces that precondition. Every major stays manual regardless.
Phase 6 — Verify
YAML parses: python3 -c "import yaml; yaml.safe_load(open('.github/dependabot.yml'))" (fall back to npx --yes yaml or careful review).
CODEOWNERS check after pushing: gh api repos/{owner}/{repo}/codeowners/errors.
Config errors and run logs surface under Insights → Dependency graph → Dependabot — tell the user to check there after the merge, since GitHub validates unknown keys only at run time.
If the user opted into auto-merge (Phase 5), the sibling automerge-setup handles and verifies the workflow; just confirm the hand-off happened.
1---2name: dependabot-setup3description: Audits and sets up .github/dependabot.yml: recommends a grouping mode (low-noise, balanced, fine-grained) from the repo's use-case, gates setup on pinned dependency versions, wires CODEOWNERS over the deprecated reviewers key, groups security updates. Use when asked to set up, review, fix, or audit Dependabot / automated dependency updates / dependency grouping.4---56# Skill: dependabot-setup78Analyzes `.github/dependabot.yml` — creating it if missing, repairing it if it deviates — and works **collaboratively**: gather evidence first, present findings and a recommended mode with reasons, let the user decide via AskUserQuestion, then write. Never overwrite an existing config without showing what's wrong with it. Pinned versions are the entry ticket: a Dependabot config over floating versions is theater, so the pin gate (Phase 3, delegating to the **`pin-node-dependencies`** / **`pin-github-actions`** siblings) must resolve before anything is written.910Run this when asked to "set up dependabot", review an existing config, or as the dependency-automation slice of a supply-chain audit (sibling skill **`release-audit`**).1112## The three modes1314The core decision is **how much review attention dependency PRs deserve**. Ready-to-adapt templates ship in `reference/` next to this SKILL.md.1516| Mode | Grouping | Cadence starting point | Right for | Template |17|---|---|---|---|---|18| **low-noise** | Everything (patch+minor+major) in one PR per ecosystem; optionally ONE repo-wide PR via multi-ecosystem groups | monthly | Solution templates, examples, internal tooling — minimal review capacity, CI is the gate | `mode-low-noise.yml`, `mode-low-noise-single-pr.yml` |19| **balanced** *(default)* | minor+patch grouped per ecosystem; **each major = own PR** | weekly | Open-source projects, production code, anything with external users — breaking changes get individual review | `mode-balanced.yml` |20| **fine-grained** | balanced + family groups (framework / testing / linting / …) + monorepo consolidation | weekly | Large dependency trees (≈40+ direct deps in one ecosystem), grouped PRs that repeatedly conflict or fail CI, monorepos | `mode-fine-grained.yml` |2122"Cadence starting point" is the mode's default before per-ecosystem tuning — see **Per-ecosystem cadence** in Phase 1 and the confirmation step in Phase 4. Security updates are never affected by `schedule.interval` (Dependabot opens those the moment a vulnerability is detected regardless of cadence), so the interval only trades off routine-update noise vs. staleness.2324Within low-noise, **one PR per ecosystem is the default**: a single-tech repo is simply one fully-grouped block, and unrelated stacks (npm frontend + gradle backend) stay in separate PRs so a broken gradle major never blocks frontend updates. The repo-wide single PR is the escalation for when even one PR per ecosystem is too many — never for unrelated stacks.2526The mode may differ per ecosystem: even in balanced mode, `github-actions` is commonly fully grouped (majors are mostly mechanical when actions are SHA-pinned and CI gates); keep actions majors separate only when workflows are the release pipeline.2728**Stack-groups variants — width follows repo type.** When Phase 1d finds coupling (dependencies across ecosystems tracking the same underlying software), two widths can bundle it, both orthogonal to the mode. **The choice is driven by *what the repo is* (Phase 1b), not by how many dependencies happen to be coupled:**2930- **Wide** (`mode-stack-groups.yml`) — bundle each coupled ecosystem *whole* into one PR per stack (all gradle + all docker/compose as one backend group; backend & client in lockstep; terraform + infra images). Right for **solution templates, examples, internal repos not consumed by other projects**: nobody reviews these PRs individually, CI is the gate, and consolidation beats precision.31- **Narrow** (`mode-fine-grained-stack-groups.yml`) — only the coupled dependency *pair* joins a multi-ecosystem group; the rest of each ecosystem keeps normal per-ecosystem handling. Right for **libraries/OSS consumed elsewhere, or a large dependency tree**, where unrelated majors still deserve individual review. Two blocks per coupled ecosystem, same directory: a "regular" block with the ecosystem's normal groups that `ignore`s the coupled dependency, and a "stack" block scoped via `patterns` to just that dependency, joining the shared `multi-ecosystem-group` — `ignore` only suppresses updates within the block that declares it, so the stack block still gets version and security updates for the coupled dependency.3233**Trade-offs to state for *either* width when proposing a stack group:** the stack shares one CI gate; everything the patterns match rides together, majors included; and **a member block that joins a multi-ecosystem group carries only `package-ecosystem`, `directory`, `patterns`, and `multi-ecosystem-group`** — `schedule`/`labels` live on the group, and `cooldown`, `commit-message`, and `groups` cannot sit on members. So every ecosystem pulled into a stack **loses its per-block `cooldown`, `commit-message` prefix, and forced `applies-to: security-updates` grouping**. Keep an ecosystem whose majors (or those knobs) need individual handling out of the stack, in a normal balanced/fine-grained block (mixing is fine).3435## Phase 1 — Discover3637**a) Ecosystems.** Find every manifest Dependabot can watch, including nested ones (each distinct directory needs its own `directory`, or one block with a `directories` glob list):3839| Manifest found | `package-ecosystem` |40|---|---|41| `package.json` | `npm` (also covers pnpm/yarn) / `bun` |42| `.github/workflows/*.yml`, `action.yml` | `github-actions` |43| `Dockerfile*` / `docker-compose*.yml` / charts | `docker` / `docker-compose` / `helm` |44| `pom.xml` / `build.gradle(.kts)` | `maven` / `gradle` |45| `requirements*.txt`, `pyproject.toml` | `pip` / `uv` |46| `go.mod` / `Cargo.toml` / `Gemfile` | `gomod` / `cargo` / `bundler` |47| `*.csproj`, `global.json` | `nuget` / `dotnet-sdk` |48| `*.tf` / `devcontainer.json` / `.pre-commit-config.yaml` | `terraform` / `devcontainers` / `pre-commit` |4950```bash51find . -path ./node_modules -prune -o \( -name package.json -o -name 'Dockerfile*' -o -name pom.xml \52 -o -name 'build.gradle*' -o -name go.mod -o -name Cargo.toml -o -name '*.tf' -o -name pyproject.toml \) -print53ls .github/workflows/ 2>/dev/null54```5556Full ecosystem list: the [options reference](https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference).5758**b) Repo identity — the primary evidence.** The mode follows from what the repo *is* and who it serves — not from how updates were handled so far:5960```bash61gh repo view --json isTemplate,isFork,isArchived,visibility,stargazerCount,description,licenseInfo62head -50 README.md # what is this, who consumes it?63gh release list --limit 5 2>/dev/null # does it actually publish?64ls .github/workflows/ # is there a CI test job that gates PRs?65jq '(.dependencies//{}|length) + (.devDependencies//{}|length)' package.json 2>/dev/null # dep count per ecosystem66```6768Answer these explicitly before recommending anything:69- **Purpose** — product people depend on, library/package others consume, solution template, example/demo, internal tooling?70- **Audience** — open-source with external users, or closed/internal where the team is the only consumer?71- **What it ships** — how many artifacts does it deploy or publish (npm packages, container images, marketplace extensions)? Every published artifact raises the cost of a silently-broken major.72- **Safety net** — CI tests that actually gate merges; release automation.73- **Scale & shape** — dep count per ecosystem, number of packages/workspaces. (Cross-ecosystem coupling is its own mandatory step — see **d** below.)7475**Per-ecosystem cadence.** The mode sets a starting point, but `schedule.interval` is decided **per ecosystem**, not once for the whole config — different ecosystems in the same repo release at different speeds:7677| Ecosystem tendency | Typical starting interval |78|---|---|79| Fast-moving app deps (npm, pip, gradle/maven app libs) in an actively developed repo | weekly |80| Slow-moving / mostly mechanical (github-actions, terraform providers, devcontainers) | monthly |81| Docker base images | weekly — patches land often and cooldown already absorbs the risk of a too-fresh tag |82| Any ecosystem in a low-activity or maintenance-mode repo, regardless of mode | monthly (or slower) — matches actual review bandwidth |8384Treat this table as a heuristic to seed the Phase 4 question, not a rule to apply silently — always confirm the actual interval per ecosystem with the user rather than defaulting to the mode's starting point.8586**c) Update history — calibration only, never the basis.** The existing config and past habits may be exactly what needs to change; deriving the target from the status quo would just ratify it. Use history to *tune within* the recommended mode:8788```bash89gh pr list --author 'app/dependabot' --state all --limit 100 --json state,createdAt,closedAt,mergedAt,title90```9192- **Many closed-without-merge / PRs open 30+ days** → noise exceeded capacity → slower cadence or higher cooldown inside the chosen mode.93- **Grouped PRs repeatedly superseded, conflicting, or red** → groups too broad → corroborates fine-grained.94- **Patches merge fast, majors rot** → raise `semver-major-days` cooldown, don't change mode.9596**d) Cross-ecosystem coupling — mandatory, explicit.** Coupling is not a judgement call to leave to prose — run it as an explicit step. After collecting the pinned version of every dependency in every ecosystem (you read these anyway for the Phase 3 pin gate), **identify dependencies in different ecosystems that track the same underlying software or release train**, and flag each such pair as a coupled candidate — manifests that must bump together. Two signals surface a pair, don't rely on only the first: an **identical version string** shared across manifests (the strongest and easiest to grep — e.g. one library pinned in two places), *and* **different version strings that nonetheless track one product** — a server and the client library that talks to it version their releases independently, so a literal-value match would miss them; recognise the shared software by name, not by number.9798Stay general — flag *any* shared software, not just the familiar shapes. Illustrative pairs only:99- a server image in `docker`/`docker-compose` and its client SDK or driver in `npm`/`gradle`/`pip` — e.g. the `postgres` image (tag `16`) and the `org.postgresql:postgresql` driver (`42.7.x`): different version numbers, same server, must move together100- a backend library and the client's pinned copy of the same library — usually an *identical* version string (backend & client released in lockstep)101- a provider/tool and the deployed image tag it manages — e.g. a terraform provider and the infra image it provisions (typically different numbers)102103Every coupled pair becomes a candidate carried into **Phase 4**, where the *width* of the bundle is chosen by repo type. If nothing across ecosystems tracks the same software, record "no coupling found" and skip the stack-group variants.104105## Phase 2 — Analyze the existing config (if present)106107Check each update block:108109- [ ] **Coverage** — a block (or `directories` entry) for every ecosystem/directory from Phase 1; no orphan blocks for manifests that no longer exist.110- [ ] **Mode coherence** — which mode does the config resemble, and is it consistent across blocks? A "balanced" repo with one all-types group hides breaking majors inside routine PRs — finding.111- [ ] **Dead & deprecated config:**112 - `reviewers:` — **removed by GitHub (Aug 2025)**, silently ignored → delete, wire `CODEOWNERS` instead.113 - `target-branch:` — a block with `target-branch` **no longer applies to security updates**, even when it names the default branch. Flag redundant `target-branch: main` for removal.114 - Duplicate blocks (same ecosystem + directory), overlapping `directory`/`directories` definitions.115- [ ] **Reviewer wiring** — for a repo owned by a small group, prefer one `CODEOWNERS` `*` rule over per-block `assignees`: it covers all PRs (not just Dependabot's) and doesn't rot in N places. Keep `assignees` only where a dedicated person triages dependency PRs *separately* from code ownership (larger orgs).116- [ ] **Groups correct:**117 - Group **order matters** — first match wins; specific families must precede the catch-all.118 - A group only affects version updates unless it says otherwise: without an `applies-to: security-updates` group, **every CVE opens its own PR**.119- [ ] **Noise controls** — `cooldown` present (supply-chain guard: new releases mature before a PR opens); `open-pull-requests-limit` sized to the expected PR count (default 5 — too low for balanced mode where majors arrive individually).120- [ ] **Clutter** — labels that don't exist in the repo or are typo'd (`gh label list`; e.g. "Technical Dept"), `schedule.time` without `timezone` (runs UTC), restated defaults, `versioning-strategy` that fights an exact-pin policy (`widen` vs pinned versions).121- [ ] **Right-sizing & dead fields** — the config must match the ecosystem's actual dependency shape (dep count, prod-vs-dev split), not a template's worst case. Flag:122 - `update-types` on a group that restates the default set — a version-updates group with no `update-types` already covers **all** of patch+minor+major, so `update-types: ['patch','minor','major']` is a no-op; write `update-types` **only** when genuinely narrowing (e.g. `['minor','patch']` in balanced mode to hold majors out). (Security-updates groups take no `update-types` at all.)123 - A `commit-message.prefix` that can never fire for that ecosystem's dependency class. `prefix-development` applies only to updates in the *development* group and only for the ecosystems that have that concept (bundler, composer, mix, maven, npm, pip, uv); `prefix` covers everything else. So a `prefix`/`prefix-development` split in an ecosystem whose deps are **all** `devDependencies` leaves `prefix` dead (only `prefix-development` ever fires) — and all-prod leaves `prefix-development` dead. Collapse to a single `prefix` unless the ecosystem actually has both classes.124 - Group count out of proportion to dep count — a handful of named family groups over an ecosystem with only 2–3 direct deps is over-engineering; one grouped block (+ the security group) is enough. Reserve fine-grained family groups for genuinely large trees (see the mode table).125126## Phase 3 — Precondition: versions must be pinned127128Dependabot PRs only reflect reality when manifests state exact versions — on floating specs the resolved dependency drifts on every install and the whole setup is theater. **Treat pinning as a gate, not a finding**: do not write a config while versions float.129130Check per ecosystem, report with file:line evidence:131132- **npm** — no `^`/`~`/`>=`/`*`/`latest`/mutable git refs; lockfile committed → fix via sibling skill **`pin-node-dependencies`**133- **github-actions** — every `uses:` pinned to a full 40-char commit SHA → fix via sibling skill **`pin-github-actions`**134- **docker / docker-compose** — exact tag, ideally tag + `@sha256:` digest, never `latest`135- **maven / gradle** — no dynamic versions (`1.+`, `[1.0,)`, `latest.release`)136- **pip** — `==` pins or a committed lockfile (uv / poetry / pip-tools)137138If anything floats, resolve the gate **before Phase 5** via AskUserQuestion: **fix pins now** (recommended — invoke the sibling skills for npm and actions, patch the other ecosystems directly) or **proceed anyway**, with the user explicitly accepting that Dependabot PRs for the floating ecosystems won't match what actually runs. Record the choice in the Phase 4 report.139140## Phase 4 — Report, recommend, decide141142Post the findings **as a normal message first** — table of Phase 2/3 checks plus the mode recommendation. The recommendation derives from the repo's **use-case (Phase 1b)**; update history (Phase 1c) only tunes cadence, cooldown, and group breadth within it. If the recommendation contradicts the current setup, say so and explain the delta — matching the status quo is not a goal:143144| Use-case | Recommend |145|---|---|146| Solution template, example/demo, internal tooling with no external consumers | low-noise |147| Open-source project or product with external users; publishes artifacts — the more it deploys, the stronger the case | balanced |148| Large dependency tree (≈40+ direct deps in one ecosystem), many packages/workspaces, monorepo with shared deps | fine-grained |149| Coupling found (Phase 1d) **and** the repo is a solution template / example / internal tool not consumed by other projects | **wide** stack groups on top — bundle each coupled ecosystem whole into one PR (`mode-stack-groups`); CI is the gate, consolidation beats precision |150| Coupling found (Phase 1d) **and** the repo is a library/OSS consumed elsewhere, or has a large dependency tree | **narrow** targeted pairing on top — only the coupled pair joins a multi-ecosystem group, the rest of each ecosystem stays per-ecosystem (`mode-fine-grained-stack-groups`) so unrelated majors keep individual review |151| **No CI test job** | never low-noise — grouped majors would merge blind; recommend balanced and adding CI |152153Then confirm via **AskUserQuestion** — recommendation first, marked "(recommended)", every option stating its consequence. Ask only what the evidence can't answer, max 4 questions:1541551. **Mode** — the three modes with one-line trade-offs. Include the single-PR multi-ecosystem variant only for clear low-noise repos. **Whenever Phase 1d found coupling, surface *both* stack-group widths in the same question** and mark the one matching the Phase-1b use-case "(recommended)":156 - **wide** — whole coupled ecosystems bundled (`mode-stack-groups`), recommended for solution-template/example/internal repos not consumed elsewhere (e.g. "all gradle + all docker/compose as one backend PR");157 - **narrow** — only the coupled pair joins the group, the rest stays per-ecosystem (`mode-fine-grained-stack-groups`), recommended for libraries/OSS consumed elsewhere or large dependency trees (e.g. "postgres image + postgres driver as one PR, rest of gradle/docker stays fine-grained").158159 Name the concrete coupled manifests/pair. State the stack-group trade-off in the option text: bundled member blocks lose their per-block `cooldown`, `commit-message` prefix, and forced `applies-to: security-updates` grouping (`schedule`/`labels` live on the group; `cooldown`/`commit-message`/`groups` can't sit on members).1602. **Cadence per ecosystem** — always confirm, never silently apply the mode's starting point. Propose an interval per detected ecosystem from the **Per-ecosystem cadence** heuristic (Phase 1) adjusted by PR history (Phase 1c) and repo activity level, and let the user override any of them.1613. **Review wiring** — CODEOWNERS-only (recommended for small teams) vs keep `assignees`, only if the existing config has assignees/reviewers.1624. **Existing customizations** (multiSelect) — which `ignore:` rules, labels, or schedule quirks to carry over vs drop.163164## Phase 5 — Create or update165166Enter this phase only once the Phase 3 pin gate is resolved — pins fixed (sibling skills run, other ecosystems patched) or floating versions explicitly accepted by the user.167168- **Update > replace.** Fix the specific gaps; carry over confirmed customizations (especially `ignore:` rules) verbatim, including comments.169- **Strip teaching comments — never emit them.** The `reference/mode-*.yml` files carry long explanatory prose comments for *agent* context only; they must **not** appear in the generated `.github/dependabot.yml`. Copy the config shape, not the rationale. The written file keeps at most **brief one-line section labels in the host repo's existing comment style** (or none at all). This does not conflict with *update > replace* above: comments already present in the repo's own config (e.g. a rationale line on an `ignore:` rule) are still carried over verbatim.170- Start from the chosen `reference/mode-*.yml`, one block per detected ecosystem/directory. Templates show `weekly`/`monthly` as illustrative placeholders only — write the interval **confirmed per ecosystem in Phase 4**, not the template's literal value. For fine-grained: derive family groups from the *actual* manifests, never ship template families the repo doesn't use, and confirm the families with the user.171- Every mode keeps: `labels: ['dependencies']`, `commit-message` prefix `chore` + `include: scope`, `cooldown`, and an `applies-to: security-updates` group per ecosystem.172- **Right-size to the ecosystem, don't emit dead fields** (mirror the Phase 2 *Right-sizing & dead fields* check when writing, not just when auditing):173 - Omit `update-types` unless it genuinely narrows the set — a version-updates group without it already means all of patch+minor+major, so `update-types: ['patch','minor','major']` is a no-op that reads as intent. In balanced mode the minor+patch group **does** carry `update-types: ['minor','patch']` (that's the narrowing that keeps majors out); low-noise's all-in-one group carries **none**.174 - Emit a single `commit-message.prefix` unless the ecosystem actually mixes prod and dev deps. Don't add `prefix-development` for an ecosystem whose deps are all `devDependencies` (only it would fire, `prefix` is dead) or all prod (the reverse). `prefix-development` is meaningful only for bundler/composer/mix/maven/npm/pip/uv **and** only when both classes are present.175 - Scale groups to dep count: for a small ecosystem (a handful of direct deps) one grouped block plus the security group is the whole config — don't manufacture family groups the mode table reserves for large trees.176 - **Grouped-PR prefix caveat:** for a *grouped* update the PR title and branch come from the group's `IDENTIFIER`, not the `commit-message` prefix; the prefix still lands on the underlying commit, and `prefix-development` only applies when every member of that group is a dev dependency (a group mixing prod + dev deps falls back to `prefix`). So a dev-only ecosystem grouped into one PR consistently uses one prefix anyway — another reason not to split it.177- If no `CODEOWNERS` exists, create `.github/CODEOWNERS` with a default owner (suggest from `gh api repos/{owner}/{repo} --jq .owner.login`):178179 ```180 # Default owners — requested as reviewers on every PR, including Dependabot's181 * @<owner-or-team>182 ```183184- Ensure referenced labels exist: `gh label create dependencies --description "Dependency updates" --color 0366d6` for any missing one.185186### Optional companion — patch/minor auto-merge187188Auto-merge is owned by the sibling skill **`automerge-setup`** (the single source of truth for the workflow, its native-setting and required-check preconditions, and the scope gate). After the `dependabot.yml` is written, **offer** (never impose) to set up patch/minor auto-merge and hand off to `automerge-setup` — don't write `.github/workflows/dependabot-automerge.yml` from here. Auto-merge is only safe when a branch ruleset with a *required status check* gates the default branch (**`branch-ruleset-setup`**) and a CI test job runs on PRs (Phase 1b); `automerge-setup` enforces that precondition. Every major stays manual regardless.189190## Phase 6 — Verify191192- YAML parses: `python3 -c "import yaml; yaml.safe_load(open('.github/dependabot.yml'))"` (fall back to `npx --yes yaml` or careful review).193- `CODEOWNERS` check after pushing: `gh api repos/{owner}/{repo}/codeowners/errors`.194- Config errors and run logs surface under **Insights → Dependency graph → Dependabot** — tell the user to check there after the merge, since GitHub validates unknown keys only at run time.195- If the user opted into auto-merge (Phase 5), the sibling **`automerge-setup`** handles and verifies the workflow; just confirm the hand-off happened.196197## Sources198199- Options reference: https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference200- Grouped updates / PR optimization: https://docs.github.com/en/code-security/tutorials/secure-your-dependencies/optimizing-pr-creation-version-updates201- Multi-ecosystem groups: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/configuring-multi-ecosystem-updates202- Targeted-pairing shape (two blocks, same ecosystem+directory, `ignore` + `patterns`/`multi-ecosystem-group`): https://github.com/dependabot/dependabot-core/discussions/12437203- Cross-directory `group-by: dependency-name` (Feb 2026): https://github.blog/changelog/2026-02-24-dependabot-can-group-updates-by-dependency-name-across-multiple-directories/204- `reviewers` removal in favor of CODEOWNERS: https://github.blog/changelog/2025-04-29-dependabot-reviewers-configuration-option-being-replaced-by-code-owners/205- Reference implementations: low-noise — https://github.com/Miragon/miravelo-shop-example/blob/main/.github/dependabot.yml · balanced — https://github.com/Miragon/bpmn-modeler/blob/main/.github/dependabot.yml
Run npx skillmds@latest add emaarco/dependabot-setup in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Audits and sets up .github/dependabot.yml: recommends a grouping mode (low-noise, balanced, fine-grained) from the repo's use-case, gates setup on pinned dependency versions, wires CODEOWNERS over the deprecated reviewers key, groups security updates. Use when asked to set up, review, fix, or audit Dependabot / automated dependency updates / dependency grouping. It is listed under Security on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
emaarco (@emaarco) published this skill. Their other Agent Skills are listed on their SkillMD profile.