ある日、チームメイトが settings.json の変更をプッシュして、あなたのローカルの権限ルールが上書きされる。あるいはあなたが自分の設定をプッシュして相手の環境を壊す。マージコンフリクト自体は些細な問題だけど、根本的な原因はそうじゃない。チーム共有の設定と個人の好みという、まったく別の用途に同じファイルを使っていて、gitにはその違いが分からない。
これをすっきり分離する方法を紹介する。
問題: 1つのファイルで2つの役割
Claude Codeはプロジェクトルートの .claude/settings.json に設定を保存する。このファイルでClaudeが使えるツール、事前承認済みのコマンド、デフォルトの権限モードなどを制御する。
ソロ開発なら問題ない。2人目のエンジニアがプロジェクトに参加した瞬間に、システムに設計上の矛盾が生まれる。
- 共有設定(Claudeがこのプロジェクトで仕事をするために必要なツール設定)はバージョン管理に含めるべきもの。チーム全員が同じベースで動くべきだから。
- 個人設定(あなたが好む権限レベル、ローカルのパス、実験的な設定)は個人のもの。コミットすると他の全員の環境が微妙にずれてしまう。
Claude Codeはこれを解決する2ファイルシステムを持っているけど、ほとんどのチームはコンフリクトが起きてから初めて知ることになる。
2ファイルシステム: settings.json と settings.local.json
Claude Codeは2つのファイルから設定を読み込む。
| ファイル | 用途 | Gitの扱い |
|---|---|---|
.claude/settings.json | チーム共有のプロジェクト設定 | コミットする |
.claude/settings.local.json | 個人の上書き設定 | 絶対にコミットしない |
settings.local.json の値は settings.json より優先される。マージはClaude Code起動時に行われるので、手動で調整する必要はない。
この分離は意図的な設計だ。Anthropicがこう設計した。共有設定は settings.json(コミット)、個人の上書きは settings.local.json(gitignore)に置く。.gitignore がこれを反映していないなら、今すぐ修正しよう。
ステップ1: .gitignoreを更新する
# .gitignore
# Claude Codeの個人設定 — コミット禁止
.claude/settings.local.json
# Claude Codeの認証情報と機密状態
.claude/.credentials.json
.claude/store/
# これらはコミットする:
# .claude/settings.json <- チーム設定
# .claude/CLAUDE.md <- チームコンテキスト(任意、後述)
.claude/store/ ディレクトリにはキャッシュされたレスポンスや内部状態が含まれる。マシン固有のもので、リポジトリに含める理由がない。
ステップ2: settings.jsonに書くこと(共有設定)
共有設定ファイルには、「あなた」ではなく「プロジェクト」について真実のことだけを書く。
プロジェクトのツール許可リスト
{
"permissions": {
"allow": [
"Bash(npm install)",
"Bash(npm run build)",
"Bash(npm run test)",
"Bash(npm run test:*)",
"Bash(npm run lint)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Edit(src/**)",
"Edit(tests/**)",
"Edit(*.json)",
"Edit(*.md)",
"Read(**)"
],
"deny": [
"Bash(git push *)",
"Bash(git reset --hard *)",
"Bash(rm -rf *)",
"Bash(curl * | bash *)"
]
}
}
これはプロジェクト固有の知識だ。プロジェクトが npm run test ではなく pytest を使っているなら、設定もそれを反映させる。許可リストは、Claude Codeがこのコードベースで仕事をするために何が必要かを定義するものだ。
拒否ルールが重要な理由
拒否リストは単なる防衛策じゃなく、ドキュメントでもある。新しいエンジニアが .claude/settings.json を見たとき、拒否リストが「このプロジェクトでClaudeが監督なしに実行すべきでないコマンドはこれ」と教えてくれる。インタラクティブセッションを開く前に期待値を設定できる。
拒否リストに git push があれば、Claudeがインタラクティブセッション中に誰かに気づかれないまま main にプッシュすることがない。rm -rf * があれば、クリーンアップ時にClaudeがテストフィクスチャを消してしまうことがない。これはClaudeが悪意を持つことへのガードではなく、ミスへのガードレールだ。
プロジェクト全体に適用されるデフォルト
{
"permissions": {
"allow": ["..."],
"deny": ["..."],
"defaultMode": "acceptEdits"
},
"env": {
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "8000"
}
}
acceptEdits モードではファイル編集を確認なしに自動承認する。チーム全員が許可リストをレビューして承認済みのチームに向いている。Claudeが何に触るべきか決まっていないうちは defaultMode を省略して、許可/拒否ルールで明示的に制御するのがいい。
ステップ3: settings.local.jsonに書くこと(個人設定)
settings.local.json は個人の好みを置く場所だ。絶対にコミットしない。
よくある個人の上書き設定
{
"permissions": {
"allow": [
"Bash(~/scripts/*)",
"Bash(python3 ~/tools/*)"
],
"defaultMode": "bypassPermissions"
},
"env": {
"ANTHROPIC_MODEL": "claude-opus-4-8"
}
}
この例は以下のような人を想定している。
- Claudeに実行させたい個人スクリプトを持っている
- ローカルではbypassモードを好む(プロジェクトの拒否リストを確認済みで信頼している)
- チームがSonnetをデフォルトにしている中、高負荷なローカル作業ではOpusを使いたい
これらはどれも共有設定に入れるものじゃない。ローカル上書きを使えば、他の人の環境を変えることなく自分だけこの設定にできる。
ローカルでbypassPermissionsを使う: 妥当な場面
個人設定で bypassPermissions を使うのが妥当な場面:
- 共有
settings.jsonの拒否リストを確認して同意している - このプロジェクトでClaude Codeが何をするか理解している
- ローカルで作業していて影響範囲が限定的
共有設定に bypassPermissions をプッシュするのは妥当ではない。それは個人の判断であって、チームの判断ではない。
ステップ4: CLAUDE.mdとsettings.jsonの違いは何か
チームでよく混乱するのがこの2つのファイルだ。目的が違う別々のツールだ。
| ファイル | 何か | 何を制御するか |
|---|---|---|
CLAUDE.md | Claudeが読むテキストのプロンプト | Claudeがプロジェクトについて「知ること」 |
settings.json | 構造化された設定 | Claudeが「できること」 |
CLAUDE.md はオンボーディング資料のようなもの。コーディング規約、好ましいテストアプローチ、このコードベースで「完了」が何を意味するかをClaudeに伝える。Claudeは毎セッションの前にコンテキストとして読み込む。
settings.json は強制執行だ。Claudeが呼び出せるツール、確認なしに実行できるコマンド、ツールが明示的に記載されていない場合のフォールバック動作を制御する。
どちらもバージョン管理に含めるべきで、どちらも相手を置き換えるものじゃない。
CLAUDE.md の構造や何を書くべきかの詳細は、CLAUDE.mdが2,000行になって誰も読まなくなった — その解決策 を参照してほしい。
ステップ5: .claude/ディレクトリの全体像
チームプロジェクトのきれいな .claude/ ディレクトリはこんな形になる。
.claude/
├── settings.json # コミット済み — チーム設定
├── settings.local.json # Gitignore済み — 個人の上書き
├── CLAUDE.md # 任意でコミット — チームコンテキスト
└── commands/ # 任意でコミット — カスタムスラッシュコマンド
├── review.md
└── deploy-check.md
対応する .gitignore への追加:
.claude/settings.local.json
.claude/.credentials.json
.claude/store/
.claude/*.log
commands/ ディレクトリには、チームが作成したカスタムスラッシュコマンドが入る。プロジェクト固有のプロンプトで、共有する意味があるものだ。チームでスタックに特化したセキュリティ問題をチェックする /review コマンドを持っているなら、全員が使えるべきだ。
チームがよくやるミス
ミス1: settings.local.jsonをコミットしてしまう
思っているより頻繁に起こる。誰かが個人設定を追加して、settings.json じゃなく settings.local.json だと気づかずにコミットしてしまう。チームの全員の環境に、bypasモードや個人のスクリプトパスが混入することになる。
対処法: 最初のコミットの前に .claude/settings.local.json を .gitignore に追加する。すでにコミット済みなら、git rm --cached .claude/settings.local.json で追跡を解除して .gitignore に追加する。
ミス2: settings.jsonが空か存在しない
リポジトリに settings.json がないと、チームの全エンジニアがローカル権限をゼロから設定しなければならない。さらに共有ベースラインがないので、ある人のClaudeは git push が事前承認されていて、別の人はされていない、という状態になる。
対処法: 早めにミニマルな settings.json を作成する。明らかなケースの許可リストと拒否リストだけでも、何もないよりはるかにいい。
ミス3: 共有設定にパスをハードコードする
{
"permissions": {
"allow": [
"Bash(/Users/alice/project/scripts/build.sh)"
]
}
}
Aliceのマシンでは動くが、他の全員の環境では壊れる。共有設定には相対パスやプロジェクトルート相対パスを使う。
{
"permissions": {
"allow": [
"Bash(./scripts/build.sh)",
"Bash(scripts/*)"
]
}
}
ミス4: 拒否ルールが優先されることを忘れる
{
"permissions": {
"allow": ["Bash(git *)"],
"deny": ["Bash(git push *)"]
}
}
settings.local.json に "allow": ["Bash(git push origin main)"] を追加すれば拒否ルールを上書きできると思ってやる人がいる。そうはならない。共有設定の拒否ルールは、ローカル設定の許可ルールで上書きできない。設計上そうなっている。
新しいエンジニアへのオンボーディングチェックリスト
Claude Codeを使うプロジェクトに新しいエンジニアが参加したとき、必要なのは正確に3つだ。
- リポジトリをクローンする —
settings.jsonとCLAUDE.mdがついてくる .gitignoreを確認する —.claude/settings.local.jsonが記載されていることを確認する- 個人の上書き設定を作成する —
.claude/settings.local.jsonを自分の好みで作成する(任意; 共有設定だけでも動く)
以上だ。共有設定が残りを処理する。エンジニアごとのセットアップコールも、「wikiから設定をコピーして」も、チームメンバー間の環境ドリフトもない。
CI/CD: 特別なケース
CI環境では、共有 settings.json だけでは通常不十分だ。CIジョブはインタラクティブなローカル使用には煩わしすぎる権限モードが必要なことが多い。
よくあるパターンは、共有 settings.json ではなく、CI固有の設定ファイルや環境変数を使ってCIで bypassPermissions を設定することだ。
# .github/workflows/claude-ci.yml
- name: Run Claude Code
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
CLAUDE_PERMISSION_MODE: bypass # CI固有の上書き
run: claude -p "run the test suite and fix any failures"
あるいはCIにのみ存在する別の設定ファイルを使う。
- name: Create CI settings
run: |
cat > .claude/settings.local.json << 'EOF'
{
"permissions": {
"defaultMode": "bypassPermissions"
}
}
EOF
要点は: CI権限はCIの問題だ。チームの全エンジニアがローカルで使う共有設定に含めるべきじゃない。
CI環境でのClaude Code実行の完全なガイドは、Claude Code × GitHub Actions: 権限エラーの修正方法 を参照してほしい。
まとめ
2ファイルシステムが設計だ。これを使おう。
.claude/settings.json— プロジェクトのデフォルト、ツール許可リスト、拒否ルール。コミットする。.claude/settings.local.json— 個人の上書き、ローカルパス、bypassモード。Gitignoreする。CLAUDE.md— Claudeが読むプロジェクトコンテキスト。コミットする。.claude/store/、.claude/.credentials.json— マシン状態、シークレット。Gitignoreする。
Claude Code設定周りのチームコンフリクトのほとんどは、settings.json を個人設定として扱っているか、settings.local.json のセットアップをまったくしていないかのどちらかから来ている。修正方法は .gitignore への2行追加と共有ベースライン設定の作成だ。どちらも10分とかからない。