From aaf7670b856a0d41440eeecba6eca108de2416c2 Mon Sep 17 00:00:00 2001 From: bastien Date: Thu, 2 Apr 2026 15:59:00 +0200 Subject: [PATCH] added settings --- README.md | 123 +++++++++++++++++++ link.sh | 9 ++ settings.json | 163 +++++++++++++++++++++++++ skills/init-project/SKILL.md | 36 +++++- templates/settings/.claudeignore | 106 ++++++++++++++++ templates/settings/SETTINGS.md | 132 ++++++++++++++++++++ templates/settings/settings.json | 81 ++++++++++++ templates/settings/settings.local.json | 32 +++++ 8 files changed, 678 insertions(+), 4 deletions(-) create mode 100644 link.sh create mode 100644 settings.json create mode 100644 templates/settings/.claudeignore create mode 100644 templates/settings/SETTINGS.md create mode 100644 templates/settings/settings.json create mode 100644 templates/settings/settings.local.json diff --git a/README.md b/README.md index d718a98..ecafcfe 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,12 @@ Clone the repo and symlink it into `~/.claude/`: git clone git@github.com:youruser/claude-config.git ~/claude-config mkdir -p ~/.claude +rm -rf ~/claude/agents ~/claude/skills ~/claude/CLAUDE.md ~/claude/settings.json ln -sf ~/claude-config/agents ~/.claude/agents ln -sf ~/claude-config/skills ~/.claude/skills ln -sf ~/claude-config/CLAUDE.md ~/.claude/CLAUDE.md +ln -sf ~/claude-config/settings.json ~/.claude/settings.json ``` Symlinks mean any update to this repo is immediately active — no manual sync needed. @@ -82,8 +84,129 @@ Standalone skills (`/analyze`, `/debug`, etc.) invoke a single specialized agent └── tester → define test strategy ``` +## Settings and permissions + +Claude Code uses three settings files to control what it can and cannot do. +Each file has a different scope and purpose. + +### `~/.claude/settings.json` — global rules (all projects) + +**What it contains and why:** + +| Section | What it blocks / controls | +|---|---| +| `deny` — secrets | Prevents Claude from reading `.env`, `.pem`, `.key`, SSH keys, cloud credentials | +| `deny` — destructive Bash | Blocks `rm -rf`, `git push --force`, `git reset --hard`, `chmod 777` | +| `deny` — system access | Blocks `sudo`, `ssh`, `scp`, `netcat`, `crontab`, `systemctl` | +| `deny` — code injection | Blocks `curl \| bash`, `wget \| sh` patterns | +| `ask` — risky but needed | Prompts before `git push`, `docker run`, `brew/apt install` | +| `allow` — safe read ops | Auto-approves `git status/log/diff`, `ls`, `cat`, `grep`, `find` | +| `disableBypassPermissionsMode` | Prevents switching to "no prompts at all" mode mid-session | + +These rules apply to every project on your machine. They cannot be +overridden by project-level settings — **deny always wins globally**. + --- +### `.claude/settings.json` — project rules (committed to git) + +Copy the project template into each new project: + +```bash +mkdir -p .claude +cp ~/claude-config/templates/settings/settings.json .claude/settings.json +``` + +**What it contains and why:** + +| Section | What it allows / controls | +|---|---| +| `allow` — build commands | Auto-approves `npm run *`, `cargo build/test`, `make`, `pytest`, `flutter *`, etc. | +| `allow` — language tools | Auto-approves formatters, linters, type checkers (ruff, mypy, clippy...) | +| `allow` — runtime commands | Auto-approves `node`, `python`, `php`, `dart` within the project | +| `ask` — database commands | Prompts before `psql`, `mysql`, `mongosh`, `redis-cli` | +| `ask` — deploy commands | Prompts before `make deploy`, `npm run deploy`, `cargo publish` | + +Only put project-specific rules here. Generic security rules belong +in `~/.claude/settings.json`, not repeated per project. + +Shared with the team via git — keep it stack-appropriate and avoid +personal paths or machine-specific commands. + +--- + +### `.claude/settings.local.json` — personal overrides (never committed) + +Copy the template and add to `.gitignore`: + +```bash +cp ~/claude-config/templates/settings/settings.local.json .claude/settings.local.json +echo ".claude/settings.local.json" >> .gitignore +``` + +**What it contains and why:** + +| Section | What it controls | +|---|---| +| `allow` — trusted WebFetch | Auto-approves fetching from specific doc domains (docs.rs, MDN, flutter.dev...) | +| `additionalDirectories` | Grants Claude access to directories outside the project root (personal shared libs, etc.) | +| Personal overrides | Any rule you want on your machine that shouldn't affect teammates | + +This file has the highest priority of all file-based settings. +Use it for anything environment-specific or personal. + +--- + +### `.claudeignore` — hard file exclusion (committed to git) + +Copy to each project root: + +```bash +cp ~/claude-config/templates/settings/.claudeignore .claudeignore +``` + +**What it does and why it is different from `deny` rules:** + +`deny` rules in `settings.json` block specific tools from accessing files. +`.claudeignore` goes further — it removes files from Claude's awareness +entirely, regardless of which tool is used. + +| Excluded by default | Why | +|---|---| +| `.env`, `.env.*` | Secrets must never appear in Claude's context | +| `*.pem`, `*.key`, `*.p12` | Private keys and certificates | +| `id_rsa*`, `id_ed25519*`, `.ssh/` | SSH credentials | +| `.aws/`, `.azure/`, `.gcloud/` | Cloud provider credentials | +| `node_modules/`, `dist/`, `build/` | Generated artifacts — noise, no value | +| `*.png`, `*.jpg`, `*.pdf`, `*.zip`... | Binaries Claude cannot process usefully | +| `*.log`, `*.sqlite`, `*.db` | Runtime state, not source | + +A `.env` file excluded via `.claudeignore` cannot be read by Claude even +if a `Bash(cat .env)` would otherwise be allowed. Use both layers for +defense in depth. + +--- + +### Precedence summary + +``` +Highest + managed-settings.json — enterprise-wide, cannot be overridden + CLI flags — --allowedTools / --disallowedTools (session only) + settings.local.json — personal machine overrides + settings.json — project rules (team, committed) + ~/.claude/settings.json — global user rules +Lowest + +DENY always wins over ALLOW at any level. +.claudeignore applies independently of all permission rules. +``` + +--- + +--- + + ## Per-project setup Each project gets its own `.claude/CLAUDE.md` for local context and overrides. diff --git a/link.sh b/link.sh new file mode 100644 index 0000000..8c07a44 --- /dev/null +++ b/link.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +mkdir -p ~/.claude +rm -rf ~/claude/agents ~/claude/skills ~/claude/CLAUDE.md ~/claude/settings.json + +ln -sf ~/claude-config/agents ~/.claude/agents +ln -sf ~/claude-config/skills ~/.claude/skills +ln -sf ~/claude-config/CLAUDE.md ~/.claude/CLAUDE.md +ln -sf ~/claude-config/settings.json ~/.claude/settings.json \ No newline at end of file diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..728011d --- /dev/null +++ b/settings.json @@ -0,0 +1,163 @@ +{ + "_readme": "Global user settings — place at ~/.claude/settings.json. Applies to ALL projects. Never commit this file.", + + "cleanupPeriodDays": 30, + + "permissions": { + + "defaultMode": "default", + + "disableBypassPermissionsMode": "disable", + + "deny": [ + + "Bash(rm -rf *)", + "Bash(rm -rf /*)", + "Bash(rmdir *)", + + "Bash(git push --force*)", + "Bash(git push -f*)", + "Bash(git reset --hard*)", + "Bash(git clean -fd*)", + + "Bash(sudo rm*)", + "Bash(sudo chmod*)", + "Bash(sudo chown*)", + "Bash(sudo dd*)", + "Bash(su *)", + + "Bash(curl * | bash)", + "Bash(wget * | bash)", + "Bash(curl * | sh)", + "Bash(wget * | sh)", + + "Bash(chmod 777 *)", + "Bash(chmod -R 777 *)", + + "Bash(ssh *)", + "Bash(scp *)", + "Bash(rsync *)", + "Bash(nc *)", + "Bash(netcat *)", + + "Bash(kill -9 *)", + "Bash(killall *)", + "Bash(pkill *)", + + "Bash(crontab *)", + "Bash(systemctl *)", + "Bash(service *)", + + "Bash(npm install -g *)", + + "Read(**/.env)", + "Read(**/.env.*)", + "Read(**/secrets/**)", + "Read(**/*.pem)", + "Read(**/*.key)", + "Read(**/*.p12)", + "Read(**/*.pfx)", + "Read(**/id_rsa*)", + "Read(**/id_ed25519*)", + "Read(**/.ssh/**)", + "Read(**/credentials)", + "Read(**/credentials.json)", + "Read(**/.aws/credentials)", + "Read(**/.azure/**)", + + "Write(**/.env)", + "Write(**/.env.*)", + "Write(**/secrets/**)", + "Write(**/*.pem)", + "Write(**/*.key)" + ], + + "ask": [ + + "Bash(git push *)", + "Bash(git push)", + + "Bash(docker run *)", + "Bash(docker exec *)", + "Bash(docker-compose up*)", + "Bash(docker compose up*)", + + "Bash(brew install *)", + "Bash(apt install *)", + "Bash(apt-get install *)", + "Bash(dnf install *)", + "Bash(pacman -S *)", + + "WebSearch", + "WebFetch" + ], + + "allow": [ + + "Bash(git status)", + "Bash(git log*)", + "Bash(git diff*)", + "Bash(git branch*)", + "Bash(git fetch*)", + "Bash(git pull*)", + "Bash(git add *)", + "Bash(git commit*)", + "Bash(git checkout *)", + "Bash(git switch *)", + "Bash(git stash*)", + "Bash(git tag*)", + "Bash(git show*)", + + "Bash(ls *)", + "Bash(ls)", + "Bash(find *)", + "Bash(cat *)", + "Bash(head *)", + "Bash(tail *)", + "Bash(grep *)", + "Bash(rg *)", + "Bash(fd *)", + "Bash(wc *)", + "Bash(echo *)", + "Bash(pwd)", + "Bash(which *)", + "Bash(type *)", + "Bash(env)", + "Bash(printenv *)", + "Bash(whoami)", + "Bash(uname *)", + + "Bash(mkdir -p *)", + "Bash(touch *)", + "Bash(cp *)", + "Bash(mv *)", + + "Bash(jq *)", + "Bash(yq *)", + "Bash(sed *)", + "Bash(awk *)", + "Bash(sort *)", + "Bash(uniq *)", + "Bash(xargs *)", + "Bash(tr *)", + "Bash(cut *)", + "Bash(diff *)", + + "Read(**/*.md)", + "Read(**/*.txt)", + "Read(**/*.json)", + "Read(**/*.yaml)", + "Read(**/*.yml)", + "Read(**/*.toml)", + "Read(**/*.lock)", + "Read(**/*.gitignore)", + "Read(**/*.dockerignore)", + "Read(**/.claudeignore)", + "Read(**/Makefile)", + "Read(**/Dockerfile*)", + "Read(**/docker-compose*)" + ], + + "additionalDirectories": [] + } +} diff --git a/skills/init-project/SKILL.md b/skills/init-project/SKILL.md index 7813c10..ca1f9e7 100644 --- a/skills/init-project/SKILL.md +++ b/skills/init-project/SKILL.md @@ -150,16 +150,43 @@ The SCAFFOLDER will, in order: - How to run tests - Environment configuration -3. **Scaffold structure** — create every folder and file from +3. **Generate Claude Code settings** — create `.claude/` with: + + a. **`.claude/settings.json`** — from `~/.claude/templates/settings/settings.json`. + Adapt the `allow` rules to the actual project stack: + - Keep only the tool blocks relevant to this stack + - Add any stack-specific commands not already in the template + - Add project-specific `ask` rules (deploy targets, DB commands) + - Leave `deny` empty — global deny rules live in `~/.claude/settings.json` + + b. **`.claudeignore`** — from `~/.claude/templates/settings/.claudeignore`. + Extend with project-specific exclusions: + - Stack-specific build artifacts not already covered + - Sensitive file patterns specific to this project + - Directories identified in the DESIGN as generated or cache + + c. After creating these files, print: + ``` + ⚙️ SETTINGS SETUP + .claude/settings.json created — project-level permissions + .claudeignore created — file exclusions for Claude + + Manual step required: + Copy ~/.claude/templates/settings/settings.local.json + to .claude/settings.local.json and add it to .gitignore. + This file is personal and must not be committed. + ``` + +4. **Scaffold structure** — create every folder and file from the DESIGN with real content. -4. **Implement v1 features** — real working code for every +5. **Implement v1 features** — real working code for every feature in the PROJECT BRIEF. No stubs. No TODOs. -5. **Write initial tests** — at minimum one happy path and one +6. **Write initial tests** — at minimum one happy path and one edge case per module. -6. **Install and build** — actually run the install command, +7. **Install and build** — actually run the install command, build, and test suite. Fix any failures before reporting. --- @@ -256,5 +283,6 @@ NEXT STEPS CLAUDE.md : ✅ complete README.md : ✅ Windows / Linux / macOS +SETTINGS : ✅ .claude/settings.json + .claudeignore generated ================================================================ ``` diff --git a/templates/settings/.claudeignore b/templates/settings/.claudeignore new file mode 100644 index 0000000..8847ff3 --- /dev/null +++ b/templates/settings/.claudeignore @@ -0,0 +1,106 @@ +# ============================================================ +# .claudeignore — files Claude cannot read or use as context +# Same syntax as .gitignore +# ============================================================ + +# ---- Secrets & credentials -------------------------------- +.env +.env.* +!.env.example +secrets/ +*.pem +*.key +*.p12 +*.pfx +*.jks +credentials +credentials.json +service-account*.json +*-credentials.json +.netrc +.pgpass +.my.cnf + +# ---- SSH -------------------------------------------------- +.ssh/ +id_rsa* +id_ed25519* +*.pub + +# ---- Cloud provider credentials --------------------------- +.aws/ +.azure/ +.gcloud/ +gcloud-credentials* + +# ---- Build artifacts & caches ---------------------------- +node_modules/ +dist/ +build/ +.next/ +.nuxt/ +out/ +target/ +__pycache__/ +*.pyc +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +*.egg-info/ +.eggs/ +vendor/ +.cargo/registry/ +.gradle/ +.m2/ + +# ---- Binary & media files -------------------------------- +*.png +*.jpg +*.jpeg +*.gif +*.webp +*.ico +*.svg +*.mp4 +*.mp3 +*.pdf +*.zip +*.tar +*.tar.gz +*.tgz +*.rar +*.7z +*.dmg +*.exe +*.dll +*.so +*.dylib +*.wasm + +# ---- IDE & OS -------------------------------------------- +.idea/ +.vscode/ +*.swp +*.swo +*~ +.DS_Store +Thumbs.db +desktop.ini + +# ---- Logs & local databases ------------------------------ +*.log +logs/ +*.sqlite +*.sqlite3 +*.db + +# ---- Lock files (optional — remove if you want Claude to read them) -- +# package-lock.json +# yarn.lock +# Cargo.lock +# poetry.lock + +# ---- Large generated files -------------------------------- +coverage/ +.nyc_output/ +*.lcov diff --git a/templates/settings/SETTINGS.md b/templates/settings/SETTINGS.md new file mode 100644 index 0000000..8d5103f --- /dev/null +++ b/templates/settings/SETTINGS.md @@ -0,0 +1,132 @@ +# Claude Code — Settings Reference + +## Where each file goes + +``` +~/.claude/ +├── settings.json ← home-settings.json (renamed) — global, NEVER commit +│ +mon-projet/ +└── .claude/ + ├── settings.json ← settings.json — project rules, commit to git + └── settings.local.json← settings.local.json — personal, gitignored +``` + +Add to your project `.gitignore`: +``` +.claude/settings.local.json +``` + +--- + +## Precedence (highest → lowest) + +``` +managed-settings.json system-wide, cannot be overridden + └── CLI flags --allowedTools, --disallowedTools (session only) + └── settings.local.json personal local + └── settings.json project (team) + └── ~/.claude/settings.json global user +``` + +**DENY always wins over ALLOW, regardless of level.** + +--- + +## What goes where + +| Rule type | File | +|---|---| +| Deny secrets, SSH, rm -rf, sudo | `~/.claude/settings.json` | +| Deny git push --force, curl\|bash | `~/.claude/settings.json` | +| Ask git push, docker run, deploy | `~/.claude/settings.json` | +| Ask package managers (brew, apt) | `~/.claude/settings.json` | +| Allow git read-only, ls, cat, grep | `~/.claude/settings.json` | +| Allow npm/cargo/make/pytest... | `.claude/settings.json` (project) | +| Ask psql, mysql, redis-cli | `.claude/settings.json` (project) | +| Allow specific WebFetch domains | `.claude/settings.local.json` | +| Personal additionalDirectories | `.claude/settings.local.json` | + +--- + +## defaultMode values + +| Value | Behavior | When to use | +|---|---|---| +| `default` | Prompts on first use of each tool | Normal development | +| `acceptEdits` | Auto-accepts file edits, prompts for Bash | Trusting sessions | +| `plan` | Read-only — Claude plans, cannot execute | Code review, audit | +| `bypassPermissions` | Skips all prompts — **dangerous** | CI/CD only, sandboxed env | + +Disable bypass permanently (set in `~/.claude/settings.json`): +```json +{ "permissions": { "disableBypassPermissionsMode": "disable" } } +``` + +--- + +## Rule syntax + +### Bash +```json +"Bash(git status)" // exact match +"Bash(npm run test:*)" // wildcard suffix +"Bash(git push*)" // prefix match +"Bash(curl * | bash)" // pipe pattern — block code injection +``` + +### Read / Write / Edit — gitignore syntax +```json +"Read(**/.env)" // any .env in any subdirectory +"Read(**/secrets/**)" // anything inside secrets/ +"Read(src/**/*.ts)" // all .ts under src/ +"Write(**/*.key)" // deny writing any .key file +``` + +### WebFetch +```json +"WebFetch(domain:docs.rs)" // specific domain only +"WebFetch" // all web fetches (no sub-pattern) +``` + +### WebSearch +```json +"WebSearch" // no sub-patterns supported +``` + +### Agent / Skill / MCP +```json +"Agent(explorer)" +"Skill(deploy *)" +"mcp__github__*" // all tools from github MCP server +"mcp__playwright__navigate" +``` + +--- + +## Security notes + +- `Read(**/.env)` only blocks the Read tool. + `Bash(cat .env)` bypasses it unless you also deny that Bash command. + → Use `.claudeignore` for hard file exclusion. + +- `disableBypassPermissionsMode: "disable"` prevents switching to + bypass mode mid-session — set it in `~/.claude/settings.json`. + +- Prefer `ask` over `allow` for anything touching external systems + (git push, deploy, database commands, package install). + +- `deny` rules in `~/.claude/settings.json` cannot be overridden + by project-level `allow` rules — deny always wins globally. + +--- + +## managed-settings.json (enterprise) + +Cannot be overridden by any user or project setting. + +| OS | Path | +|---|---| +| Windows | `C:\ProgramData\ClaudeCode\managed-settings.json` | +| macOS | `/Library/Application Support/ClaudeCode/managed-settings.json` | +| Linux | `/etc/claude-code/managed-settings.json` | diff --git a/templates/settings/settings.json b/templates/settings/settings.json new file mode 100644 index 0000000..ea95801 --- /dev/null +++ b/templates/settings/settings.json @@ -0,0 +1,81 @@ +{ + "_readme": "Project-level settings — commit this file. Extends ~/.claude/settings.json. Only put project-specific rules here.", + + "permissions": { + + "allow": [ + + "Bash(npm run *)", + "Bash(npm install)", + "Bash(npm ci)", + + "Bash(yarn *)", + "Bash(pnpm *)", + + "Bash(cargo build*)", + "Bash(cargo test*)", + "Bash(cargo run*)", + "Bash(cargo check*)", + "Bash(cargo clippy*)", + "Bash(cargo fmt*)", + "Bash(cargo clean*)", + + "Bash(go build *)", + "Bash(go test *)", + "Bash(go run *)", + "Bash(go fmt *)", + "Bash(go mod *)", + "Bash(go vet *)", + "Bash(go generate *)", + + "Bash(python *)", + "Bash(python3 *)", + "Bash(pytest *)", + "Bash(pip install *)", + "Bash(pip install -r *)", + "Bash(uv *)", + "Bash(ruff *)", + "Bash(black *)", + "Bash(mypy *)", + "Bash(alembic *)", + + "Bash(make)", + "Bash(make *)", + + "Bash(php *)", + "Bash(composer *)", + "Bash(wp *)", + + "Bash(flutter *)", + "Bash(dart *)", + + "Bash(docker build *)", + "Bash(docker ps*)", + "Bash(docker images*)", + "Bash(docker logs *)", + "Bash(docker stop *)", + "Bash(docker rm *)", + + "Bash(node *)", + "Bash(ts-node *)", + "Bash(tsx *)", + "Bash(npx *)", + + "Bash(norminette*)" + ], + + "ask": [ + + "Bash(make deploy*)", + "Bash(npm run deploy*)", + "Bash(cargo publish*)", + + "Bash(psql *)", + "Bash(mysql *)", + "Bash(mongosh *)", + "Bash(redis-cli *)" + ], + + "deny": [] + } +} diff --git a/templates/settings/settings.local.json b/templates/settings/settings.local.json new file mode 100644 index 0000000..e522343 --- /dev/null +++ b/templates/settings/settings.local.json @@ -0,0 +1,32 @@ +{ + "_readme": "Personal local overrides — DO NOT commit. Add .claude/settings.local.json to .gitignore. Highest priority after CLI flags.", + + "permissions": { + + "defaultMode": "default", + + "allow": [ + + "WebFetch(domain:docs.anthropic.com)", + "WebFetch(domain:developer.mozilla.org)", + "WebFetch(domain:docs.rs)", + "WebFetch(domain:pkg.go.dev)", + "WebFetch(domain:pypi.org)", + "WebFetch(domain:npmjs.com)", + "WebFetch(domain:crates.io)", + "WebFetch(domain:docs.python.org)", + "WebFetch(domain:react.dev)", + "WebFetch(domain:nextjs.org)", + "WebFetch(domain:vuejs.org)", + "WebFetch(domain:laravel.com)", + "WebFetch(domain:flutter.dev)" + ], + + "deny": [], + + "ask": [], + + "additionalDirectories": [ + ] + } +}