# Release Drafter

> Configure Release Drafter for automated release notes, label-based categorization, and semantic version suggestions in GitHub Actions.

- **Type:** Skill
- **Install:** `agentstack add skill-brpaz-agent-skills-release-drafter`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [brpaz](https://agentstack.voostack.com/s/brpaz)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [brpaz](https://github.com/brpaz)
- **Source:** https://github.com/brpaz/agent-skills/tree/main/skills/release-drafter

## Install

```sh
agentstack add skill-brpaz-agent-skills-release-drafter
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Release Drafter - Automated Release Notes

Use this skill when creating automated release notes workflows with GitHub Actions. Release Drafter drafts release notes by aggregating merged pull requests, categorizing them by labels, and suggesting version numbers based on semantic versioning.

## When to Use

- Adding automated release note drafting to a GitHub repository
- Setting up PR autolabeling based on file paths, branches, or title patterns
- Configuring semantic version resolution (patch/minor/major) from PR labels
- Creating a publication workflow that publishes draft releases via GitHub Actions

## What is Release Drafter?

Release Drafter automatically:
- Creates draft releases as PRs are merged
- Categorizes changes by PR labels (Features, Bug Fixes, etc.)
- Suggests next version number (patch, minor, major)
- Auto-labels PRs based on files/branches/title/body
- Maintains a changelog in draft releases
- Publishes releases on demand

**Key benefit:** Always have release notes ready - just review and publish.

## Quick Start

### Step 1: Create GitHub Actions Workflow

Create `.github/workflows/release-drafter.yml`:

```yaml
name: Release Drafter

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, reopened, synchronize]

permissions:
  contents: read

jobs:
  update_release_draft:
    permissions:
      contents: write
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
      - uses: release-drafter/release-drafter@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### Step 2: Create Configuration File

Create `.github/release-drafter.yml`:

```yaml
template: |
  ## What's Changed
  
  $CHANGES
```

### Step 3: Merge a PR

Once you merge a pull request, Release Drafter will:
1. Create a draft release (if none exists)
2. Add the PR to the release notes
3. Update the version number

**That's it.** You now have automated release notes.

## Basic Configuration

### Minimal Config

```yaml
# .github/release-drafter.yml
template: |
  ## Changes
  
  $CHANGES
```

### Recommended Config

```yaml
# .github/release-drafter.yml
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'

template: |
  ## What's Changed
  
  $CHANGES

change-template: '- $TITLE @$AUTHOR (#$NUMBER)'

categories:
  - title: '🚀 Features'
    labels:
      - 'feature'
      - 'enhancement'
  - title: '🐛 Bug Fixes'
    labels:
      - 'fix'
      - 'bugfix'
      - 'bug'
  - title: '📚 Documentation'
    label: 'documentation'
  - title: '🧰 Maintenance'
    label: 'chore'

version-resolver:
  major:
    labels:
      - 'major'
  minor:
    labels:
      - 'minor'
  patch:
    labels:
      - 'patch'
  default: patch
```

## Configuration Options

### Core Settings

| Option | Required | Description |
|--------|----------|-------------|
| `template` | Yes | Body of the draft release. Use template variables. |
| `name-template` | No | Release name template. Example: `"v$NEXT_PATCH_VERSION"` |
| `tag-template` | No | Release tag template. Example: `"v$NEXT_PATCH_VERSION"` |
| `change-template` | No | Format for each PR entry. Default: `"* $TITLE (#$NUMBER) @$AUTHOR"` |
| `header` | No | Prepended to `template` |
| `footer` | No | Appended to `template` |

### Advanced Settings

| Option | Description |
|--------|-------------|
| `category-template` | Template for category headings. Default: `"## $TITLE"` |
| `version-template` | Custom version format. Default: `"$MAJOR.$MINOR.$PATCH"` |
| `change-title-escapes` | Characters to escape in PR titles. Default: `""` |
| `no-changes-template` | Text when no PRs merged. Default: `"* No changes"` |
| `no-contributors-template` | Text when no contributors. Default: `"No contributors"` |
| `sort-by` | Sort by `merged_at` or `title`. Default: `merged_at` |
| `sort-direction` | `ascending` or `descending`. Default: `descending` |
| `prerelease` | Mark as prerelease. Default: `false` |
| `latest` | Mark as latest. Values: `true`, `false`, `legacy`. Default: `true` |
| `commitish` | Target branch/commit. Default: workflow ref |

## Template Variables

### Main Template Variables

Use in `template`, `header`, `footer`, `name-template`, `tag-template`:

| Variable | Description | Example |
|----------|-------------|---------|
| `$CHANGES` | List of merged PRs | (formatted list) |
| `$CONTRIBUTORS` | Comma-separated contributor list | `@alice, @bob, @charlie` |
| `$PREVIOUS_TAG` | Previous release tag | `v1.2.3` |
| `$REPOSITORY` | Current repository | `myorg/myapp` |
| `$OWNER` | Repository owner | `myorg` |

### Version Variables

| Variable | Description | Example (from v1.2.3) |
|----------|-------------|----------------------|
| `$NEXT_PATCH_VERSION` | Next patch version | `v1.2.4` |
| `$NEXT_MINOR_VERSION` | Next minor version | `v1.3.0` |
| `$NEXT_MAJOR_VERSION` | Next major version | `v2.0.0` |
| `$RESOLVED_VERSION` | Auto-resolved by labels | (varies) |

### Change Template Variables

Use in `change-template`:

| Variable | Description | Example |
|----------|-------------|---------|
| `$NUMBER` | PR number | `42` |
| `$TITLE` | PR title | `Add alien technology` |
| `$AUTHOR` | PR author username | `gracehopper` |
| `$BODY` | PR body | `Fixed spelling mistake` |
| `$URL` | PR URL | `https://github.com/...` |
| `$BASE_REF_NAME` | Base branch | `main` |
| `$HEAD_REF_NAME` | PR branch | `fix/bug-123` |

### Category Template Variables

Use in `category-template`:

| Variable | Description |
|----------|-------------|
| `$TITLE` | Category title |

## Categorize Pull Requests

Group PRs by labels into sections:

```yaml
categories:
  - title: '🚀 Features'
    labels:
      - 'feature'
      - 'enhancement'
  
  - title: '🐛 Bug Fixes'
    labels:
      - 'fix'
      - 'bugfix'
      - 'bug'
  
  - title: '📚 Documentation'
    label: 'documentation'
  
  - title: '🔒 Security'
    label: 'security'
  
  - title: '⬆️ Dependencies'
    label: 'dependencies'
    collapse-after: 5  # Collapse if more than 5 PRs
  
  - title: '🧰 Maintenance'
    labels:
      - 'chore'
      - 'refactor'
```

**Result:**

```markdown
## 🚀 Features

- Add authentication system @alice (#123)
- Implement dark mode @bob (#124)

## 🐛 Bug Fixes

- Fix memory leak in parser @charlie (#125)

## ⬆️ Dependencies

6 changes

- Bump lodash from 4.17.19 to 4.17.21 @dependabot (#126)
- Update typescript to 5.0.0 @dependabot (#127)
...

```

**Note:** `collapse-after` automatically collapses categories with many PRs.

## Auto-Label Pull Requests

Automatically label PRs based on file changes, branch name, title, or body:

```yaml
autolabeler:
  # Label by files changed
  - label: 'documentation'
    files:
      - '*.md'
      - 'docs/**/*'
  
  # Label by branch name (regex)
  - label: 'feature'
    branch:
      - '/^feature\/.+/'
      - '/^feat\/.+/'
  
  - label: 'bugfix'
    branch:
      - '/^fix\/.+/'
      - '/^bugfix\/.+/'
  
  # Label by PR title (regex)
  - label: 'breaking'
    title:
      - '/breaking change/i'
      - '/BREAKING:/i'
  
  # Label by PR body (regex)
  - label: 'needs-review'
    body:
      - '/JIRA-[0-9]{1,4}/'
  
  # Multiple matchers (any match = label applied)
  - label: 'dependencies'
    files:
      - 'package.json'
      - 'package-lock.json'
      - 'go.mod'
      - 'go.sum'
    title:
      - '/^(build|deps):/i'
```

**Matchers:**
- `files` - Glob patterns
- `branch` - Regex
- `title` - Regex
- `body` - Regex

**Logic:** Matchers are evaluated independently. Label is applied if **any** matcher succeeds.

## Version Resolution

Auto-increment version based on PR labels:

```yaml
version-resolver:
  major:
    labels:
      - 'breaking'
      - 'major'
  minor:
    labels:
      - 'feature'
      - 'enhancement'
      - 'minor'
  patch:
    labels:
      - 'fix'
      - 'bugfix'
      - 'patch'
  default: patch
```

**Logic:**
1. Scan all PRs since last release
2. Find highest priority label (major > minor > patch)
3. Increment that version component
4. Use `default` if no matching labels found

**Example:**

Current version: `v1.2.3`

Merged PRs:
- PR #1: labels `[bugfix]` → patch
- PR #2: labels `[feature]` → minor
- PR #3: labels `[fix]` → patch

Highest: `minor`

Result: `$RESOLVED_VERSION` = `1.3.0`

## Exclude/Include Pull Requests

### Exclude by Label

```yaml
exclude-labels:
  - 'skip-changelog'
  - 'no-release-notes'
  - 'duplicate'
```

PRs with these labels are omitted from release notes.

### Include Only Specific Labels

```yaml
include-labels:
  - 'production-ready'
  - 'approved'
```

**Only** PRs with these labels appear in release notes.

**Note:** `exclude-labels` and `include-labels` can be used together. Include is applied first, then exclude.

## Exclude Contributors

Remove specific users from `$CONTRIBUTORS`:

```yaml
exclude-contributors:
  - 'dependabot'
  - 'dependabot[bot]'
  - 'github-actions[bot]'
  - 'myusername'
```

Useful for:
- Hiding bots
- Hiding yourself to highlight external contributors

## Replacers

Search and replace in generated changelog:

```yaml
replacers:
  # Link CVE IDs
  - search: '/CVE-(\\d{4})-(\\d+)/g'
    replace: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-$1-$2'
  
  # Link Jira tickets
  - search: '/JIRA-([0-9]+)/g'
    replace: 'https://jira.example.com/browse/JIRA-$1'
  
  # Expand usernames
  - search: '@myorg-bot'
    replace: 'MyOrg Automation Bot'
  
  # Remove internal references
  - search: '/\\[INTERNAL\\].*/g'
    replace: ''
```

Replacers run **in order** on the final changelog body.

## Advanced Template Examples

### Include Previous Tag and Date

```yaml
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'

template: |
  ## Changes since $PREVIOUS_TAG
  
  $CHANGES
  
  **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION
```

### Contributor Shoutouts

```yaml
template: |
  ## What's Changed
  
  $CHANGES
  
  ## 👏 Contributors
  
  Thanks to all contributors who made this release possible: $CONTRIBUTORS
```

### Complex Multi-Section Template

```yaml
template: |
  ## 📦 Release v$RESOLVED_VERSION
  
  ### What's Changed
  
  $CHANGES
  
  ### 🔗 Links
  
  - [Documentation](https://docs.example.com)
  - [Migration Guide](https://docs.example.com/migration/v$RESOLVED_VERSION)
  - [Full Changelog](https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION)
  
  ### 👥 Contributors
  
  $CONTRIBUTORS
  
  ---
  
  **Installation:** `npm install $REPOSITORY@$RESOLVED_VERSION`

header: |
  🎉 We're excited to announce the release of v$RESOLVED_VERSION!

footer: |
  ---
  
  Found a bug? [Report it here](https://github.com/$OWNER/$REPOSITORY/issues/new)
```

## Prerelease Configuration

### Basic Prerelease

```yaml
prerelease: true
```

Draft releases will be marked as prerelease.

### Prerelease with Identifier

```yaml
prerelease: true
prerelease-identifier: 'beta'
```

Versions will be: `v1.2.3-beta.1`, `v1.2.3-beta.2`, etc.

**Automatic prerelease increment:** Each merge bumps the prerelease number.

### Conditional Prerelease (via Action Input)

```yaml
# .github/workflows/release-drafter.yml
- uses: release-drafter/release-drafter@v6
  with:
    prerelease: ${{ github.ref != 'refs/heads/main' }}
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

Prereleases on non-main branches, regular releases on main.

## Non-Semantic Versioning Projects

Override version format:

```yaml
version-template: '$MAJOR.$MINOR'
```

If current version is `2.5`, then:
- `$NEXT_MINOR_VERSION` = `2.6`
- `$NEXT_MAJOR_VERSION` = `3.0`

### Date-Based Versioning

```yaml
version-template: 'YYYY.MM.DD'
name-template: 'Release $RESOLVED_VERSION'
tag-template: 'release-$RESOLVED_VERSION'
```

Requires manual version setting via action input.

## Action Inputs

Override configuration via workflow:

```yaml
- uses: release-drafter/release-drafter@v6
  with:
    config-name: my-custom-config.yml
    name: 'Custom Release Name'
    tag: 'v1.2.3'
    version: '1.2.3'
    publish: true
    prerelease: false
    latest: true
    commitish: 'main'
    disable-autolabeler: false
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

| Input | Description |
|-------|-------------|
| `config-name` | Config file name (relative to `.github/`). Default: `release-drafter.yml` |
| `name` | Override release name |
| `tag` | Override tag name |
| `version` | Override version (bypasses resolver) |
| `publish` | Immediately publish release. Default: `false` |
| `prerelease` | Mark as prerelease |
| `latest` | Mark as latest |
| `commitish` | Target branch/commit |
| `header` | Prepend text to body |
| `footer` | Append text to body |
| `disable-autolabeler` | Disable auto-labeling |

## Action Outputs

Use outputs in subsequent steps:

```yaml
- uses: release-drafter/release-drafter@v6
  id: release_drafter
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Use release info
  run: |
    echo "Release ID: ${{ steps.release_drafter.outputs.id }}"
    echo "Release URL: ${{ steps.release_drafter.outputs.html_url }}"
    echo "Tag: ${{ steps.release_drafter.outputs.tag_name }}"
    echo "Version: ${{ steps.release_drafter.outputs.resolved_version }}"
```

| Output | Description |
|--------|-------------|
| `id` | Release ID |
| `name` | Release name |
| `tag_name` | Tag name |
| `body` | Release body (markdown) |
| `html_url` | Release page URL |
| `upload_url` | Asset upload URL |
| `resolved_version` | Resolved version (e.g., `1.2.3`) |
| `major_version` | Major component |
| `minor_version` | Minor component |
| `patch_version` | Patch component |

## Complete Workflow Examples

### Basic: Draft Only

```yaml
name: Release Drafter

on:
  push:
    branches: [main]
  pull_request:
    types: [opened, reopened, synchronize]

permissions:
  contents: write
  pull-requests: write

jobs:
  draft:
    runs-on: ubuntu-latest
    steps:
      - uses: release-drafter/release-drafter@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### Advanced: Auto-Publish on Tag

```yaml
name: Release

on:
  push:
    branches: [main]
    tags: ['v*']
  pull_request:
    types: [opened, reopened, synchronize]

permissions:
  contents: write
  pull-requests: write

jobs:
  draft:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: release-drafter/release-drafter@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish:
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - uses: release-drafter/release-drafter@v6
        with:
          publish: true
          name: 'Release ${{ github.ref_name }}'
          tag: ${{ github.ref_name }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### Production: Draft, Build, Publish

```yaml
name: Release Pipeline

on:
  push:
    branches: [main]
    tags: ['v*']
  pull_request:
    types: [opened, reopened, synchronize]

permissions:
  contents: write
  pull-requests: write

jobs:
  draft:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: release-drafter/release-drafter@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  build-and-publish:
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build artifacts
        run: |
          npm ci
          npm run build
          npm run package
      
      - uses: release-drafter/release-drafter@v6
        id: release
        with:
          publish: true
          name: 'Release ${{ github.ref_name }}'
          tag: ${{ github.ref_name }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Upload artifacts
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url:

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [brpaz](https://github.com/brpaz)
- **Source:** [brpaz/agent-skills](https://github.com/brpaz/agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-brpaz-agent-skills-release-drafter
- Seller: https://agentstack.voostack.com/s/brpaz
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
