← All posts

Stop Using Claude Code on Defaults

Defaults are for someone else

Most devs install Claude Code, run /init once, and never open settings.json again. Then they wonder why their token bill looks like a phone bill from 2003.

I get it. The defaults work, and nothing scary happens when you press enter. They’re tuned to be safe for everyone, which means they’re tuned for nobody in particular.

Here are five settings I changed in ~/.claude/settings.json and ~/.claude/CLAUDE.md. Each one buys back something specific: tokens, output quality, or hours of my week.

1. Delegate research to Gemini

This is the one that pays for itself in a day.

In your ~/.claude/CLAUDE.md, give Claude an explicit instruction: when you need to do heavy reading, shell out to Gemini.

gemini --sandbox -p "Read src/lib/auth and explain how the session refresh works. Be concise."

Whenever Claude needs to summarize a 12,000-line PRD, explore an unfamiliar package, or trace a function across forty files, it shells out to a sandboxed gemini subprocess. Gemini reads the haystack in its own context window, hands back the summary, and exits. Claude’s context never sees the raw text.

Yes, Gemini, from Google, the one your CTO hasn’t found a budget line for yet. I don’t care. Gemini does the reading, Claude does the thinking, and they work surprisingly well together.

Claude’s window stays clean for editing my code. I’m not burning 80K tokens just to figure out where a function lives. That work happens on someone else’s clock.

This is context engineering at its most literal: the context window is a scarce resource, so make somebody else burn theirs.

2. Stop paying Opus rates for janitorial work

"CLAUDE_CODE_SUBAGENT_MODEL": "sonnet"

Subagents are the worker bees of Claude Code. They go off, grep, search, read three files, and report back “yeah this looks fine.” Your application gets written elsewhere; this is janitorial reasoning.

Paying Opus rates to run subagents is like hiring a senior engineer to delete node_modules. They’ll do it correctly. They will also charge you for it.

Sonnet handles subagent work indistinguishably from Opus 95% of the time. The remaining 5% I can’t pick out blind. The bill, I can.

3. Kill the invisible bloat

"CLAUDE_CODE_DISABLE_1M_CONTEXT": "1",
"CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1",
"CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING": "1"

The three features behind these flags are on by default, and each sounds like something you’d want. I turn all three off.

The 1M context window (DISABLE_1M_CONTEXT) sounds like a cheat code. In practice it sets fire to tokens, makes your first-token latency worse and makes output quality decay faster. In a 200K-token conversation you’ve usually buried the signal under a pile of stuff Claude can’t usefully ignore, and a 30K-token one would have done the job better.

Auto memory (DISABLE_AUTO_MEMORY) is when Claude silently writes things to a memory file across sessions. Sounds helpful until you realize you didn’t write that memory and don’t always know what’s in it. Then one day Claude insists on a pattern from a project you abandoned six months ago, and you can’t figure out why.

Adaptive thinking (DISABLE_ADAPTIVE_THINKING) means thinking tokens you didn’t ask for, billed to you anyway. I’d rather decide for myself when I want extended thinking on. Mostly I don’t.

4. Turn LSP on (the free lunch)

"ENABLE_LSP_TOOL": "1"

This one is for accuracy: it stops Claude from making things up.

Without LSP, Claude finds symbols by grepping. Grep doesn’t know that useUser is exported from three different files, or which User type you mean. It’s a regex with confidence issues.

With LSP on, Claude calls into your actual language server and gets real types, definitions and call sites. Hallucinated function signatures basically vanish, and so do wrong-import suggestions. The difference is big enough that I think it should be on by default. It isn’t, so here we are.

If you do nothing else from this post, do this one. It’s a single env var.

5. Read-only by default, surgical writes

"permissions": {
  "allow": [
    "Read", "Glob", "Grep", "LSP",
    "Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)",
    "Bash(npm run:*)", "Bash(npx tsc:*)",
    "Bash(ls:*)"
  ]
}

My allowlist is read tools, the read-only git commands, npm run, npx tsc, and ls. There’s no Edit, no Write, no rm and no destructive bash.

That sounds like I’ve crippled the agent, but Claude can still write code. It just has to ask first, and approving takes one keystroke.

What this kills is the death-by-a-thousand-prompts loop where you approve git status for the four hundredth time and slowly lose your will to ship. The 80% of operations that are obviously safe just happen, silently, instantly. The 20% that aren’t get a real human in the loop. I haven’t lost work to a stray rm -rf in months, and I haven’t approved an ls in just as long.

The whole thing

Here’s the general-purpose ~/.claude/settings.json underneath all five moves. Nothing project-specific. Steal what you like.

{
  "env": {
    "ENABLE_LSP_TOOL": "1",
    "CLAUDE_CODE_DISABLE_1M_CONTEXT": "1",
    "CLAUDE_CODE_SUBAGENT_MODEL": "sonnet",
    "CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1",
    "CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1",
    "CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING": "1"
  },
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "LSP",
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(git branch:*)",
      "Bash(git show:*)",
      "Bash(git blame:*)",
      "Bash(npm run:*)",
      "Bash(npx tsc:*)",
      "Bash(ls:*)",
      "Bash(node:*)",
      "WebFetch",
      "WebSearch",
      "Skill"
    ],
    "defaultMode": "default"
  },
  "effortLevel": "max",
  "voiceEnabled": true
}

A couple of extras aren’t in the five moves above. I set effortLevel: max because I want maximum reasoning effort on the main thread; the cost saving already happened in the subagents. voiceEnabled is there because I talk to my computer like a sociopath. Not pictured but just as important: prune your enabledPlugins. Every enabled plugin loads its tool descriptions into the context window, the same tool-surface tax that endpoint-shaped MCP servers impose. Keep only what you actually use turned on.

And the relevant chunk of ~/.claude/CLAUDE.md that powers Move 1:

## Gemini CLI Delegation

Use Gemini CLI (`gemini`) to offload research and heavy-read tasks,
preserving your context window for editing and reasoning.

### When to Delegate to Gemini

- Summarizing or analyzing large documentation files
- Exploring unfamiliar codebases, libraries, or dependencies
- Searching for patterns across many files and synthesizing findings
- Reviewing large diffs or changelogs for relevant changes

### When NOT to Delegate

- Reading files you need in context for an immediate edit
- Writing, editing, or creating files (Gemini cannot use your tools)
- Git operations or any tool-dependent task
- Anything involving secrets, env vars, or auth tokens

That’s the config. It isn’t finished; I tweak it most weeks.

The defaults aren’t yours

The defaults exist for the new user who hasn’t yet earned the right to break things, and for the marketing demo where everything has to work without setup. If you’ve shipped something with Claude Code and watched it eat tokens, you know where it flails and where it flies, and you’ve outgrown vibe-coding on defaults.

Treat your settings.json like your .vimrc: something you tune over years until it fits your hand.