Claude Code の「Thinking...」を今日のニュースに差し替えてみた

記事タイトルとURLをコピーする

Claude Code の「Thinking...」を今日のニュースに差し替えてみた

こんにちは、サーバーワークスで生成AIの活用推進を担当している針生です。

Claude Code を使っていると、AI が処理中のときにターミナルにスピナーが表示されます。その横に出る「Thinking...」「Reasoning...」の部分、実は ~/.claude/settings.json で自由に書き換えられます。

最初は「ゴリラ」「ラッパ」の2語にして楽しんでいたのですが、1日で飽きました。毎回同じ文字がループするだけでは面白くない。「どうせなら毎朝変わったら楽しくない?」と思い、今日のニュース見出しをスピナーに流すようにしました。

spinnerVerbs とは

~/.claude/settings.json に以下のように書くと、スピナーに表示される動詞をカスタムできます。

"spinnerVerbs": {
  "mode": "replace",
  "verbs": ["ゴリラ", "ラッパ"]
}

mode は2種類あります。

  • replace — 標準の「Thinking」「Reasoning」などをリストで完全に置き換える
  • append — 標準語句に自分のリストを追加する

「ゴリラ」だけ流したいなら replace 一択です。append にすると「Thinking」「Reasoning」「ゴリラ」が混在します。

外部スケジューラで settings.json を書き換える

Claude Code は settings.json を動的に読み込むので、verbs の中身を差し替えると 再起動なしで次のスピナーから新しい動詞が使われます。裏で毎朝書き換えておけば、10:00 以降は自動でその日のニュースに切り替わる、という寸法です。

仕組みは以下のとおりです。

[launchd 平日10:00]
    ↓
[~/.claude/scripts/update-spinner-verbs.sh]
    ↓
[claude -p "今日のニュース見出しをJSON配列で" --allowedTools WebSearch]
    ↓
[~/.claude/settings.json の spinnerVerbs.verbs を書き換え]

ニュースの取得に RSS パーサーを使っても良いですが、今回は実装がシンプルな claude -p + WebSearch を選びました。LLM に当日の見出しをまとめてもらうだけです。

しかも claude -p は Claude Code 本体の認証をそのまま使うので、Anthropic API キーを別途用意する必要もありません。

実装

シェルスクリプト

~/.claude/scripts/update-spinner-verbs.sh:

#!/usr/bin/env bash
set -euo pipefail

SETTINGS="$HOME/.claude/settings.json"
BACKUP="$HOME/.claude/settings.json.bak"
LOG="$HOME/.claude/logs/update-spinner-verbs.log"
CLAUDE_BIN="$HOME/.local/bin/claude"

mkdir -p "$(dirname "$LOG")"
exec >> "$LOG" 2>&1
echo "[$(date '+%Y-%m-%d %H:%M:%S')] start"

PROMPT='今日(日本時間)の主要ニュース見出しを、一般・国際・経済・テック・クラウド/AWS から幅広く選び、日本語で8〜10本。文字数制限なし、見出しは元の長さのまま。出力は JSON 配列のみ。前後に ``` や説明を付けない。例: ["見出し1","見出し2"]'

RAW=$("$CLAUDE_BIN" -p "$PROMPT" --allowedTools WebSearch --output-format text 2>&1) || {
  echo "[$(date '+%H:%M:%S')] claude call failed: $RAW"; exit 1;
}

VERBS=$(printf '%s' "$RAW" | python3 -c '
import sys, re, json
txt = sys.stdin.read()
m = re.search(r"\[.*?\]", txt, re.S)
if not m:
    m = re.search(r"\[[\s\S]*?\]", txt)
if not m:
    sys.exit("no array found in: " + txt[:200])
arr = json.loads(m.group(0))
if not (isinstance(arr, list) and 5 <= len(arr) <= 12 and all(isinstance(x, str) and x.strip() for x in arr)):
    sys.exit("invalid array: " + repr(arr))
print(json.dumps(arr, ensure_ascii=False))
') || { echo "[$(date '+%H:%M:%S')] extract failed. raw: $RAW"; exit 1; }

cp "$SETTINGS" "$BACKUP"
TMP=$(mktemp)
jq --argjson v "$VERBS" '.spinnerVerbs.verbs = $v | .spinnerVerbs.mode = "replace"' "$SETTINGS" > "$TMP"
jq empty "$TMP"
mv "$TMP" "$SETTINGS"

echo "[$(date '+%H:%M:%S')] updated: $VERBS"

ポイントは3つです。

1. claude -p --allowedTools WebSearch Claude Code headless モードではツールの利用範囲が制限されます。WebSearch を使うには --allowedTools WebSearch で明示的に許可する必要があります。

2. 正規表現で JSON 配列を抜き出す LLM は「配列だけ返して」と言っても前後に説明文を添えることがあります。Python の正規表現で [...] 部分だけを抽出しています。抽出後に件数(5〜12本)と型(文字列のみ)をチェックし、外れた場合はスクリプトを失敗扱いにして既存の settings.json を触りません。

3. atomic 書き換え 一時ファイルに書いて jq empty で JSON バリデーションを通してから mv します。途中で処理が中断されても settings.json が壊れません。書き換え前には cp でバックアップも作ります。

launchd への登録

ここから先は MacBook(macOS)前提です。Linux なら cron、Windows ならタスクスケジューラに読み替えてください。

~/Library/LaunchAgents/com.yourname.claude-spinner-verbs.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.yourname.claude-spinner-verbs</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>/Users/yourname/.claude/scripts/update-spinner-verbs.sh</string>
  </array>
  <key>StartCalendarInterval</key>
  <array>
    <dict><key>Weekday</key><integer>1</integer><key>Hour</key><integer>10</integer><key>Minute</key><integer>0</integer></dict>
    <dict><key>Weekday</key><integer>2</integer><key>Hour</key><integer>10</integer><key>Minute</key><integer>0</integer></dict>
    <dict><key>Weekday</key><integer>3</integer><key>Hour</key><integer>10</integer><key>Minute</key><integer>0</integer></dict>
    <dict><key>Weekday</key><integer>4</integer><key>Hour</key><integer>10</integer><key>Minute</key><integer>0</integer></dict>
    <dict><key>Weekday</key><integer>5</integer><key>Hour</key><integer>10</integer><key>Minute</key><integer>0</integer></dict>
  </array>
  <key>StandardOutPath</key><string>/Users/yourname/.claude/logs/update-spinner-verbs.out</string>
  <key>StandardErrorPath</key><string>/Users/yourname/.claude/logs/update-spinner-verbs.err</string>
</dict>
</plist>

StartCalendarInterval を配列にして Weekday 1〜5(月曜〜金曜)の 10:00 を指定しています。cron でも同じことはできますが(0 10 * * 1-5)、launchd の方が MacBook を使う場合に有利です。cron はスリープ中に予定時刻を跨ぐとジョブをスキップしますが、launchd は起床後に自動で実行してくれます。

登録は以下のコマンドで1行です。

launchctl load ~/Library/LaunchAgents/com.yourname.claude-spinner-verbs.plist

実際に Claude Code を動かすと、ニュースが表示されました。

応用アイデア

同じ仕組みで verbs の中身は何でも変えられます。

  • 天気予報 — Weather API から当日の天気・気温を取得して流す
  • 今日の TODO — Google Calendar から当日の予定を抜いてくる
  • PR レビュー待ち — 自分宛のレビュー依頼タイトルを GitHub API から取得して流す

仕事に関係する情報を流せば、ターミナルがちょっとしたダッシュボードになります。

まとめ

  • Claude Code の spinnerVerbssettings.json で差し替えられる。mode: "replace" で標準語句を完全置換
  • claude -p --allowedTools WebSearch で API キー不要の LLM + Web 検索が使える。当日のニュース取得に便利
  • launchd の StartCalendarInterval(Weekday 1〜5)でスリープを跨いでも平日 10:00 に確実に実行できる

ニュース見出しが流れるスピナーを眺めながら「今日もいろいろ起きているな」と思う朝。実用性はともかく、気分は悪くないです。

針生 泰有(執筆記事の一覧)

サーバーワークスで生成AIの活用推進を担当