autohand "Generate release notes for version 2.4.0 from the git log since the v2.3.0 tag. Group changes by type (features, fixes, improvements). Include PR numbers and contributor names."

What you'll learn

  • How to generate structured release notes from a git log between two tags
  • How to set up conventional commits for better classification
  • How to customize the output format for GitHub releases, emails, or JSON
  • How to automate release note generation in a CI pipeline

Before you start

  • Autohand Code installed. Run autohand --version to confirm. See Your First Autohand Session if you need to install it.
  • Git tags for previous releases. Run git tag --list to check what tags exist. Adjust the prompt if your project uses a different tagging convention like release/2.3.0.
  • Commit messages with context. Clear messages like feat: add dark mode toggle produce much better output than wip or misc changes.
  • PR numbers in commits (optional). GitHub and GitLab add PR numbers automatically when you use squash merge or merge commit. Autohand extracts and links them.

Set up conventional commits

Conventional commits are a lightweight standard that makes release notes generation much more reliable. If your project does not use them yet, it takes about five minutes to set up.

The format is simple: type(scope): description. Common types are feat, fix, docs, refactor, test, and chore.

bash

feat(auth): add OAuth2 login with Google
fix(api): correct pagination offset on user list endpoint
docs(readme): update installation instructions for Node.js 20
refactor(db): move connection pooling to shared module
chore(deps): bump typescript from 5.3.0 to 5.4.0

Add a commit message linter to enforce the format.

bash

npm install --save-dev @commitlint/cli @commitlint/config-conventional husky

Ask Autohand to generate the configuration files.

bash

Set up commitlint with conventional commits config and add a husky commit-msg hook
that runs commitlint. Create all the config files needed.

Run the release notes prompt

Navigate to your repository root and start Autohand. No special flags are needed.

bash

cd path/to/your-repo
autohand

Run the prompt with your actual version numbers and tag names.

bash

Generate release notes for version 2.4.0 from the git log since the v2.3.0 tag.
Group changes by type: New Features, Bug Fixes, Performance Improvements, Internal Changes.
Include PR numbers as links to https://github.com/my-org/my-repo/pull/NUMBER.
Include contributor GitHub usernames next to each item.
Format the output as Markdown suitable for a GitHub release.

Autohand runs the git log internally, parses the commits, classifies them by type, and writes the Markdown. The whole process takes under a minute for a typical release with 30-80 commits.

Review the output

Autohand produces a Markdown block you can copy directly into your GitHub release or CHANGELOG.md. Here is what a typical output looks like.

markdown

## What's Changed in v2.4.0

### New Features
- Add OAuth2 login with Google (#142) @sarah-dev
- Support dark mode toggle in user preferences (#138) @markj
- Add bulk export for CSV and JSON formats (#145) @sarah-dev

### Bug Fixes
- Fix pagination offset on user list endpoint (#151) @alex-ops
- Resolve login session timeout on mobile Safari (#149) @markj
- Correct email validation for international addresses (#144) @devbot

### Performance Improvements
- Move database connection pooling to shared module (#147) @alex-ops
- Add Redis caching for user profile queries (#139) @sarah-dev

### Internal Changes
- Bump TypeScript from 5.3.0 to 5.4.0 (#153) @devbot
- Update CI to Node.js 20 (#150) @alex-ops

**Full changelog:** https://github.com/my-org/my-repo/compare/v2.3.0...v2.4.0

Read through the output and check that nothing important is missing. If a significant change was not captured, follow up in the same session.

bash

The PR #136 added webhook support which is a major feature.
It was committed as "chore: add webhook endpoint" so it was categorized wrong.
Move it to New Features and rewrite the description as "Add webhook support for real-time event delivery (#136) @markj".

Customize the format

The default output is GitHub Markdown. You can ask for a different format in the same session.

Plain text for an email announcement.

bash

Reformat the release notes as plain text for an email announcement.
Use a friendly tone, no Markdown syntax, and keep it under 300 words.

JSON for a programmatic pipeline.

bash

Output the same data as a JSON array where each item has:
type, description, pr_number, author, and breaking (boolean).

Append to an existing CHANGELOG.md file using the Keep a Changelog format.

bash

Format the release notes following the keepachangelog.com format with
Added, Changed, Deprecated, Removed, Fixed, and Security sections.
I will insert it at the top of CHANGELOG.md under the [Unreleased] section.

Automate in CI

You can run this as part of your release pipeline using Autohand's headless mode. Add a step to your GitHub Actions workflow that triggers when a version tag is pushed.

yaml

name: Release\n\non:\n  push:\n    tags:\n      - 'v*'\n\njobs:\n  release-notes:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0  # full history needed for git log\n\n      - name: Get previous tag\n        id: prev-tag\n        run: |\n          PREV=$(git tag --sort=-version:refname | grep -v "^${GITHUB_REF_NAME}$" | head -1)\n          echo "tag=$PREV" >> $GITHUB_OUTPUT\n\n      - name: Install Autohand\n        run: curl -fsSL https://autohand.ai/install.sh | sh\n\n      - name: Generate release notes\n        env:\n          AUTOHAND_PROVIDER: autohandai\n          AUTOHAND_API_KEY: ${{ secrets.AUTOHAND_API_KEY }}\n          AUTOHAND_AI_API_KEY: ${{ secrets.AUTOHAND_API_KEY }}\n        run: |\n          autohand --bare --restricted -p "Generate release notes for ${GITHUB_REF_NAME} from the git log since ${{ steps.prev-tag.outputs.tag }}. Format as GitHub release Markdown." > release-notes.md\n\n      - name: Create GitHub release\n        uses: softprops/action-gh-release@v2\n        with:\n          body_path: release-notes.md

The runner has no stored Autohand sign-in, so the step runs Autohand with --bare and sets AUTOHAND_PROVIDER, AUTOHAND_API_KEY, and AUTOHAND_AI_API_KEY. Without --bare, the CLI waits for a browser sign-in and the job hangs. See Authenticate in CI and containers.

Tip: Use fetch-depth: 0 in the checkout step. Without it, GitHub Actions does a shallow clone and the git log since the previous tag will be empty.

Best practices for commit messages

The single highest-leverage thing you can do to improve release notes quality is write better commit messages. Here are the patterns that work best.

  • Describe the change from the user's perspective. "Add bulk export" is better than "implement export controller method".
  • Put breaking changes in the commit body. Add BREAKING CHANGE: in the commit body for any change that breaks the public API. Autohand surfaces these prominently in the release notes.
  • Use imperative mood. "Fix login bug" not "Fixed login bug" or "Fixes login bug". This is the git convention and it reads naturally in a list.
  • Reference issues and PRs. Including (#123) at the end of a commit message gives Autohand and readers a direct link to the discussion context.

bash

# Good commit message\nfeat(api): add rate limiting to public endpoints (#167)\n\nAdds token bucket rate limiting at 100 requests per minute per API key.\nReturns 429 with a Retry-After header when the limit is exceeded.\n\nBREAKING CHANGE: The /v1/search endpoint now requires authentication.\nUnauthenticated requests will receive a 401 instead of being rate-limited.\n\n# Poor commit message\nfix stuff and add some rate limiting

What you learned

  • Generated structured release notes from a git log grouped by change type
  • Set up conventional commits with commitlint and husky for consistent messages
  • Customized the output format for GitHub releases, plain text emails, and JSON
  • Automated release note generation in a GitHub Actions pipeline on tag push

Try next

autohand "Generate a GitHub Actions workflow that runs release notes generation, creates a GitHub release, and posts a summary to our Slack channel on every version tag push"