Claude Code auto-classifier: the security layer between model and tools

Martin

Every time Claude Code runs a tool call that isn’t on your allowlist, a second model gets a vote. That second model is the auto-classifier — a small, fast LLM that lives between Claude and the outside world and decides, in real time, whether the requested action looks risky enough to interrupt.

This article explains what the auto-classifier does, how it fits into the wider defense hierarchy, and how to control it without disabling the safety net.

What the auto-classifier is

The auto-classifier is a lightweight LLM that runs alongside the main Claude model. Its job is narrow: read the proposed tool call (which tool, which arguments, in which context) and produce a risk score with a short rationale. If the score crosses a threshold, the tool call is paused and surfaced to the user for explicit confirmation — or blocked outright with an explanation.

The classifier doesn’t run on every tool call. Reads against the local filesystem, simple Greps, and anything explicitly allowlisted via /permissions skip the check. Writes, shell commands with side effects, and calls against external systems are where it earns its keep.

How it decides

The classifier looks at three things together:

  • The tool being called. Bash with destructive flags is treated differently from Read. A custom MCP tool that writes to a production database carries more weight than one that reads a config file.
  • The arguments. A Bash call with rm -rf or a force-push to main raises the score sharply. A set-status MCP call that tries to move a record from failed straight to approved (skipping intermediate states) gets flagged as a likely state-machine violation.
  • The conversation context. Did the user explicitly authorize this? Is the agent about to make a write against production that wasn’t asked for? The classifier reads the recent turns to see whether the action was sanctioned.

A clear example: a tool call that attempts to set a row’s status from failed to approved when the schema only allows failed -> in_review -> approved is exactly the kind of pattern the classifier will catch — even if the underlying MCP tool would also reject it. The classifier is the first line, the tool logic is the second.

The defense hierarchy

Think of safety in Claude Code as three independent layers:

  1. The auto-classifier. Live risk scoring of tool calls before they execute. Catches the cases where the model went off-script, misread a request, or got tricked by injected content.
  2. The tool logic itself. A well-built MCP tool validates its own inputs — invalid state transitions return E_INVALID_STATE_TRANSITION (or your project’s equivalent), missing permissions return 403, malformed payloads return 400. The tool refuses the call even if the classifier let it through.
  3. The database / system constraints. Foreign keys, check constraints, role-based access, audit triggers. The last line. Even if a tool bug let bad data through, the DB rejects it.

The point isn’t that any single layer is perfect — none of them is. The point is that all three would have to fail simultaneously for a bad action to land, and that’s a very different risk profile from “one wrong tool call and we corrupt prod.”

Why it’s intentionally conservative

The classifier is tuned to err on the side of pausing rather than allowing. That means it sometimes interrupts perfectly safe actions — a routine status update, a write against a dev database, a script that looks like it could be destructive but isn’t.

This is a deliberate trade-off. False positives cost you a confirmation click. False negatives cost you a corrupted database. The cost ratio is heavily asymmetric, so the classifier is calibrated for the cheaper failure mode. Treat the occasional over-cautious prompt as the system working, not as friction to engineer away.

How to control it

Two main levers, both inside Claude Code:

  • /permissions allowlists. If you run the same safe tool call dozens of times a session, allowlist it. The classifier skips allowlisted calls entirely. Use this for frequent reads, common shell commands, and tools you’ve verified are safe.
  • Permission modes. Claude Code ships with four modes: Plan (no tool execution at all, the model only proposes), Default (classifier active, prompts on risky calls), Accept Edits (file edits go through without prompting, other risky calls still gated), and Bypass (no classifier, no prompts — only for sandboxed environments where nothing important is reachable).

The honest recommendation: stay in Default for normal work. Switch to Accept Edits during long refactors where you’ll review the diff anyway. Use Bypass only inside a throwaway container or VM.

When the classifier intervenes — concrete examples

A few patterns that reliably trigger it:

  • A Bash call containing rm -rf against any path above the current project.
  • A force push to main or master without explicit user instruction.
  • A write against a production database that wasn’t authorized in the conversation.
  • An MCP set-status call that violates a documented state machine.
  • A WebFetch against a host the agent hasn’t been told to access, especially when the response would be fed back into further tool calls.

In each case, the classifier’s job is to stop and ask. Not to refuse forever — to make sure the human knows what’s about to happen.

Bottom line

The auto-classifier isn’t a perfect filter. It’s an independent second opinion that catches the cases where the main model got it wrong, and it sits inside a stack of two further independent defenses (tool logic, DB constraints). Two reasonable safety layers in series beat one heavily over-engineered one, and that’s the architecture Claude Code is built on.

Knowing what the classifier does — and what it doesn’t — is the difference between trusting the tool with real work and either over-trusting it or fighting it constantly.