auto-merge
Automatically merge open PRs that have passing CI, no blocking reviews, and no conflicts
Skill by aeonfun
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/aeonfun-auto-merge
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
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
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/auto-merge
What's inside
- Skill name
auto-merge- Description
- Automatically merge open PRs that have passing CI, no blocking reviews, and no conflicts
- License
- MIT
- Metadata
- var: · title: Auto Merge · category: core
- Instructions
- 139 lines in SKILL.md · view on GitHub
Before installing
- Instructions call the network
Files (1)
- SKILL.md
SKILL.md (first lines)
<!-- autoresearch: variation C — safety-hardened (author allowlist, size cap, UNKNOWN retry, fork block, dry-run mode) so an autonomous agent with merge credentials cannot accidentally ship a hostile or oversized PR -->
> **${var}** — Repo (owner/repo) to target. If empty, uses every repo in memory/watched-repos.md.
> Env: `AUTO_MERGE_DRY_RUN=1` logs intent without merging. `MAX_AUTO_MERGE=N` caps merges per run (default 3).
Merge open PRs that are fully green **and** pass an explicit safety policy. The policy exists because this skill runs autonomously with write access — a bug in the gate is a bug that ships to main.
Read memory/MEMORY.md and memory/watched-repos.md for repos to target.
Read the last 2 days of memory/logs/ to avoid re-logging PRs already merged.
## Safety policy
A PR merges only when every one of the following holds:
- **Author allowlist**: `author.login` is one of `dependabot[bot]`, `renovate[bot]`, `github-actions[bot]`, OR appears under a `## Trusted Authors` section in memory/watched-repos.md. No allowlist → only the three bot logins are eligible.
- **Size cap**: `additions + deletions ≤ 500`. Override by applying the label `auto-merge-large` on the PR.
- **Base branch**: `baseRefName` is `main` or `master`. Refuse any other target.
- **Not a fork**: `isCrossRepository == false` (fork CI can be tampered with).
- **Not draft**: `isDraft == false`.
- **Not already queued**: `autoMergeRequest == null` (avoid fighting GitHub's native auto-merge if a human enabled it) and the PR is not already in a merge queue (`mergeQueueEntry == null`, checked in step 2b).
- **No opt-out label**: none of {`do-not-merge`, `wip`, `hold`, `needs-review`, `blocked`} present.
- **Mergeable state**: `mergeStateStatus == "CLEAN"` (this is stricter than `mergeable == "MERGEABLE"` — CLEAN additionally requires branch-protection gates to be satisfied).
- **Reviews**: `reviewDecision != "CHANGES_REQUESTED"`.
- **Checks**: every entry in `statusCheckRollup` has `conclusion` in `{SUCCESS, NEUTRAL, SKIPPED}`. Any `FAILURE`, `TIMED_OUT`, `CANCELLED`, `PENDING`, or `null` conclusion disqualifies the PR.
- **Retry cap**: this PR has been attempted fewer than 3 times. A PR that has hit `MERGE_FAIL` three times across runs is paused — repeated failure on a CLEAN-looking PR usually means something subtle (a required check that didn't surface, branch-protection drift, token scope drift). Surface it and stop looping.
## Steps
0. **Bootstrap state** — per-PR retry counter lives in `memory/topics/auto-merge-state.json`:
```bash
mkdir -p memory/topics
[ -f memory/topics/auto-merge-state.json ] || echo '{"prs":{},"last_run":null}' > memory/topics/auto-merge-state.json
```
Schema:
```json
{
"last_run": "2026-05-23T08:00:00Z",
"prs": {
"owner/repo#123": {
"first_seen": "2026-05-21T10:00:00Z",
"last_attempt": "2026-05-23T08:00:00Z",
"attempts": 2,
"last_outcome": "merge_failed",
"last_error": "Pull Request is in unstable state"
}
}
}
```
PR keys are `<owner>/<repo>#<number>` so state survives multi-repo runs. Cap to 50 most-recent entries (LRU by `last_attempt`). Validate with `jq empty` after write; restore from `.bak` on failure.
1. **List open PRs** for each watched repo with the full field set:
```bash
gh pr list -R owner/repo --state open --json number,title,author,isDraft,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,autoMergeRequest,isCrossRepository,labels,additions,deletions,baseRefName
```
2. **Handle UNKNOWN state** — GitHub computes `mergeStateStatus` lazily. If a PR returns `UNKNOWN`, sleep 3 seconds and re-query once:
```bash
sleep 3 && gh pr view NUMBER -R owner/repo --json mergeStateStatus,mergeable,statusCheckRollup
```
If still UNKNOWN after the retry, skip the PR with reason `UNKNOWN-persistent` and let the next run retry.
2b. **Skip PRs already in a merge queue.** A PR this skill queued on an earlier run is still open, so it would be merged again, bump `attempts`, and hit the retry cap while it waits. `gh pr list` does not expose the queue, so ask GraphQL per PR:
```bash
gh api graphql -f query='query($o:String!,$r:String!,$n:Int!){repository(owner:$o,name:$r){pullRequest(number:$n){mergeQueueEntry{state}}}}' \
-f o=owner -f r=repo -F n=NUMBER --jq '.data.repository.pullRequest.mergeQueueEntry.state // ""'
```
A non-empty state (e.g. `QUEUED`, `AWAITING_CHECKS`, `MERGEABLE`) skips the PR as `SKIP:already-queued:<state>`. A failed lookup skips it as `SKIP:merge-queue-unknown`. Neither counts as an attempt: do not touch its `attempts`, and leave its state entry as is.
3. **Apply the safety policy** to each PR. Record a verdict for every PR: either `MERGE` or `SKIP:<specific-reason>`. Reasons must name the failing gate — e.g. `SKIP:author-not-allowlisted:contributor123`, `SKIP:size-cap:823-lines`, `SKIP:mergeStateStatus=BEHIND`, `SKIP:label:do-not-merge`, `SKIP:check-failed:lint`, `SKIP:retry-cap:3-attempts`. Vague reasons like `SKIP:not-ready` are not acceptable.
4. **Merge qualifying PRs**, up to MAX_AUTO_MERGE (default 3):
- If `AUTO_MERGE_DRY_RUN=1`, log `DRY_RUN:would-merge #N` and continue — **do NOT** invoke merge.
- Otherwise:
```bash
gh pr merge NUMBER -R owner/repo --squash --delete-branch
```
A zero exit is not proof of a merge: on a repo with a merge queue, `gh pr merge` exits 0 after only adding the PR to the queue. Confirm with GitHub before counting or reporting it:
```bash
gh pr view NUMBER -R owner/repo --json state,mergeCommit --jq '[.state, (.mergeCommit.oid // "")] | @tsv'
```
Only `MERGED` with a commit SHA is a merge: report that SHA, never one inferred from the command output. `OPEN` means it was queued: log `QUEUED #N`, record `last_outcome: queued`, and report it as queued, not merged. Any other result, or a failed lookup, is logged as `MERGE_UNCONFIRMED #N` and reported as such. Both count toward `MAX_AUTO_MERGE`: a merge was attempted and GitHub accepted the command, so the cap still bounds how much this run can send to `main`.
Increment `state.prs["<owner>/<repo>#<N>"].attempts` on every attempt regardless of outcome. Set `first_seen` if absent. Reset to 0 (delete the entry) for PRs that no longer appear in the open list (already merged or closed since the last run).
If the merge fails (non-zero exit), capture stderr and log `MERGE_FAIL #N: <stderr>`. Record `last_outcome: merge_failed` and `last_error: <stderr ≤200 chars>` on the state entry. A failed merge does NOT count toward the per-run `MAX_AUTO_MERGE` cap — continue to the next qualifying PR. A PR whose `attempts` has reached 3 is filtered out in step 3 with `SKIP:retry-cap:3-attempts`; surface it in step 5b instead of retrying.
5. **Send a notification** only when at least one real (non-dry-run) merge succeeded **or** at least one PR has hit the retry cap (5b below). No merges and no cap hits → no notification, just a log entry.
5a. **At least one merge succeeded:**
```
*Auto Merge — ${today}*
Merged N PR(s) on owner/repo:
- #123: PR title (+45/-12, by @author) — squash merged abc1234 (the mergeCommit SHA GitHub returned)
Queue cleared. Self-improve cycle unblocked.
```
5b. **Retry cap reached on ≥1 PR** (`AUTO_MERGE_RETRY_CAP`) — include in the same message if both fire, otherwise stand-alone:
```
*Auto Merge — retry cap*
Hit retry cap (3 attempts) on:
- owner/repo#40 — last error: "Pull Request is in unstable state"
Stopping auto-merge attempts on this PR. Investigate manually.
```
Dedup: suppress re-notify if the *exact same* set of cap-hit PR keys already notified within the last 24h (grep `memory/logs/` for prior `AUTO_MERGE_RETRY_CAP` entries).
6. **Persist state** — write the updated `memory/topics/auto-merge-state.json`. Update `last_run` to current timestamp. Validate with `jq empty`; on failure restore from a `.bak` written before this run.
7. **Log to memory/logs/${today}.md** under an `### auto-merge` heading:
- `Mode`: live | dry-run
- `Repo(s)`: list
- `Merged`: `#N title @author +A-D SHA` per line, confirmed `MERGED` by GitHub
- `Queued`: `#N` per line (merge queue accepted it; not merged yet)
- `Skipped`: `#N SKIP:<reason>` per line
- `Retry-capped`: `owner/repo#N — <last_error>` per line (empty if none)
- `Totals`: `merged=X queued=Q qualified=Y considered=Z retry_capped=R`
- If zero qualified, include a verdict breakdown: `AUTO_MERGE_SKIP: 0/Z qualifying (behind=B blocked=L failing=F draft=D already-queued=U author-blocked=A size-blocked=S retry-capped=R)`
## Network note
`gh` authenticates via the workflow's GITHUB_TOKEN — no curl needed. If `gh pr merge` fails with `Resource not accessible by integration`, the workflow token lacks merge permission on that repo; log once and notify at most once per 7 days (check memory/logs/ for prior notification) to avoid alert spam.
## ConstraintsFrom aeonfun/aeon, MIT.
More from aeonfun/aeon
- 0.722score
anatomy
aeonfun
Build crafted, highly detailed, interactive isometric SVG figures that explain a technical idea as a real physical object (a test rig, a dial gauge, a cabinet…
SkillAFreshness: A★ 782Claude Code +9 - 0.719score
base-mcp
aeonfun
Access a Base Account via the Base MCP server (mcp.base.org) - wallet, portfolio, sending, swapping, signing, x402 payments, batched calls, and transaction…
SkillAFreshness: A★ 782Claude Code +9 - 0.718score
aeon
aeonfun
Set up and run an Aeon agent instance - get started from scratch, pick which skills to turn on or install more from packs, reschedule or change what runs…
SkillAFreshness: A★ 782Claude Code +9 - 0.717score
get-started
aeonfun
First-run setup for the Aeon plugin.
SkillAFreshness: A★ 782Claude Code +9 - 0.717score
hunter-22
aeonfun
Scan the ClawHunter agent bounty marketplace for opportunities that genuinely match this agent's real capabilities (code, security research, writing) and…
SkillAFreshness: A★ 782Claude Code +9 - 0.715score
seo-audit
aeonfun
Daily on-page and technical SEO audit of every page on a site - discovers URLs from the sitemap, scores each page, adds cross-page checks (duplicate titles…
SkillAFreshness: A★ 782Claude Code +9 - 0.714score
github-trending
aeonfun
Curated trending across GitHub repos and the Hugging Face Hub (models, datasets, spaces) - filtered, clustered, and labeled by momentum with a one-line…
SkillAFreshness: A★ 782Claude Code +9 - 0.714score
bd-radar
aeonfun
Business-development radar across your product family - find who's building, forking, integrating, and mentioning your products, ranked into a…
SkillAFreshness: A★ 782Claude Code +9 - 0.714score
digest
aeonfun
Generate and send a digest on a configurable topic, optionally pulling RSS/Atom feeds as an input source alongside web + X signal
SkillAFreshness: A★ 782Claude Code +9 - 0.714score
fetch-tweets
aeonfun
Search and curate X/Twitter behind one selector - keyword, topic roundup, a single or tracked-account digest, an X list, or the AI-agent buzz preset -…
SkillAFreshness: A★ 782Claude Code +9 - 0.714score
feedback-builder
aeonfun
Point Aeon at a service's /feedback endpoint - pull what agents reported (bugs, missing features), triage and cluster it, then build the best accepted request…
SkillAFreshness: A★ 782Claude Code +9 - 0.714score
heartbeat
aeonfun
Ambient fleet-health check that surfaces anything worth attention (default), or an on-demand priority brief - the 3 things to focus on, why now, and what…
SkillAFreshness: A★ 782Claude Code +9
Signals
- Stars
- 782
- Forks
- 292
- Open issues
- 0
- Last commit (this folder)
- Oct 1, 2026 (27 days ago)
- Last release
- Jul 9, 2026 (3 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/aeonfun/aeon
- Website
- www.aeon.fun/
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from aeonfun
- 0.722score
anatomy
aeonfun
Build crafted, highly detailed, interactive isometric SVG figures that explain a technical idea as a real physical object (a test rig, a dial gauge, a cabinet…
SkillAFreshness: A★ 782Claude Code +9 - 0.719score
base-mcp
aeonfun
Access a Base Account via the Base MCP server (mcp.base.org) - wallet, portfolio, sending, swapping, signing, x402 payments, batched calls, and transaction…
SkillAFreshness: A★ 782Claude Code +9 - 0.718score
aeon
aeonfun
Set up and run an Aeon agent instance - get started from scratch, pick which skills to turn on or install more from packs, reschedule or change what runs…
SkillAFreshness: A★ 782Claude Code +9 - 0.717score
get-started
aeonfun
First-run setup for the Aeon plugin.
SkillAFreshness: A★ 782Claude Code +9 - 0.717score
hunter-22
aeonfun
Scan the ClawHunter agent bounty marketplace for opportunities that genuinely match this agent's real capabilities (code, security research, writing) and…
SkillAFreshness: A★ 782Claude Code +9 - 0.715score
seo-audit
aeonfun
Daily on-page and technical SEO audit of every page on a site - discovers URLs from the sitemap, scores each page, adds cross-page checks (duplicate titles…
SkillAFreshness: A★ 782Claude Code +9
Cite this page
auto-merge skill. Agent Mart. https://agentmart.dev/skills/aeonfun-auto-merge (last updated 2026-10-24)