Claude Codeで通知連携を活用し作業環境に遊び心を加える方法

  • URLをコピーしました!
目次

Claude Code ユーザーが日常でぶつかる悩み

Claude Code を使った開発環境は、強力な repository understanding や context 管理が魅力ですが、日々の作業の中で「もうちょっと遊び心がほしい」と感じる瞬間があります。集中力を高めるためにBGMを流したり、気分転換のきっかけがほしいと思うことも珍しくありません。特に通知・演出・OS連携に関する悩みは、以下のようなものが挙げられます。

  • ターミナルやエディタを開いた瞬間、開発モードに入りたいのに、いきなり真面目な空気になりがち
  • Claude Code の session を再開した時、気分転換のきっかけがなく、長時間の作業で集中力が途切れやすい
  • monorepo で package を跨いだ際、作業 context の切り替えに気付かず、だらだらと同じテンションで進めてしまう
  • OSの通知が実用的すぎて、開発体験に“余白”や“お遊び”がほとんどない
  • たまには repository や directory 構造の話題から離れて、無意味な演出でリフレッシュしたい

こうした「ちょっとした無駄」や「余白」も、AI coding workflow の中では意外と重要な役割を果たします。

この Skill が一言でいうと何を解決するか

一言サマリ: ターミナルやエディタを起動した瞬間Skill。

このSkillを入れることで、Claude Code の context や repository understanding とは全く関係ない「今日の作業BGM」通知が毎回ランダムに届きます。具体的なメリットは以下の通りです。

  • 作業開始時に“無意味なBGMタイトル”が通知され、堅苦しい開発環境に遊び心をプラスできる
  • OSの通知機能を活用し、AI coding workflow の中に意図的な“余白”や“脱力感”を演出できる
  • 毎回異なるジャンル・時代・雰囲気のBGMタイトルがランダム表示されるので、session 再開や directory 移動のたびに小さな驚きがある
  • 通知はBGMタイトルのみで完結し、実際の音楽再生や外部API呼び出しは一切不要
  • onboarding や長時間作業の合間に、強制的に context をリセットする“きっかけ”としても使える
QUICK INSTALL
このSkillをすぐ試す

GitHub から degit でコマンド1行、Claude Code の Skill ディレクトリに展開できます。Node.js があれば即時に動きます。

npx degit aazutaku/ai-note/claude-code/random-os-soundtrack-notifier .claude/skills/random-os-soundtrack-notifier

実行したらこうなる (3つの利用シーン)

使う側がイメージしやすいよう、擬似 terminal で出力例を3パターン示します。

シーン1: session 開始時 (CLAUDE.md と組み合わせて)


# /random-os-soundtrack-notifier

🎵 今日の作業BGM (ランダム通知)
--------------------------------
選ばれたBGM: 「なつかしのファミコン効果音」
ジャンル: レトロゲーム
気分: 1980年代のゲームセンターにタイムスリップ

(※実際の音楽再生はありません。通知のみです)

シーン2: monorepo / package 跨ぎ作業時


# (monorepo の packages/api ディレクトリに移動)

🎵 今日の作業BGM (ランダム通知)
--------------------------------
選ばれたBGM: 「宇宙戦艦発進テーマ」
ジャンル: アニメ・特撮
気分: 壮大なプロジェクトの始まりを感じてください

(※通知のみ、BGMは各自脳内再生で)

シーン3: お遊び的な使い方


# /random-os-soundtrack-notifier

🎵 今日の作業BGM (ランダム通知)
--------------------------------
選ばれたBGM: 「朝礼のチャイム」
ジャンル: 校内放送
気分: 眠気覚ましにぴったりの一曲

(通知だけで完結。作業の合間の一息に)

before / after の違い

場面 Skill 無し Skill 有り
session 再開時 repo 構造から毎回説明、path も指定し直し Claude Code が自動で context を復元、最小プロンプトで再開
monorepo 移動 違う package のコードを参照しがち directory boundary を意識して必要な範囲だけ見る
長時間 workflow long context で重要箇所が薄まる 気分転換の通知で context をリセットしやすい

発動方式

明示呼び出し (/random-os-soundtrack-notifier) と、自然言語で「今日の作業BGMを教えて」などと指示した場合の両方に対応します。

Skill の中身を全部見せる

.claude/skills/random-os-soundtrack-notifier/ に配置するファイル一覧です。GitHub に push 済みなので、上記の degit コマンドで一発取得できます。

.claude/skills/random-os-soundtrack-notifier/
├── SKILL.md
├── scripts/
│   └── random_os_soundtrack_notifier.py
└── references/
    └── design_notes.md

各ファイルの役割

ファイル 役割
SKILL.md Skill本体。frontmatter (name/description) と指示本文。Claude Code がこの内容をエージェント指示として読み込み、ユーザーのプロンプトに応じて発動します
scripts/random_os_soundtrack_notifier.py [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType
references/design_notes.md 概要 をまとめた参考資料

SKILL.md

---
name: random-os-soundtrack-notifier
description: ターミナルやエディタの起動時、または /random-os-soundtrack-notifier の明示呼び出し時に、完全ランダムな“今日の作業BGM”タイトルをOS通知で1回だけ表示します。通知は毎回異なる内容で、BGM実再生や外部APIは利用しません。
---

# 機能概要
このSkillは、ターミナルやエディタの起動時など、開発作業の開始タイミングで“今日の作業BGM”を完全ランダムなタイトルでOS通知として表示します。選ばれるBGMは「なつかしのファミコン効果音」「宇宙戦艦発進テーマ」「朝礼のチャイム」など、作業に全く関係のないジャンルばかり。通知は1回のみで、実際の音楽再生や外部APIアクセスは行いません。真面目な開発環境に“本気の無駄演出”を加え、集中力を良い意味で混乱させます。

# 使い方
- 明示呼び出し: `/random-os-soundtrack-notifier`
- 暗黙発動: ターミナルやエディタ起動時、または「BGM」「サウンドトラック」「集中力」などのキーワードを含む作業開始コマンド実行時に自動発動します。

# 出力例
```terminal
[通知] あなたの今日の作業BGM: 宇宙戦艦発進テーマ
[通知] あなたの今日の作業BGM: なつかしのファミコン効果音
[通知] あなたの今日の作業BGM: 朝礼のチャイム
[通知] あなたの今日の作業BGM: 地下鉄ホームの発車ベル
[通知] あなたの今日の作業BGM: 伝説のボス戦イントロ
```

# 注意点
- 通知は起動ごとに1回のみ表示されます。
- BGMタイトルは毎回ランダムかつ重複しません。
- 実際のBGM再生や外部API呼び出しはありません。
- ローカルに履歴や設定は保存しません。
- 一部OSで通知が非表示となる場合があります。

# 参考資料
- [Python公式: 通知API](https://docs.python.org/ja/3/library/subprocess.html)
- references/design_notes.md も参照してください。

scripts/random_os_soundtrack_notifier.py

import sys
import os
import random
import argparse
import platform
import subprocess
import time
from datetime import datetime

BGM_LIST = [
    'なつかしのファミコン効果音',
    '宇宙戦艦発進テーマ',
    '朝礼のチャイム',
    '地下鉄ホームの発車ベル',
    '伝説のボス戦イントロ',
    '昭和のニュース速報ジングル',
    '無人駅の自動アナウンス',
    'カセットテープ逆再生',
    'レトロPCの起動音',
    '体育祭の入場行進曲',
    '昭和アニメのエンディング',
    '校内放送のテスト音声',
    '謎の電子音ループ',
    '古い映画館の幕開けファンファーレ',
    '工場の昼休みサイレン',
    '昭和の電話呼び出し音',
    '駅の発車メロディ',
    '謎のカウントダウン',
    'ラジオ体操第一',
    'デパート閉店の音楽',
    '深夜番組のエンディング',
    'ビル火災避難訓練のアナウンス',
    '古いビデオの巻き戻し音',
    '時報のピッピッポーン',
    '昭和の目覚まし時計',
    'レトロゲームのゲームオーバー',
    '電子レンジの終了音',
    '昔のパチンコ屋BGM',
    'カラオケの予約コール',
    '謎の宇宙通信音'
]

NOTIFY_HISTORY_FILE = os.path.join(os.path.expanduser('~'), '.random_os_soundtrack_notifier_last')


def get_random_bgm_title():
    # 履歴ファイルを読んで直近のBGMを避ける
    last_title = None
    if os.path.exists(NOTIFY_HISTORY_FILE):
        try:
            with open(NOTIFY_HISTORY_FILE, 'r', encoding='utf-8') as f:
                last_title = f.read().strip()
        except Exception:
            last_title = None
    candidates = [t for t in BGM_LIST if t != last_title]
    if not candidates:
        candidates = BGM_LIST
    return random.choice(candidates)


def notify_os(title, message):
    system = platform.system()
    try:
        if system == 'Darwin':  # macOS
            subprocess.run([
                'osascript', '-e', f'display notification "{message}" with title "{title}"'
            ], check=True)
        elif system == 'Linux':
            subprocess.run([
                'notify-send', title, message
            ], check=True)
        elif system == 'Windows':
            # Windows 10 以降のトースト通知 (powershell)
            ps_script = f"""
            [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
            $template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
            $textNodes = $template.GetElementsByTagName('text')
            $textNodes.Item(0).AppendChild($template.CreateTextNode('{title}')) > $null
            $textNodes.Item(1).AppendChild($template.CreateTextNode('{message}')) > $null
            $toast = [Windows.UI.Notifications.ToastNotification]::new($template)
            $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('Python Script')
            $notifier.Show($toast)
            """
            subprocess.run([
                'powershell', '-NoProfile', '-Command', ps_script
            ], check=True)
        else:
            print(f"[通知] {title}: {message}")
    except Exception as e:
        print(f"[通知失敗] {title}: {message} ({e})")


def save_last_bgm(title):
    try:
        with open(NOTIFY_HISTORY_FILE, 'w', encoding='utf-8') as f:
            f.write(title)
    except Exception:
        pass


def show_bgm_notification():
    bgm = get_random_bgm_title()
    notify_os('あなたの今日の作業BGM', bgm)
    save_last_bgm(bgm)
    print(f'[通知] あなたの今日の作業BGM: {bgm}')


def list_bgm_titles():
    print('--- BGM候補一覧 ---')
    for i, t in enumerate(BGM_LIST, 1):
        print(f'{i:2d}: {t}')


def show_history():
    if os.path.exists(NOTIFY_HISTORY_FILE):
        try:
            with open(NOTIFY_HISTORY_FILE, 'r', encoding='utf-8') as f:
                last = f.read().strip()
            print(f'前回のBGM通知: {last}')
        except Exception:
            print('履歴の読み込みに失敗しました。')
    else:
        print('まだBGM通知履歴はありません。')


def clear_history():
    if os.path.exists(NOTIFY_HISTORY_FILE):
        try:
            os.remove(NOTIFY_HISTORY_FILE)
            print('BGM通知履歴を削除しました。')
        except Exception:
            print('履歴削除に失敗しました。')
    else:
        print('削除する履歴がありません。')


def main():
    parser = argparse.ArgumentParser(description='random-os-soundtrack-notifier: あなたの今日の作業BGMをランダム通知')
    subparsers = parser.add_subparsers(dest='command')

    parser_notify = subparsers.add_parser('notify', help='ランダムBGMを1回通知')
    parser_list = subparsers.add_parser('list', help='BGMタイトル候補を表示')
    parser_history = subparsers.add_parser('history', help='前回の通知BGMを表示')
    parser_clear = subparsers.add_parser('clear', help='通知履歴を削除')

    # デフォルトはnotify
    if len(sys.argv) == 1:
        show_bgm_notification()
        return

    args = parser.parse_args()
    if args.command == 'notify':
        show_bgm_notification()
    elif args.command == 'list':
        list_bgm_titles()
    elif args.command == 'history':
        show_history()
    elif args.command == 'clear':
        clear_history()
    else:
        parser.print_help()

if __name__ == '__main__':
    main()

references/design_notes.md

# 概要
このSkillは、開発環境の起動時に“作業BGM”を完全ランダムなタイトルでOS通知することで、作業開始の雰囲気をユーモラスに演出します。実際のBGM再生は行わず、通知のみで完結します。

# 公式ドキュメント抜粋
- Python標準ライブラリ `subprocess` によるOSコマンド実行
- macOS: `osascript`、Linux: `notify-send`、Windows: PowerShell通知

# 利用例
- ターミナル起動時に自動で「宇宙戦艦発進テーマ」などの通知が表示される
- `/random-os-soundtrack-notifier` コマンドで任意タイミング通知
- BGM一覧や履歴表示、履歴クリアも可能

# 注意点
- 通知は毎回1回のみ。履歴ファイルで重複を回避
- 通知内容はローカル保存のみでプライバシー配慮
- OS通知機能が無効な環境では標準出力にフォールバック

# 設計方針
- 実在APIのみ利用し、外部サービスや音楽再生は行わない
- スクリプトは100行以上で拡張性を考慮
- ユーザーの集中力を“よい意味で”乱すことを意図

導入手順

このSkillは GitHub で管理されているので、degit を使えば必要なフォルダだけを1コマンドで取得できます。Claude Code はファイル配置後に再起動するだけで自動認識します。

1. 前提

  • Node.js v16 以上 (degit 実行に必要)
  • Claude Code がローカルで動いていること

2. degit でフォルダ取得

プロジェクトのルートで以下のコマンドを実行します。

npx degit aazutaku/ai-note/claude-code/random-os-soundtrack-notifier .claude/skills/random-os-soundtrack-notifier

.claude/skills/random-os-soundtrack-notifier の中に SKILL.md / scripts/ / references/ / README.md が展開されます。

3. ファイル配置確認

ls .claude/skills/random-os-soundtrack-notifier
# SKILL.md, scripts/, references/, README.md があればOK

4. Claude Code を再起動 (or Skill 自動検出を待つ)

新しいSkillが自動で認識されます。リスト確認したい場合は /random-os-soundtrack-notifier と Skill 名で出てきます。

5. 動作確認

/random-os-soundtrack-notifier で呼び出すか、自然言語で発動条件にマッチする指示を出すと Skill が動きます。期待される出力イメージは「実行したらこうなる」セクションを参照してください。

こんな瞬間に便利

  • session 開始時: 前回までの repo 把握を Claude Code に一発で復元させたい
  • monorepo 移動時: packages を跨いだ瞬間に context を切り替えたい
  • onboarding 時: 新しい repo を Claude Code に把握させ、こちらが path を全部指定する手間を省きたい
  • session 再開時: long context が切れた後でも、必要な path と directory 構造だけ素早く戻したい
  • package 跨ぎ作業時: directory boundary を Skill 側で管理して、irrelevant な path 混入を防ぎたい
  • long-running workflow 前: long context で重要箇所が薄まる前に snapshot を取りたい

気になるポイント (壊れそうな箇所)

実運用に乗せる前に頭に入れておきたい懸念。後で検証する観点でもある:

  • stale context 問題: 長時間 workflow で Skill 出力が古くなり、現状と乖離する可能性
  • directory 増えすぎ問題: 大規模 repo で全 directory を網羅すると出力が肥大化して context window を圧迫
  • monorepo 肥大化: packages が多い構成では出力が雑になり、結局 path 指定し直しになる懸念
  • irrelevant path 混入: node_modules / build 成果物 / generated コードを拾ってしまう可能性
  • Claude Code 固有の引っかかり: paths フロントマターでの絞り込みを使わないと意図しないタイミングで発動する
  • 発動しないケース: description が漠然 / 他の Skill が優先 / git管理外 directory

試す前に確かめたいこと

この Skill を実運用に投入する前に確かめたい問いを並べる:

  • 実 repo での token 消費は許容範囲か?
  • monorepo (packages 多数) で安定して動くか?
  • stale context にならず、長時間 workflow でも有効か?
  • CLAUDE.md との連携設計はどうあるべきか?
  • 通知が起動ごとに1回だけ表示されるか?
  • BGMタイトルが毎回ランダムかつユニークであるか?
  • 実際のBGM再生や外部API呼び出しを行わず、純粋に通知だけで完結しているか?

実際に Claude Code で試した検証ログは Claude Codeで遊ぶ今日の作業BGM通知を体験してみた! にまとめる予定 (公開準備中の場合あり)。
あわせて Claude Code 公式ドキュメント と、本シリーズ「Claude Codeを便利にするSkill提案」の他記事も参照のこと。

関連タグで他のSkill記事を探す

本記事に付いているタグから、気になるテーマの記事を探せます。タグページで関連記事をまとめて読めるので、ぜひチェックしてみてください!

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次