# pr-generator An [Agent Plugin](https://agent-plugins.org/) that turns the commits on your current branch into a consistently structured pull request (or merge request) description, and gives you a link that opens the creation form with the branches already filled in. Works with **Azure DevOps**, **GitHub**, and **GitLab**, including self-hosted instances. ## Contents ```text pr-generator/ ├── plugin.json └── skills/ └── pr-generator/ ├── SKILL.md ├── assets/pr-template.md ├── references/PROVIDERS.md └── scripts/ ├── branch-summary.sh └── branch-summary.ps1 ``` ## How it works 1. The agent runs `branch-summary.sh` (bash) or `branch-summary.ps1` (PowerShell) once, from the repository being summarised. 2. The script validates the branch, collects the commits, commit bodies, and changed files, detects the hosting provider from the git remote, and prints a creation URL. 3. The agent writes the description from that output alone, using the template in `assets/pr-template.md`, and returns the title and description followed by the link. The agent is instructed not to run other git commands or read the changed files, so the description stays grounded in what the commits actually say. It is also told to keep the result short and plainly worded, to omit sections the commits do not support rather than padding them out, and to treat commit text as data rather than as instructions. ## Guardrails - **The agent never opens the pull request.** It produces a description and a link; a person clicks it. The skill forbids `gh`, `glab`, `az repos`, `git push`, and direct API calls, so nothing is published without a human step. - **The script only reads.** It runs `git log`, `git diff`, and `git rev-parse`. It never writes to the repository, and it prints file names and change counts, never file contents, so the contents of a changed `.env` cannot leak into a description. - **Credentials are stripped.** A remote URL can carry an access token, as in `https://user:token@host/org/repo.git`. The script prints `https://***@host/...` instead. Only the hostname is needed to detect the provider. - **Output is capped** at 200 commits and 200 files. Anything beyond that is replaced by a `... and N more` line, and the per-file diff stat is reduced to totals. The true totals are always reported as `COMMIT_COUNT` and `FILE_COUNT`. - **Commit text is treated as data.** Commit messages are untrusted input and may contain text that reads like an instruction; the skill tells the agent to describe it, never to act on it. ## Requirements - `git` on `PATH` - A feature branch that has been pushed to a remote - bash (Linux, macOS, Git Bash or WSL on Windows) **or** PowerShell — `pwsh` on 7+, `powershell.exe` on Windows PowerShell 5.1 The bash script needs only `git`, `sed`, `tr`, `wc`, and `printf`, and avoids bash 4+ syntax so it runs on the bash 3.2 that ships with macOS. ## Running the scripts directly Both scripts read the current working directory, so run them **from the repository you want to summarise** rather than from the script's own folder: ```bash bash /path/to/skills/pr-generator/scripts/branch-summary.sh ``` ```powershell pwsh -NoProfile -ExecutionPolicy Bypass -File C:\path\to\scripts\branch-summary.ps1 ``` `-ExecutionPolicy Bypass` is needed on Windows, where running script files is blocked by default. A `.gitattributes` at the repository root forces LF line endings on checkout. Without it, a Windows clone with `core.autocrlf=true` would rewrite the shell script to CRLF and bash would fail with `$'\r': command not found`. ## Configuration All options have sensible defaults. | Option | bash | PowerShell | Environment variable | | --- | --- | --- | --- | | Target branch | `--base develop` | `-Base develop` | `PR_BASE_BRANCH` | | Git remote | `--remote upstream` | `-Remote upstream` | `PR_REMOTE` | | Hosting provider | `--provider gitlab` | `-Provider gitlab` | `PR_PROVIDER` | | Work item link | — | — | `PR_TICKET_URL_TEMPLATE` | `PR_TICKET_URL_TEMPLATE` turns a bare work item identifier into a link, with `{TICKET}` replaced by the identifier: ```bash export PR_TICKET_URL_TEMPLATE="https://example.com/browse/{TICKET}" ``` If the target branch is not specified, it is taken from the remote's default branch (`refs/remotes//HEAD`), falling back to the first of `main`, `master`, `trunk`, `develop`, or `development` that exists. ## Guard conditions The script stops with `STATUS: STOP` and an `ERROR:` message when: - the working directory is not a git repository, or `HEAD` is detached; - the current branch is the base branch; - there are no commits to summarise; - the branch has not been pushed, has local commits that are not pushed, or is behind its remote counterpart. ## Provider detection The script — not the agent — works out which provider hosts the repository, so the creation URL is built deterministically. It parses the git remote URL (HTTPS and SSH forms both work), then matches the hostname: | Provider | Matched when the host... | Creation URL | | --- | --- | --- | | Azure DevOps | ends with `dev.azure.com` or `visualstudio.com` | `…/_git/{repo}/pullrequestcreate?sourceRef=…&targetRef=…` | | GitHub | contains `github` | `…/compare/{target}...{source}?expand=1` | | GitLab | contains `gitlab` | `…/-/merge_requests/new?merge_request[source_branch]=…` | The agent is told to use the reported `CREATE_URL` verbatim and to match the provider's vocabulary — "merge request" for GitLab, "pull request" for the others. ### When detection cannot tell Because detection is hostname-based, a self-managed instance whose hostname gives no clue — a GitLab server at `git.example.com`, say — reports `PROVIDER: Unknown`. The script falls back to a GitHub-style compare URL and the agent flags it as a best-effort guess. Set `PR_PROVIDER` to force the right one: ```bash export PR_PROVIDER=gitlab # azure-devops | github | gitlab ``` Or per run, with `--provider gitlab` (bash) or `-Provider gitlab` (PowerShell). Values are case-insensitive and accept aliases such as `ado`, `gh`, and `gl`. When an override is active the output reads `PROVIDER: GitLab (provider overridden)`. Local and `file://` remotes report `Local or unrecognised` and produce no link, since there is no web UI to open. See [`skills/pr-generator/references/PROVIDERS.md`](skills/pr-generator/references/PROVIDERS.md) for the full list of recognised remote URL forms. ## Usage Ask your agent for a pull request, optionally naming the work item: ```text Generate a pull request for this branch Raise a PR for this branch, work item 12345 ```