Auto-PR¶
Centralized AI coding agent pipeline. Developers can create new PRs from Linear comments and iterate on existing PRs from GitHub comments, without installing workflows in each target repo.
How It Works¶
There are two supported trigger flows:
A) Create a New PR (Linear)¶
- A developer posts on a Linear issue:
@auto-pr scenarix/frontend-app Fix the null pointer in the login form - Worker receives
/webhook/linear, verifies signature and allowlist, then dispatches to GitHub Actions - Central workflow clones target repo, runs Aider, creates branch/commit, opens a PR
- Result is reported back to Linear
B) Iterate on an Existing PR (GitHub)¶
- A developer comments on a PR:
@auto-pr Please handle empty input and update tests - Worker receives
/webhook/github, verifies signature and allowlist, then dispatches to GitHub Actions - Central workflow checks out that PR head branch, runs Aider, and pushes follow-up commits to the same branch
- Result is posted as a PR comment
Architecture¶
Trigger source (Linear issue comment OR GitHub PR comment)
│
▼
Cloudflare Worker (/webhook/linear, /webhook/github)
│
├── Verify HMAC signature + allowlists
├── Parse @auto-pr instruction text
▼
GitHub Actions (in scenarix/auto-pr via repository_dispatch)
│
├── Generate GitHub App token scoped to target repo
├── Configure AWS credentials via OIDC
├── Clone target repo
├── Fetch context from source (Linear issue details, etc.)
├── Run Aider with AWS Bedrock (Claude)
├── New PR mode: create branch + open PR
├── Iteration mode: update existing PR branch
└── Report result to source (Linear or PR comment)
Project Structure¶
auto-pr/
├── .github/workflows/
│ ├── ai-worker.yml # Central orchestrator (thin — calls scripts)
│ ├── ai-worker-cc.yml # Claude Code orchestrator
│ ├── ai-review-worker-cc.yml # Centralized PR review workflow
│ ├── preview-deploy.yml # Preview deploy/teardown workflow
│ └── deploy-worker.yml # CI/CD for Cloudflare Worker
├── worker/
│ ├── src/
│ │ ├── index.js # Router (maps routes to handlers)
│ │ ├── handlers/
│ │ │ ├── linear.js # Linear webhook handler
│ │ │ └── github.js # GitHub webhook handler (review + preview)
│ │ └── lib/
│ │ ├── crypto.js # HMAC verification
│ │ ├── dispatch.js # GitHub dispatch + acknowledgement
│ │ └── utils.js # json(), log()
│ ├── wrangler.toml # Worker config + allowed actors/repos
│ └── package.json
├── scripts/
│ ├── run-aider.sh # Aider wrapper (reads prompt template)
│ ├── run-claude-code.sh # Claude Code wrapper
│ ├── fetch-context.sh # Source-aware context resolution
│ ├── create-pr.sh # PR creation with formatted body
│ ├── report-result.sh # Source-aware result reporting
│ ├── coolify-deploy.sh # Coolify API: create/update + deploy preview app
│ └── coolify-teardown.sh # Coolify API: delete preview app
├── coolify-preview-infra/
│ ├── README.md # Coolify setup, DNS, env vars, secrets
│ └── terraform/ # EC2 + Coolify infrastructure
│ ├── main.tf # EC2 instance, security group, EIP, key pair
│ ├── variables.tf
│ └── outputs.tf
├── prompts/
│ └── 2026-02-23-v1.md # Prompt template (versioned by date)
├── .gitignore
└── README.md
Setup¶
1. Create a GitHub App¶
- Navigate to Scenarix org settings → Developer settings → GitHub Apps → New
- Set permissions:
- Repository: Contents (read + write)
- Repository: Pull requests (read + write)
- Repository: Metadata (read)
- Events: none needed
- Generate and download the private key (.pem file)
- Note the App ID
- Install the app on the Scenarix organization (all repos or specific ones)
2. Create a Linear API Key¶
- Linear Settings → API → Create new key
- Scopes: Read + Create Comments
- Save the key (needed as both a Worker secret and a GitHub Actions secret)
3. Set Up AWS Bedrock OIDC Role¶
- In AWS IAM, create an OIDC identity provider for
token.actions.githubusercontent.com(if not already done) - Create an IAM role (e.g.
auto-pr-bedrock-role) with: - Trust policy: allow
sts:AssumeRoleWithWebIdentityfrom the OIDC provider, restricted torepo:scenarix/auto-pr:* - Permission policy:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", "bedrock:ListFoundationModels", "bedrock:ListInferenceProfiles" ], "Resource": "*" } ] } - Note the role ARN
4. Configure GitHub Actions Secrets and Variables¶
In the scenarix/auto-pr repo settings:
If some of these are org secrets, need not set them in the repo again.
| Type | Name | Value |
|---|---|---|
| Secret | AUTO_PR_BOT_APP_PRIVATE_KEY |
GitHub App private key PEM |
| Secret | LINEAR_API_KEY |
Linear API key (used by AI workflow + Worker secret sync) |
| Secret | AWS_BEDROCK_ROLE_TO_ASSUME |
AWS role ARN |
| Secret | CLOUDFLARE_API_TOKEN |
Cloudflare API token |
| Secret | CLOUDFLARE_ACCOUNT_ID |
Cloudflare account ID |
| Secret | LINEAR_WEBHOOK_SECRET |
Linear webhook signing secret (synced to Worker secret) |
| Secret | AUTO_PR_GH_WEBHOOK_SECRET |
GitHub webhook signing secret (synced to Worker secret GH_WEBHOOK_SECRET) |
| Variable | AUTO_PR_BOT_APP_ID |
GitHub App ID |
| Variable | AWS_REGION |
us-east-1 |
| Variable | BEDROCK_MODEL |
e.g. bedrock/us.anthropic.claude-opus-4-5-20251101-v1:0 |
Check AWS Bedrock console for the exact model ID or inference profile ID for your region.
5. Set Up Coolify Preview Infrastructure¶
See coolify-preview-infra/README.md for Terraform setup, Coolify configuration, DNS, environment variables, and GitHub Actions secrets/variables.
6. Deploy the Cloudflare Worker¶
Push to main with changes under worker/** (or rerun deploy-worker.yml) and CI will:
- Install Worker dependencies
- Sync Worker runtime secrets from GitHub Actions secrets:
LINEAR_WEBHOOK_SECRETGH_WEBHOOK_SECRET(from GitHub secretAUTO_PR_GH_WEBHOOK_SECRET)AUTO_PR_BOT_APP_IDAUTO_PR_BOT_APP_PRIVATE_KEYLINEAR_API_KEY- Deploy Worker code via
wrangler deploy
No manual wrangler secret put step is needed when using this CI path.
Note the deployed Worker URL (e.g. https://auto-pr-worker.<subdomain>.workers.dev).
7. Configure the Linear Webhook¶
- Linear Settings → Webhooks → Create webhook
- URL:
https://auto-pr-worker.<subdomain>.workers.dev/webhook/linear - Events: select "Issue comments"
- Copy the signing secret → store it in GitHub Actions secret
LINEAR_WEBHOOK_SECRET(step 4), then rerundeploy-worker.yml - Test with "Send test event" and check Worker logs
8. Configure the GitHub Webhook (PR Iteration + Review)¶
On each target repository where you want PR iteration and centralized PR review:
- Settings → Webhooks → Add webhook
- Payload URL:
https://auto-pr-worker.<subdomain>.workers.dev/webhook/github - Content type:
application/json - Secret: set a strong value and store the same value in
scenarix/auto-prsecretAUTO_PR_GH_WEBHOOK_SECRET - Events: select Issue comments and Pull requests
- Save and test with a PR comment containing
@auto-pr ...
Configuration¶
Allowed Actors and Repos¶
These are configured in worker/wrangler.toml as [vars] — update via PR, no manual secret rotation:
[vars]
ALLOWED_ACTOR_EMAILS = '["developer@scenarix.ai","teammate@scenarix.ai"]'
ALLOWED_GITHUB_LOGINS = '["developer-gh","teammate-gh"]'
# Existing command/code-change allowlist name retained for compatibility
ALLOWED_REPOS = '["scenarix/frontend-app","scenarix/api"]'
ALLOWED_REPOS_REVIEW = '["scenarix/frontend-app"]'
ALLOWED_GITHUB_LOGINS is used for GitHub PR-comment iteration (/webhook/github) and must contain lowercase GitHub usernames.
ALLOWED_REPOS controls where @auto-pr command dispatching is allowed (Linear + GitHub issue comments).
ALLOWED_REPOS_REVIEW controls where pull-request auto-review dispatching is allowed.
ALLOWED_REPOS_PREVIEW controls where preview deployments are triggered. Target repos must have a Dockerfile at the repo root.
Branch policy for auto-review and preview deployments:
- triggered for branch -> staging
- triggered for branch -> main
- not triggered for staging -> main
Prompt Template¶
The prompt sent to Aider lives in prompts/ as a versioned markdown file. The active template is set in scripts/run-aider.sh:
PROMPT_TEMPLATE="2026-02-23-v1.md"
To iterate on the prompt: create a new file (e.g. prompts/2026-03-15-v2.md), update the variable in run-aider.sh, and push. Previous versions stay in the repo as history.
Usage¶
Create a new PR from Linear¶
On any Linear issue, post:
@auto-pr scenarix/frontend-app Fix the null pointer in the login form
Result:
- Immediately acknowledge: "Working on it..."
- Clone the repo, run the AI agent, and open a PR
- Post back the PR link (or report failure)
Iterate on an existing PR from GitHub¶
On an existing PR in an allowed repo, post:
@auto-pr Please rename this helper and add tests for the empty input case.
Result:
- Existing PR branch is checked out
- Follow-up commits are pushed to that same branch
- Status is posted as a PR comment
Centralized PR review from GitHub pull_request events¶
When a PR is opened/synchronized/reopened/ready_for_review in an allowed review repo:
- Worker validates signature, allowlist, and branch policy rules.
- Worker dispatches
auto_pr_review_cctoscenarix/auto-pr. - Worker posts an acknowledgement comment that review has been triggered.
ai-review-worker-cc.ymlruns Claude Code review and posts inline comments/verdict.
Preview deployments (branch-based)¶
When a PR is opened/reopened/synchronized against staging or main (except staging -> main) in a repo listed in ALLOWED_REPOS_PREVIEW:
- Worker dispatches
preview_deploytoscenarix/auto-pr. preview-deploy.ymlcalls Coolify API to create/update a preview app and trigger a build.- Once deployed, the preview URL is posted as a PR comment.
- When the PR is closed or merged, Worker dispatches
preview_teardownand the Coolify app is deleted.
Preview apps are named deterministically as preview-<repo_name>-pr-<number> and run on a shared EC2 instance managed by Coolify. Each gets a unique subdomain via Coolify's Traefik reverse proxy.
Target repos must have a Dockerfile at the repo root. Runtime env vars (DB, Redis, API keys, etc.) are stored in the PREVIEW_ENV_VARS GitHub Actions secret and injected per-app via Coolify's API at creation time. GITHUB_PKG_TOKEN for private @scenarix npm packages is set as a build argument in Coolify.
Trigger requirements (important)¶
- Only PR comments containing
@auto-prare considered - Comment author must be in the configured allowlist
- Repository must be in
ALLOWED_REPOSfor command workflows - Repository must be in
ALLOWED_REPOS_REVIEWfor pull_request auto-review workflows - Invalid/missing webhook signatures are rejected
Run Worker tests locally¶
From the repo root:
cd worker
npm ci
Run all Worker tests:
npm test
Run only the GitHub integration test file:
node --test ./test/github-handler.integration.test.js
Agent selection flags¶
By default, Auto-PR dispatches to the Claude Code workflow.
--cc: explicitly use Claude Code workflow--aider: override to use Aider workflow
Flags can be included in either Linear or GitHub instructions and are stripped before sending the final instruction text to the agent.
Examples:
@auto-pr scenarix/frontend-app --aider fix flaky login test and update docs
@auto-pr --cc please refactor this helper and add coverage for empty input
Extensibility¶
The system is designed to be source-agnostic. Each trigger source gets its own route in the Worker and its own blocks in the scripts:
| Component | Linear | Adding a new source |
|---|---|---|
| Worker | worker/src/handlers/linear.js, worker/src/handlers/github.js |
Add worker/src/handlers/slack.js + one line in index.js router |
| Context fetch | scripts/fetch-context.sh |
Add an elif [[ "$SOURCE" == "slack" ]] block |
| Result reporting | scripts/report-result.sh |
Add a "slack" case |
| PR creation | scripts/create-pr.sh |
No changes needed (fully generic) |
| Workflow | ai-worker.yml |
No changes needed (calls scripts via env vars) |
The client_payload.source field tells the workflow where the request came from. The scripts/fetch-context.sh script normalizes any source into generic outputs (identifier, title, description, url) that the core pipeline consumes.