Skip to content

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:

  1. Fetches the PR diff via the GitHub API
  2. Looks for a PR template in the repository (.github/PULL_REQUEST_TEMPLATE.md, PULL_REQUEST_TEMPLATE.md, or docs/PULL_REQUEST_TEMPLATE.md)
  3. If a template is found — Copilot fills it in preserving all headings, sections, and checkboxes
  4. If no template is found — Copilot generates structured suggestions (description, change type, testing approach, impact areas, breaking changes)
  5. Posts the result as a PR comment
  6. Deletes any previous auto-fill comment on re-runs (keeps the PR clean)
  7. 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_SUMMARY

File 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 + reopened

Template Service

TemplateFieldsOutput

typescript
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:

PriorityPath
1.github/PULL_REQUEST_TEMPLATE.md
2PULL_REQUEST_TEMPLATE.md
3docs/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 keywords

Setup

Add your PR Template

Place your template at .github/PULL_REQUEST_TEMPLATE.md in any repo using this workflow. Example:

markdown
## 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:

yaml
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

bash
GITHUB_TOKEN=$(gh auth token) bun run src/copilot/generate/test-local.ts \
  --owner your-org \
  --repo your-repo \
  --pr 42 \
  --type template

In GitHub Actions

The workflow triggers automatically when a PR is opened against main. To test manually:

  1. Push a branch with changes
  2. Open a PR against main
  3. Go to Actions tab and watch Copilot PR Template Auto-fill
  4. Check the PR comment — it will contain either the pre-filled template or structured suggestions

Performance

AspectNotes
SpeedCompletes in 15–40 seconds (diff fetch + Copilot call run in parallel)
CostUses gpt-5-mini by default — inexpensive
TriggersOnce per PR (opened only)
ConcurrencyCancel-in-progress per PR number
IdempotentPrevious bot comment is deleted before posting a new one

Troubleshooting

Auto-fill comment doesn't appear

  1. Go to PR → Actions tab
  2. Look for Copilot PR Template Auto-fill
  3. If it failed, check the step logs
  4. Verify COPILOT_TOKEN secret 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.ts script

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.

bash
# Get a valid token
gh auth login
gh auth token   # copy the gho_ token

See Also