Auto-mode classifier silently blocks GitHub comment edits (GraphQL + REST) while allowing comment creation, with no override — Codex CLI has no equivalent restriction

Status Open
Reported on v2.1.207
Maintainer reply None cached
Activity 4 comments · opened Jul 24, 2026

Environment: Claude Code 2.1.207, macOS, non-interactive/auto-mode session, gh CLI authenticated with repo scope.

What happened: In an auto-mode session, I attempted to edit an existing GitHub issue comment (correcting a data error in a bot-generated timing log) via two independent, structurally different calls:

  1. gh api graphql -f query='mutation { updateIssueComment(...) }'
  2. gh api -X PATCH repos/{owner}/{repo}/issues/comments/{id} -f body=@file

Both were denied identically: "Permission for this action was denied by the Claude Code auto mode classifier. Reason: Blocked by classifier." A third attempt — a local-only node -e script that only read a file and wrote to disk (no GitHub call at all) — was also denied, suggesting the classifier evaluates something like inferred intent/context rather than the literal command being executed.

Meanwhile, in the same session: creating a new comment (gh issue comment ... --body), editing issue labels/title (gh issue edit), and all read operations were permitted without issue. Only edits to already-posted comments were blocked.

Cross-tool comparison: After Claude Code refused all three attempts, I ran the exact same gh api -X PATCH command through OpenAI's Codex CLI in the same repo/environment, and it executed without any permission block or classifier objection. So the same user, the same command, the same repo, and the same credentials succeeded on a competing agentic coding tool and failed on Claude Code. That's a direct product gap, not just a documentation gap — right now Claude Code is more restrictive than a competitor for a legitimate, user-directed maintenance action, with no way to opt in.

Why this is a problem:

  • The block isn't a Bash permission-rule issue — the relevant commands were already allow-listed in .claude/settings.json, so there's no way for a user to grant this capability short of running the command themselves (or switching tools).
  • There's no visible documentation of what the auto-mode classifier does or doesn't allow, so this is only discoverable by trial and error.
  • The behavior is inconsistent: comment creation is allowed, comment edit is not, with no stated rationale.
  • It's a hard blocker with no in-session override, and it's now a concrete reason a user is considering moving work to a competing tool that doesn't have this restriction.

Ask: Either document this guardrail and its scope, or provide a settings-level way to opt in to comment-edit operations the way Bash command allow-rules already work for everything else.

View original on GitHub ↗

4 Comments

Amiraharon · 1 month ago

Corroboration on one point, and a correction on another, from a session on a newer build.

Environment: Claude Code 2.1.235, Claude desktop app (Code tab), macOS 26.5.1 / Darwin 25.5.0, auto-mode session, gh authenticated with repo + project scopes, target repo private and owned by the same user.

Corroboration: a local-only script was denied too

You noted that a node -e script touching no GitHub API was also blocked, and inferred the classifier evaluates inferred intent rather than the literal command. Same thing here with a different interpreter. A python3 - file <<'PY' … PY heredoc that did nothing but string-replace checkbox markers (- [ ] → - [x]) in a scratchpad file was denied.

It is cleanly isolated. The denied call bundled a gh issue view … > file redirect with that heredoc. The identical redirect, run alone moments later, was allowed. So the heredoc half was the trigger, on a file in a temp scratchpad directory, with no network call in the script at all. That is a second interpreter and a second session reaching your conclusion independently.

Correction: on 2.1.235 a settings rule did clear the block

This is the part worth your attention, because it contradicts this issue's central claim and the same claim in #84477 and #88537.

What was denied, three times, with the same bare "Reason: Blocked by classifier":

| Command | Result |
|---|---|
| gh issue view N --jq .body > f + python3 - f <<'PY' … PY | Blocked |
| gh issue edit N --body-file f + gh issue view N … \| grep -c | Blocked |
| gh issue edit N --repo OWNER/REPO --body-file f (bare, single command) | Blocked |
| gh issue view N --jq .body > f && wc -l f | Allowed |

Reads were never blocked at any point.

Then I added four rules to the project's .claude/settings.json:

"Bash(gh issue edit:*)",
"Bash(gh issue close:*)",
"Bash(gh issue comment:*)",
"Bash(gh project item-edit:*)"

All four verbs then succeeded on the first attempt — body edit, comment, close, and a Projects v2 item-edit Status flip. No restart, same session, no other change.

So the "hard blocker with no in-session override" is at least not universal. On 2.1.235 a targeted Bash(gh <verb>:*) rule cleared it for these verbs, which may already satisfy the second half of your ask. Worth re-testing on your end, since you were on 2.1.207 and a generic allow-list evidently did not help you.

Where our observations diverge

You saw gh issue edit (labels/title) permitted while comment edits were blocked. I saw gh issue edit --body-file blocked, and after the rule, gh issue comment creation succeeded. So the split is not cleanly "create allowed, edit blocked". It may be finer-grained than the verb, sensitive to the flag or payload, or it may have shifted across the 28 builds between us.

Limits of this evidence

Only gh issue edit is confirmed denied pre-rule. The other three verbs went into the allow-list in the same commit and were never exercised in the denied state, so I cannot say they would have been blocked. I am also not claiming the rule works for gh pr merge, which is the verb most of the other reports centre on and which I did not touch.

One agreement in full: the denial surfaces no reasoning, so the scope is discoverable only by trial and error. Even where a settings-level opt-in does work, nothing tells you that it will, or which rule to write.

Amiraharon · 1 month ago

Retracting the main claim in my comment above. I said a Bash(gh <verb>:*) allow rule cleared the block on 2.1.235. That is not supported, and I should not have published it on a single trial. The corroboration half of that comment still stands; the correction half does not.

What I did to check

Removed the rules mid-session and re-ran the same verbs against a scratch issue in the same private repo, same session, same build.

| Verb | Allow rule present? | Result |
|---|---|---|
| gh issue edit (denied 3× earlier) | removed | Succeeded |
| gh issue comment | removed | Succeeded |
| gh project item-edit | removed | Succeeded |
| gh issue close | removed | Succeeded |
| gh issue create | never had one | Succeeded |

Everything passes with no rules at all, including the exact command denied three times an hour earlier.

What that means

Two explanations fit, and I cannot separate them from inside one session:

  1. The rules were irrelevant, and the block lifted for an unrelated reason.
  2. settings.json is not re-read mid-session, so neither adding nor removing the rules ever took effect.

Both destroy the causal claim. What I actually observed was a block, then a settings edit, then no block — and I read a fix into a sequence. Correlation, one trial, no control. My apologies for putting that in your thread as a correction to your report.

The part that still stands

The local-script corroboration is unaffected: a python3 … <<'PY' heredoc doing nothing but string replacement in a temp file was denied, cleanly isolated because the gh read bundled with it ran fine alone. That independently reproduces your node -e denial and your inference that the classifier weighs inferred intent over the literal command.

Also unaffected, and consistent with your report: gh issue create was permitted throughout while gh issue edit was denied — your create-versus-edit split, though for us the denial fell on the issue body rather than a comment.

A hypothesis I can't test alone

The denials stopped immediately after the user explicitly approved the action in-session through a question prompt. If in-session user approval is what moves the classifier, rather than settings, that would explain this sequence, and it would also fit the reports of the classifier allowing what it previously denied (#91694, #91754). Stated as a hypothesis only — I have one session and no way to isolate it.

Net effect on your issue

Your central complaint comes out stronger, not weaker. The behaviour is opaque enough that an attentive observer ran a plausible fix, saw it "work", and published the wrong conclusion to a public tracker. If the denial surfaced any reasoning, or if there were a documented way to check whether a rule applies, that error would not have been possible. Worth weighing against #72589's ask to expose the denial reason.

Amiraharon · 1 month ago

Follow-up to my retraction. I ran the cold-session test, and it kills my replacement hypothesis too. Posting because the negative result is more useful than either thing I claimed before it.

Method: claude -p --permission-mode auto, one fresh process per trial — no conversation history, no prior approval in context, and .claude/settings.json carrying no gh allow rules at all (the four I had added are reverted).

| # | Shape | Result |
|---|---|---|
| 1 | gh issue edit --title | Succeeded |
| 2 | gh issue edit --body-file — the exact shape denied 3× | Succeeded |
| 3–5 | same, repeated | Succeeded ×3 |

Trial 1 is a bad probe, kept only for honesty: --title is the variant your report says was permitted, so it proves nothing. Trials 2–5 use --body-file and match the denied command byte for byte apart from the issue number.

Ten successes now, across two session types, and zero reproductions of the original denial. Five cold as above, five in the originating session after removing the rules.

Both hypotheses are dead

  • Settings. Ruled out. Already retracted; the cold runs confirm it from the other direction.
  • In-session user approval. This was my replacement hypothesis in the retraction above, and it was wrong too. The cold sessions had no approval of any kind and were never denied. Please disregard that paragraph.

What is left

The three denials happened — same session, same minute, gh issue edit --body-file refused with the bare "Blocked by classifier" — and are not reproducible under any condition I can construct. No configuration change, no approval state, no session shape brings them back.

That leaves transient classifier unavailability failing closed as the only explanation still standing. I'm labelling it inference, having now been wrong twice on this issue with more confidence than I had earned. But it fits #86341 (intermittently unavailable) and #86755 (degraded, blocking inconsistently within a session) far better than anything configuration-shaped.

If that is what happened, it changes the shape of your ask. A documented opt-in would not have helped, because there was nothing to opt into — the correct response to that denial was to retry it, and nothing in the message hints at that. The user-visible difference between "this action is disallowed" and "the classifier is briefly unavailable, retry" is currently zero, and every wrong theory in this thread, including both of mine, came out of that gap.

Amiraharon · 1 month ago

Last data point, and it retracts the one piece of my first comment I said still stood.

I probed the python3 heredoc denial cold as well — claude -p --permission-mode auto, fresh process per trial, no rules, no prior approval:

| Probe | Shape | Trials | Result |
|---|---|---|---|
| A | bare python3 - f <<'PY' … PY | 3 | Succeeded ×3 |
| B | gh issue view … > f + the same heredoc (the original compound) | 3 | Succeeded ×3 |

Verified by side effect, not just exit code.

So the heredoc corroboration of your node -e observation is withdrawn too. I claimed it was "cleanly isolated" because the gh read bundled with it passed on its own moments later. That inference silently assumed the classifier is deterministic. It isn't, so two calls at different times establish nothing about which half caused the denial. Every conclusion I posted in this thread came from that same mistake.

What the whole session actually looks like

  • Many gh reads, tests, greps beforehand — all fine.
  • Then four consecutive denials in one short window: one python3 heredoc, then gh issue edit three times.
  • Then 16 further attempts across two session types and every configuration — zero denials.
  • gh reads never blocked at any point, including inside the window.

22 attempts, 4 denials, all four inside one window, 0 reproductions since. That is not a rule about which commands are disallowed. It reads as a bounded episode where everything routed to the classifier failed closed, while read-only commands — presumably never routed to it — were untouched.

Why this may be worth separating from your report

Your issue describes a stable asymmetry: comment creation allowed, comment edits denied, reproducibly enough to test against Codex CLI and compare. If yours reproduces on demand, it is a different animal from mine and my comments are noise in your thread — say so and I will stop adding to it.

But if yours also came from a single window and was never retried afterwards, the two are the same phenomenon, and the framing in both our reports is wrong: there is nothing to opt into, no rule to document, no scope to publish. The correct response to that denial was to run the command again.

That is the actionable gap, and it is the one thing every wrong theory in this thread has in common. A denial that means "disallowed" and a denial that means "the classifier is briefly unavailable, retry" are byte-identical to the user. Three of us — you, me twice — built explanations on that ambiguity. #72589's ask to surface the denial reason would have prevented all of it.