# Claude Code stopped using its own tools

> Source: <https://dev.to/dionysos/claude-code-stopped-using-its-own-tools-3h8g>
> Published: 2026-09-03 10:00:00+00:00

A week ago I installed the TypeScript LSP plugin for Claude Code. The pitch sold me. The agent works the way I do in an editor, navigating with go-to-definition and find-references instead of grepping around, and catching type errors as it writes instead of at the end of a task. I watched it work in that session and forgot about it.

A week later I went back to check what it had bought me. Nine calls, all inside the session where I tested it, on August 25. Zero across the twenty-seven sessions since.

That was annoying enough to go digging.

I pulled every session transcript from `~/.claude/projects`

for one repo, a large Next.js app I work in daily. 76 sessions, 8,343 tool calls, all on Opus 5, July 31 to September 1.

Across the whole period Bash took 70% of all tool calls. Over the last two weeks, 84%, while the built-in file tools fell to 7%.

(`defaultMode: "auto"`

the whole window, so that didn't change.)

`Grep`

and `Glob`

were called zero times in 8,343 tool calls. `grep`

ran 1,165 times through Bash and `rg`

another 116.

Here's one from my transcripts, reading a file:

```
sed -n 269,352p src/domains/billing/server/database/read.ts
```

This one ran three times in a row across different files:

```
perl -pi -e 's{\bvendorContracts\b}{importedContracts}g' previewVendorContractsSyncFunction.ts
```

`perl -pi`

to rename a symbol. In a repo where the LSP plugin with

find-references was installed and enabled. I stared at that one for a while, wondering if some phrasing of mine had nudged it toward the shell. No idea. There were 325 `python3`

and `perl`

rewrites doing what `Edit`

does natively.

When Claude actually modified a file it mostly used `Edit`

and `Write`

. The swaps happen when it reads and searches.

The [permissions docs](https://code.claude.com/docs/en/permissions#read-only-commands) explain a big chunk of it. A fixed set of Bash commands runs with no permission prompt in every mode:

These include

`ls`

,`cat`

,`head`

,`grep`

,`find`

, and read-only forms of

`git`

. The set is not configurable.

Every shell command it reached for instead of a built-in is on that list. 22%of my 5,837 Bash calls used nothing but commands from that list, 31% counting `git`

. None of them ever prompted.

Two of the rules in my deny list:

```
"deny": ["Read(**/.env)", "Bash(rm -rf:*)"]
```

Here is a command from my own transcripts, August 11:

```
DB=$(grep -m1 '^DATABASE_URL' .env | sed 's/^DATABASE_URL=//; s/^"//; s/"$//') \
  && psql "$DB" -c 'select u.email, um."organizationId", o.name, um.role from "User" u ...'
```

`Read(**/.env)`

is denied, but that call is not a `Read`

. It is a `grep`

, on the prompt-free list, so it never asked.

The v2.1.116 changelog says Glob and Grep are deliberately removed on native macOS and Linux builds, "replaced by embedded `bfs`

and `ugrep`

available through the Bash tool — faster searches without a separate tool round-trip." On my machine, `which bfs ugrep`

finds neither. The tools reference still lists `Grep`

and `Glob`

. The native build ships neither them nor the replacements.

I don't know whether that is deliberate or a build regression nobody caught.

There are open issues either way.[#64136](https://github.com/anthropics/claude-code/issues/64136) ties the missing tools to Bash storms and fabricated file paths.

[#52121](https://github.com/anthropics/claude-code/issues/52121) describes my exact setup, and calls it "particularly problematic for systems where bash grep/find are restricted by permission policies, as there's no alternative code-search path." And [#80267](https://github.com/anthropics/claude-code/issues/80267), labelled

`reproduced`

by maintainers, treats shell-based file editing as normal: diagnostics go stale "because Claude Code likes to use `sed`

, `python`

, and similar tools to edit files in place".

An undocumented env var helped a little (`CLAUDE_CODE_THRIFTY_SONIC=false`

, mentioned in one of those issues, documented nowhere). `Read`

and `Edit`

came back, `grep`

still won. So I wrote a `PreToolUse`

hook that denies Bash for

anything a built-in tool does better.

Blocking `grep`

did not make Claude reach for `Grep`

. It reached for `git grep`

, then `git ls-files`

, and I had to close those specifically. With those closed, it finally uses the right tools. It costs a few calls at the start of every session while the model works out what's blocked.

A hook that blocks `grep`

and `find`

leaves no search path at all. So the current setup allows `rg`

, `fd`

, `ls`

, `grep`

and `find`

through and keeps denying the rest.

The hook and the scripts are at [Dionysos5/claude-code-tool-mix](https://github.com/Dionysos5/claude-code-tool-mix).

Nothing in my settings changed. I only found out because a plugin got zero calls.

The deny list is still sitting in my settings and I couldn't tell you what else it doesn't cover. Permission rules bind to tool names, and the harness picks the tool. Am I supposed to write a rule for every shell equivalent of every built-in, and keep them current against a build that changes weekly? That's roughly what my hook is now, and I don't think it should be my job.
