◉CLAUDE LABEN
●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/Claude Code
⟐ Claude Code/2026-07-16上級

許可ルールを積み上げたセッションが毎ターン重くなる — ルールセットの棚卸しと、安全性を保ったまま数を減らす設計

deny/ask ルールを増やすほど毎ターン遅くなる問題が 2.1.209 で修正されました。ただしルール設計そのものの負債は残ります。棚卸しスクリプト・被覆検出・ターン時間の実測手順と、列挙型から接頭辞型へ移す設計をまとめます。

Claude Code265パーミッション3settings.json8MCP54パフォーマンス4

✦ プレミアム記事

個人開発で回している自動投稿パイプラインの settings.json を開いたら、deny の配列が 140 行を超えていました。

一つひとつは覚えがあります。夜間に走らせて肝を冷やしたコマンドを足し、うっかり読まれたくないパスを足し、新しい MCP サーバを入れるたびに念のための行を足す。半年でこうなりました。

そして、そのセッションはどれも「なんとなく重い」のです。原因が分からないまま、モデルが遅いのだろうと片付けていました。

2.1.209 のリリースノートに、その正体が書いてありました。deny/ask ルールが多いセッションで、毎ターン数秒遅くなる問題が修正された、と。マッチャをコンパイルしてキャッシュするようになったそうです。安全側に倒すつもりで積み上げた設定が、そのまま速度を削っていたことになります。

修正で消えたコストと、手元に残るコスト

まず切り分けておきたいことがあります。2.1.209 で消えたのは実行時の再コンパイルであって、ルールセットの設計負債ではありません。

コストの種類2.1.209 以降誰の責任か
ルール文字列のマッチャ化(毎ターン)キャッシュされ解消Claude Code 側
MCP ツールプールの組み立て(毎ラウンド)キャッシュされ最大7倍速Claude Code 側
ルール数そのもの(照合の母数)変わらず線形に増える私たち
被覆・矛盾したルールの判断ゆれ変わらず残る私たち
接続する MCP サーバの本数変わらず増える私たち

上の2行はアップデートで受け取れます。下の3行は、こちらが片付けないかぎり残ります。

しかも厄介なことに、コンパイルコストが消えたおかげで「重さ」の体感は薄れます。痛みが消えると、負債は静かに増えていきます。今のうちに数えておくのが得だと考えました。

まず数える — ルールセットの棚卸し

推測で削るのは危険なので、機械に数えさせます。settings.json を読んで、ルール数・重複・ツール別の分布を出すスクリプトです。

#!/usr/bin/env python3
"""audit_permissions.py — settings.json のパーミッションルールを棚卸しする。
 
使い方:
    python3 audit_permissions.py ~/.claude/settings.json .claude/settings.json
"""
import json
import re
import sys
from collections import Counter, defaultdict
from pathlib import Path
 
BUCKETS = ("allow", "ask", "deny")
 
# "Bash(rm -rf:*)" → ("Bash", "rm -rf:*") / "Read" → ("Read", None)
RULE_RE = re.compile(r"^(?P<tool>[A-Za-z_][\w-]*)(?:\((?P<arg>.*)\))?$")
 
 
def parse_rule(rule: str):
    m = RULE_RE.match(rule.strip())
    if not m:
        return None, rule.strip()
    return m.group("tool"), m.group("arg")
 
 
def load(path: Path) -> dict:
    if not path.exists():
        print(f"  skip (not found): {path}")
        return {}
    with path.open(encoding="utf-8") as fh:
        return json.load(fh)
 
 
def audit(paths):
    total = Counter()
    by_tool = defaultdict(lambda: defaultdict(list))
    seen = defaultdict(list)  # rule -> [(bucket, file), ...]
 
    for p in paths:
        data = load(Path(p).expanduser())
        perms = data.get("permissions", {})
        for bucket in BUCKETS:
            for rule in perms.get(bucket, []):
                total[bucket] += 1
                tool, arg = parse_rule(rule)
                by_tool[tool][bucket].append(arg)
                seen[rule].append((bucket, str(p)))
 
    print("=== 合計 ===")
    for b in BUCKETS:
        print(f"  {b:5s}: {total[b]:4d}")
    print(f"  total: {sum(total.values())}")
 
    print("\n=== ツール別(多い順) ===")
    rows = sorted(by_tool.items(), key=lambda kv: -sum(len(v) for v in kv[1].values()))
    for tool, buckets in rows:
        counts = " ".join(f"{b}={len(buckets[b])}" for b in BUCKETS if buckets[b])
        print(f"  {tool:28s} {counts}")
 
    print("\n=== 完全重複・バケット衝突 ===")
    dup = 0
    for rule, hits in seen.items():
        if len(hits) < 2:
            continue
        dup += 1
        buckets = {b for b, _ in hits}
        mark = "⚠ 衝突" if len(buckets) > 1 else "重複"
        print(f"  [{mark}] {rule}")
        for b, f in hits:
            print(f"        {b:5s} ← {f}")
    if dup == 0:
        print("  なし")
    return sum(total.values())
 
 
if __name__ == "__main__":
    args = sys.argv[1:] or ["~/.claude/settings.json", ".claude/settings.json"]
    n = audit(args)
    sys.exit(0 if n else 1)

私の環境で走らせたところ、deny 141・ask 22・allow 63 の計 226 でした。完全重複が 9 件、ユーザー設定とプロジェクト設定でバケットが食い違っている衝突が 2 件。衝突の 2 件は、プロジェクト側で allow に入れたものをユーザー側で deny していたもので、動作としては安全側に倒れていたため気づけていませんでした。

数える前に「たぶん 60 行くらい」と見積もっていたので、桁が違いました。ここが出発点になります。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦自分の settings.json のルール数・重複・被覆を機械的に洗い出す棚卸しスクリプト
✦ターンあたりのオーバーヘッドを claude -p で測る計測ハーネスと、比較の取り方
✦列挙型ルールを接頭辞型へ畳み込みつつ、危険な穴を開けない書き換えの手順
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⟐ Claude Code2026-09-04
~/.claude.json の巻き戻しは v2.1.259 で直りました。消えた設定は自分で戻します
同時に走らせたセッションが ~/.claude.json を互いに巻き戻す不具合が v2.1.259 で修正されました。消えた信頼設定と MCP を洗い出して戻すまでを、キー集合の差分を取る小さなスクリプトとあわせて書き残します。
⟐ Claude Code2026-09-01
MCPサーバが十数個を超えてから、起動直後の一覧を信用しなくなりました
起動直後に「接続できません」と並ぶサーバのうち、こちらから手を打てるものは一部だけです。応答なし・起動失敗・プロトコル拒否を分けて返すプローブを実装し、14台構成で逐次22.03秒が並列5.09秒まで縮むところ、待ち時間を詰めると健全なサーバが失敗に化けるところを実測で残しました。
⟐ Claude Code2026-08-27
使うモデルだけを /model に並べる modelPicker の設定と、置き換えで消える行
Claude Code v2.1.242 で入った modelPicker で、/model のピッカーに自分の行を並べる方法をまとめました。追加と置き換えの違い、プロジェクト設定では読まれない理由、availableModels と重ねたときに選択肢が狭まる境目までを扱います。