Tech 5 min read

Claude Code Settings: Ideal vs. Reality

@adocomplete posted “5 Claude Code Settings” on X. Went in hoping to escape the constant Ask prompts — and came out with a clearer picture of where the ideal meets reality.

Previously wrote about Claude Code permission settings being completely opaque, about three weeks ago. Did anything change? Time to check.

The 5 Settings

Here’s what Ado shared:

1. defaultMode: “acceptEdits”

{
  "permissions": {
    "defaultMode": "acceptEdits"
  }
}

Auto-approve file edits. Bash commands still prompt.

The idea: you’re reviewing the diff anyway, so clicking “approve” on each edit is just noise.

2. attribution

{
  "attribution": {
    "commit": "",
    "pr": ""
  }
}

Controls the Co-authored-by: Claude line in git commits and pull requests. Empty string gives you a clean history.

Replaces the old includeCoAuthoredBy setting.

3. cleanupPeriodDays

{
  "cleanupPeriodDays": 0
}

How many days to keep session history. Default is 30.

  • 0: wipe every session
  • Larger values: keep history longer

4. alwaysThinkingEnabled

{
  "alwaysThinkingEnabled": true,
  "env": {
    "MAX_THINKING_TOKENS": "8000"
  }
}

Enables Extended Thinking on every response. Trades latency for quality.

The MAX_THINKING_TOKENS env var controls how many tokens to spend on thinking.

5. additionalDirectories

{
  "permissions": {
    "additionalDirectories": ["../shared-lib", "~/docs"]
  }
}

By default, Claude Code is sandboxed to the project directory. Use this to grant access to shared libraries or sibling directories in a monorepo.

Where the Settings Live

OSUser settingsProject settings
Windows%USERPROFILE%\.claude\settings.json.claude/settings.json
macOS/Linux~/.claude/settings.json.claude/settings.json

Project settings can be committed to git. Personal overrides go in .claude/settings.local.json (gitignore recommended).

The Gap Between Expectation and Reality

Here’s where things get interesting.

Wildcards aren’t truly wild

Writing Bash(npm *) doesn’t prevent Bash(npm run build:*) from being added separately.

The official docs say it plainly:

Bash rules use prefix matching, not regex

Bash patterns are prefix matches and can be bypassed

Prefix matching, not regex. And explicitly “can be bypassed.”

bypassPermissions still asks for some things

defaultMode has three levels:

ModeBehavior
askAlwaysPrompt every time (default)
acceptEditsAuto-approve files, prompt for Bash
bypassPermissionsAuto-approve everything

Thought bypassPermissions meant fully hands-off. In practice, some minimum confirmations still appeared — WebFetch needed individual approval too.

Side note: built a WebFetch alternative skill to skip approval prompts, but it’s not a complete solution since Claude Code can’t access sites it can’t access regardless of the skill.

One creative workaround: use an MCP to have Gemini fetch URLs and pass back only the results. AI collaboration — Gemini is less likely to block Google’s own ecosystem.

The allow list has limits

{
  "permissions": {
    "allow": [
      "Bash(pnpm:*)",
      "Bash(git:*)"
    ]
  }
}

This should mean “pnpm and git, no questions.” Mostly.

In practice, each new subcommand gets appended to settings.local.json. The issue described in the previous article is still there.

What Actually Works

Perfect control isn’t realistic. Tune to your workflow.

”One task, one chat” style

{
  "cleanupPeriodDays": 0,
  "permissions": {
    "defaultMode": "acceptEdits"
  }
}

No need for session history. Once the task is done, the context is done. Useful knowledge goes into CLAUDE.md.

”Just let it run” style

{
  "permissions": {
    "defaultMode": "acceptEdits",
    "allow": [
      "Bash(pnpm:*)",
      "Bash(npm:*)",
      "Bash(git:*)",
      "Bash(docker:*)"
    ]
  }
}

Pre-allow the common commands. Not perfect, but reduces the Ask frequency.

Quality-focused style

{
  "alwaysThinkingEnabled": true,
  "env": {
    "MAX_THINKING_TOKENS": "10000"
  }
}

Useful for complex refactors or architecture decisions. But there’s a latency and cost tradeoff (when using the API).

For simple tasks, using /think on demand is often more efficient than always-on thinking.

What I Adopted and What I Didn’t

SettingAdoptedReason
defaultMode: "acceptEdits"YesWant to hand off the work
cleanupPeriodDays: 0YesOne task, one chat
attribution: ""NoKeeping AI attribution for transparency
alwaysThinkingEnabledNo/think when needed is enough
additionalDirectoriesNoNot needed for current project structure

There’s no single configuration that makes Claude Code perfect.

  • Wildcards are prefix matches and can be bypassed
  • bypassPermissions still prompts for some things
  • The allow list isn’t airtight, but it does reduce Ask frequency

Don’t chase perfection. Cherry-pick what fits your workflow and accept that things won’t always behave exactly as configured — that’s just how it is.

References