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. They don’t crash. Nothing scary happens when you press enter. That’s the whole point — defaults are tuned to be safe for everyone, which is another way of saying they’re optimal for nobody.
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."
That’s the trick. 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 reads, Claude thinks. They make a surprisingly good couple.
Claude’s window stays clean for the part that actually matters: 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.” They are not writing your application. They are doing 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"
Three flags. All off by default. All of them sound like features you’d want. None of them are.
DISABLE_1M_CONTEXT. The 1M context window sounds like a cheat code. In practice it’s a way to set fire to tokens while making your first-token latency worse and your output quality decay faster. A 200K-token conversation is not “better” than a 30K-token one — it’s one where you’ve buried the signal under a pile of stuff Claude can’t usefully ignore. More context is not more intelligence. It’s just more haystack.
DISABLE_AUTO_MEMORY. 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, you don’t always know what’s in it, and you can’t figure out why Claude is suddenly insisting on a pattern from a project you abandoned six months ago. The road to a polluted context starts with one auto-saved fact you forgot you ever told it.
DISABLE_ADAPTIVE_THINKING. 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 isn’t about saving tokens. It’s about Claude no longer making things up.
Without LSP, Claude finds symbols by grepping. Grep does not know that useUser is exported from three different files. Grep does not know which User type you mean. Grep is a regex with confidence issues.
With LSP on, Claude calls into your actual language server. Real types. Real definitions. Real call sites. Hallucinated function signatures basically vanish. So do wrong-import suggestions. The difference is so big I’d argue it should be on by default — but 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. That’s it. No Edit. No Write. No rm. No destructive bash.
Sounds like I’ve crippled the agent. I haven’t. Claude can still write code — it just has to ask first. Asking 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. Both wins.
A fast loop is a focused loop.
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 you’ll notice that aren’t in the five moves above. effortLevel: max — I want maximum reasoning effort on the main thread, since the cost-saving already happened in the subagents. voiceEnabled because I talk to my computer like a sociopath. Not pictured but equally important: prune your enabledPlugins. Every enabled plugin loads its tool descriptions into the context window. Keep on only what you actually use and leave the rest off. Default-on plugins are an underrated tax.
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’s not 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. You’re neither of those anymore. You’ve shipped something with this thing. You’ve watched it eat tokens. You know where it flails and where it flies. You’ve outgrown vibe-coding on defaults.
Treat your settings.json like your .vimrc — something you tune over years until it fits your hand.
The default config is the one optimized for nobody. Yours should be optimized for you.