kkamegawa's weblog

Visual Studio,TFS,ALM,VSTS,DevOps関係のことについていろいろと書いていきます。Google Analyticsで解析を行っています

Claude CodeでC#のファイル編集が Python経由になる問題を何とかする

10月上旬からClaude CodeがC#コードの編集を必ずPython経由でやってくれるようになりました。その結果、Pythonはautoでも危険な処理だからということで必ず承認を求めるようになり、大変困っていました。現象が始まった当初、Claudeに聞いたのですが、「僕悪くない。まったくわかりません」で終わったのですが、先日とうとう堪忍袋の緒が切れて、もう一度やってもらって原因が分かりました。

ここでは48回中41回と出ていますが、複数台のPCで使っているので、実際は100回以上承認してます。以下そのまま。現代のC#はBOMなしUTF-8、LFでもちゃんと認識されるはずですが、リポジトリでコロコロ変えるのもあれなので(gitattributesで設定するのでもいいけど)、基本的にBOMありUTF-8, CRLFにしています。

dotfilesで設定しましたが、さてどうなるか…。CodexやGitHub Copilotは同じ設定でもPythonを使うことはありません。CLAUDE_CODE_THRIFTY_SONICという隠し設定、8月下旬には追加されたみたいですね。

結論

原因はユーザー側の設定やフックではありません。Claude Code本体がautoモードのときに私へ注入している指示です。そこに「BOM+CRLF必須」というリポジトリのルールが重なって、py経由の編集になっていました。

経緯

  1. 本体が「Bashで編集しろ」と指示している

    • autoモードでは、セッションごとに auto_mode という system-reminder が注入されます。
    • 中身は「ファイル変更は sed・heredoc・短いスクリプトで行い、Read/Edit/Write ツールの代わりにする」というものです。
    • 過去のjsonlを見ると、本体のフラグ bashFirst は次のように推移しています。
    時期 バージョン bashFirst 指示の強さ
    〜8月中旬 2.1.229まで false 指示なし
    9月 2.1.260〜 true strict(「Bashでできる限り全部やれ」)
    10/2以降 2.1.281〜2.1.299 true relaxed
    • 本体バイナリ(2.1.299)を読むと、モデルがOpus 5.5の場合は bashFirst が forced(強制有効) になります。私のモデルが切り替わった時期と一致しています。
  2. Pythonになるのはリポジトリのルールのせい

    • vsextensionforcodex の CLAUDE.md、AGENTS.md、.editorconfig は UTF-8 BOM + CRLF を必須にしています。
    • 複数行のC#置換を sed でやるとBOMや改行が壊れやすいです。そこで、utf-8-sig を指定した py -3 - <<'EOF' が「短いスクリプト」として選ばれていました。
  3. autoモードで承認待ちになる理由

    • インライン実行されるPythonは任意コード実行なので、autoモードの分類器が影響を判定できず、承認待ちに回します。
    • 10/12のセッションでは48回中41回が承認待ちになっていました。
  4. 以前の対策が効かなかった理由

    • 10/12 07:49 に feedback_auto_mode_tool_choice.md というメモリ(「pyを使わずEditを使え」)が書かれています。
    • それでも、09:00に始まった同じプロジェクトのセッションでpy編集が29回ありました。プロジェクトのメモリは、毎セッション注入されるsystem-reminderに負けています。

数値で見た変化

指示がpy編集をゼロから生んだわけではありません。Editとpyの比率を逆転させた、というのが正確です。

セッション bashFirst Edit py
8/04 なし 166 28
8/26 false 64 0
10/02 true 6 36
10/12 true 7 29
10/12 true 0 14

対策

~/.claude/settings.json は私の編集が deny されているので、手で env に1行追加してください。

"env": {
  "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "60",
  "CLAUDE_CODE_THRIFTY_SONIC": "0"
}
  • 効く仕組み: 本体の bashFirst 判定は、最初にこの環境変数を見ます。0 / false / no / off を指定すると、モデルによる強制より優先して無効になります。これはバイナリで確認しました。
  • 注意点:
    • これは公開ドキュメントにない内部の実験フラグなので、今後のバージョンで名前や挙動が変わる可能性があります。
    • 似たフラグ CLAUDE_CODE_COZY_TEAPOT は、指示を strict と relaxed で切り替えるだけで、無効化はできません。
  • 確認方法: 設定後に新しいセッションを開始してください。そのjsonlで、"type":"auto_mode" の添付に "bashFirst":false が付いているか、指示文が入っていなければ効いています。デスクトップアプリから起動したCLIが settings.json の env を読み込んでいるかも、これで確認できます。
  • 補強(任意): フラグが将来変わったときの保険として、~/.claude/CLAUDE.md に「C#/XAMLの編集は必ずEdit/Writeツールで行い、python/sedによる書き換えは禁止」と追記しておくと確実です。メモリより優先度が高い場所です。