Tuning Your Claude Code Settings
Claude Code ships with a ton of features, and not all of them are useful. Some of them actively get in the way. There are also a lot of options for tuning it, enough that it gets overwhelming fast. So this is a short guide to everything I’ve done to tune my Claude Code settings, and why. I hope it helps you.
Every JSON block below is copy-ready. Drop the pieces you want into your own settings.json, and the $schema line validates them as you go, which is exactly why that’s the first thing to set up.
Start with the schema
The single most helpful change is one line, and it makes every other change easier. Point your settings file at the JSON schema and your editor gives you autocomplete, inline docs, and validation for every key and value, so you stop guessing which options exist and what they accept.
{ "$schema": "https://json.schemastore.org/claude-code-settings.json"}Get this right first and everything below becomes self-documenting in your editor.
For the $schema line to do anything, your editor needs a JSON language server installed. The one that powers this is Microsoft’s vscode-json-languageservice. In Neovim I run it as jsonls via nvim-lspconfig, pointed at both the settings and keybindings schemas:
jsonls = { settings = { json = { schemas = { { fileMatch = { '**/.claude/settings.json', '**/.claude/settings.local.json' }, url = 'https://json.schemastore.org/claude-code-settings.json', }, { fileMatch = { '**/.claude/keybindings.json' }, url = 'https://json.schemastore.org/claude-code-keybindings.json', }, }, validate = { enable = true }, }, },}Privacy and outbound traffic
I opt out of the outbound analytics. I run client work through Claude, so the less that leaves my machine, the better. These go in the env block, plus feedbackSurveyRate: 0 to kill the “How is Claude doing?” survey.
{ "env": { "DISABLE_TELEMETRY": "1", "DISABLE_ERROR_REPORTING": "1", "DISABLE_NON_ESSENTIAL_MODEL_CALLS": "1" }, "feedbackSurveyRate": 0}Note that env values are strings ("1", not 1), since they’re environment variables. feedbackSurveyRate is a number between 0 and 1.
Context management
{ "cleanupPeriodDays": 365}cleanupPeriodDays: 365keeps a year of transcript history instead of losing anything older than the default 30 days.
Update channel
I pin updates to the stable channel. On client work I’d rather the tool not shift under me mid-session, so I trade a few days of lag for a build I can trust.
{ "autoUpdatesChannel": "stable"}The other value is latest, which pulls new features (and the occasional rough edge) sooner. If you like being on the bleeding edge, flip it.
Permissions
My permissions are curated, not blanket. defaultMode: auto lets the classifier decide what’s safe, but the allow list only names things I’m comfortable running unattended, and the deny list hard-blocks the stuff I never want touched.
{ "permissions": { "defaultMode": "auto", "allow": [ "Read", "Edit", "Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(git show:*)", "Bash(git add:*)", "Bash(git commit:*)", "Bash(git branch:*)", "Bash(git checkout:*)", "Bash(git switch:*)", "Bash(git stash:*)", "Bash(git fetch:*)", "Bash(git pull:*)", "Bash(git restore:*)", "Bash(git rev-parse:*)", "Bash(git remote:*)", "Bash(git tag:*)", "Bash(git blame:*)", "Bash(git worktree:*)", "Bash(npm *)", "Bash(pnpm *)", "Bash(node *)", "Bash(ls *)", "Bash(which *)", "Bash(mkdir *)", "Bash(cat *)", "Bash(jq *)" ], "deny": [ "Read(.env*)", "Edit(.env*)", "Bash(cat *.env*)", "Bash(head *.env*)", "Bash(tail *.env*)", "Bash(less *.env*)", "Bash(more *.env*)" ] }}The valid values for defaultMode are default, acceptEdits, plan, and auto. I’m on auto.
The key idea in the allow list is that I enumerate safe git verbs rather than granting Bash(git *) wholesale. Everyday work like status, diff, commit, branch, and checkout stays prompt-free. But destructive verbs I didn’t list (reset --hard, rebase, clean) fall through to the classifier and ask first. That’s the tradeoff: a little friction on the dangerous stuff, none on the daily stuff.
The deny list layers several .env denials instead of trusting one. That’s deliberate; see the Gotchas below.
Trimming the system prompt
This is a different token angle from everything above. The privacy settings trim outbound traffic. These trim the system prompt itself: the tool and feature definitions Claude Code ships on every request. Matt Pocock’s point is that harnesses front-load thousands of tokens of built-in tooling you may never use, and disabling a feature removes its definition from the prompt entirely. His logic, which I buy: the less you send over the wire, the less there is to distract the agent, so outputs get better, not just cheaper.
{ "disableArtifact": true, "disableWorkflows": true, "disableBundledSkills": true, "env": { "CLAUDE_CODE_DISABLE_CRON": "1" }}What each one turns off:
disableArtifact— the Artifact tool. No use for it in a terminal workflow.disableWorkflows— the dynamic Workflow orchestration tool. Big footprint, never used it.disableBundledSkills— nukes all first-party bundled skills (/init,/run,/simplify,/keybindings-help, etc.), not just the one I was after. My plugin skills and custom vault skills are unaffected. I chose the full cut for the token savings.CLAUDE_CODE_DISABLE_CRON: "1"— cron / scheduled tasks. This one is env-var only; there’s nosettings.jsonkey for it.
What I kept on purpose: AskUserQuestion (I like being asked to choose), and remote control — it exists as disableRemoteControl, but leaving it off is what drives my phone push notifications during sessions.
What I couldn’t disable: plan mode. There’s no key for it; EnterPlanMode / ExitPlanMode are hardwired, and the disable is a known open request.
Does it actually help?
I measured it instead of taking anyone’s word. I pointed ANTHROPIC_BASE_URL at a tiny local server, ran claude -p "hi" once with the flags off and once on, and diffed the captured request body.
| System prompt + tools | Before | After | Δ |
|---|---|---|---|
| Tool count | 10 | 9 | −1 |
| Estimated tokens | ~20,162 | ~14,770 | −5,391 |
That’s a ~27% smaller baseline, ~5,391 tokens saved per request. The entire delta was disableWorkflows removing the Workflow tool.
One caveat: this measured print mode (claude -p), which uses a deferred-tool architecture, so disableArtifact, disableBundledSkills, and cron showed zero effect in this test. Those get injected at runtime in interactive sessions, so their real savings land there and weren’t captured here.
Token limits
The trimming above shrinks what goes out on every request. These cap what comes back, so a single response, tool call, or subagent can’t blow up my context in one shot. They all live in the same env block as the privacy settings.
{ "env": { "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "16000", "MAX_THINKING_TOKENS": "8000", "MAX_MCP_OUTPUT_TOKENS": "25000", "TASK_MAX_OUTPUT_LENGTH": "20000" }}What each one caps:
CLAUDE_CODE_MAX_OUTPUT_TOKENS— the ceiling on a single response. Keeps replies from running away.MAX_THINKING_TOKENS— the extended-thinking budget.8000is plenty for the reasoning I want without paying for a marathon.MAX_MCP_OUTPUT_TOKENS— how much an MCP tool call can dump back into context. MCP responses are the worst offenders for silently eating the window, so this one earns its keep.TASK_MAX_OUTPUT_LENGTH— the cap on what a subagentTaskreturns to the main thread.
Same rule as before: these are strings ("16000"), since they’re environment variables. And as noted in the Gotchas, Fable 5 ignores MAX_THINKING_TOKENS entirely, since it always reasons adaptively.
Attribution
I don’t want Claude co-authoring my commits.
{ "includeCoAuthoredBy": false}Spinner verbs
A small joy: I replace the default spinner text with my own list. mode is replace (swap the whole list) or append (add to it). Because I like these, I deliberately do not set spinnerTipsEnabled: false.
{ "spinnerVerbs": { "mode": "replace", "verbs": [ "Hallucinating responsibly", "Pretending to think", "Confidently guessing", "Consulting my imagination", "Speedrunning your tech debt", "Apologizing in advance", "Vibing with your codebase", "Submitting my best guess", "Amaze amaze amaze", "Breeding astrophage", "Harvesting xenonite", "Using the Force", "Making the Kessel Run", "Powering up the hyperdrive", "Negotiating aggressively", "Bypassing the compressor", "Walking into Mordor", "Speaking friend and entering", "Dodging bullets", "Downloading kung fu", "Following the white rabbit", "Declaring bankruptcy", "Treating myself", "Casting Expelliarmus", "Brewing polyjuice potion", "Hitting 88 mph", "Storming the castle", "Warping through pipes", "Making a huge mistake", "Making fetch happen", "Riding the sandworm", "Enhancing the image", "Hacking the mainframe", "Assembling the Avengers", "Choosing violence", "Rolling a nat 20", "Pulling a Leeroy Jenkins", "Activating ludicrous speed", "Activating lightspeed", "Stealing the moon", "Reconnecting the chiral network", "Refining the scary numbers", "Trying to exit Vim", "Compiling shaders", "Pulling a shot" ] }}Keybindings I actually use
These aren’t in settings.json. They live in ~/.claude/keybindings.json (editable via /keybindings). The three I reach for most at the prompt:
- Ctrl-S — stash the current prompt. Whatever I’ve typed gets set aside; press Ctrl-S again on an empty prompt to bring it back. Good for parking a half-written thought.
- Ctrl-G — send the current prompt to
$EDITOR. For anything longer than a line or two I’d rather compose in vim. (Ctrl-X Ctrl-Eis the readline alias.) - Ctrl-V — paste from the clipboard, including images (drops in as an
[Image #N]chip).
Others worth knowing:
| Key | What it does | Why I care |
|---|---|---|
| Shift-Tab | Cycle permission modes | Switch to plan mode without leaving the prompt |
| Esc Esc | Open the rewind menu | Restore conversation/code to an earlier point |
| Ctrl-R | Reverse-search prompt history | Fuzzy find a prompt I’ve run before |
| Ctrl-O | Toggle the transcript viewer | Full tool trace, timestamps, expanded MCP calls |
| Ctrl-B | Background the running task | Park a long build/test and keep working |
| Ctrl-T | Toggle Claude’s task checklist | Glance at the current plan |
| /btw | Ask a side question without polluting history | Quick “what’s this?” while Claude works |
macOS caveat: the Option/Alt bindings need Option-as-Meta enabled (iTerm: Profiles → Keys → Left/Right Option = “Esc+”). Ctrl-C and Ctrl-D are hardcoded and can’t be rebound.
Gotchas
denyrules aren’t a hard secrets boundary. There are reports of Claude reading.envdespite a deny rule, which is why I layer multiple.envdenials rather than trusting one. Don’t treat deny as a security guarantee.- Narrowing git means
reset --hard/rebase/cleannow prompt. Everyday commits stay prompt-free; the destructive verbs intentionally ask first. - Fable 5 ignores all thinking toggles.
MAX_THINKING_TOKENS=0, the session toggle, andalwaysThinkingEnabledhave no effect on it, since it always reasons adaptively.
Settings I evaluated but skipped
defaultMode: plan(the plan-then-auto-accept loop) — deliberately staying onauto; it’s a workflow philosophy change, not a clear win for me.spinnerTipsEnabled: false— I like my custom spinner verbs too much./sandboxmode — file + network isolation that reduces prompts; worth revisiting.disableClaudeAiConnectors— kills the Gmail/QuickBooks/MongoDB/Slack connector definitions in one shot, likely the single biggest remaining token chunk. Worth measuring with a proxy before pulling.
Wrapping up
Claude Code is a powerful tool with a lot of capabilities, and that’s exactly why it’s worth spending some time on it. Sometimes just a few minutes to tweak your preferences and adjust your settings. A few well-chosen changes cut the noise and get the tool out of your way. Take what’s useful here, skip what isn’t, and tune it until it gives you the best results.
Sources
- Trimming the Claude Code system prompt — Matt Pocock
- 12 Hidden Settings to Enable in Claude Code — Simon Scrapes
- Claude Code settings.json complete guide — eesel AI
- My Claude Code Setup (2026 Edition) — Marco Lancini
- How I Use Every Claude Code Feature — Shrivu Shankar
- Claude Code docs: environment variables
Sign-Up for New Posts
Stay in the loop and get the latest blog posts about dotfiles sent to your inbox.
Or use the