Skip to content

Create a merge-pr skill #382

Description

@williamthorsen

Problem

There's no skill that composes a merge-commit message and executes a PR merge through the platform's API. Users run gh pr merge directly with hand-typed flags, missing the project's title-rendering machinery (describe-change.sh), label-based scope/type inference, and consistent merge-log voice.

Context

The project already has the building blocks:

  • describe-change.sh renders titles from declarative templates and emits a merge_commit_title field (to be renamed merge_title).
  • create-pr / create-gh-pr / create-bitbucket-pr establishes the orchestrator-and-delegate pattern that splits decisions from per-platform execution.
  • summarize-change produces release-notes-voice ## What sections that feed the PR body, which in turn should feed the merge-commit body.
  • .meta/label-map.json defines forward scope/type → label mappings, easily reverse-lookable for inference.

The existing merge_commit: preferences section was created when only title_format was needed. With action-of-merging concerns coming in, that name is misleading — rebase strategy produces no merge commit at all. Renaming to merge: and reserving the namespace for future settings is the cleanest forward path.

Solution

A three-skill family mirroring the create-pr pattern:

  • merge-pr — user-invocable orchestrator. Owns all decisions: PR resolution, body composition, scope/type/strategy resolution, approval gate.
  • merge-gh-pr — internal GitHub delegate. Owns gh pr view, gh pr merge, label fetching, PR-state validation.
  • merge-bb-pr — internal Bitbucket delegate. Stub for this iteration, parallel to how create-ticket handles Jira.

Configuration:

  • Rename merge_commit:merge: in both preferences files (.agents/preferences.yaml, ~/.agents/preferences.yaml), describe-change.sh, its tests, commit-format.md, and packages/agents/README.md.
  • Rename JSON output key merge_commit_titlemerge_title in describe-change.sh.
  • This iteration hard-codes defaults (strategy=squash, delete_branch=true); resolver functions are shaped to accept future preference-file lookup as a one-line additive change. The merge: section is reserved for these keys; they are documented as reserved-but-unhonored.

CLI surface (merge-pr):

Flag Effect Default
--pr {n} Merge PR {n} instead of the current branch's PR current branch's PR
--scope {s} Override scope inference inferred
--type {t} Override type inference inferred
--strategy {squash|merge|rebase} Override merge strategy squash
--delete-branch {yes|no} Override branch deletion yes

Process (orchestrator):

  1. Resolve session context (get-session-context) and PR number (--pr or current-branch lookup).
  2. Run pre-merge checks: branch in sync with remote; PR exists and open; not draft; mergeable (no conflicts, required checks pass, required reviews approved). Refuse with a specific reason on any failure.
  3. Resolve scope/type: CLI override → reverse-lookup of PR labels via .meta/label-map.json → commit-message majority across default_branch...HEAD → mark ambiguous.
  4. Resolve strategy and delete_branch from CLI override or hard-coded default.
  5. Render merge-commit title via describe-change.sh (merge_title field).
  6. Compose merge-commit body: extract ## What section content (heading dropped) from the live PR body via gh pr view --json body. If missing or thin, compose fresh from commits + diff in release-notes voice.
  7. Approval gate: render proposed merge commit (title + body), strategy, branch-deletion choice. If scope/type are ambiguous, ask the user to fill them in now. Prompt 👍🏼👎🏼 before invoking the API.
  8. Delegate to merge-gh-pr (or stub merge-bb-pr).
  9. Save merge artifact in the ticket directory recording PR URL, merged-at timestamp, commit SHA, strategy, title, body, branch-deletion outcome.
  10. Report results. Local state untouched.

Out of scope (intentionally):

  • Auto-merge (gh pr merge --auto).
  • --admin bypass of branch protections.
  • Local cleanup (checkout main, pull, delete local branch).
  • Bitbucket execution (stub only — full implementation is a follow-up).
  • Preference-file lookup for merge.strategy / merge.delete_branch (resolver shape supports it; lookup deferred).

Acceptance criteria

  • Three skills exist: merge-pr (user-invocable), merge-gh-pr (internal delegate), merge-bb-pr (internal delegate, stub).
  • merge-pr accepts --pr, --scope, --type, --strategy, --delete-branch overrides; defaults to current-branch PR with strategy=squash and delete_branch=yes.
  • Pre-merge checks refuse the merge with a specific reason when: branch out of sync, PR missing, PR closed/merged, PR draft, conflicts present, failing required checks, missing required reviews.
  • Merge-commit title is rendered via describe-change.sh's merge_title field.
  • Merge-commit body is extracted from the ## What section of the live PR description; falls back to fresh release-notes-voice composition when missing or thin.
  • Scope/type inference order is: CLI override → PR label reverse-lookup → commit majority → user prompt at approval gate.
  • Approval gate is always shown before the API call; no bypass flag.
  • On success, merge-pr saves a merge artifact in the ticket directory recording PR URL, commit SHA, strategy, title, body, and branch-deletion outcome.
  • merge-bb-pr SKILL.md exists with the delegate interface declared and a notice that Bitbucket merge is not yet implemented.
  • merge_commit: section is renamed to merge: in .agents/preferences.yaml, ~/.agents/preferences.yaml, describe-change.sh, describe_change_test.sh, commit-format.md, and packages/agents/README.md. References to merge_commit_title and merge_commit: are removed wherever they occur.
  • JSON output key in describe-change.sh is renamed from merge_commit_title to merge_title.
  • Skill body documents that merge.strategy and merge.delete_branch keys are reserved for future use and not yet honored.
  • New and modified behavior in this change is covered by tests (script test for describe-change.sh rename + parser changes; resolver functions for scope/type/strategy/delete_branch; pre-merge check logic).
  • User-facing surface changes (new skills, renamed config key, renamed JSON output key) are reflected in skill content and packages/agents/README.md; obsolete references are removed.

Metadata

Metadata

Labels

featureAdded or improved external functionalityscope:agents

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions