Skip to content

Action — pr-description ​

Writes the description of the current pull request with Claude Code and stores it in a managed block at the top of the pull request body. It is the engine of the pr-description workflow, which most callers should use instead.

Usage ​

The job needs contents: read and pull-requests: write. The runner needs curl, git, jq and python3, but no GitHub CLI: GitHub-hosted runners and the actions-runner image used by self-hosted ARC runners have them.

yaml
steps:
  - uses: actions/checkout@v7
    with:
      ref: ${{ github.event.pull_request.head.sha }}
      fetch-depth: 0
      persist-credentials: false

  - uses: KevinDeBenedetti/github-workflows/.github/actions/setup-claude-code@main

  - uses: KevinDeBenedetti/github-workflows/.github/actions/pr-description@main
    with:
      claude-code-oauth-token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      model: opus

Inputs ​

InputTypeDefaultDescription
claude-code-oauth-tokenstring— (required)Token from claude setup-token
modelstring— (required)Claude model: an alias (opus, sonnet, …) or a full name
effortstring''Claude Code effort level; empty for Claude Code's default
languagestringEnglishLanguage of the text; the section headings stay in English
max-diff-bytesstring100000Size cap of the diff sent to Claude, in bytes
github-tokenstringthe job's GITHUB_TOKENToken allowed to edit the pull request
pr-numberstringfrom the pull_request eventPull request to update
base-shastringfrom the pull_request eventBase commit of the diff
head-shastringfrom the pull_request eventHead commit of the diff
titlestringfrom the pull_request eventPull request title

Steps ​

  1. collect-context.sh prints the title, the commit messages, the diffstat and the diff (lockfiles left out, cut at max-diff-bytes)
  2. write-description.sh runs claude -p with the model, the effort and the system prompt in system-prompt.md, with no tool, from empty working and configuration directories. Only this step gets the Claude token
  3. update-body.sh reads the current body through the REST API with curl, merge-body.py replaces the managed block or puts one on top, and the body is saved only when it changed. Only this step gets the GitHub token, through a header file rather than a command line

The managed block ​

markdown
<!-- pr-description:start (rewritten on every push: write your own notes outside this block) -->
## Summary

What the pull request changes and why.

## Changes

- **Area**: Change
<!-- pr-description:end -->

Write your own notes or Closes #12 outside the block: they are kept as they are. A pull request template that holds the block gets it filled in place (see Pull request template); otherwise the block goes on top of the body. Delete the block to get a fresh one on top at the next push.