From 9b85d3d6bbe2e505cabe0ad6d73844d2268a27e3 Mon Sep 17 00:00:00 2001 From: Damien Daspit Date: Thu, 1 Oct 2026 13:53:24 -0400 Subject: [PATCH 1/3] Start a port when a porting issue is created A porting issue is created with the porting label, and that label now starts the @claude workflow, which ports the change with the port-pr skill and opens a pull request. A merged PR now gets a porting issue only when it has the needs porting label. Every new PR gets the label, so porting stays the default, and the author removes it to opt out. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/claude.yml | 9 ++++++--- .github/workflows/create-porting-issue.yml | 4 +++- .github/workflows/label-needs-porting.yml | 23 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/label-needs-porting.yml diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 7a4cfd18..7dc9a3a8 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -6,7 +6,7 @@ on: pull_request_review_comment: types: [created] issues: - types: [opened, assigned] + types: [opened, assigned, labeled] pull_request_review: types: [submitted] @@ -29,7 +29,8 @@ jobs: ((github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))) + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) || + (github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'porting')) runs-on: ubuntu-latest permissions: contents: read @@ -75,6 +76,8 @@ jobs: uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + # Porting issues are created with this label, so each one starts a port. + label_trigger: porting # This is an optional setting that allows Claude to read CI results on PRs additional_permissions: | @@ -84,6 +87,6 @@ jobs: # appended prompt has Claude open the pull request itself. claude_args: >- --allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh issue view:*),Bash(git log:*),Bash(git blame:*),Bash(git show:*),Bash(git diff:*),Bash(git status:*),Bash(poetry run:*),Bash(./local_check.sh:*)" - --append-system-prompt "When invoked on an issue and you change code, open the pull request yourself once your commits are pushed: gh pr create --base main --head . Post its link in your comment in place of a Create a PR link. Write the title and body with the pr-authoring skill, and put Closes # in the body. Before opening it, run ./local_check.sh --agent-strict and report its result in the body. Dependencies are already installed, and you work on the branch this action created: where a skill such as port-pr says to install, create or switch branches, or push, commit on the current branch and push it the way these instructions say." + --append-system-prompt "When invoked on an issue and you change code, open the pull request yourself once your commits are pushed: gh pr create --base main --head . Post its link in your comment in place of a Create a PR link. Write the title and body with the pr-authoring skill, and put Closes # in the body. Before opening it, run ./local_check.sh --agent-strict and report its result in the body. Dependencies are already installed, and you work on the branch this action created: where a skill such as port-pr says to install, create or switch branches, or push, commit on the current branch and push it the way these instructions say. When the issue is labeled porting, port it with the port-pr skill." # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://code.claude.com/docs/en/cli-reference for available options diff --git a/.github/workflows/create-porting-issue.yml b/.github/workflows/create-porting-issue.yml index f62c0a31..2ee6293a 100644 --- a/.github/workflows/create-porting-issue.yml +++ b/.github/workflows/create-porting-issue.yml @@ -10,7 +10,9 @@ permissions: jobs: create-port-issue: - if: github.event.pull_request.merged == true + if: | + github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'needs porting') runs-on: ubuntu-latest steps: diff --git a/.github/workflows/label-needs-porting.yml b/.github/workflows/label-needs-porting.yml new file mode 100644 index 00000000..c46ed59f --- /dev/null +++ b/.github/workflows/label-needs-porting.yml @@ -0,0 +1,23 @@ +name: Label Needs Porting + +on: + # pull_request_target so fork PRs get a token that can write labels. It is safe here + # because the job never checks out or runs the PR's code. + pull_request_target: + types: [opened] + +permissions: + issues: write + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + steps: + # Every PR is ported by default. The author removes the label to opt out. + - name: Add needs porting label + env: + GH_TOKEN: ${{ github.token }} + run: >- + gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels" + -f "labels[]=needs porting" From dd64807fca2569931e33d98fe973edaabf33dea0 Mon Sep 17 00:00:00 2001 From: Damien Daspit Date: Thu, 1 Oct 2026 14:43:37 -0400 Subject: [PATCH 2/3] Skip runs that a label cannot start The mention clause did not check the event action, so adding any label to an issue that mentions @claude ran the full job before the action exited. It now skips labeled events. It also skips porting issues, which the label clause already starts, so one issue cannot start two ports. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/claude.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 7dc9a3a8..af1ed05a 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -29,7 +29,8 @@ jobs: ((github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) || + (github.event_name == 'issues' && github.event.action != 'labeled' && + !contains(github.event.issue.labels.*.name, 'porting') && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) || (github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'porting')) runs-on: ubuntu-latest permissions: From f3df62ac423d90aa7625f71ca709674e4b87041d Mon Sep 17 00:00:00 2001 From: Damien Daspit Date: Fri, 2 Oct 2026 18:37:44 -0400 Subject: [PATCH 3/3] Opt PRs out of porting with a no porting label Adding a needs porting label to every PR took its own pull_request_target workflow, and PRs opened before it, or ports themselves, had the wrong label. Porting is the default, so a merged PR now gets a porting issue unless it has the no porting label. The labeling workflow is removed. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/create-porting-issue.yml | 3 ++- .github/workflows/label-needs-porting.yml | 23 ---------------------- 2 files changed, 2 insertions(+), 24 deletions(-) delete mode 100644 .github/workflows/label-needs-porting.yml diff --git a/.github/workflows/create-porting-issue.yml b/.github/workflows/create-porting-issue.yml index 2ee6293a..87363fd9 100644 --- a/.github/workflows/create-porting-issue.yml +++ b/.github/workflows/create-porting-issue.yml @@ -10,9 +10,10 @@ permissions: jobs: create-port-issue: + # Porting is the default. The no porting label opts a PR out. if: | github.event.pull_request.merged == true && - contains(github.event.pull_request.labels.*.name, 'needs porting') + !contains(github.event.pull_request.labels.*.name, 'no porting') runs-on: ubuntu-latest steps: diff --git a/.github/workflows/label-needs-porting.yml b/.github/workflows/label-needs-porting.yml deleted file mode 100644 index c46ed59f..00000000 --- a/.github/workflows/label-needs-porting.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Label Needs Porting - -on: - # pull_request_target so fork PRs get a token that can write labels. It is safe here - # because the job never checks out or runs the PR's code. - pull_request_target: - types: [opened] - -permissions: - issues: write - pull-requests: write - -jobs: - label: - runs-on: ubuntu-latest - steps: - # Every PR is ported by default. The author removes the label to opt out. - - name: Add needs porting label - env: - GH_TOKEN: ${{ github.token }} - run: >- - gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels" - -f "labels[]=needs porting"