Build This Now
Build This Now
キーボードショートカットステータスラインガイド
フックガイドClaude Code クロスプラットフォームフックClaude Code セットアップフックストップフック自己検証する Claude Code エージェントClaude Code セッションフックClaude Code コンテキストバックアップフックスキルアクティベーションフックClaude Code パーミッションフック
speedy_devvkoen_salo
Blog/Toolkit/Hooks/Cross-Platform Hooks for Claude Code

Claude Code クロスプラットフォームフック

Claude Codeのクロスプラットフォームフック: .cmd・.sh・.ps1のラッパーを捨て、nodeを直接呼び出すことで、1つの.mjsファイルがmacOS・Linux・Windowsで動く方法。

設定をやめて、構築を始めよう。

AIオーケストレーション付きSaaSビルダーテンプレート。

Published Jan 16, 2026Toolkit hubHooks index

問題: cmd /c や PowerShell 経由で Windows から配布したフックは、Linux チームメンバーがリポジトリを開いた瞬間にエラーになる。多くの人が行き着く回避策は見苦しい。フックごとに3つのシムスクリプトを用意する方法だ。Windowsには .cmd、Linuxには .sh、PowerShell には .ps1。3つとも全く同じことをする。つまり、本当に重要な .mjs ファイルを呼び出すだけだ。

素早い解決策: ラッパーを捨てる。フック設定を Node.js に直接向ける:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/formatter.mjs"
          }
        ]
      }
    ]
  }
}

変更なしで Windows、Linux、macOS で動く。node は常に $PATH に存在する。Claude Code が Node.js をハードな要件としているからだ。

OSが変わるとフックが壊れる理由

自分しか設定を触らない場合、この問題には遭遇しない。問題が生じるのは .claude/settings.json が共有されたとき、リポジトリが公開されたとき、あるいは Windows のデスクトップと macOS のノートパソコンを行き来するようになったときだ。コマンド内に bash や powershell が現れた瞬間、チームの半分が実行できなくなる。

多くのチュートリアルがプラットフォーム固有の書き方をしている:

// Windows-only
"command": "cmd /c \".claude\\hooks\\formatter.cmd\""
 
// Linux-only
"command": "bash .claude/hooks/formatter.sh"
 
// PowerShell-only
"command": "powershell -NoProfile -File .claude/hooks/statusline.ps1"

これらのラッパーはどれも node 呼び出しの周りに2行のボイラープレートを追加しているだけだ。3つのファイル、3つのプラットフォーム、すべてで同じ仕事をしている。OSについて知っているレイヤーがシムだけなら、シムを削除できる。

settings.json のユニバーサルパターン

settings.json 内のフックは共通の形状を持つ:

{
  "statusLine": {
    "type": "command",
    "command": "node .claude/hooks/statusline-monitor.mjs"
  },
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/skill-activation.mjs"
          }
        ]
      }
    ],
    "PreCompact": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/backup.mjs",
            "async": true
          }
        ]
      }
    ]
  }
}

cmd /c なし。bash なし。powershell なし。ただ node だけ。すべてのフック型が同じ形状を取るため、PostToolUse、SessionStart/SessionEnd、Stop、12すべてのライフサイクルイベントが同じように設定できる。

クロスプラットフォームフックロジックの3つのルール

各 .mjs ファイルの中で、3つの習慣がロジックをどのOSでも移植可能に保つ。

プラットフォーム変数の代わりに os.homedir() を使う

import { homedir } from "os";
import { join } from "path";
 
// Cross-platform: resolves to C:\Users\you or /home/you
const settingsPath = join(homedir(), ".claude", "settings.json");

$HOME、$env:USERPROFILE、%USERPROFILE% をソースコードに書かない。ヘルパーに適切なものを選ばせる。

一時ファイルパスには os.tmpdir() を使う

import { tmpdir } from "os";
import { join } from "path";
 
// Cross-platform: resolves to C:\Users\you\AppData\Local\Temp or /tmp
const cacheFile = join(tmpdir(), "my-hook-cache.json");

/tmp や $env:TEMP を手書きしない。

すべてのファイルパス構築に path.join() を使う

import { join } from "path";
 
// Cross-platform path construction
const logFile = join(".claude", "hooks", "logs", "hook.log");

/ や \\ でパスを手動で連結するのをやめる。Node.js はフックが実行されるOSに応じた適切なセパレータをすでに知っている。

両プラットフォームをカバーするパーミッション

settings.json の permissions ブロックには Windows の名前と Unix の名前を並べて記述する:

{
  "permissions": {
    "allow": [
      "Bash(where:*)",
      "Bash(which:*)",
      "Bash(tasklist:*)",
      "Bash(ps:*)",
      "Bash(taskkill:*)",
      "Bash(kill:*)",
      "Bash(findstr:*)",
      "Bash(node:*)"
    ]
  }
}

現在のマシンにインストールされていないコマンドは静かに無視される。両方を記述してもコストはかからないし、フックは権限ダイアログを発生させることなく実際に存在するコマンドを選んで実行する。この側面のより詳細な自動化については、パーミッションフックガイドを参照してほしい。

完全な例: クロスプラットフォームファイルロガー

1つのフックをそのまま使える形で示す。仕事はファイルロガーだ。Claude が行った Write または Edit をすべてログに追記する:

#!/usr/bin/env node
import { readFileSync, appendFileSync, mkdirSync } from "fs";
import { join } from "path";
 
const logDir = join(".claude", "hooks", "logs");
mkdirSync(logDir, { recursive: true });
 
try {
  const input = JSON.parse(readFileSync(0, "utf-8"));
  const toolName = input.tool_name;
  const filePath = input.tool_input?.file_path || "unknown";
  const timestamp = new Date().toISOString();
 
  appendFileSync(
    join(logDir, "file-changes.log"),
    `${timestamp} | ${toolName} | ${filePath}\n`,
  );
} catch {
  // Silent fail -- don't block Claude
}
 
process.exit(0);

settings.json に登録する:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/file-logger.mjs"
          }
        ]
      }
    ]
  }
}

Windows 11、Arch Linux、macOS Sequoia で同じ動作をする。ラッパーはゼロだ。

1つのOSで壊れるときのデバッグ

あるマシンでは動くがほかのマシンで失敗するフックがある?このリストを上から順に確認してほしい:

  1. ハードコードされたパスセパレータ。 すべての .mjs ファイルで、パス内に現れる / や \\ を検索する。それらを path.join() に渡す。
  2. 環境変数の参照。 process.env.HOME、process.env.USERPROFILE、process.env.TEMP を探し、それぞれを os.homedir() または os.tmpdir() に置き換える。
  3. settings.json 内のシェル固有のコマンド。 bash、cmd、powershell、sh に言及する command エントリはそのOS以外ではすべて壊れる。node に向け直す。

手動でフックを発火させると失敗を隠せない:

echo '{"tool_name":"Write","tool_input":{"file_path":"test.js"}}' | node .claude/hooks/your-hook.mjs
echo $?  # Should output 0

あるOSでは 0 が返り、ほかでは違う値が返る場合、問題は settings.json のフックエントリではなく .mjs ファイルのパス処理にある。

リリースチェックリスト

チームへの展開または公開リリース前にこのリストを確認してほしい:

  • settings.json のすべての command が cmd、powershell、bash ではなく node を指している
  • ホームディレクトリは $HOME や %USERPROFILE% ではなく os.homedir() から取得している
  • 一時パスは /tmp や $env:TEMP ではなく os.tmpdir() から取得している
  • パスは手打ちのセパレータではなく path.join() で構築している
  • パーミッションに Windows と Unix の両方の同等コマンドが記述されている
  • statusLine のコマンドが powershell ではなく node を指している

1つのファイル。3つのプラットフォーム。メンテナンスなし。

Claude Code のフックは Windows で動くか?

動く。そのOSにしか存在しないシェルではなく node を通じて呼び出せば、Windows、Linux、macOS で同じように動作する。Node.js はすべてのプラットフォームで Claude Code のハードな要件なので、node は常に $PATH にある。settings.json に node .claude/hooks/your-hook.mjs を記述すれば、3つすべてで同一の動作が得られる。

フックに Node.js の代わりに Python を使えるか?

Python でも動く。ただし、チームメンバー全員がすでにインタープリターをマシンに持っている必要がある。command フィールドでは python ではなく python3 を使う。一部の Linux ディストリビューションには python というコマンドが存在しないからだ。Node.js の方が安全な選択だ。Claude Code はすべてのプラットフォームで Node.js を保証しているが、Python は保証していない。

プラットフォームをまたいだ改行コードの扱いは?

ほぼ何もしなくてよい。readFileSync と writeFileSync はすでに改行を正規化している。すべてのフックは stdin から JSON を読み込み、JSONパーサーは改行が CRLF か LF かを気にしない。例外は自分でシェルスクリプトを出力するフックだ。そのパスでは \n を書き、残りは Git の autocrlf 設定に任せる。

Continue in Hooks

  • Claude Code セットアップフック
    スクリプト、エージェント、ドキュメントをClaude Codeのセットアップフックに組み合わせる方法。1つのコマンドで決定論的スクリプトを実行し、診断エージェントに出力を渡し、自動更新されるドキュメントを記録する。
  • Claude Code コンテキストバックアップフック
    StatusLineを活用したClaude Codeのコンテキストバックアップフック。10Kトークンごとに構造化されたスナップショットを書き込み、自動圧縮によってエラー文字列・関数シグネチャ・判断内容が失われるのを防ぐ。
  • フックガイド
    Claude Code フックの基礎から実践まで: 終了コード、JSON出力、非同期コマンド、HTTPエンドポイント、PreToolUseとPostToolUseのマッチャー、本番環境パターン。
  • Claude Code パーミッションフック
    3階層の Claude Code パーミッションフックをインストールする: 安全な呼び出しは即時許可、危険な呼び出しは即時拒否、グレーゾーンは LLM チェック。スキップフラグ不要。
  • 自己検証する Claude Code エージェント
    自己検証する Claude Code エージェント: PostToolUse リントフック、Stop フック、読み取り専用レビュアーのサブエージェントをエージェント定義に組み込み、不良な出力が出荷されないようにする。
  • Claude Code セッションフック
    4 つの Claude Code セッションライフサイクルフック: オンデマンドで init を実行し、SessionStart でプロジェクトコンテキストを注入し、トランスクリプトをバックアップし、SessionEnd 終了時にログクリーンアップを行う。

More from Toolkit

  • キーボードショートカット
    Claude Codeのkeybindings.jsonを設定する: 17のコンテキスト、キーストローク構文、コードシーケンス、修飾キーの組み合わせ、デフォルトショートカットを即座に無効化する方法。
  • ステータスラインガイド
    Claude Code のステータスラインにモデル名、gitブランチ、セッションコスト、コンテキスト使用量を表示する方法。settings.json の設定、JSON入力、bash、Python、Node.js スクリプトを解説。
  • AIによるSEOとGEO最適化
    Generative Engine Optimizationの解説: Googleで上位表示されるだけでなく、ChatGPT、Claude、Perplexityの回答内でコンテンツが引用されるようにする方法。
  • 2026年版 Claude Code と Cursor の比較
    2026年の Claude Code と Cursor を並べて比較します。エージェントモデル、コンテキストウィンドウ、料金プラン、そして各ツールが異なる開発ワークフローにどう適合するかを解説します。

設定をやめて、構築を始めよう。

AIオーケストレーション付きSaaSビルダーテンプレート。

On this page

OSが変わるとフックが壊れる理由
settings.json のユニバーサルパターン
クロスプラットフォームフックロジックの3つのルール
プラットフォーム変数の代わりに os.homedir() を使う
一時ファイルパスには os.tmpdir() を使う
すべてのファイルパス構築に path.join() を使う
両プラットフォームをカバーするパーミッション
完全な例: クロスプラットフォームファイルロガー
1つのOSで壊れるときのデバッグ
リリースチェックリスト
Claude Code のフックは Windows で動くか?
フックに Node.js の代わりに Python を使えるか?
プラットフォームをまたいだ改行コードの扱いは?

設定をやめて、構築を始めよう。

AIオーケストレーション付きSaaSビルダーテンプレート。