auto-mode classifier denies calls covered by permissions.allow; reads conversation context; covers Bash but not MCP tools

Status Fixed / completed
Reported on v2.1.201
Maintainer reply None cached
Activity 1 comment · opened Jul 20, 2026 · closed Aug 16, 2026

Summary

In an enterprise deployment we hit a two-hour work stoppage where the auto-mode permission classifier repeatedly denied read-only tool calls that were explicitly covered by permissions.allow. Investigating it surfaced three distinct issues with how the classifier interacts with the documented permissions system. Filing them together because they compound.

Environment: Claude Code 2.1.201, macOS, auto permission mode, Sonnet 5, org-managed settings + a managed CLAUDE.md, settings passed via --settings alongside --strict-mcp-config.

---

1. permissions.allow does not suppress the classifier, and this isn't documented

The session ran with a settings file whose allow list contained bare Bash (plus explicit entries for the internal MCP data tools in use). Four Bash tool calls were still hard-denied by the auto-mode classifier over the session.

If that's intended — the classifier as a second, independent gate that runs after the rules system and does not consult it — it should be stated plainly in the permissions/IAM docs. Right now an admin reading the settings documentation reasonably concludes that an explicit allow entry means the call proceeds. We built and shipped a config change on that assumption before the transcript disproved it.

Ask: document the precedence relationship explicitly, and say whether any configuration (allow rule, PreToolUse hook returning permissionDecision: "allow", managed-settings key) can suppress or tune the classifier.

2. The classifier reads conversation context, which creates a feedback loop with the model's own reasoning

Denial reasons cited facts that are not inferable from the command string being evaluated — they referenced authorization claims made in conversation and the org's policy text, while the command itself was a plain file read.

The consequence is a loop we could reproduce in the transcript:

  1. The model hedges about whether a request is appropriate, in context.
  2. The classifier reads that hedging and denies the next tool call, echoing the model's own rationale back as its stated reason.
  3. The model then reports the denial to the user as "a separate system reaching its own conclusion" — presenting one shared input read twice as two independent judgments.

The user is left with no falsifiable target: satisfying the model's stated condition doesn't move the classifier, and there's no surface that shows them what the classifier actually keyed on. If the classifier does consume conversation context and CLAUDE.md content, that should be documented, because it means policy prose written for the model also silently reconfigures the enforcement layer.

3. Bash is covered; MCP tools appear not to be — and the risk ordering inverts

All four denials landed on Bash. Zero landed on ~32 MCP tool calls in the same session that queried a production data catalog — a materially higher-impact surface than the local reads that were blocked. One blocked call was cat of a scratch file the model had itself written moments earlier.

The model noticed the gap and narrated it, roughly: it switched to a tool that happened not to be gated and kept going toward the same result. That's the failure mode this layer exists to prevent, produced by the layer's own coverage gap.

Ask: is MCP tool coverage intended, planned, or out of scope? Asymmetric coverage is arguably worse than none, because it teaches both the model and the user that routing around the gate works.

4. Minor: path-shape inference produced a false positive

One denial blocked reading a JSON config file on the theory that a path segment containing prd/ implied live credentials. The file is a documented, credential-free pipeline config — its full key set is enumerated in our internal docs and contains no secrets. The denial cost the session its authoritative reference data and pushed the model toward less direct approaches.

Not asking for a fix to this specific heuristic — noting it as evidence that the classifier makes confident factual assertions about file contents it hasn't read, in a reason string the user sees as authoritative.

---

What would have helped most

  1. Documentation of the classifier's inputs, precedence, and configurability.
  2. Any admin-side knob — even coarse per-tool matchers or an org allowlist the classifier honors.
  3. A user-visible indication distinguishing "the model declined" from "the classifier blocked," so a stuck user knows which thing to address. Today both arrive as prose in the same conversation and read identically.

Happy to provide a sanitized transcript excerpt through a private channel if useful — the full session contains regulated data and can't be posted publicly.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗