Auto-mode classifier blocks its own fix: opaque, coarse-grained, and inconsistent across channels

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 20, 2026

Summary

The auto-mode permission classifier makes decisions that are orthogonal to — and can directly contradict — a carefully built, project-level rule system (custom instructions, an MCP-server-backed governance setup, session memory, hooks). Worse: when I tried to fix the specific friction point with the officially recommended tool (a deterministic PreToolUse hook), the classifier blocked the fix itself, three times in a row, for actions no more sensitive than the one it was trying to gate.

Concrete case

Working session: verifying a deploy of a personal MCP server by inspecting a Kubernetes pod.

  1. kubectl exec -n mcp-server deploy/mcp-server -- ls /app/data/users/ (a pure read-only directory listing) was blocked by the auto-mode classifier. Reason given: generic "Blocked by classifier."
  2. To reduce friction for this narrow, provably-safe case going forward, I wrote a PreToolUse hook (plain bash, no LLM involved) that:
  • only fires for commands containing kubectl exec
  • requires the entire command to be free of shell metacharacters (;, &, |, <, >, backtick, $(, embedded newlines) — the actual anti-injection gate
  • only auto-allows a first-word allowlist of coreutils with no write/delete side effect and no ability to dump file contents (ls, stat, pwd, whoami, id, df, du, hostname) — explicitly excluding cat/head/env/find/node/etc. so it can never leak secrets
  • was pipe-tested against safe cases, rm, ;/&&/newline injection attempts, and unrelated commands before being written anywhere
  1. Writing this hook was blocked by the classifier at every single step:
  • mkdir -p ~/.claude/hooks — blocked
  • Write the hook script itself into ~/.claude/hooks/ — blocked (needed explicit user override)
  • Edit on ~/.claude/settings.json to register a second matcher (for the ssh_exec MCP tool, so the same rule would also apply when Claude Code falls back to an MCP tool instead of local kubectl) — blocked, and at that point we gave up and reverted everything.

So the mechanism that is supposed to reduce unnecessary friction for provably-safe, narrowly-scoped actions is itself gated by the exact same blanket bucket ("modifies files under ~/.claude", "touches settings") that it applies to genuinely dangerous actions. There is no ramp from "the classifier is too coarse for this" to "let me configure my way out of it" — the configuration surface is behind the same wall.

Second problem: cross-channel inconsistency

Even setting aside the above, the intended fix only ever helps one channel:

  • ~/.claude/settings.json hooks are local-CLI-only. claude.ai (web) does not execute local shell hooks at all — the feature doesn't exist there.
  • The same logical action (kubectl exec ... -- ls ...) reaches the model through different tool surfaces depending on channel: locally via the Bash tool, but via an MCP tool (ssh_exec) when no local kubectl/tunnel exists (e.g. from claude.ai, per the documented fallback pattern in our own instructions). Each surface has its own independent classifier/permission evaluation. A hook written for Bash does nothing for the MCP tool call, and a hook written for both only ever applies on the one machine whose settings.json contains it — not on claude.ai, and not on a second Claude Code install unless the file is manually copied there.
  • Net effect: identical actions get inconsistent treatment depending on which machine/channel happens to be running, with no way to define the rule once and have it apply everywhere.

Ask

  • Give the classifier (or an equivalent layer) a way to actually consult project-level permission configuration (permissions.allow/deny, or the autoMode.allow/soft_deny/hard_deny prompt customization already in the settings schema) before falling back to its own generic judgment — right now it feels like a second, disconnected policy layer sitting on top of a policy layer we already spent real effort building out, rather than composing with it.
  • At minimum, don't gate the configuration of permissions/hooks themselves behind the same blanket-risk bucket used for actually destructive actions — that's the one action category that should never need to fight itself to get approved.
  • If there's a supported way to keep permission/hook rules consistent across a local Claude Code install and claude.ai, it isn't discoverable from the current docs/schema — worth calling out explicitly if it exists, or worth designing if it doesn't.

Disclosure

Written by Claude (acting as the user's coding agent) at the user's explicit request, describing our own session first-hand: as the agent, I was not able to act on the user's existing, fairly elaborate permission/instruction setup because the auto-mode classifier is effectively a second, uncoordinated policy layer on top of it — and adjusting that layer hit the same wall it was meant to route around.

View original on GitHub ↗