Enable @claude workflow to open PRs#70
Conversation
- bump claude.yml permissions to write for contents / pull-requests / issues so @claude can push a branch and open a PR when asked. - add an --allowedTools list covering the git + gh commands needed for branch push and PR creation, plus the quarto / R helpers most useful on this repo. - add CLAUDE.md (project guidance — Quarto/R conventions, things not to edit, PR expectations) so Claude has the same context the Copilot instructions provide. - add .claude/settings.json with default allow/deny rules for local Claude Code use; .claude/.gitignore keeps settings.local.json out. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR configures Claude Code for this Quarto/R template repository so @claude invocations can create branches and PRs, while adding repo-specific Claude guidance and local permission defaults.
Changes:
- Expands
.github/workflows/claude.ymlpermissions and Claude allowed tools. - Adds
CLAUDE.mdwith project conventions and PR expectations. - Adds
.claude/defaults for Claude Code settings and local settings ignores.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
CLAUDE.md |
Adds Claude Code repository guidance and workflow expectations. |
.github/workflows/claude.yml |
Grants write permissions and configures Claude allowed tools for branch/PR creation. |
.claude/settings.json |
Adds default local Claude Code allow/deny permissions. |
.claude/.gitignore |
Keeps local Claude settings out of version control. |
| contents: write # so Claude can push a branch | ||
| pull-requests: write # so Claude can open / edit PRs | ||
| issues: write # so Claude can comment on issues |
- claude.yml: gate the job on `author_association` so only OWNER / MEMBER / COLLABORATOR @claude mentions trigger a write-scoped run (anyone-can-comment + write GITHUB_TOKEN was the original risk). - claude.yml: narrow allowed `git push` to `origin` only and add an explicit `--disallowedTools` list for force / delete / mirror / all-tags variants. - CLAUDE.md: correct the submodule wording — only `macros/` is a submodule per `.gitmodules`; extensions in `_extensions/` are vendored. - CLAUDE.md: drop the 6-item parenthetical under `.github/workflows/` to comply with the file's own "3+ items → bullet list" rule. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulled from the pre-upstream-landing local versions: - Both workflows: header docstring explaining purpose, required secret, and CLAUDE.md pointer so the file is self-documenting. - Both workflows: `submodules: recursive` on checkout so Claude can see the `macros/` submodule when asked to render or modify pages that depend on it. - claude-code-review.yml: skip drafts and Dependabot PRs to avoid burning API spend on patch bumps and WIP work. Not cherry-picked (separate design decisions for a follow-up): - ANTHROPIC_API_KEY auth (current uses CLAUDE_CODE_OAUTH_TOKEN) - actions/checkout@v6 (repo standard is v4/v5) - Custom Quarto-specific review prompt + inline-comment MCP tools (would replace the upstream code-review plugin) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
.github/workflows/claude.yml:68
- Allowing unrestricted
Rscript -e *lets Claude run arbitrary shell commands from R (for example viasystem()), which bypasses the--disallowedToolsprotections for destructivegit pushvariants. If the workflow needs write-scoped tokens, restrict this helper to specific safe commands or run validation helpers in a separate non-writing context.
claude_args: |
--allowedTools "Bash(quarto render),Bash(quarto check),Bash(Rscript -e *),Bash(git diff:*),Bash(git log:*),Bash(git status:*),Bash(git checkout:*),Bash(git switch:*),Bash(git branch:*),Bash(git add:*),Bash(git commit:*),Bash(git push origin:*),Bash(git push -u origin:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr create:*),Bash(gh pr edit:*),Bash(gh issue view:*)" --disallowedTools "Bash(git push --force:*),Bash(git push -f:*),Bash(git push --delete:*),Bash(git push -d:*),Bash(git push --mirror:*),Bash(git push --tags:*),Bash(git push --all:*)"
| # Skip drafts and Dependabot PRs — neither benefits from an LLM review | ||
| # and Dependabot bumps would burn API spend on every patch release. | ||
| if: github.event.pull_request.draft == false && github.event.pull_request.user.login != 'dependabot[bot]' |
|
@claude apply changes based on the comments in this thread |
|
Claude finished @d-morrison's task in 4m 25s —— View job Applying Copilot review changes
What was committed
Manual changes still needed
Replace the broad "Bash(Rscript -e 'lintr::*')",
"Bash(Rscript -e 'devtools::check*')",
"Bash(Rscript -e 'devtools::document*')",
"Bash(Rscript -e 'pkgdown::*')",
The workflow file needs:
These require a human with workflow-write permissions to apply. · Branch |
- Split _extensions/ and macros/ onto separate lines in the layout section so it is unambiguous that only macros/ is a git submodule - Add explicit '(see .gitmodules)' reference on the macros/ line - Strengthen submodule note to say macros/ is the *only* submodule Addresses Copilot review comment on CLAUDE.md submodule accuracy. Co-authored-by: Douglas Ezra Morrison <d-morrison@users.noreply.github.com>
Addresses outstanding security feedback on PR #70 that the prior in-CI Claude run was blocked from applying (workflow-file edits + locked settings). - `Bash(Rscript -e *)` is replaced with package-prefixed patterns (`lintr::lint*`, `devtools::check*`, `devtools::document*`, `pkgdown::build*`). A bare `Rscript -e *` would let Claude shell out via `system()` and bypass the `git push --force:*` deny rule. - Adds `Bash(git push origin +*)` and `Bash(git push -u origin +*)` to the workflow deny list to cover the `+ref` force-update refspec form that the existing `--force` / `-f` deny rules don't catch. - The mirror `:ref` delete-refspec form can't be expressed in Claude Code's pattern syntax (a trailing `:*` is the trailing-wildcard alias, not a literal `:` plus wildcard — see code.claude.com docs). Documented in the workflow comment; defense-in-depth comes from branch protection on `main`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (3)
.github/workflows/claude.yml:78
- The allowed
git push origin:*/git push -u origin:*patterns still permit delete refspecs such asgit push origin :some-branch, while the deny list only blocks the--delete/-dforms. With the write-scoped token this can delete any unprotected branch, so the workflow should narrow the allowed push form (for example to a dedicated branch prefix/refspec) or otherwise block colon delete refspecs before granting push access.
claude_args: |
--allowedTools "Bash(quarto render),Bash(quarto check),Bash(Rscript -e 'lintr::lint*'),Bash(Rscript -e 'devtools::check*'),Bash(Rscript -e 'devtools::document*'),Bash(Rscript -e 'pkgdown::build*'),Bash(git diff:*),Bash(git log:*),Bash(git status:*),Bash(git checkout:*),Bash(git switch:*),Bash(git branch:*),Bash(git add:*),Bash(git commit:*),Bash(git push origin:*),Bash(git push -u origin:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr create:*),Bash(gh pr edit:*),Bash(gh issue view:*)" --disallowedTools "Bash(git push --force:*),Bash(git push -f:*),Bash(git push --delete:*),Bash(git push -d:*),Bash(git push --mirror:*),Bash(git push --tags:*),Bash(git push --all:*),Bash(git push origin +*),Bash(git push -u origin +*)"
.github/workflows/claude.yml:78
- The workflow permits
git commitbut never configures a Git committer identity, and the allowed tool list does not permitgit configfor Claude to set one. GitHub-hosted runners are not guaranteed to haveuser.name/user.email, so the branch/PR flow can fail atgit commitwith “Author identity unknown”; add an explicit setup step or narrowly allow the neededgit config user.*commands.
claude_args: |
--allowedTools "Bash(quarto render),Bash(quarto check),Bash(Rscript -e 'lintr::lint*'),Bash(Rscript -e 'devtools::check*'),Bash(Rscript -e 'devtools::document*'),Bash(Rscript -e 'pkgdown::build*'),Bash(git diff:*),Bash(git log:*),Bash(git status:*),Bash(git checkout:*),Bash(git switch:*),Bash(git branch:*),Bash(git add:*),Bash(git commit:*),Bash(git push origin:*),Bash(git push -u origin:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr create:*),Bash(gh pr edit:*),Bash(gh issue view:*)" --disallowedTools "Bash(git push --force:*),Bash(git push -f:*),Bash(git push --delete:*),Bash(git push -d:*),Bash(git push --mirror:*),Bash(git push --tags:*),Bash(git push --all:*),Bash(git push origin +*),Bash(git push -u origin +*)"
.github/workflows/claude.yml:78
- The allowed
gh pr createpath still lacks authentication for the GitHub CLI:ghexpects a token inGH_TOKEN/GITHUB_TOKEN, but this workflow does not export${{ github.token }}(the Claude OAuth token is unrelated). Without that env, PR creation can fail withghauthentication errors even though the job permissions are write-scoped.
claude_args: |
--allowedTools "Bash(quarto render),Bash(quarto check),Bash(Rscript -e 'lintr::lint*'),Bash(Rscript -e 'devtools::check*'),Bash(Rscript -e 'devtools::document*'),Bash(Rscript -e 'pkgdown::build*'),Bash(git diff:*),Bash(git log:*),Bash(git status:*),Bash(git checkout:*),Bash(git switch:*),Bash(git branch:*),Bash(git add:*),Bash(git commit:*),Bash(git push origin:*),Bash(git push -u origin:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr create:*),Bash(gh pr edit:*),Bash(gh issue view:*)" --disallowedTools "Bash(git push --force:*),Bash(git push -f:*),Bash(git push --delete:*),Bash(git push -d:*),Bash(git push --mirror:*),Bash(git push --tags:*),Bash(git push --all:*),Bash(git push origin +*),Bash(git push -u origin +*)"
| # Skip drafts and Dependabot PRs — neither benefits from an LLM review | ||
| # and Dependabot bumps would burn API spend on every patch release. | ||
| if: github.event.pull_request.draft == false && github.event.pull_request.user.login != 'dependabot[bot]' |
|
@claude apply changes based on the comments in this thread |
|
Claude finished @d-morrison's task in 7m 5s —— View job Review of Copilot comment thread #4315522929
What's already addressed (prior commits)The branch (
Items from review #4315522929 — assessmentNon-suppressed (high confidence):
Suppressed (low confidence):
SummaryBoth actionable items from this review require human intervention (workflow-write permissions for the |
`quarto render` and `quarto check` evaluate R code chunks during build, and chunks in this repo can call `system()` — which would bypass the git-push deny list we set up earlier in this PR. Remove both from the `--allowedTools` line and document the reasoning in the inline comment. If a `@claude` task ever needs a build, run it in a separate job that doesn't have the write-scoped GITHUB_TOKEN. Addresses Copilot review #4315522929 follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@claude please review the new commit |
|
Claude finished @d-morrison's task in 2m 25s —— View job Review of commit
|
| Issue | Status |
|---|---|
| Actor gate (OWNER/MEMBER/COLLABORATOR only) | ✅ Fixed (07299ef) |
Rscript -e * → specific safe namespaces |
✅ Fixed (b961e69) |
+ref force-update refspec deny list |
✅ Fixed (b961e69) |
quarto render/quarto check bypass |
✅ Fixed (130efcb) |
macros/ as the only submodule |
✅ Fixed (3305641) |
| CLAUDE.md parenthetical CI list | ✅ Fixed (bb30796) |
PR body describing claude-code-review.yml changes |
✅ Fixed (PR body updated) |
:branch delete-refspec |
Documented limitation; mitigated by branch protection |
git commit committer identity |
Handled by claude-code-action setup step — not a concern |
GH_TOKEN for gh CLI |
Exposed by action automatically when pull-requests: write — not a concern |
The PR is in good shape. The only thing I'd call out to address before merge is the redundant actions: read (item 1 above), if you want a clean config — but it has no functional impact.
· Branch
`actions: read` was set in both the job-level `permissions:` block and the action's `additional_permissions` input. The job-level grant is what gives the GITHUB_TOKEN the scope; the action input was redundant. Keep the job-level entry (canonical GitHub Actions syntax) and drop the action-input duplicate. Addresses @claude review feedback on this PR (item 1). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@claude please review the new commit |
|
Claude finished @d-morrison's task in 45s —— View job Review of commit
|
| Issue | Status |
|---|---|
| Actor gate (OWNER/MEMBER/COLLABORATOR only) | ✅ Fixed (07299ef) |
Rscript -e * → specific safe namespaces |
✅ Fixed (b961e69) |
+ref force-update refspec deny list |
✅ Fixed (b961e69) |
quarto render/quarto check bypass |
✅ Fixed (130efcb) |
macros/ as the only submodule in CLAUDE.md |
✅ Fixed (3305641) |
CLAUDE.md parenthetical CI list |
✅ Fixed (bb30796) |
PR body describing claude-code-review.yml changes |
✅ Fixed (PR body updated) |
Redundant actions: read in additional_permissions |
✅ Fixed (91b2bb2) |
:branch delete-refspec not blockable |
Documented limitation (lines 65–69); mitigated by branch protection on main |
| Git committer identity | Handled by claude-code-action setup step — not a concern |
GH_TOKEN for gh CLI |
Exposed automatically by the action when pull-requests: write — not a concern |
No remaining actionable items. The PR is ready to merge.
· Branch
| if: | | ||
| (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 == 'issue_comment' && contains(github.event.comment.body, '@claude') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) || | ||
| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) || | ||
| (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.review.author_association)) || | ||
| (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association)) |
| # Skip drafts and Dependabot PRs — neither benefits from an LLM review | ||
| # and Dependabot bumps would burn API spend on every patch release. | ||
| if: github.event.pull_request.draft == false && github.event.pull_request.user.login != 'dependabot[bot]' |
|
@claude apply changes based on the comments in this thread and other unaddressed comments |
|
Claude finished @d-morrison's task in 1m 51s —— View job Review of thread #4316868793 — assessment complete
Both actionable items from review #4316868793 are in Item 1 —
|
| Issue | Status |
|---|---|
| Actor gate (OWNER/MEMBER/COLLABORATOR only) | ✅ Fixed (07299ef) |
Rscript -e * → specific safe namespaces |
✅ Fixed (b961e69) |
+ref force-update refspec deny list |
✅ Fixed (b961e69) |
quarto render/quarto check bypass |
✅ Fixed (130efcb) |
macros/ as the only submodule in CLAUDE.md |
✅ Fixed (3305641) |
CLAUDE.md parenthetical CI list |
✅ Fixed (bb30796) |
PR body describing claude-code-review.yml changes |
✅ Fixed (PR body updated) |
Redundant actions: read in additional_permissions |
✅ Fixed (91b2bb2) |
issues.assigned checks issue author, not actor |
Manual fix needed — remove assigned from issues.types in claude.yml |
| Review workflow runs on fork PRs (secret unavailable) | Manual fix needed — add head.repo.full_name == github.repository guard to claude-code-review.yml |
:branch delete-refspec not blockable |
Documented limitation; mitigated by branch protection on main |
| · Branch |
|
@claude implement recommended fixes, then review again |
|
Claude finished @d-morrison's task in 2m 9s —— View job Implementation attempt + final review
What was attempted (local commit
|
| Issue | Status |
|---|---|
| Actor gate (OWNER/MEMBER/COLLABORATOR only) | ✅ Fixed (07299ef) |
Rscript -e * → specific safe namespaces (CI) |
✅ Fixed (b961e69) |
Rscript -e * in .claude/settings.json (local) |
✅ Fixed (b961e69) — local sessions don't carry write-scoped token, intentionally broader |
+ref force-update refspec deny list |
✅ Fixed (b961e69) |
quarto render/quarto check bypass in CI |
✅ Fixed (130efcb) |
macros/ as the only submodule in CLAUDE.md |
✅ Fixed (3305641) |
CLAUDE.md parenthetical CI list |
✅ Fixed (bb30796) |
PR body describing claude-code-review.yml changes |
✅ Fixed (PR body updated) |
Redundant actions: read in additional_permissions |
✅ Fixed (91b2bb2) |
issues.assigned checks issue author, not actor |
|
| Review workflow runs on fork PRs (secret unavailable) | |
:branch delete-refspec not blockable |
Documented limitation (lines 65–69 of claude.yml); mitigated by branch protection on main |
The two remaining items are purely defensive — neither is a regression introduced by this PR (the original workflow had no issues.assigned trigger and no review workflow if: at all). The PR is safe to merge as-is and the two fixes can be applied as a follow-up commit.
· Branch
Addresses the two remaining items from the latest @claude review on this PR (the in-CI Claude couldn't push these because the GitHub App token lacks `workflows` scope). claude.yml: - Drop `assigned` from `issues:` trigger types. The job-level `if:` gate checks `github.event.issue.author_association`, which describes the issue *author*, not the assigner. A collaborator assigning themselves to an outsider's issue would fail the gate even though they're trusted. Collaborators can still invoke @claude by leaving a comment. claude-code-review.yml: - Add a same-repo guard so fork PRs skip cleanly. Fork PRs don't have access to repo secrets, so `CLAUDE_CODE_OAUTH_TOKEN` would be empty and the action would fail with a noisy red check for external contributors. The new `head.repo.full_name == github.repository` predicate short-circuits before the action runs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@claude please review the new commit |
|
Claude finished @d-morrison's task in 44s —— View job Review of commit
|
| Issue | Status |
|---|---|
| Actor gate (OWNER/MEMBER/COLLABORATOR only) | ✅ Fixed (07299ef) |
Rscript -e * → specific safe namespaces (CI) |
✅ Fixed (b961e69) |
+ref force-update refspec deny list |
✅ Fixed (b961e69) |
quarto render/quarto check bypass in CI |
✅ Fixed (130efcb) |
macros/ as the only submodule in CLAUDE.md |
✅ Fixed (3305641) |
CLAUDE.md parenthetical CI list |
✅ Fixed (bb30796) |
PR body describing claude-code-review.yml changes |
✅ Fixed (PR body updated) |
Redundant actions: read in additional_permissions |
✅ Fixed (91b2bb2) |
issues.assigned checks issue author, not actor |
✅ Fixed (7fabe9c) |
| Review workflow runs on fork PRs (secret unavailable) | ✅ Fixed (7fabe9c) |
:branch delete-refspec not blockable |
Documented limitation (claude.yml lines 70–74); mitigated by branch protection on main |
No remaining actionable items. The PR is ready to merge.
Mirrors the PR #70 round-4 fix so this branch's claude-code-review.yml agrees with the version that's about to land on main. Without this, when #70 merges and this branch needs to pull base, the `if:` line would conflict. Functionally identical to the change on #70: skips fork PRs since they can't read `CLAUDE_CODE_OAUTH_TOKEN` and would otherwise fail with a noisy red check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches the change in commit 7fabe9c: the if-guard now also skips fork PRs, so update the file-level summary at the top to mention it. Keeps the top-of-file summary in sync with the if-guard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@claude please review the new commit |
|
Claude finished @d-morrison's task in 39s —— View job Review of commit
|
| Issue | Status |
|---|---|
| Actor gate (OWNER/MEMBER/COLLABORATOR only) | ✅ Fixed (07299ef) |
Rscript -e * → specific safe namespaces (CI) |
✅ Fixed (b961e69) |
+ref force-update refspec deny list |
✅ Fixed (b961e69) |
quarto render/quarto check bypass in CI |
✅ Fixed (130efcb) |
macros/ as the only submodule in CLAUDE.md |
✅ Fixed (3305641) |
CLAUDE.md parenthetical CI list |
✅ Fixed (bb30796) |
PR body describing claude-code-review.yml changes |
✅ Fixed (PR body updated) |
Redundant actions: read in additional_permissions |
✅ Fixed (91b2bb2) |
issues.assigned checks issue author, not actor |
✅ Fixed (7fabe9c) |
| Review workflow runs on fork PRs (secret unavailable) | ✅ Fixed (7fabe9c) |
Header comment out of sync with if: guard |
✅ Fixed (80f43f9) |
:branch delete-refspec not blockable |
Documented limitation (claude.yml lines 70–74); mitigated by branch protection on main |
No remaining actionable items. The PR is ready to merge.
· Branch
|
| - name: Run Claude Code | ||
| id: claude | ||
| uses: anthropics/claude-code-action@v1 | ||
| with: | ||
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} |
Summary
claude.ymlpermissions towriteforcontents,pull-requests, andissuesso an@claudeinvocation can push a branch and open a PR.claude.ymlto trusted authors (OWNER / MEMBER / COLLABORATOR) via the job-levelif:guard — a write-scoped token shouldn't be reachable by anyone who can comment on a public issue.--allowedToolslist toclaude_argscovering thegit+ghcommands needed for branch push and PR creation, plus a narrowed set ofRscript -epatterns (lintr::lint*,devtools::check*,devtools::document*,pkgdown::build*) — a bareRscript -e *would let Claude shell out viasystem()and bypass the git-push deny list.--disallowedToolsto cover the+refforce-push refspec form (Bash(git push origin +*),Bash(git push -u origin +*)) in addition to the--force/-f/--delete/--mirror/--tags/--allflag forms. The:refdelete-refspec can't be expressed in Claude Code's pattern syntax (a trailing:*is the trailing-wildcard alias, not a literal:+ wildcard); defense-in-depth comes from GitHub branch protection onmain.quarto render/quarto checkare intentionally not in the allowed list — rendering this site evaluates R code chunks which can callsystem()and re-open the bypass. Builds belong in a separate non-write job if@claudeever needs one.CLAUDE.md(Quarto/R conventions, things not to edit, PR expectations) so the workflow's Claude has the same project context the existing Copilot instructions provide..claude/settings.jsonwith sensible default allow/deny rules for local Claude Code use;.claude/.gitignorekeepssettings.local.jsonout of git.if:guard toclaude-code-review.ymlto skip draft PRs and Dependabot bumps — neither benefits from an LLM review and Dependabot bumps would otherwise burn API quota on every patch release. Also switches the checkout tosubmodules: recursiveso reviews can see themacros/submodule content.Without the
claude.ymlchanges, the canonical workflow onmainhas all-read permissions and an empty allowed-tools list, so it can comment but can't push branches or callgh pr create.Test plan
@claudeasking for a small fix; verify the workflow pushes a branch and opens a PR rather than only commenting.--allowedToolslist and no permission errors.@claudemention from a non-collaborator account (e.g. via a draft PR from a fork).🤖 Generated with Claude Code