A GitHub Action that turns prompts into Pull Requests using LLMs. Point it at files, describe what to change, and get an automated PR — on push, on schedule, or on demand.
/!\ This is an early production, please report issues (code, bug, vulnerabilities) when you spot one
Get a working Prompt2PR workflow in under 5 minutes:
-
Get an API key from your LLM provider (see Provider Setup below).
-
Add the key as a GitHub Secret in your repository under Settings → Secrets and variables → Actions (e.g.,
OPENAI_API_KEY). -
Create a workflow file at
.github/workflows/sync-readme.yml:name: Sync README on: schedule: # Every Wednesday at 8:00 UTC - cron: '0 8 * * 3' workflow_dispatch: inputs: prompt: description: 'Custom prompt (optional — overrides default)' required: false default: '' permissions: contents: write pull-requests: write jobs: sync-readme: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: davd-gzl/Prompt2PR@v1 with: prompt: >- ${{ github.event.inputs.prompt || 'Compare the README.md with the actual source code. Find any code examples, API references, or configuration options in the README that are outdated or do not match the current implementation. Update the README to accurately reflect the code. Do not change source files — only update README.md.' }} provider: openai paths: 'src/**,README.md' max_files: 1 max_changes: 200 label: 'prompt2pr,documentation' env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
Trigger the workflow — it runs automatically every Wednesday, or you can trigger it manually from the Actions tab with an optional custom prompt. See Scheduling & Triggers for more options.
All inputs are configured via the standard GitHub Actions with: syntax.
| Input | Required | Default | Description |
|---|---|---|---|
prompt |
yes | — | Plain-English instruction describing what changes to make. Sent to the LLM along with scoped file contents. |
provider |
yes | — | LLM provider: mistral, openai, anthropic, or github. |
model |
no | (see below) | Model identifier. If omitted, the provider's default model is used. |
paths |
no | ** |
Comma-separated glob patterns for files to include as context and allow modifications. |
max_files |
no | 10 |
Maximum number of files the LLM may modify in a single run. Responses exceeding this are rejected. |
max_changes |
no | 200 |
Maximum total lines changed across all files. Responses exceeding this are rejected. |
label |
no | prompt2pr |
Comma-separated labels to apply to the PR. prompt2pr is always included. |
branch_prefix |
no | prompt2pr/ |
Prefix for the created branch name. Full name: {prefix}{timestamp}. |
dry_run |
no | false |
When true, runs the full pipeline but skips branch creation and PR submission. |
base_url |
no | (empty) | Override the LLM provider API base URL (useful for proxies or self-hosted endpoints). |
| Provider | Default Model |
|---|---|
mistral |
mistral-large-latest |
openai |
gpt-4o |
anthropic |
claude-sonnet-4-20250514 |
github |
openai/gpt-4o |
The action sets several outputs you can use in downstream steps.
| Output | Type | Description |
|---|---|---|
pr_url |
string |
URL of the created Pull Request. Empty when dry_run: true or no changes detected. |
pr_number |
string |
Number of the created Pull Request. Empty when dry_run: true or no changes detected. |
files_changed |
string |
Number of files the LLM modified. Set even in dry-run mode. |
lines_changed |
string |
Total lines changed across all modified files. Set even in dry-run mode. |
skipped |
string |
"true" if PR creation was skipped (no changes detected or dry_run enabled). "false" otherwise. |
- uses: davd-gzl/Prompt2PR@v1
id: p2pr
with:
prompt: 'Add missing JSDoc comments to all exported functions'
provider: openai
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Only runs if a PR was actually created
- if: steps.p2pr.outputs.skipped != 'true'
run: |
echo "PR: ${{ steps.p2pr.outputs.pr_url }}"
echo "Changed ${{ steps.p2pr.outputs.files_changed }} files (${{ steps.p2pr.outputs.lines_changed }} lines)"
# Useful for dry-run auditing
- if: steps.p2pr.outputs.skipped == 'true'
run: |
echo "No PR created."
echo "Would have changed ${{ steps.p2pr.outputs.files_changed }} files (${{ steps.p2pr.outputs.lines_changed }} lines)"Prompt2PR is a standard GitHub Action — it works with any trigger you'd use
in normal CI. The prompt can be hardcoded in the workflow file, typed in
manually, or pulled from event context (commit message, issue body, comment,
etc.).
Run automatically when code is pushed, just like a linter or test suite:
on:
push:
branches: [main]
paths: ['src/**']
jobs:
prompt2pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: davd-gzl/Prompt2PR@v1
with:
prompt:
'Review recent changes for bugs, dead imports, and code smells. Fix
any issues.'
provider: mistral
paths: 'src/**'
env:
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Run automatically on a recurring schedule:
on:
schedule:
# Every Monday at 9:00 UTC
- cron: '0 9 * * 1'Run on demand from the Actions tab:
on:
workflow_dispatch:
inputs:
prompt:
description: 'What should the AI fix?'
required: trueCombine a schedule with a manual override:
on:
schedule:
- cron: '0 9 * * 1'
workflow_dispatch:
inputs:
prompt:
description: 'Custom prompt (optional)'
required: false
default: ''Use event context as the prompt — for example, trigger from an issue body:
on:
issues:
types: [opened, labeled]
jobs:
prompt2pr:
if: contains(github.event.issue.labels.*.name, 'prompt2pr')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: davd-gzl/Prompt2PR@v1
with:
prompt: ${{ github.event.issue.body }}
provider: mistral
env:
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Ready-to-use workflow files organized by use case in the
examples/ directory. Copy any file to .github/workflows/ in
your repository. See each category's readme for detailed descriptions.
Providers are interchangeable. Each example uses a specific provider, but you can swap
provider:and the corresponding API key to use any supported provider.Single-shot design. Prompt2PR makes one LLM call per run — it cannot run tests or iterate on its output. Internet access depends on the model and provider (some models can browse the web, others cannot). The examples below are designed with this in mind.
Keep your docs accurate and up to date.
| Workflow | Description | Trigger |
|---|---|---|
| update-copyright.yml | Update copyright year across all files | Yearly cron |
| sync-readme.yml | Keep readme in sync with actual source code | Weekly cron |
| translate-docs.yml | Translate Markdown docs into another language | Manual |
Improve code structure, safety, and standards compliance.
| Workflow | Description | Trigger |
|---|---|---|
| add-jsdoc.yml | Add missing JSDoc comments to exported functions | Manual |
| enforce-style-guide.yml | Fix naming conventions and replace magic numbers | Push to main |
| add-error-handling.yml | Add try/catch blocks and input validation | Manual |
| generate-tests.yml | Generate unit tests for untested functions | Weekly cron |
Event-driven workflows and change previews.
| Workflow | Description | Trigger |
|---|---|---|
| accessibility-audit.yml | Audit frontend files for a11y issues | Weekly cron |
| dry-run-audit.yml | Preview changes without creating a PR (dry_run: true) |
Manual |
| on-issue-comment.yml | Trigger via /prompt2pr comment on issues |
Issue comment |
Handle routine cleanup and housekeeping.
| Workflow | Description | Trigger |
|---|---|---|
| improve-logging.yml | Replace console.log with structured logging | Manual |
| cleanup-todos.yml | Remove resolved TODO/FIXME/HACK comments | Weekly cron |
| fix-dead-links.yml | Fix broken or dead links in Markdown files | Weekly cron |
Prompt2PR supports four LLM providers. Providers are interchangeable — pick
whichever you prefer and swap the provider: input and API key.
- Sign up at console.mistral.ai.
- Navigate to API Keys and create a new key.
- In your GitHub repository, go to Settings → Secrets and variables → Actions
and add
MISTRAL_API_KEYwith your key-value. - Set
provider: mistralin your workflow.
- Sign up at platform.openai.com.
- Navigate to API Keys and create a new secret key.
- In your GitHub repository, add
OPENAI_API_KEYas a GitHub Secret. - Set
provider: openaiin your workflow.
- Sign up at console.anthropic.com.
- Navigate to API Keys and create a new key.
- In your GitHub repository, add
ANTHROPIC_API_KEYas a GitHub Secret. - Set
provider: anthropicin your workflow.
Use LLMs directly through GitHub's built-in Models API — no external API key needed. This works with any GitHub Copilot subscription.
- Ensure your GitHub account has access to GitHub Models.
- No additional secrets required — the built-in
GITHUB_TOKENis used for authentication. - Add
models: readto your workflow permissions. - Set
provider: githuband use models inpublisher/model-nameformat (e.g.,openai/gpt-4o,anthropic/claude-sonnet-4.5).
permissions:
contents: write
pull-requests: write
models: read
jobs:
prompt2pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: davd-gzl/Prompt2PR@v1
with:
prompt: 'Fix typos in README.md'
provider: github
model: openai/gpt-4o
paths: 'README.md'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Check the workflow run logs in the Actions tab. Common causes:
- No changes detected — The LLM found nothing to change. The log will say
"Found 0 issues. No PR created.". Theskippedoutput will be"true". - Dry run enabled — If
dry_run: true, the pipeline runs but skips PR creation. Checkfiles_changedandlines_changedoutputs to see what would have been modified.
Missing API key: environment variable 'MISTRAL_API_KEY' is not set.
Make sure you have added the correct secret in Settings → Secrets and variables
→ Actions and passed it via the env: block in your workflow:
env:
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Each provider expects a specific environment variable:
| Provider | Environment Variable |
|---|---|
mistral |
MISTRAL_API_KEY |
openai |
OPENAI_API_KEY |
anthropic |
ANTHROPIC_API_KEY |
github |
GITHUB_TOKEN (built-in) |
If the LLM provider returns HTTP 429 (rate limited), Prompt2PR automatically retries once after a 5-second backoff. If it still fails, the run will error with details about the rate limit. Consider:
- Upgrading your API plan for higher limits.
- Reducing the
pathsscope to send fewer files. - Running the action less frequently.
If you scope too many files, the total context may exceed the LLM's token limit. To fix this:
- Narrow the
pathsinput (e.g.,src/**/*.tsinstead of**). - The action automatically tracks file sizes and truncates content when limits are approached, logging a warning when this happens.
Prompt2PR needs contents: write and pull-requests: write permissions. Add
these to your workflow:
permissions:
contents: write
pull-requests: writeYou must also enable PR creation at the repository level: go to Settings → Actions → General → Workflow permissions and check "Allow GitHub Actions to create and approve pull requests". Without this, the action will fail with:
GitHub Actions is not permitted to create or approve pull requests.
Guardrail violation: Number of changed files (15) exceeds max_files (10).
The LLM tried to modify more files or lines than allowed. Increase max_files
or max_changes if the change is expected, or narrow the paths scope to give
the LLM less to work with.
If the LLM tries to modify files outside your paths globs, the guardrail will
reject the change:
Guardrail violation: File "config/secrets.json" is outside the allowed paths scope.
This is a safety feature. If you need the LLM to modify those files, expand your
paths input.
See the full Roadmap for what's coming next, including:
- PR deduplication and auto-assign reviewers
- LiteLLM proxy mode for any provider
- Agentic mode — multi-step LLM loops with tool use (read files, run tests, explore codebase)
- Structured prompts DSL —
task,scope,rulesfor precision - Community prompt templates and a prompt marketplace
- Cross-repo dashboard and self-improving prompts
- Node.js 20 (see
.node-version) - npm
# Install dependencies
npm install
# Run the full pipeline: format, lint, test, coverage badge, bundle
npm run all| Script | Description |
|---|---|
npm run all |
Format + lint + test + coverage + bundle |
npm test |
Run Jest tests with ESM support |
npm run lint |
Run ESLint |
npm run bundle |
Format + Rollup bundle to dist/index.js |
npm run local-action |
Test locally with @github/local-action |
- Copy
.env.exampleto.envand fill in your API keys. - Run
npm run local-actionto simulate a GitHub Actions run locally.
Use the release script to tag and publish a new version:
script/releaseThis handles SemVer tagging (v1.x.x) and floats the major tag (v1) for users
referencing @v1.