From 20b17c00149036b1a13113e70450a97d1d7c914a Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Fri, 11 Sep 2026 18:33:18 -0500 Subject: [PATCH 1/3] Widen claude-code-review's allowedTools to what the plugin actually needs Every run of the automated code-review job completes successfully but never posts a review: the `/code-review` plugin's own steps launch haiku/sonnet/opus subagents (Task) to do the actual analysis and read PR data via `gh pr diff`, `gh pr view`, etc., but claude_args' --allowedTools only granted mcp__github_inline_comment__create_inline_comment plus baseline read/git-write tools -- neither Task nor any gh subcommand was in the effective allowlist, so every attempt to use them was silently denied until the run gave up. Add exactly the Bash(gh ...) subcommands the plugin's own allowed-tools frontmatter declares (commands/code-review.md in anthropics/claude-code@main), plus Task for its subagent architecture -- verified against the SDK's own allowedTools dump and permission_denials_count in two runs that reached "success" without posting anything. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/claude-code-review.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 3f998c7..7251501 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -192,4 +192,21 @@ jobs: # starts, the tool genuinely doesn't exist in the session, and the # plugin silently falls back to one consolidated PR comment instead # of real inline line comments. - claude_args: '--allowedTools mcp__github_inline_comment__create_inline_comment' + # + # The rest of this list closes the actual gap: --allowedTools is an + # allowlist in agent mode, so anything the plugin calls that isn't + # named here is silently denied rather than granted-by-default. + # `Bash(gh ...)` entries mirror the plugin's own `allowed-tools` + # frontmatter (anthropics/claude-code plugins/code-review/commands/ + # code-review.md) verbatim -- that's the plugin telling us what it + # needs, not a guess. `Task` isn't in that frontmatter (core tools + # don't need frontmatter declaration in a normal session) but the + # command's steps 1-6 explicitly launch haiku/sonnet/opus subagents + # to do the actual review work, so without it there is no reviewer + # left to run. Confirmed against two runs that reached + # `"subtype": "success"` without ever posting a review + # (34648962488: num_turns 11, permission_denials_count 20; + # 34652912518: num_turns 6, permission_denials_count 23) -- neither + # `Task` nor any of these `gh` subcommands appeared in either run's + # actual SDK `allowedTools` dump. + claude_args: '--allowedTools mcp__github_inline_comment__create_inline_comment,Task,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)' From 8b49556548cf11e8ad03b29c9490c94ce05b4237 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Fri, 11 Sep 2026 18:55:42 -0500 Subject: [PATCH 2/3] Wrap allowedTools value in double quotes so it survives shell-quote claude_args reaches claude-code-action as a bare string that it re-tokenizes with the shell-quote npm package, which splits on whitespace. The previous commit's unquoted, comma-joined list broke on the spaces inside every Bash(gh ...) entry, so none of those seven grants actually survived intact -- subagents could launch but every gh pr diff/view/comment call was still denied, reproducing the original bug for a different reason. Wrapping the whole value in double quotes keeps it as one token; verified against the actual shell-quote package mirroring claude-code-action's own parsing logic. Also add TodoWrite: the plugin's Notes unconditionally say to create a todo list before starting, and that tool isn't in the action's baseline set either. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/claude-code-review.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 7251501..9bf18c4 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -201,12 +201,17 @@ jobs: # code-review.md) verbatim -- that's the plugin telling us what it # needs, not a guess. `Task` isn't in that frontmatter (core tools # don't need frontmatter declaration in a normal session) but the - # command's steps 1-6 explicitly launch haiku/sonnet/opus subagents + # command's steps 1-5 explicitly launch haiku/sonnet/opus subagents # to do the actual review work, so without it there is no reviewer - # left to run. Confirmed against two runs that reached - # `"subtype": "success"` without ever posting a review - # (34648962488: num_turns 11, permission_denials_count 20; - # 34652912518: num_turns 6, permission_denials_count 23) -- neither - # `Task` nor any of these `gh` subcommands appeared in either run's - # actual SDK `allowedTools` dump. - claude_args: '--allowedTools mcp__github_inline_comment__create_inline_comment,Task,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)' + # left to run. `TodoWrite` likewise isn't a frontmatter entry but is + # not in the action's baseline tool set either, and the plugin's + # own Notes unconditionally say to create a todo list before + # starting. + # + # The whole value MUST stay one shell-quote token: claude_args is a + # bare (unquoted-by-us) string that claude-code-action re-tokenizes + # with the `shell-quote` npm package, which splits on whitespace. + # Without the surrounding double quotes, the spaces inside each + # `Bash(gh ...)` entry split it into multiple garbage tokens instead + # of one tool name. + claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment,Task,TodoWrite,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"' From 5a5a501a04141c4c867262e50a1f7db71228fbd9 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Fri, 11 Sep 2026 18:59:45 -0500 Subject: [PATCH 3/3] Clarify claude-code-review.yml allowedTools comment wording State the actual non-obvious fact directly: YAML's own quotes never reach claude-code-action, so the inner double quotes around --allowedTools aren't redundant even though the line already looks quoted. --- .github/workflows/claude-code-review.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 9bf18c4..0dc2d72 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -203,15 +203,17 @@ jobs: # don't need frontmatter declaration in a normal session) but the # command's steps 1-5 explicitly launch haiku/sonnet/opus subagents # to do the actual review work, so without it there is no reviewer - # left to run. `TodoWrite` likewise isn't a frontmatter entry but is - # not in the action's baseline tool set either, and the plugin's + # left to run. `TodoWrite` likewise isn't a frontmatter entry, and + # isn't in the action's baseline tool set either -- the plugin's # own Notes unconditionally say to create a todo list before # starting. # - # The whole value MUST stay one shell-quote token: claude_args is a - # bare (unquoted-by-us) string that claude-code-action re-tokenizes - # with the `shell-quote` npm package, which splits on whitespace. - # Without the surrounding double quotes, the spaces inside each - # `Bash(gh ...)` entry split it into multiple garbage tokens instead - # of one tool name. + # The whole value MUST stay one shell-quote token. YAML's own outer + # single quotes below are consumed by the YAML parser and never + # reach claude-code-action -- what it actually receives is the bare + # string after that, which it re-tokenizes with the `shell-quote` + # npm package, splitting on whitespace. The inner double quotes are + # what keep the value one token; without them the spaces inside + # each `Bash(gh ...)` entry split it into multiple garbage tokens + # instead of one tool name. claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment,Task,TodoWrite,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'