How the Claude Plugins Community Close-External-PRs Workflow Works
The close-external-prs workflow in the anthropics/claude-plugins-community repository automatically closes pull requests from external contributors because the repo is a read-only mirror, while exempting github-actions[bot] to allow automated bump PRs from the internal Bump-Plugin-SHAs workflow to remain open for review.
The close-external-prs workflow is a critical guardrail for this GitHub repository. Since the anthropics/claude-plugins-community repo serves as a public mirror of Anthropic's internal plugin marketplace, direct community contributions via pull request cannot be merged. The workflow enforces this policy gracefully—closing external PRs with an explanatory comment—while carefully preserving the repository's own internal automation.
Trigger Mechanism: Why pull_request_target Matters
The workflow runs on pull_request_target events of types opened or reopened. This choice is deliberate and security-critical.
- Base-repo context: Unlike standard
pull_requestevents,pull_request_targetexecutes in the context of the target repository, not the fork. - Write token availability: This allows the workflow to post comments and close PRs even when they originate from untrusted forks, using a
GITHUB_TOKENwith write permissions.
The workflow grants minimal permissions—only pull-requests: write and issues: write—sufficient for commenting and state changes without exposing broader repository access.
Core Logic in close-external-prs.yml
The implementation in [.github/workflows/close-external-prs.yml](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/close-external-prs.yml) follows a three-tier validation flow:
Step 1: Extract the PR Author
The script reads context.payload.pull_request.user.login to identify who created the pull request. This value is authoritative—it reflects the authenticated GitHub user, not spoofable metadata like branch names.
Step 2: Exempt github-actions[bot]
The critical exemption appears early in the script:
if (author === 'github-actions[bot]') {
console.log(`${author} is this repo's bump automation — allowing PR`);
return;
}
This check prevents the workflow from closing PRs created by the Bump-Plugin-SHAs workflow defined in [.github/workflows/bump-plugin-shas.yml](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/bump-plugin-shas.yml). That nightly automation updates plugin SHAs and creates PRs using the default GITHUB_TOKEN, which attributes authorship to github-actions[bot].
Why author verification beats branch name filtering: A malicious fork could name a branch bump/plugin-shas to impersonate internal automation. The user.login property cannot be forged by external actors, making it the only reliable signal for identifying trusted automation.
Step 3: Check Collaborator Permissions
For non-bot authors, the workflow queries permission levels via repos.getCollaboratorPermissionLevel:
const { data: permission } = await octokit.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: author
});
if (permission.permission === 'admin' || permission.permission === 'write') {
console.log(`${author} has ${permission.permission} access — allowing PR`);
return;
}
Users with admin or write permissions are internal collaborators whose PRs should proceed.
Step 4: Close External PRs
Any remaining PRs—those from external contributors without elevated permissions—trigger the closure sequence:
- Post explanatory comment via
issues.createComment, directing users to the official submission portal atclau.de/plugin-directory-submission - Close the PR via
pulls.updatewithstate: 'closed'
The Automation Ecosystem: How Bump-Plugin-SHAs Creates Exempt PRs
Understanding the exemption requires examining the complementary automation in [.github/workflows/bump-plugin-shas.yml](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/bump-plugin-shas.yml) and its supporting action at .github/actions/bump-plugin-shas.
This workflow runs on a schedule to:
- Detect updated plugin versions from Anthropic's internal registry
- Generate commits with updated SHA references
- Create pull requests using the default
GITHUB_TOKEN
The resulting PRs appear as:
# Commit attribution when using GITHUB_TOKEN
Author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Without the author exemption in close-external-prs.yml, every nightly maintenance PR would be immediately closed, breaking the repository's sync mechanism.
Security Design: Defending Against Evasion
The workflow's architecture reflects careful threat modeling:
| Attack Vector | Mitigation |
|---|---|
Branch name spoofing (bump/*) |
Author verification, not branch pattern matching |
| Fork impersonating internal user | pull_request_target runs in base repo with verified actor identities |
| Token privilege escalation | Minimal permissions declaration; no contents or actions scopes |
| Comment/closure API abuse | Explicit error handling and logging for observability |
Practical Example: External vs. Internal PR Handling
External contributor PR (auto-closed)
When a community member opens a PR from a fork:
# Triggered by: pull_request_target with types: [opened, reopened]
# Author detected: some-external-user
# Permission check: returns 'read' or 'none'
# Result: comment posted, PR closed
The contributor receives:
Thanks for the PR! This repo is a read-only mirror — its contents are synced
nightly from Anthropic's internal review pipeline, so direct pull requests are
closed automatically.
To submit a plugin to the community marketplace, use clau.de/plugin-directory-submission.
Internal bump PR (preserved)
When the scheduled Bump-Plugin-SHAs workflow runs:
# Triggered by: schedule (cron)
# Creates PR with: GITHUB_TOKEN
# Author detected: github-actions[bot]
# Result: early return, PR remains open
The bump PR proceeds through normal review and merge workflow.
Summary
- The close-external-prs workflow uses
pull_request_targetto safely handle PRs from forks with write-level permissions github-actions[bot]is exempted to prevent automatic closure of nightly SHA bump PRs created by the repository's own automation- Author verification (
user.login) provides a non-spoofable signal for identifying trusted automation, unlike branch names or commit messages - Permission level checks allow legitimate maintainers with write/admin access to submit PRs
- All external contributors receive actionable guidance for the correct submission channel instead of silent rejection
Frequently Asked Questions
Why does the workflow use pull_request_target instead of pull_request?
The pull_request_target event runs workflows in the context of the base repository with access to secrets and write tokens, even when triggered by forks. This is necessary because the workflow must close PRs and post comments, which requires write permissions that pull_request events from forks cannot safely receive. The trade-off requires careful code review since the workflow executes untrusted PR code in a privileged context.
Could an attacker bypass the github-actions[bot] exemption by naming their account similarly?
No. GitHub strictly controls the github-actions[bot] identity. Only workflows running with the default GITHUB_TOKEN can create commits and PRs attributed to this bot. External users cannot register accounts with brackets or impersonate this system identity—the user.login value is cryptographically verified by GitHub's authentication system.
What happens if the Bump-Plugin-SHAs workflow uses a custom token instead of GITHUB_TOKEN?
If the bump workflow used a Personal Access Token (PAT) or GitHub App token, the PR author would reflect that token's owner rather than github-actions[bot]. The close-external-prs exemption would need updating to include that new actor, or the bump workflow would need to retain the default token for PR creation specifically. The current design intentionally uses GITHUB_TOKEN to simplify identity verification.
Where is the official plugin submission process documented for users whose PRs are closed?
The workflow's closure comment directs contributors to clau.de/plugin-directory-submission. This external portal represents Anthropic's internal review pipeline—the same system that feeds the nightly sync into this read-only mirror. The comment template is defined in the workflow's JavaScript execution context within [.github/workflows/close-external-prs.yml](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/close-external-prs.yml).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →