まず何をすればいい?
この方法は Claude 公式の機能ではありません。
Claude Desktop / Claude Code のローカル設定を利用した非公式の方法です。
実行前にバックアップは自動作成されますが、環境によって動かない可能性があります。
不安な方は無理に実行しなくてOKです。
Mac 中心に確認済みです。Windows 版もありますが、検証数はまだ少なめです。
Mac の方
- Claude Desktop で新しいチャットを開く
- 下の「Mac 用の呪文を全文コピー」を押す
- Claude に貼り付けて送信する
- Claude の案内に従う(途中で許可ボタンが出たら内容を確認して押す)
- 完了したら Cmd+Q で Claude Desktop を完全終了 → 再起動する
Windows の方
Windows 版もありますが、検証数が少なめです。
必ずバックアップを取ってから進めてください。
Mac 用の呪文
この呪文を全文コピーして Claude Desktop の新規セッション(または Claude Code)に貼り付けると、自動でセットアップしてくれます。Claude がファイル作成・設定変更を提案するので、内容を確認してから許可します。
Claude Desktop の Recents サイドバーに表示されるセッションタイトルを、自動で日本語化するセットアップをして欲しいです。
## 環境前提
- macOS であること
- Claude Code がインストール済みであること
- jq / python3 が必要(無ければ後述の手順で自動案内します)
## やってほしいこと
### 1. 前提確認 + 不足時の自動セットアップ
a. macOS か確認 (`uname` が Darwin)。違うなら停止し、Windows ユーザーにはこのページの Windows セクションを案内。
b. 依存コマンドの存在チェック: `jq` `python3` `claude` `brew`
c. **不足があれば、可能な範囲で自動インストールしてください** (非エンジニアにターミナル操作させない方針):
- **`jq` だけ無い + `brew` がある**:
ユーザーに「`brew install jq` を実行していいですか?」と 1 回確認。
承諾されたら **あなた (Claude) が Bash ツールで実行**してください。
完了確認後にセットアップ続行。
- **`brew` 自体が無い**:
Bash ツールで自動インストールするには重い (sudo パスワード入力が必要)。
ターミナル App での手動インストールを案内:
1. Spotlight (Cmd+Space) で「ターミナル」検索 → 起動
2. https://brew.sh のトップにある installer コマンドを貼り付けて実行
3. 完了後この会話に戻って「Homebrew 入れたので続けて」と書く
→ 続行時は再度 brew の存在を確認してから jq インストールへ
- **`python3` が無い**:
macOS は通常 `/usr/bin/python3` が標準搭載。無い場合は Xcode CLT 未インストールが多い。
`xcode-select --install` を Bash ツールで起動 (GUI ダイアログが出る)、
ユーザーにダイアログ操作してもらう。完了後「続けて」で再開。
- **`claude` コマンドが見つからない**:
ユーザーは現在 Claude Code を使っているはずなので Claude Code 本体は存在する。
PATH の問題の可能性が高い。`find /Applications /usr/local /opt/homebrew -name claude -type f 2>/dev/null` 等で
実パスを探し、見つかれば「`export PATH=...` を `~/.zshrc` に追加してください」と案内。
見つからなければ https://claude.ai/claude-code 再インストールを案内。
d. **重要なお願い**: 上記の Bash ツール実行はユーザーが許可ボタンを押す前提ですが、
どれも「依存をインストールするだけ」の安全な操作なので、許可促進の説明を添えてください
(例: 「`brew install jq` を実行します。JSON 操作用の小さなツールを 1 つ追加するだけです」)。
e. **すべて揃ったらセットアップ続行**。ここまでで停止した場合は、ユーザーが「続けて」と書いたら最初から再実行してください。
### 2. ファイル `~/.claude/hooks/rename-session-title.sh` を以下の内容で作成
(ディレクトリも無ければ `mkdir -p ~/.claude/hooks` で作成)
```bash
#!/usr/bin/env bash
set -uo pipefail
LOG="$HOME/.claude/hooks/rename-session-title.log"
mkdir -p "$(dirname "$LOG")"
log() { printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG"; }
if [ "${CLAUDE_RENAME_HOOK_ACTIVE:-}" = "1" ]; then exit 0; fi
export CLAUDE_RENAME_HOOK_ACTIVE=1
log "=== hook fired (pid=$$) ==="
if [ "$(uname)" != "Darwin" ]; then
log "ERROR this script supports macOS only (got: $(uname))"
exit 0
fi
MISSING=()
for cmd in jq python3 claude; do
command -v "$cmd" >/dev/null 2>&1 || MISSING+=("$cmd")
done
if [ ${#MISSING[@]} -gt 0 ]; then
log "ERROR missing required commands: ${MISSING[*]}"
log " Install hint:"
log " - jq: brew install jq"
log " - python3: brew install python3 (or use system python)"
log " - claude: visit https://claude.com/claude-code"
log " Ensure they are in PATH (e.g. /opt/homebrew/bin or /usr/local/bin)"
exit 0
fi
CLAUDE_BIN=$(command -v claude)
INPUT=$(cat 2>/dev/null || true)
SID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty' 2>/dev/null || echo "")
EVENT=$(printf '%s' "$INPUT" | jq -r '.hook_event_name // empty' 2>/dev/null || echo "")
log "event=$EVENT session_id=$SID"
SESSIONS_DIR="$HOME/Library/Application Support/Claude/claude-code-sessions"
[ -d "$SESSIONS_DIR" ] || { log "no sessions dir"; exit 0; }
LOCKDIR="$HOME/.claude/hooks/.rename.lock.d"
PID_FILE="$LOCKDIR/pid"
acquire_lock() {
local retries=3
while [ $retries -gt 0 ]; do
if mkdir "$LOCKDIR" 2>/dev/null; then echo "$$" > "$PID_FILE"; return 0; fi
local old_pid=""
[ -f "$PID_FILE" ] && old_pid=$(cat "$PID_FILE" 2>/dev/null)
if [ -n "$old_pid" ] && kill -0 "$old_pid" 2>/dev/null; then
log "lock held by alive pid=$old_pid, skipping"; return 1
fi
log "stale lock (pid=${old_pid:-none} not alive), taking over"
rm -rf "$LOCKDIR"; retries=$((retries - 1))
done
log "could not acquire lock after retries, skipping"
return 1
}
if [ -d "$LOCKDIR" ]; then
if [ -n "$(find "$LOCKDIR" -maxdepth 0 -mmin +10 2>/dev/null)" ]; then
rm -rf "$LOCKDIR"; log "removed stale lock by age (fallback)"
fi
fi
if ! acquire_lock; then exit 0; fi
trap 'rm -rf "$LOCKDIR"' EXIT
is_non_ascii() {
printf '%s' "$1" | python3 -c 'import sys; sys.exit(0 if any(b>=0x80 for b in sys.stdin.buffer.read()) else 1)'
}
COUNT=0; SCANNED=0
while IFS= read -r -d '' f; do
SCANNED=$((SCANNED+1))
TITLE=$(jq -r '.title // empty' "$f" 2>/dev/null)
[ -n "$TITLE" ] || continue
if is_non_ascii "$TITLE"; then continue; fi
log "translating: $TITLE ($f)"
PROMPT="次の英語のセッションタイトルを、自然で簡潔な日本語に翻訳してください。
ルール:
- タイトルだけを1行で返す
- 引用符・前置き・補足説明は不要
- 20文字以内を目安に
- **半英半日のミックスを避け、完全な日本語タイトルにする** (自然さ最優先)
- 動物名・地名・人名・一般的なサービス名は日本語/カタカナにする
例: Scottish Fold cats → スコティッシュフォールド猫、Tokyo → 東京
- コマンド・ファイル名・拡張子・技術用語のみ原文維持
例: \`git rebase\`、\`file.json\`、\`npm install\` は英語のまま
タイトル: $TITLE"
# macOS の BSD sed はマルチバイト文字クラスでバイト境界を壊すため python3 で処理する
JP_TITLE=$("$CLAUDE_BIN" -p --model haiku "$PROMPT" </dev/null 2>>"$LOG" \
| head -1 | python3 -c '
import sys
s = sys.stdin.read()
strip_chars = "
"'''「『」』"
print(s.strip(strip_chars))
')
[ -n "$JP_TITLE" ] || { log " empty result, skip"; continue; }
[ ${#JP_TITLE} -le 200 ] || { log " too long, skip"; continue; }
if ! is_non_ascii "$JP_TITLE"; then log " ascii result, skip: $JP_TITLE"; continue; fi
TMP="${f}.tmp.$$"
if jq --arg t "$JP_TITLE" '.title = $t | .titleSource = "user"' "$f" > "$TMP" 2>>"$LOG"; then
if jq -e '.sessionId and .cliSessionId and (.title != null)' "$TMP" >/dev/null 2>&1; then
BACKUP_DIR="$HOME/.claude/hooks/backup/$(date '+%Y-%m-%d')"
if ! mkdir -p "$BACKUP_DIR" 2>>"$LOG"; then
rm -f "$TMP"; log " backup dir creation failed, aborting"; continue
fi
BACKUP_FILE="$BACKUP_DIR/$(basename "$f")"
if [ ! -f "$BACKUP_FILE" ]; then
if ! cp "$f" "$BACKUP_FILE" 2>>"$LOG"; then
rm -f "$TMP"; log " backup failed, aborting"; continue
fi
fi
if mv "$TMP" "$f" 2>>"$LOG"; then
log " -> $JP_TITLE file=$f backup=$BACKUP_FILE"
COUNT=$((COUNT+1))
else
rm -f "$TMP"; log " mv failed, original not overwritten"
fi
else
rm -f "$TMP"; log " health check failed, skipping"
fi
else
rm -f "$TMP"; log " jq failed"
fi
done < <(find "$SESSIONS_DIR" -name "local_*.json" -print0 2>/dev/null)
log "done. scanned=$SCANNED translated=$COUNT"
exit 0
```
### 3. 実行権限を付ける
`chmod +x ~/.claude/hooks/rename-session-title.sh`
### 4. `~/.claude/settings.json` を編集 (重要: 重複登録に注意)
以下の要件を必ず満たしてください:
- ファイルが無ければ `{}` で新規作成
- 既存の場合はバックアップ (`cp ~/.claude/settings.json ~/.claude/settings.json.bak.$(date +%s)`)
- `.hooks` / `.hooks.Stop` / `.hooks.SessionStart` キーが存在しなくても壊れないマージ処理
- 同じ command が既に登録されていれば一度削除してから追加 (2 回実行しても重複しない冪等処理)
- `command` には `~` ではなく `$HOME` を展開した絶対パスを使用
参考の jq コマンド (安全版):
```bash
HOOK_CMD="$HOME/.claude/hooks/rename-session-title.sh"
[ -f ~/.claude/settings.json ] && cp ~/.claude/settings.json ~/.claude/settings.json.bak.$(date +%s)
[ -f ~/.claude/settings.json ] || echo '{}' > ~/.claude/settings.json
jq --arg cmd "$HOOK_CMD" '
.hooks = (.hooks // {}) |
.hooks.Stop = (
(.hooks.Stop // [])
| map(.hooks = ((.hooks // []) | map(select(.command != $cmd))))
| map(select((.hooks // []) | length > 0))
) |
.hooks.SessionStart = (
(.hooks.SessionStart // [])
| map(.hooks = ((.hooks // []) | map(select(.command != $cmd))))
| map(select((.hooks // []) | length > 0))
) |
.hooks.Stop += [{
"hooks": [{
"type": "command",
"command": $cmd,
"async": true,
"timeout": 120
}]
}] |
.hooks.SessionStart += [{
"hooks": [{
"type": "command",
"command": $cmd,
"async": true,
"timeout": 120
}]
}]
' ~/.claude/settings.json > ~/.claude/settings.json.tmp \
&& mv ~/.claude/settings.json.tmp ~/.claude/settings.json
```
### 5. `~/.claude/CLAUDE.md` の末尾に以下を追記
(ファイルが無ければ新規作成。既に同じセクションがある場合は重複追記しない)
```
## セッションタイトル
新しいセッションのタイトル / 会話のタイトルは必ず日本語で生成してください。
```
### 6. 動作確認
- `~/.claude/hooks/rename-session-title.sh` が +x で存在
- `~/.claude/settings.json` が valid JSON (`jq . ~/.claude/settings.json`)
- 手動 1 回走らせて動作確認:
`echo '{"session_id":"setup-test","hook_event_name":"Stop"}' | bash ~/.claude/hooks/rename-session-title.sh`
ログ確認: `tail -20 ~/.claude/hooks/rename-session-title.log`
### 7. 完了報告
完了したら以下をユーザーに伝えてください:
- 「セットアップ完了しました。Cmd+Q で Claude Desktop を完全終了 → 再起動してください。」
- 「再起動後、Recents の英語タイトルが順次日本語化されます (新規セッションも自動で日本語タイトルになるよう設定済み)」
- バックアップ場所: `~/.claude/hooks/backup/<日付>/` に編集前ファイルが残ります
途中で詰まったら、どこで止まったか教えてください。 うまくいかない時
コマンドに慣れていない方へ
このセクションにはコマンド(黒い画面に入力するやつ)が出てきますが、Claude Code の新規セッションに状況をそのまま伝えるだけでも調査・対処してもらえます。
「サイドバーのタイトルが日本語になりません。ログを確認して原因を調べてください」
↑ こんな感じで頼めばOKです。コマンドが分からなくても大丈夫。
セッションタイトルが日本語にならない
1. まずログを確認(Terminal または Claude Code に依頼)
tail -50 ~/.claude/hooks/rename-session-title.log 2. よくあるエラーと対処
-
lock held by alive pid=..., skipping
別の hook 実行が走り続けている可能性。しばらく待つ。10 分以上続く場合のみ強制クリア:
rm -rf ~/.claude/hooks/.rename.lock.d -
ERROR missing required commands
不足しているコマンドをインストール:
brew install jq/which claudeで確認 -
done. scanned=0 translated=0
Claude Desktop のアップデートで保存場所が変わった可能性。スクリプト内
SESSIONS_DIRが指す~/Library/Application Support/Claude/claude-code-sessionsが存在するか確認。
セッションが消えた等の重大トラブル
Qiita で Windows ユーザーが過去スレッド消失した事例あり(macOS では未観測)
バックアップはファイル名のみで保存されるため、元のサブディレクトリ情報はバックアップ側からは分かりません。ただしログにフルパスが残っているので復元は可能です。
- ログ (
~/.claude/hooks/rename-session-title.log) を見て、file=<フルパス> backup=<バックアップフルパス>の行を探す - その対応関係に従って、バックアップを元のパスへ個別にコピー (
cp <backup> <file>) - 不安な場合は手動復元せず、必ず詳しい人に相談する
機械的な一括コピーは推奨しません。複数 workspace に同名ファイルがある可能性、上書き対象を誤る可能性があります。
ログを確認したい場合
方法 A:Terminal アプリで実行
Mac の Terminal(またはiTerm2)を開いて、下のコマンドをコピペして Enter。
方法 B:Claude Code に頼む
Claude Code の新規セッションで「ログを見せて」と伝えるだけで確認してくれます。コマンドが分からなくてもOK。
Terminal を使う場合は、下記コマンドでリアルタイムにログを確認できます。
tail -f ~/.claude/hooks/rename-session-title.log done. scanned=N translated=M が出れば正常に動作している証拠です。
元に戻したい時
ターミナルに慣れていない方は Claude に頼む
Claude Desktop のチャット画面に以下を貼り付けるだけで元に戻してもらえます。
サイドバー日本語化のセットアップを元に戻してください。settings.json をバックアップから復元し、rename-session-title.sh と関連ファイルを削除して、CLAUDE.md のセッションタイトルのセクションも削除してください。終わったら Claude Desktop を完全終了して再起動するよう教えてください。
ターミナルで自分で実行する場合:
~/.claude/hooks/ には他のスクリプトが入っている可能性があるため、ディレクトリごと削除はしないようにしてください。
# 1. settings.json をバックアップから復元 (タイムスタンプは適宜置換) cp ~/.claude/settings.json.bak.<タイムスタンプ> ~/.claude/settings.json # 2. このセットアップ関連ファイルだけ削除 rm -f ~/.claude/hooks/rename-session-title.sh rm -f ~/.claude/hooks/rename-session-title.log rm -rf ~/.claude/hooks/.rename.lock.d # 3. ~/.claude/CLAUDE.md に追記した以下のセクションをエディタで削除 # ## セッションタイトル # 新しいセッションのタイトル / 会話のタイトルは必ず日本語で生成してください。 # 4. Claude Desktop を Cmd+Q で完全終了して再起動
バックアップ (~/.claude/hooks/backup/) はしばらく残しておくのが安全です。完全に不要になったら手動削除:
rm -rf ~/.claude/hooks/backup/ 途中で「Homebrew が必要です」と言われたら
Homebrew は macOS 向けのパッケージ管理ツールで、jq などの開発ツールを簡単に入れるために使います。エンジニアには馴染み深いツールですが、非エンジニアには入っていないことが多いです。
インストールは 1 回だけ、ターミナル App に 1 行貼り付けるだけで完了します(所要時間: 5〜10 分)。
手順
- 1
ターミナル App を開く
Finder → アプリケーション → ユーティリティ → ターミナル、または Spotlight(Cmd+スペース)で「ターミナル」と検索。
- 2
下のコマンドを全文コピーして貼り付け、Enter を押す
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - 3
Mac のログインパスワードを入力して Enter
パスワードを入力しても画面に文字は表示されません(正常です)。入力後 Enter を押してください。
- 4
5〜10 分待つ → 完了したら Claude Desktop に戻って「Homebrew 入れたので続けて」と書く
インストール中は何行かログが流れます。最後に
Installation successful!のような表示が出れば完了です。
よくある質問
- 「Press RETURN to continue」と出たら Enter を押す
- 「Xcode Command Line Tools」のインストールを求められたら「インストール」を選ぶ(無料・安全)
- M1/M2/M3 Mac では追加で PATH 設定が必要な場合がある(画面に指示が出るのでそれに従う)
「claude コマンドが見つかりません」と言われたら
サイドバー日本語化の仕組みは、裏側で Claude CLI(ターミナル版の Claude) を使ってタイトルを翻訳しています。Claude Desktop とは別のツールで、ターミナル App で動きます。
ステップ 1: ターミナルを開く
ターミナルとは、Mac に最初から入っている黒い画面のアプリです。以下のどちらかで開けます:
- Spotlight 検索: キーボードで Cmd ⌘ + スペース を押して「ターミナル」と入力 → Enter
- Finder から: アプリケーション → ユーティリティ → ターミナル.app
黒い画面が開いて、文字が入力できる状態になればOKです。
ステップ 2: Claude CLI が入っているか確認する
Claude Desktop をすでに使っている方は、Claude CLI も一緒にインストールされている場合がほとんどです。 まず確認してみてください:
claude --version ✓ バージョン番号が出た場合
インストール済みです。ステップ 3 に進んでください。
✗ 「command not found」と出た場合
インストールが必要です。下の手順に進んでください。
Claude CLI をインストールする手順(command not found の場合)
まず Node.js が入っているか確認:
node --version バージョン番号が出なければ nodejs.org から LTS 版をインストールしてください。
Node.js が入ったら Claude CLI をインストール:
npm install -g @anthropic-ai/claude-code 完了後、もう一度 claude --version を実行してバージョン番号が出ればOKです。
ステップ 3: claude コマンドで初回セットアップを始める
ターミナルに以下を入力して Enter を押すと、初回セットアップが始まります:
claude 以下の画面が順番に表示されます。英語ですが、ひとつずつ説明します。
各画面の説明
英語で表示されますが、以下の通りに進めれば大丈夫です。
画面 1
テーマ(見た目)の選択
→ 2. Dark mode が選ばれていればそのまま Enter
矢印キー(↑↓)で選択肢を変えられます。どれでも動作に影響はないので、好みで選んで Enter を押せばOKです。
画面 2
ログイン方法の選択
→ 1. Claude account with subscription を選んで Enter
Claude Pro / Max などのサブスクリプションを使っている方はこれを選びます。API キーを別途持っている方は 2 番を選んでください。
画面 3
ブラウザで認証ページを開く
→ ダイアログが出たら 「Open」 をクリック
ブラウザが自動で開いて認証ページに進みます。もし開かない場合は、ターミナルに表示された URL をコピーしてブラウザに貼り付けてください。
画面 4
ブラウザで「承認する」
→ 「承認する」 をクリック
「Claude Code があなたの Claude アカウントに接続しようとしています」という画面です。内容を確認して「承認する」を押してください。「拒否する」を押すとログインできません。
画面 5
認証完了 → ブラウザを閉じる
→ 「このウィンドウを閉じることができます」と出たらブラウザを閉じてターミナルに戻る
「素晴らしいものを作りましょう / Claude Code の設定が完了しました」と表示されれば認証成功です。
画面 6
ログイン確認 → Enter を押して続ける
→ Enter を押す
「Logged in as(あなたのメールアドレス)/ Login successful. Press Enter to continue…」と出ていればOK。Enter を押して先へ進みます。
画面 7
セキュリティの注意書き → Enter を押して続ける
→ 内容を確認して Enter
「Claude はミスをすることがある」「信頼できるコードにだけ使うこと」という注意書きです。読んで Enter を押してください。
画面 8
ターミナル設定の推奨
→ 1. Yes, use recommended settings のまま Enter(推奨)
「Shift+Enter で改行できるようにする」という設定です。1 番が選ばれた状態で Enter を押せばOK。あとで変えたければ /terminal-setup で変更できます。
画面 9
フォルダの信頼確認
→ 1. Yes, I trust this folder を選んで Enter
「このフォルダを信頼しますか?」という確認です。自分のホームディレクトリやプロジェクトフォルダであれば 1 番を選んでください。見知らぬフォルダで開いてしまった場合は 2 番(No, exit)で一度終了してから、ターミナルで cd ~ と入力してからもう一度 claude を実行してください。
画面 10・11
セットアップ完了・起動確認
→ プロンプト(>)が出たら完了
「こんにちは!」などと話しかけて日本語で返事が来れば正常に動いています。確認できたら /exit と入力して一度終了し、次のセクションの呪文に進んでください。
セットアップ後の動作確認コマンド
ターミナルで以下を実行して、バージョン番号が出ればインストール成功です:
claude --version 詳しい仕組みを知りたい方向け
セットアップ後の動作
| 場面 | 挙動 |
|---|---|
| 再起動前から存在してた英語セッション | 再起動後にほぼ全部日本語化される |
| 既に日本語化されたセッション | クリックしても英語に戻らない |
| 新規セッション作成直後 | 数秒だけ英語表示 → hook 発火後に日本語に切り替わる |
仕組み概要
| 要素 | 役割 |
|---|---|
| Stop hook | Claude が応答完了するたびに発火 → 全英語タイトル翻訳 |
| SessionStart hook | Desktop 起動 / セッションフォーカス時に発火 → 同上 |
| titleSource: "user" | Desktop に「ユーザー設定」と認識させる(これで上書きされにくくなる) |
| PID ベースロック | 同時実行を防ぎつつ、ハングしたら即奪取 |
| バックアップ | 編集前ファイルを ~/.claude/hooks/backup/<日付>/ に保存 |
| JSON 健全性チェック | 編集後ファイルが壊れていないか確認、壊れていたら書き込みキャンセル |
既知の制約
- ・新規セッション直後の数秒: hook 発火までに英語が一瞬見える可能性(実害なし)
- ・Anthropic 側の挙動変更: Claude Desktop のアップデートで
titleSource: "user"の扱いが変わると壊れる可能性 - ・ネットワーク不調時:
claude -p haikuの失敗 → その回は英語のまま(次の hook 発火で再挑戦)
コスト目安
Claude Haiku 4.5 の API 単価(2026年5月時点): 入力 $1 / 100万トークン、出力 $5 / 100万トークン
タイトル翻訳は短文(入力 ~150 トークン / 出力 ~20 トークン)なので、1 回あたりのコストは非常に小さい想定です。
ただし claude -p の課金・利用枠の扱いは認証・契約形態(Pro / Max / Team / API キー直接)によって変わる可能性があります。
公式対応について
この問題は GitHub Issue でも複数報告されています。特に今回のセットアップに近いのは:
- #55951
— Desktop sidebar ignores UserPromptSubmit hook
sessionTitleoutput - #54440 — [FEATURE] Localize auto-generated session titles in "Recents" sidebar
- #58848 — Session titles generated in English despite language setting
開けるものに 👍 しておくと公式対応が早まる可能性があります。公式対応が来たらこの hook は不要になるので、ロールバック手順で剥がしてください。
なお ターミナルで claude コマンドからセッション開始する習慣にすると、hook 経由で公式の backend rename がトリガされてサーバー側のタイトルも日本語になります。Desktop 新規セッションより筋がよい方法です。
Windows 向け(Git Bash、1名確認済み)
✅ 1名の Windows ユーザー (Git Bash + winget jq) で動作確認済み
ただし環境差(Windows 11 のバージョン / OneDrive 設定 / インストール経路)で動かないケースもあり得ます。段階テスト前提で進めてください。
⚠️ Windows 特有のリスク: チャット履歴消失ケースあり
Qiita で報告された事例として、%APPDATA%\Claude\claude-code-sessions\ の JSON を直接編集して過去スレッドが全消失したケースがあります。
必ずこの順序を守ってください:
- Claude Desktop を完全終了(タスクトレイ右クリック→ Quit + Task Manager 確認)
%APPDATA%\Claude\を zip で全体バックアップ- 手動 1 件テスト → 動作確認 → 段階展開
- 複数回動いてから hook 自動登録
試し方:
- 下の「Windows 向け呪文を表示」を開いてコピーする
- Claude Desktop のチャット画面に貼り付ける
- あとは Claude の指示通りに進める(バックアップ・テスト手順も呪文の中に含まれています)
動作要件
- Windows 10/11
- Git Bash 必須(
git --versionが通る必要あり。未インストールなら git-scm.com から Git for Windows をインストール) - Claude Desktop がインストール済み
- claude CLI がインストール済み(Claude Desktop インストール時に自動で
~/.local/bin/claudeに入ることが多い) - jq は未インストールでも OK(呪文の中で
winget install jqlang.jqを案内) python3は 不要(Windows Store のスタブを踏むので使わない、trで代替)
Windows 向け呪文を表示 閉じる
下記のコピーボタンを押して Claude Desktop のチャット画面に貼り付けるだけで OK です。macOS 版とは独立したスタンドアロン実装です。
Claude Desktop の Recents サイドバーに表示されるセッションタイトルを、Windows 環境で自動日本語化するセットアップをして欲しいです。
実証済みの Windows 用構成です。1 名の Windows ユーザー (Git Bash + winget jq) で動作確認済みですが、環境差で動かないケースもあるので、必ず段階テストしてから進めてください。
## ⚠️ 重大な注意: 安全策を必ず実施
Qiita で `%APPDATA%\Claude\claude-code-sessions\` の JSON を直接編集して過去スレッドが消失した事例があります。下記の順序を厳守してください:
1. **Claude Desktop を完全終了** (タスクトレイの Claude アイコン右クリック → Quit、Task Manager で残プロセス無いか確認)
2. `%APPDATA%\Claude\` を zip で全体バックアップ
3. **手動 1 件だけ** スクリプトをテスト
4. UI で反映確認 + 健全性確認
5. **複数回問題なく動いてから** hook を settings.json に自動登録
6. 万一壊れたら zip から復元
## やってほしいこと (順番に)
### 1. 環境探索
Git Bash を経由してすべて確認してください (PowerShell では一部見えないケースあり):
```bash
# シェルと OS 確認
uname -s # MINGW64_NT-... が出れば Git Bash
ver # Windows のバージョン
# claude CLI のパス
where.exe claude # PowerShell スタイル
command -v claude # Git Bash スタイル
# jq の有無
where.exe jq # 無ければ後で winget install
# python3 は Windows ストアのスタブを踏むので、tr で代替する (確認不要)
# Claude Desktop データの実パス
# %APPDATA% は OneDrive リダイレクトで PowerShell から見えないケースがあるので、Git Bash の cygpath で確認
cygpath -u "$APPDATA"
ls "$(cygpath -u "$APPDATA")/Claude/claude-code-sessions" 2>/dev/null | head -5
# もし見えなければ、find で広く探す:
find /c/Users -name "claude-code-sessions" -type d 2>/dev/null | head -3
```
### 2. jq の準備 (未インストールなら)
`where.exe jq` で見つからなければ、ユーザーに **PowerShell (管理者不要)** で以下を実行してもらう:
```powershell
winget install jqlang.jq
```
完了後、Git Bash で jq の実パスを取得:
```bash
JQ_WIN=$(where.exe jq 2>/dev/null | head -1 | tr -d '\r')
JQ=$(cygpath -u "$JQ_WIN")
"$JQ" --version # 動けば OK
```
### 3. Claude Desktop の完全終了 + バックアップ
ユーザーに以下を依頼:
1. タスクトレイ (画面右下) の Claude アイコンを右クリック → Quit
2. Task Manager (Ctrl+Shift+Esc) で Claude 関連プロセスが残ってないか確認
その後 Git Bash で:
```bash
BACKUP_NAME="Claude-backup-$(date +%Y%m%d%H%M%S)"
# OneDrive を使ってる場合は OneDrive 配下に、そうでなければ Desktop に
BACKUP_DEST="$(cygpath -u "$USERPROFILE")/Desktop/$BACKUP_NAME"
APPDATA_UNIX=$(cygpath -u "$APPDATA")
cp -r "$APPDATA_UNIX/Claude" "$BACKUP_DEST"
echo "完了: $BACKUP_DEST"
ls "$BACKUP_DEST" | head -5
```
PowerShell の `Compress-Archive` でも良いが、OneDrive リダイレクトで `$env:APPDATA` が違うパスを返すケースがあるため、**Git Bash の `cp -r` を推奨**。
### 4. スクリプトを作成
`%USERPROFILE%\.claude\hooks\rename-session-title.sh` を以下の内容で作成 (Git Bash 経由で改行コード LF 維持):
```bash
#!/usr/bin/env bash
# Windows (Git Bash) 用: Claude Desktop の全 local_*.json を走査し、
# title が英語のものを claude -p haiku で日本語化する。
set -uo pipefail
LOG="$HOME/.claude/hooks/rename-session-title.log"
mkdir -p "$(dirname "$LOG")"
log() { printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG"; }
if [ "${CLAUDE_RENAME_HOOK_ACTIVE:-}" = "1" ]; then exit 0; fi
export CLAUDE_RENAME_HOOK_ACTIVE=1
log "=== hook fired (pid=$$) ==="
# Windows (Git Bash) 判定
case "$(uname -s)" in
MINGW*|MSYS*|CYGWIN*) : ;;
*) log "ERROR this script requires Git Bash on Windows (uname=$(uname -s))"; exit 0 ;;
esac
# jq の解決 (PATH に無くても where.exe で探す)
JQ=""
if command -v jq >/dev/null 2>&1; then
JQ=$(command -v jq)
else
JQ_WIN=$(where.exe jq 2>/dev/null | head -1 | tr -d '\r')
[ -n "$JQ_WIN" ] && JQ=$(cygpath -u "$JQ_WIN")
fi
if [ -z "$JQ" ] || ! "$JQ" --version >/dev/null 2>&1; then
log "ERROR jq not found. Install via PowerShell: winget install jqlang.jq"
exit 0
fi
# claude CLI の解決
CLAUDE_BIN=$(command -v claude 2>/dev/null)
if [ -z "$CLAUDE_BIN" ]; then
log "ERROR claude CLI not found in PATH"
exit 0
fi
# tr で非 ASCII 判定 (python3 不要)
is_non_ascii() {
[ -n "$(printf '%s' "$1" | tr -d '\000-\177')" ]
}
INPUT=$(cat 2>/dev/null || true)
SID=$(printf '%s' "$INPUT" | "$JQ" -r '.session_id // empty' 2>/dev/null || echo "")
EVENT=$(printf '%s' "$INPUT" | "$JQ" -r '.hook_event_name // empty' 2>/dev/null || echo "")
log "event=$EVENT session_id=$SID jq=$JQ claude=$CLAUDE_BIN"
# セッション保存先 (cygpath で APPDATA を Unix 形式に)
SESSIONS_DIR="$(cygpath -u "$APPDATA")/Claude/claude-code-sessions"
[ -d "$SESSIONS_DIR" ] || { log "no sessions dir at $SESSIONS_DIR"; exit 0; }
# ロック (時間ベースのみ: Windows では kill -0 が不安定なため PID 判定は使わない)
LOCKDIR="$HOME/.claude/hooks/.rename.lock.d"
if [ -d "$LOCKDIR" ]; then
if [ -n "$(find "$LOCKDIR" -maxdepth 0 -mmin +10 2>/dev/null)" ]; then
rm -rf "$LOCKDIR"; log "removed stale lock by age (>10min)"
else
log "lock held, skipping"; exit 0
fi
fi
mkdir "$LOCKDIR" 2>/dev/null || { log "lock acquire failed, skipping"; exit 0; }
trap 'rm -rf "$LOCKDIR"' EXIT
COUNT=0
SCANNED=0
while IFS= read -r -d '' f; do
SCANNED=$((SCANNED+1))
TITLE=$("$JQ" -r '.title // empty' "$f" 2>/dev/null)
[ -n "$TITLE" ] || continue
# 既に非 ASCII (= 日本語) ならスキップ
if is_non_ascii "$TITLE"; then continue; fi
log "translating: $TITLE ($f)"
PROMPT="次の英語のセッションタイトルを、自然で簡潔な日本語に翻訳してください。
ルール:
- タイトルだけを1行で返す
- 引用符・前置き・補足説明は不要
- 20文字以内を目安に
- **半英半日のミックスを避け、完全な日本語タイトルにする** (自然さ最優先)
- 動物名・地名・人名・一般的なサービス名は日本語/カタカナにする
例: Scottish Fold cats → スコティッシュフォールド猫、Tokyo → 東京
- コマンド・ファイル名・拡張子・技術用語のみ原文維持
例: \`git rebase\`、\`file.json\`、\`npm install\` は英語のまま
タイトル: $TITLE"
# Git Bash の GNU sed は UTF-8 を正しく扱うが、念のため strip は ASCII 範囲のみ
JP_TITLE=$("$CLAUDE_BIN" -p --model haiku "$PROMPT" </dev/null 2>>"$LOG" \
| tr -d '\r' \
| head -1 \
| sed -E 's/^[[:space:]"'\'']+//; s/[[:space:]"'\'']+$//')
[ -n "$JP_TITLE" ] || { log " empty result, skip"; continue; }
[ ${#JP_TITLE} -le 200 ] || { log " too long, skip"; continue; }
if ! is_non_ascii "$JP_TITLE"; then
log " ascii result, skip: $JP_TITLE"; continue
fi
TMP="${f}.tmp.$$"
if "$JQ" --arg t "$JP_TITLE" '.title = $t | .titleSource = "user"' "$f" > "$TMP" 2>>"$LOG"; then
if "$JQ" -e '.sessionId and .cliSessionId and (.title != null)' "$TMP" >/dev/null 2>&1; then
BACKUP_DIR="$HOME/.claude/hooks/backup/$(date '+%Y-%m-%d')"
if ! mkdir -p "$BACKUP_DIR" 2>>"$LOG"; then
rm -f "$TMP"; log " backup dir creation failed, aborting"; continue
fi
BACKUP_FILE="$BACKUP_DIR/$(basename "$f")"
if [ ! -f "$BACKUP_FILE" ]; then
if ! cp "$f" "$BACKUP_FILE" 2>>"$LOG"; then
rm -f "$TMP"; log " backup failed, aborting"; continue
fi
fi
if mv "$TMP" "$f" 2>>"$LOG"; then
log " -> $JP_TITLE file=$f backup=$BACKUP_FILE"
COUNT=$((COUNT+1))
else
rm -f "$TMP"; log " mv failed, original not overwritten"
fi
else
rm -f "$TMP"; log " health check failed, skipping"
fi
else
rm -f "$TMP"; log " jq failed"
fi
done < <(find "$SESSIONS_DIR" -name "local_*.json" -print0 2>/dev/null)
log "done. scanned=$SCANNED translated=$COUNT"
exit 0
```
ファイル作成時の注意:
- 改行コードは **LF** (CRLF だと Git Bash で `bad interpreter` エラー)
- BOM 無し
- 実行権限は Git Bash 経由なら `chmod +x` 不要 (NTFS の制約)
### 5. 手動テスト (重要、まだ hook 登録しない)
```bash
# Claude Desktop を起動した状態でも未起動でも OK
bash "$HOME/.claude/hooks/rename-session-title.sh" <<< '{"session_id":"manual-test","hook_event_name":"Stop"}'
tail -20 "$HOME/.claude/hooks/rename-session-title.log"
```
ログに `translated=N` (N >= 1) が出れば 1 件以上翻訳成功。
### 6. UI 確認
1. Claude Desktop を起動
2. Recents サイドバーで英語タイトルが日本語化されているか確認
3. 該当セッションをクリック → 日本語タイトルのまま維持されるか確認 (`titleSource: "user"` が効いてるか)
4. JSON の健全性確認:
```bash
"$JQ" '.title, .titleSource, .sessionId' "$(find "$SESSIONS_DIR" -name 'local_*.json' | head -1)"
```
### 7. CLAUDE.md に指示を追記
`%USERPROFILE%\.claude\CLAUDE.md` の末尾に以下を追記 (既存セクションあれば内容更新、重複追記しない):
```
## セッションタイトル
新しいセッションのタイトル / 会話のタイトルは必ず日本語で生成してください。
```
### 8. hook 登録 (settings.json) — テスト OK のときだけ
`%USERPROFILE%\.claude\settings.json` の `hooks.Stop` と `hooks.SessionStart` に登録 (冪等マージ):
```bash
HOOK_CMD="$(cygpath -u "$USERPROFILE")/.claude/hooks/rename-session-title.sh"
SETTINGS="$HOME/.claude/settings.json"
[ -f "$SETTINGS" ] && cp "$SETTINGS" "$SETTINGS.bak.$(date +%s)"
[ -f "$SETTINGS" ] || echo '{}' > "$SETTINGS"
"$JQ" --arg cmd "$HOOK_CMD" '
.hooks = (.hooks // {}) |
.hooks.Stop = (
(.hooks.Stop // [])
| map(.hooks = ((.hooks // []) | map(select(.command != $cmd))))
| map(select((.hooks // []) | length > 0))
) |
.hooks.SessionStart = (
(.hooks.SessionStart // [])
| map(.hooks = ((.hooks // []) | map(select(.command != $cmd))))
| map(select((.hooks // []) | length > 0))
) |
.hooks.Stop += [{
"hooks": [{ "type": "command", "command": $cmd, "async": true, "timeout": 120 }]
}] |
.hooks.SessionStart += [{
"hooks": [{ "type": "command", "command": $cmd, "async": true, "timeout": 120 }]
}]
' "$SETTINGS" > "$SETTINGS.tmp" && mv "$SETTINGS.tmp" "$SETTINGS"
```
### 9. Claude Desktop 完全終了 → 再起動 → 確認
タスクトレイ → Quit → Task Manager 確認 → 再起動。Recents サイドバーが全部日本語タイトルになっていれば成功。
### 10. 完了報告
ユーザーに以下を伝えてください:
- セットアップ完了
- バックアップ場所: `%USERPROFILE%\Desktop\Claude-backup-YYYYMMDDHHMMSS\`
- ログ場所: `%USERPROFILE%\.claude\hooks\rename-session-title.log` (Git Bash で `tail -f` で監視可能)
- 今後新しいセッションが英語タイトルで作られた場合、Stop / SessionStart のタイミングで自動日本語化される macOS 版との主な違い
| 観点 | macOS 版 | Windows 版 |
|---|---|---|
| シェル | bash(標準) | Git Bash 必須(uname -s が MINGW*) |
| 非 ASCII 判定 | python3 -c '...any(b>=0x80)...' | tr -d '\000-\177'(python3 不要) |
| jq パス | PATH 内(brew) | where.exe jq → cygpath -u で変換 |
| APPDATA パス | Unix ネイティブ | cygpath -u "$APPDATA" で変換 |
| 完全終了 | Cmd+Q | タスクトレイ → Quit + Task Manager 確認 |
| バックアップ | tar/zip | Git Bash の cp -r(OneDrive リダイレクト対応) |
| 改行コード | LF | LF 維持必須(CRLF だと bad interpreter) |
| 実行権限 | chmod +x 必要 | Git Bash 経由なら不要(NTFS) |