Batch Dependabot Resolver Skill
Purpose
Discover open Dependabot dependency-version PRs in a target repository and enqueue
one pr-resolver workflow per matching PR, so Dependabot bumps can be resolved
automatically on a daily or weekly recurring schedule. This is a narrower,
safer-by-default discovery/filter layer over batch-pr-resolver: it reuses the
same child pr-resolver payload shape, fork/cross-repo safety, runtime
inheritance, and /api/executions submission path, and adds Dependabot-specific
matching, a cross-run-stable idempotency key, a dry-run mode, an optional maxPrs
cap, and a Dependabot-specific summary artifact.
This parent batch skill does not publish repository changes itself. It records
child workflow queueing evidence in artifacts/batch_dependabot_resolver_result.json;
each queued pr-resolver child owns its repository publishing outcome.
Inputs (skill args)
repo(string, required): Target repository inowner/repoform. Falls back to parent task context,git remote origin, then env, likebatch-pr-resolver.state(string, optional): PR state filter for discovery. Defaultopen. Other states print a warning.mergeMethod(string, optional): Merge method passed topr-resolver. Defaultsquash.maxIterations(number, optional):pr-resolverloop cap. Default5.maxAttempts(number, optional): Queue jobmaxAttemptsfor each created task. Default3.priority(number, optional): Queue job priority. Default0.packageManagers(list, optional): Allowlist of package managers, e.g.pip,npm,github-actions. Matched against the Dependabot branch ecosystem segment with alias normalization (npm↔npm_and_yarn,github-actions↔github_actions). Omit to allow all.titleRegex(string, optional): Override for the version-bump title matcher. Default^(?!.* from .* from )(?!.* to .* to )(?:Bump|[A-Za-z][A-Za-z0-9_-]*\(deps(?:-dev)?\): bump) .+ from \S+ to \S+(?: in /.+)?$(matches both Dependabot's legacyBump anthropic from 0.105.2 to 0.107.1titles and conventional-commit titles whose type is scoped todepsordeps-dev, such asBuild(deps): bump anthropic from 0.105.2 to 0.107.1, including subdirectory suffixes likein /frontend, while rejecting grouped or edited titles that contain multiplefrom ... to ...update segments).includeSecurityUpdates(boolean, optional): Defaulttrue. Whenfalse, PRs labeledsecurityare skipped.maxPrs(number, optional): Safety cap on the number of resolver workflows queued per run.dryRun(boolean, optional): Defaultfalse. Whentrue, compute and report the resolver workflows that would be submitted without creating any.runtimeMode/runtimeModel/runtimeEffort/runtimeProviderProfile(string, optional): Inherited likebatch-pr-resolverwhen omitted.
Workflow
- Run the helper script:
python3 .agents/skills/batch-dependabot-resolver/bin/batch_dependabot_resolver.py \
--repo <owner/repo> \
--merge-method squash \
--max-iterations 3 \
--package-managers pip,npm,github-actions \
--max-prs 25 \
--runtime-mode <runtime_mode> \
--runtime-model <model> \
--runtime-effort <effort> \
--runtime-provider-profile <profile_id>
Add --dry-run to validate a schedule without creating resolver workflows.
Always forward the parent task's explicit runtime selection fields when present so the
queued pr-resolver tasks reuse the same runtime/model/effort/provider profile.
The skill discovers open PRs via
gh pr list --json number,title,author,headRefName,headRefOid,headRepository,headRepositoryOwner,isCrossRepository,labels.A PR is matched only when ALL of:
- it is open and not a fork/cross-repository PR (same head-locality check as
batch-pr-resolver), - the author is
dependabot[bot](also acceptsapp/dependabot), - the head branch starts with
dependabot/, - the title matches
titleRegex, - it passes the optional
packageManagersallowlist, - (when
includeSecurityUpdates=false) it is not asecurity-labeled PR, - it has a head SHA available for the idempotency key.
Every non-matching PR is recorded as skipped with a reason:
fork-pr,not-dependabot-author,non-dependabot-branch,title-mismatch,package-manager-filtered,security-update-excluded,missing-head-sha, ormax-prs-cap.- it is open and not a fork/cross-repository PR (same head-locality check as
For each matched PR, submit a
pr-resolvertask with the canonicalbatch-pr-resolverpayload (repository,task.inputs = { repo, pr, branch, mergeMethod, maxIterations },task.git.startingBranch/branch,task.skill.name = pr-resolver,task.publish.mode = auto, inherited runtime) and a stable idempotency key:batch-dependabot-resolver:{repo}:pr:{number}:head:{headSha}. Submit viaPOST /api/executions, require the canonicalworkflowId, and verify it viaGET /api/executions/{workflowId}before counting the child as queued (MOONMIND_URLmust point at the MoonMind API). When MoonMind suppliesMOONMIND_EXECUTION_FANOUT_BEARER_TOKEN, forward it as the execution-scoped bearer and mark both calls as fan-out v1.Write a summary artifact
batch_dependabot_resolver_result.json(under the managed session artifact spool when available, otherwise the configured--artifacts-dir) listing discovered PRs, matched count, queued / would-queue resolver workflows, skipped PRs with reasons, runtime-inheritance mode, and submission errors. A deliberate zero-match run also writesskill_outcome.jsonwithstatus: "no_op". When the default title contract rejects a Dependabot title that still has the shape of a single version bump (bump ... from ... to ...), the helper records title-contract drift and fails instead of silently reporting a successful no-op.Print a short summary to stdout (
matched,queued,would_queue,skipped,errors).
Idempotency
The idempotency key is batch-dependabot-resolver:{repo}:pr:{number}:head:{headSha} (capped at
128 chars with a sha256 fallback). The same Dependabot PR at the same commit only ever gets one
resolver across separate scheduled runs; if Dependabot rebases or updates the PR (new head SHA),
a fresh resolver is allowed.
Recurring schedule (daily / weekly)
Target this skill from a queue_task recurring schedule rather than pr-resolver directly.
Example POST /api/recurring-workflows body:
{
"name": "Daily Dependabot resolver (MoonLadderStudios/MoonMind)",
"description": "Resolve open Dependabot version-bump PRs every morning.",
"enabled": true,
"scheduleType": "cron",
"cron": "0 7 * * *",
"timezone": "UTC",
"scopeType": "personal",
"target": {
"kind": "queue_task",
"job": {
"type": "task",
"priority": 0,
"maxAttempts": 3,
"payload": {
"repository": "MoonLadderStudios/MoonMind",
"requiredCapabilities": ["gh"],
"task": {
"title": "batch-dependabot-resolver",
"instructions": "Discover open Dependabot version-bump PRs and enqueue one pr-resolver workflow for each.",
"skill": { "name": "batch-dependabot-resolver", "version": "1.0" },
"inputs": {
"repo": "MoonLadderStudios/MoonMind",
"mergeMethod": "squash",
"maxIterations": 5,
"packageManagers": ["pip", "npm", "github-actions"],
"dryRun": false
},
"publish": { "mode": "auto" }
}
}
}
}
}
Use "cron": "0 7 * * *" for daily 07:00 UTC or "cron": "0 7 * * 1" for weekly (Mondays).
MoonMind delegates cron/time handling to Temporal Schedules. Set "dryRun": true in inputs
to validate a schedule without creating resolver workflows.
Safety constraints
- Reject missing
repounless it can be inferred from task context /git remote origin/ env. - Use
state=openby default to avoid dispatching against non-open PRs. - Skip fork and cross-repository PRs (cannot reliably check out fork head refs in queued jobs).
- Match conservatively: author AND branch AND title must all indicate a Dependabot version bump.
- Require
MOONMIND_URLto reach the MoonMind API; the legacy direct-DB queue fallback is unsupported. - Never queue a PR without a head SHA (no stable idempotency key) — skip it instead.