🦁

Claude CodeのHookでmdファイルへの書き込みを制限する

に公開

Claude Codeは強力なコーディングアシスタントですが、
ドキュメントファイル(.md)を過剰に作成してしまうことがあります。
本記事では、Hook機能を使ってこの問題を解決する方法を紹介します。

Claude CodeのHook機能とは

Claude Codeは~/.claude/settings.jsonでPreToolUse/PostToolUseフックを設定できます。これらのフックは、ツール実行の前後に任意のコマンドを実行する仕組みです。

https://docs.anthropic.com/ja/docs/claude-code/hooks

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "shコマンド"
      }]
    }]
  }
}

Hook でのパラメータの受け取り方

JSONデータがSTDIN経由で渡されます。
つまりこんな感じで cat で受け取る必要があります。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "json=$(cat); file_path=$(echo \"$json\" | jq -r '.tool_input.file_path // empty'); if [[ \"$file_path\" == *.md ]]; then echo '{\"decision\": \"block\", \"reason\": \"Creating or editing .md files is prohibited\"}'; fi""
          }
        ]
      }
    ]
  }
}

素直に書くと読めないぐらい長い

改行を含む入力の問題

また、Hookはシェルスクリプトが発火するため、改行やダブルクオートを含むコンテンツをjqでパースすることが難しかったりします。

実際、そこそこの行数のmdファイルはパースに失敗して読めませんでした。

最終形

そういうわけでこんな感じにしました。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "hook受取用のスクリプト"
          }
        ]
      }
    ]
  }
}

「hook受取用のスクリプト」は

  • 標準入力(STDIN)を受け取って
  • 以下のような構造の標準出力

を行えばよいです。

{
  "decision": "block", // もしくは allow
  "reason": "Claude Codeに伝えるメッセージ"
}

参考コード

https://github.com/yki-t/dotfiles/commit/7a35ea37589697c925fd496ccb9963d53e26cc3c
一応貼っておきますが、コードを読むよりこの記事をそのままClaude Codeに食わせたほうが作りたいものができると思います。

まとめ

参考コードはRustなのですが Claude Codeのおかげで実装コストはほぼゼロでした。
良い時代になりましたね。

Discussion