← Back to Blog

VelocitySignals

Stop Repeating Yourself to Claude Code

By Darshil Shah · Nov 2026 · 8 min read

  • Claude Code
  • AI Coding
  • Developer Productivity
  • settings.json
  • Automation

Every Claude Code user picks up the same habit: typing the same instructions again and again.

“Use yarn, not npm.”

“Do not read my .env file.”

“Run linting after every edit.”

“Ask me before you run git push.”

Claude Code forgets them the moment the session ends. Nothing is written down anywhere.

Write them down once in `settings.json` and Claude Code never forgets them.

## What is settings.json?

`settings.json` is a plain text file written in JSON. Think of it as Claude Code’s control panel: every rule you write there changes how Claude Code behaves.

An instruction you type in the chat lasts only for that conversation. A rule in this file applies to every session, because Claude Code reads the file each time it starts.

A file with the settings most people use looks like this:

```json

{

"$schema": "https://json.schemastore.org/claude-code-settings.json",

"model": "sonnet",

"cleanupPeriodDays": 14,

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

"permissions": {

"defaultMode": "acceptEdits",

"allow": ["Bash(yarn test *)", "Bash(yarn lint *)", "Bash(git diff *)"],

"ask": ["Bash(git push *)"],

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

},

"hooks": {

"PostToolUse": [

{

"matcher": "Edit|Write",

"hooks": [{ "type": "command", "command": "bash .claude/hooks/prettier.sh" }]

}

]

}

}

```

Read it from the top:

- **`$schema`:** points your editor at the list of valid settings. Your editor then suggests setting names and marks typos as you type.

- **`model`:** keeps every session on Sonnet, so you never pick a model at startup.

- **`cleanupPeriodDays`:** how long Claude Code keeps old sessions and related local data before deleting them. The default is 30 days.

- **`attribution`:** sets the note Claude adds to commits and pull requests. An empty string on either field removes that note.

- **`permissions`:** decides what Claude may run on its own, what needs your approval and what it must never do.

- **`hooks`:** runs your commands automatically, such as Prettier after an edit.

Claude Code reads this file when it starts and keeps watching it while it runs. Most edits apply right away. `model` is the one exception: restart Claude Code after you change it.

To use this file well, you need three ideas: scope, permissions and hooks.

## Scope

Claude Code reads settings from more than one place. Each place is called a scope. Strongest to weakest:

1. **Managed scope (enterprise policy).** A company sets these rules for its employees. You cannot create or edit this file yourself. This scope always wins.

2. **Local scope** (`.claude/settings.local.json`). Your personal settings for one project. Saved on your computer only, not shared with your team.

3. **Project scope** (`.claude/settings.json`). Shared settings for one project. Saved in git, so your whole team uses the same file.

4. **User scope** (`~/.claude/settings.json`). Your personal defaults for every project. This one is the weakest.

When two files set the same thing to different values, the one higher on that list wins.

Say your user scope file sets `"model": "sonnet"` and a project scope file sets `"model": "opus"`. Project scope is higher, so that project runs on Opus. Projects without their own file still run on Sonnet.

Permissions are the one exception: they add up instead of replacing each other. If your user scope allows `Bash(git *)` and your project scope allows `Bash(yarn lint *)`, both stay active. A deny rule in any file wins over an allow rule in any other file.

When a setting does not work, a higher scope is almost always overriding it. Usually it is a local scope file you forgot about or a managed scope file you did not know was there.

You can also set something for one session only with a command-line flag, such as `claude --model opus`. A flag lasts only for that session and it overrides every settings file except managed scope.

## Permissions

`permissions` has three main keys:

- **`allow`:** Claude runs these without asking. Use it for safe commands you run many times a day.

- **`ask`:** Claude checks with you every time. Use it for things that should happen rarely and on purpose.

- **`deny`:** Claude never does these and does not even ask. Use it for things that must never happen.

```json

{

"permissions": {

"allow": ["Bash(yarn test *)"],

"ask": ["Bash(git push *)"],

"deny": ["Read(./.env)"]

}

}

```

Each entry is a rule with a tool name and an optional detail in brackets. `Bash(yarn test *)` means the Bash tool, matching commands that start with `yarn test`.

Leave out the brackets and the rule applies to everything that tool does. In a deny list, a plain `Bash` would block every command Claude runs.

### How path rules work

For Read and Edit, the detail is a file path. How you start that path decides which folder Claude Code looks in:

- `./` is the folder you started Claude Code in, so `Read(./.env)` covers the `.env` file in that folder.

- `/` is the folder your settings file is in, usually your project root, so `Edit(/src/**/*.ts)` covers the project-level `src` folder.

- `~/` is your own user folder, so `Read(~/.ssh/**)` covers your SSH keys.

- `//` is a disk path, so `Read(//tmp/**)` covers the `/tmp` folder on your machine.

`*` matches inside one folder name. `**` matches across folders.

### Which rule Claude Code uses

Claude Code checks every action against your rules in a fixed order: deny first, then ask, then allow. The first match decides the answer and Claude Code stops checking there.

A more specific rule does not change this order. If you deny `Bash(docker *)` and also allow `Bash(docker ps)`, `docker ps` still gets blocked. Do not pair a broad deny with a narrow allow. Deny only the commands you actually want to stop.

### How modes work

Rules control individual tools. A mode sets behavior for a whole session. Set `permissions.defaultMode` to pick which mode your sessions start in:

- **`manual`:** read files, nothing more.

- **`plan`:** read files and explore, then write a plan for you to approve.

- **`acceptEdits`:** read and edit files. It also runs basic file commands like `mkdir`, `mv`, `cp` and `rm`.

- **`auto`:** everything, with a safety check on risky actions before they run.

- **`dontAsk`:** only the commands your allow list already covers. It never waits for you, so it fits CI pipelines.

- **`bypassPermissions`:** everything, with no checks at all.

A few limits worth knowing:

- In plan mode, your files stay untouched until you approve the plan.

- `acceptEdits` skips the prompt only for files inside the folder you started Claude Code in.

- `auto` works on Opus 4.6 or later, Sonnet 4.6 or later and Fable 5. On any other model your session runs in manual instead.

- Your deny and ask rules still apply in every mode, even `bypassPermissions`.

- Use `bypassPermissions` only inside a container or a virtual machine.

You are not stuck with the mode you started in. Press Shift+Tab in the terminal to move between modes.

## Hooks

Permissions only allow or block what Claude tries to do. Hooks run your commands.

For example, a hook can run Prettier after every edit. It does not depend on Claude remembering to format the file.

Keep each hook simple: fast, doing one thing and safe to run many times.

```json

{

"hooks": {

"PostToolUse": [

{

"matcher": "Edit|Write",

"hooks": [{ "type": "command", "command": "bash .claude/hooks/prettier.sh" }]

}

]

}

}

```

This hook has three parts:

- **Event:** `PostToolUse` — when the hook fires.

- **Matcher:** `"Edit|Write"` — which tools it watches.

- **Handler:** the command that runs your script.

Keep the real logic in script files under `.claude/hooks/` instead of writing it all inside the JSON file.

Events you will use most:

- **`PreToolUse`:** runs just before a tool starts. Your script can cancel the action.

- **`PostToolUse`:** runs after a tool has finished.

- **`Stop`:** runs when Claude thinks it has finished. If your script says the work is not done, Claude keeps working.

- **`SessionStart` / `SessionEnd`:** run when a session opens and when it closes.

### How your script cancels an action

Your script ends by returning an exit code:

- **`exit 2`:** cancels the action. Claude reads the message printed by your script.

- **`exit 0`:** nothing is wrong. The action goes ahead.

- **`exit 1`:** your script hit a problem. Claude Code shows a warning and the action still goes ahead.

A common mistake is ending a safety hook with `exit 1`. That prints your warning, but the action still runs. Use `exit 2` instead.

Of those events, only `PreToolUse` and `Stop` can cancel this way.

## What we learned

- **Scope:** where to put your settings file and which file wins when two of them disagree.

- **Permissions:** what Claude can run on its own, what needs your approval and what is never allowed.

- **Hooks:** how to make the important steps run every time, without depending on Claude to remember them.

Write each of these down once and you stop repeating yourself. The official docs always have the latest details, so keep them bookmarked. Claude Code changes quickly and new settings keep getting added.