PR Template Auto-fill with Copilot SDK
Automatically pre-fills your PR description when a pull request is opened, using the Copilot SDK to analyze the diff. If a PR template exists in the repository, Copilot fills it in directly. Otherwise it posts structured suggestions you can copy into your description.
Overview
When you open a pull request the Copilot PR Template Auto-fill workflow triggers once (opened event) and:
- Fetches the PR diff via the GitHub API
- Looks for a PR template in the repository (
.github/PULL_REQUEST_TEMPLATE.md,PULL_REQUEST_TEMPLATE.md, ordocs/PULL_REQUEST_TEMPLATE.md) - If a template is found — Copilot fills it in preserving all headings, sections, and checkboxes
- If no template is found — Copilot generates structured suggestions (description, change type, testing approach, impact areas, breaking changes)
- Posts the result as a PR comment
- Deletes any previous auto-fill comment on re-runs (keeps the PR clean)
- Writes the output to the Actions job summary
Output Modes
Mode 1 — Template Found (pre-filled template)
When a PULL_REQUEST_TEMPLATE.md exists, the comment contains your template with every section filled in by Copilot:
## 🤖 Copilot PR Auto-fill
Based on your changes, here is a pre-filled PR description.
Copy the content below into your PR description:
---
## Description
Adds a persistent multi-turn chat session to the Copilot CLI...
## Type of change
- [x] New feature (non-breaking change that adds functionality)
- [ ] Bug fix
## Testing
- [ ] Unit tests added for `ChatSession`
- [x] Manually tested with `bun run chat`
---
*Generated by [Copilot Tools] · Copy the content above into your PR description.*Mode 2 — No Template Found (structured suggestions)
When no template is found, the comment posts structured field suggestions:
## 🤖 Copilot PR Auto-fill
> No PR template was found. Use the suggested values below to fill in your PR description.
**Description**
Adds real-time streaming to the Copilot chat interface...
**Change Type:** ✨ `feature`
**Testing Approach**
Run `bun test src/copilot/chat/` and manually verify streaming output...
**📌 Potential Impact Areas**
- src/copilot/chat/
- src/shared/copilot.client.ts
---
*Generated by [Copilot Tools] · Copy the values above into your PR description.*How It Works
Architecture
PR opened
↓
copilot-pr-autofill.yml
↓
.github/actions/copilot (tool: generate, type: template)
↓
GenerateTool → GenerateService → TemplateService
↓
├── getPRDiff() ← GitHub API (parallel)
└── fetchPRTemplate() ← GitHub API (parallel, graceful fallback)
↓
[template found] [no template]
fillTemplate() generateStructuredFields()
(Copilot fills template) (Copilot returns JSON)
↓
formatAsMarkdown()
↓
Write to /tmp/pr-autofill.md + footer
↓
Delete previous bot comment → Post new comment
↓
Write to GITHUB_STEP_SUMMARYFile Structure
src/copilot/generate/
├── template.service.ts — fetches template, fills it or generates structured fields
├── generate.service.ts — routes "template" type to TemplateService
├── generate.schema.ts — Zod schema (type: "template" enum)
└── index.ts — GenerateTool entry point
.github/
└── workflows/
├── copilot-pr-autofill.yml — runs on PR opened
├── copilot-pr-autofill.reusable.yml — workflow_call variant (for other repos)
└── copilot-pr-summary.yml — runs on opened + synchronize + reopenedTemplate Service
TemplateFieldsOutput
interface TemplateFieldsOutput {
description: string; // 1-2 sentence summary
changeType: // bug | feature | refactor | docs | perf | breaking
| "bug" | "feature" | "refactor" | "docs" | "perf" | "breaking";
testingApproach: string; // Concrete testing steps
impactAreas: string[]; // Affected code areas
breakingChanges: string[]; // Breaking changes (empty array if none)
filledTemplate?: string; // Set when a PR template was found and filled
}Template Discovery
TemplateService tries these paths in order and uses the first match:
| Priority | Path |
|---|---|
| 1 | .github/PULL_REQUEST_TEMPLATE.md |
| 2 | PULL_REQUEST_TEMPLATE.md |
| 3 | docs/PULL_REQUEST_TEMPLATE.md |
If none exist, the service falls back to the structured analysis mode.
Fallback Chain
Copilot fills template → success: filledTemplate set
↓ (on error)
generateStructuredFields() → success: structured JSON fields
↓ (on error)
getFallbackFields() → heuristic detection from PR title keywordsSetup
Add your PR Template
Place your template at .github/PULL_REQUEST_TEMPLATE.md in any repo using this workflow. Example:
## Description
<!-- Describe the changes and why you made them -->
## Type of change
- [ ] Bug fix
- [ ] New feature
- [ ] Refactor
- [ ] Documentation
## Testing
- [ ] Unit tests added or updated
- [ ] Manually tested
## Breaking changes
<!-- List any breaking changes, or "None" -->Copilot will fill every section based on the PR diff while preserving the structure.
Workflow Configuration
The model is defined once as a job-level env var and reused in both the action call and the footer:
jobs:
autofill:
env:
MODEL: gpt-5-mini # change here to update everywhere
steps:
- uses: ./.github/actions/copilot
with:
model: ${{ env.MODEL }}
options: '{"type":"template"}'Usage
Manual Testing
GITHUB_TOKEN=$(gh auth token) bun run src/copilot/generate/test-local.ts \
--owner your-org \
--repo your-repo \
--pr 42 \
--type templateIn GitHub Actions
The workflow triggers automatically when a PR is opened against main. To test manually:
- Push a branch with changes
- Open a PR against
main - Go to Actions tab and watch Copilot PR Template Auto-fill
- Check the PR comment — it will contain either the pre-filled template or structured suggestions
Performance
| Aspect | Notes |
|---|---|
| Speed | Completes in 15–40 seconds (diff fetch + Copilot call run in parallel) |
| Cost | Uses gpt-5-mini by default — inexpensive |
| Triggers | Once per PR (opened only) |
| Concurrency | Cancel-in-progress per PR number |
| Idempotent | Previous bot comment is deleted before posting a new one |
Troubleshooting
Auto-fill comment doesn't appear
- Go to PR → Actions tab
- Look for Copilot PR Template Auto-fill
- If it failed, check the step logs
- Verify
COPILOT_TOKENsecret is set (Settings → Secrets → Actions)
Generated content doesn't match my template
Ensure your template is committed to the default branch (main) at one of the discovered paths. The diff fetch and template fetch happen in parallel at PR open time.
Analysis is inaccurate
- Make sure the PR title is descriptive
- Re-run the workflow (Actions tab → re-run jobs)
- Test locally with the
test-local.tsscript
Token errors
The COPILOT_TOKEN must be an OAuth user token (gho_ prefix) from an account with an active Copilot subscription. Classic PATs (ghp_) are not supported.
# Get a valid token
gh auth login
gh auth token # copy the gho_ tokenSee Also
- Copilot PR Summary Workflow
- Reusable Workflows — use this workflow in other repos
- Copilot Chat & Sessions
- GitHub Actions — Reusable Workflows