Codexで謎の誕生日通知を活用して作業の意外なリズムを作る方法

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

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

AI coding workflow を Codex で回していると、日々の作業の中で思わず「またか」と感じるシーンがいくつもあります。特に repository understanding や path management、context の取り扱いが絡む場面では、集中力を保つのが意外と難しいものです。

  • Codex が context を見失って違う場所のコードを参照することがあり、意図しない directory の情報が混入する
  • monorepo で package を跨いだ瞬間、Codex が repository 構造や context をリセットしてしまい、再度説明が必要になる
  • session を再開すると、前回までの context や path 指定をまるごと再説明しないと、Codex の repository understanding が追いつかない
  • 長時間の AI coding workflow で long context が膨らみすぎて、重要な情報が stale context の中に埋もれてしまう
  • 「ここはこういう構造のリポジトリです」と毎回チャット冒頭に directory 構造や path を書く手間が発生し、作業テンポが乱れる

こうした悩みは、通知・演出・OS連携系の Skill を導入することで、時に良い意味で workflow に「ノイズ」を加え、集中力をリフレッシュするきっかけにもなります。

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

一言サマリ: このスキルは、作業中に突如「謎のOS公式・本日誕生日通知」を炸裂させることで、マンネリ化した AI coding workflow にシュールな刺激とリフレッシュを提供する Skill。

もう少し具体化すると、このSkillを入れることで以下のような状態になる:

  • 単調になりがちな長時間の repository 作業や onboarding の合間に、突発的な「謎イベント」が発生し、集中力をリセットできる
  • Codex の context 管理や memory の煩雑さに疲れたとき、意図せず笑える通知で気分転換できる
  • monorepo で directory や path management に行き詰まった際、思わぬタイミングで「本日誕生日: src/utils/parseDate.js」などのシュールな通知が入り、作業の流れを一度リフレッシュできる
  • AI coding workflow に「意味不明な年表」や「祝福コメント」が混ざることで、リポジトリや context の重苦しさを和らげる
  • onboarding や session 再開時の緊張感を、遊び心ある通知でほぐすことができる
QUICK INSTALL
このSkillをすぐ試す

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

npx degit aazutaku/ai-note/codex/random-os-fake-birthday-notifier .agents/skills/random-os-fake-birthday-notifier

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

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

シーン1: session 開始時 (プロジェクト初動で)


# /skills menu or random-os-fake-birthday-notifier mention
> 開発を始める

🎉【祝】あなたの左Ctrlキー 31周年記念祭🎉
本日、あなたのキーボード左Ctrlキーが誕生してから31年が経ちました。
年表:
- 1993: 最初のCtrl + C を記録
- 2001: 一度だけCapsLockと間違えられる
- 2017: キートップがやや摩耗
- 2024: 現役続行中
コメント: これからもショートカットの要としてご活躍ください。

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


> packages/api/ から packages/web/ に移動

【謎の通知】本日誕生日: packages/shared/utils/formatDate.ts
生誕 4 年目を迎えました。おめでとうございます。
年表:
- 2020: 初commit
- 2021: 5回リファクタ
- 2022: formatISO対応
- 2024: 依然として現役
コメント: そろそろ型定義を見直してあげてください。

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


> 何か面白いことない?

【OS公式発表】ターミナルの黒背景 18周年
- 2006: 初期設定で黒に
- 2012: たまに白背景に浮気
- 2020: ダークモード流行で再評価
コメント: 黒背景は永遠に不滅です。

before / after の違い

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

発動方式

明示呼び出し (/skills menu or random-os-fake-birthday-notifier mention) と暗黙発動 (description マッチ) の両方に対応。

Skill の中身を全部見せる

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

.agents/skills/random-os-fake-birthday-notifier/
├── SKILL.md
├── scripts/
│   └── random_os_fake_birthday_notifier.py
└── references/
    └── design_notes.md

各ファイルの役割

ファイル 役割
SKILL.md Skill本体。frontmatter (name/description) と指示本文。Codex がこの内容をエージェント指示として読み込み、ユーザーのプロンプトに応じて発動します
scripts/random_os_fake_birthday_notifier.py random-os-fake-birthday-notifier
references/design_notes.md 概要 をまとめた参考資料

SKILL.md

---
name: random-os-fake-birthday-notifier
description: このSkillは、作業中のターミナルやデスクトップで「謎のOS公式・本日誕生日通知」を突発的に発動します。明示的な /skills メニュー呼び出しや、'祝う', '誕生日', '記念日' などのキーワード入力時にも作動します。
---

# 機能概要
random-os-fake-birthday-notifierは、開発者の作業環境に突如として“謎のOS公式・本日誕生日通知”を発生させるSkillです。通知対象は毎回完全ランダムで、例えば「あなたの左Ctrlキーの誕生日」「プロジェクト最古ファイルの生誕祭」「ターミナルの黒背景18周年」など、実用性皆無な対象を祝福します。通知にはシュールな年表や無意味なコメントが添えられ、開発者の集中力を絶妙にかき乱します。日常のマンネリ打破やチームのアイスブレイクにも活用可能です。

# 使い方
- 明示呼び出し: `/skills menu` または `$random-os-fake-birthday-notifier` を入力
- 暗黙発動: '祝う', '誕生日', '記念日', '周年', '生誕祭' などの単語を含む発言やコマンド実行時に自動発動

# 出力例
```
🎉 本日、あなたの左Ctrlキーが誕生してから 14 年目です!
Ctrlキー年表:
- 2009: 初めてコーヒーをこぼされる
- 2014: 一度だけCapsLockと間違えられる
- 2021: ついにキートップが消える
おめでとうございます!

---
祝: プロジェクト最古ファイル生誕祭(/home/user/project/README.md, 2017/06/28 作成)
- 2017: 初commit
- 2019: 1度だけ消されかける
- 2023: 6年間誰にも編集されず
```

# 注意点
- 通知対象は完全ランダム生成です。実在しない記念日も含まれます。
- 連続発動防止のため、一定時間内の多重発動は制限されます。
- ローカル環境のファイル・キーボード情報取得にはOS依存APIを利用します。
- 通知内容はログ保存されません。必要に応じて手動で保存してください。

# 参考資料
- [Python公式: os, random, datetime モジュール](https://docs.python.org/3/library/)
- references/design_notes.md も参照してください。

scripts/random_os_fake_birthday_notifier.py

import os
import sys
import random
import datetime
import time
import argparse
import platform
from pathlib import Path

# --- 記念日ネタ候補 ---
FAKE_TARGETS = [
    {
        'name': 'あなたの左Ctrlキー',
        'get_date': lambda: get_keyboard_install_date(),
        'timeline': [
            '初めてコーヒーをこぼされる',
            '一度だけCapsLockと間違えられる',
            'ついにキートップが消える'
        ]
    },
    {
        'name': 'プロジェクト最古ファイル',
        'get_date': lambda: get_oldest_file_date('.'),
        'timeline': [
            '初commit',
            '1度だけ消されかける',
            '6年間誰にも編集されず'
        ]
    },
    {
        'name': 'ターミナルの黒背景',
        'get_date': lambda: get_terminal_anniversary(),
        'timeline': [
            '初めてlsコマンドを実行',
            '背景色を白にしようとして諦める',
            '真夜中だけ明るく感じる'
        ]
    },
    {
        'name': 'ホームディレクトリ',
        'get_date': lambda: get_home_dir_birth(),
        'timeline': [
            '初めてファイルが保存される',
            'ゴミ箱が溢れる',
            'パーミッション地獄を経験'
        ]
    },
    {
        'name': 'Python実行環境',
        'get_date': lambda: get_python_install_date(),
        'timeline': [
            'pip installに失敗',
            'バージョンアップで混乱',
            'venvが量産される'
        ]
    }
]

LAST_NOTIFY_FILE = Path.home() / '.random_os_fake_birthday_last'
NOTIFY_INTERVAL_SEC = 60 * 10  # 10分に1回まで

# --- ヘルパー関数群 ---
def get_keyboard_install_date():
    # OSによって取得不可。適当に2009年1月1日を返す
    return datetime.date(2009, 1, 1)

def get_oldest_file_date(root_dir):
    oldest = None
    oldest_time = time.time()
    for dirpath, _, filenames in os.walk(root_dir):
        for f in filenames:
            try:
                fp = os.path.join(dirpath, f)
                stat = os.stat(fp)
                ctime = stat.st_ctime
                if ctime < oldest_time:
                    oldest_time = ctime
                    oldest = fp
            except Exception:
                continue
    if oldest:
        return datetime.date.fromtimestamp(oldest_time)
    return datetime.date.today()

def get_terminal_anniversary():
    # ターミナルの黒背景記念日: 適当に2006年6月6日
    return datetime.date(2006, 6, 6)

def get_home_dir_birth():
    home = Path.home()
    try:
        stat = home.stat()
        return datetime.date.fromtimestamp(stat.st_ctime)
    except Exception:
        return datetime.date(2010, 1, 1)

def get_python_install_date():
    # Python実行ファイルのctime
    pyexe = sys.executable
    try:
        stat = os.stat(pyexe)
        return datetime.date.fromtimestamp(stat.st_ctime)
    except Exception:
        return datetime.date(2015, 5, 5)

def random_timeline(base_timeline, years):
    # 年表をランダムに生成
    base_year = datetime.date.today().year - years
    out = []
    for i, event in enumerate(base_timeline):
        year = base_year + random.randint(i, years)
        out.append(f'- {year}: {event}')
    return out

def format_birthday_message(target, date, timeline):
    years = datetime.date.today().year - date.year
    if years <= 0:
        years = 1
    msg = f'本日、{target}が誕生してから {years} 年目です!\n'
    msg += f'{target}年表:\n'
    msg += '\n'.join(timeline)
    msg += '\nおめでとうございます!\n'
    return msg

def format_file_birthday_message(filepath, date, timeline):
    years = datetime.date.today().year - date.year
    fn = os.path.basename(filepath)
    msg = f'祝: プロジェクト最古ファイル生誕祭({filepath}, {date} 作成)\n'
    for t in timeline:
        msg += f'{t}\n'
    return msg

def check_last_notify():
    if not LAST_NOTIFY_FILE.exists():
        return True
    try:
        with open(LAST_NOTIFY_FILE, 'r') as f:
            last = float(f.read().strip())
        if time.time() - last > NOTIFY_INTERVAL_SEC:
            return True
        return False
    except Exception:
        return True

def update_last_notify():
    try:
        with open(LAST_NOTIFY_FILE, 'w') as f:
            f.write(str(time.time()))
    except Exception:
        pass

def notify():
    if not check_last_notify():
        print('(通知は連続発動防止のためスキップされました)')
        return
    target = random.choice(FAKE_TARGETS)
    date = target['get_date']()
    years = datetime.date.today().year - date.year
    timeline = random_timeline(target['timeline'], years)
    if target['name'] == 'プロジェクト最古ファイル':
        oldest_file = get_oldest_file_path('.')
        msg = format_file_birthday_message(oldest_file, date, timeline)
    else:
        msg = format_birthday_message(target['name'], date, timeline)
    print(msg)
    update_last_notify()

def get_oldest_file_path(root_dir):
    oldest = None
    oldest_time = time.time()
    for dirpath, _, filenames in os.walk(root_dir):
        for f in filenames:
            try:
                fp = os.path.join(dirpath, f)
                stat = os.stat(fp)
                ctime = stat.st_ctime
                if ctime < oldest_time:
                    oldest_time = ctime
                    oldest = fp
            except Exception:
                continue
    return oldest if oldest else '不明なファイル'

def list_targets():
    print('祝われる対象候補:')
    for t in FAKE_TARGETS:
        print(f'- {t["name"]}')

def summary():
    print('random-os-fake-birthday-notifier 概要')
    print('・突発的に謎の誕生日/記念日通知を出します')
    print('・対象は毎回ランダムです')
    print('・通知内容には無意味な年表やコメントが含まれます')
    print(f'・通知間隔: {NOTIFY_INTERVAL_SEC//60}分以上')

def parse_args():
    parser = argparse.ArgumentParser(description='random-os-fake-birthday-notifier')
    subparsers = parser.add_subparsers(dest='command')
    subparsers.add_parser('notify', help='今すぐ謎の誕生日通知を出す')
    subparsers.add_parser('list', help='祝われる対象リストを表示')
    subparsers.add_parser('summary', help='Skillの概要を表示')
    return parser.parse_args()

if __name__ == '__main__':
    args = parse_args()
    if args.command == 'notify' or args.command is None:
        notify()
    elif args.command == 'list':
        list_targets()
    elif args.command == 'summary':
        summary()
    else:
        print('使い方: python random_os_fake_birthday_notifier.py [notify|list|summary]')

references/design_notes.md

# 概要
random-os-fake-birthday-notifierは、開発現場に“謎の記念日”を突発的に通知し、集中力を絶妙にかき乱すことを目的としたシュール系演出Skillです。実用性よりも「意味不明さ」「OSや開発環境への愛着喚起」「チームのアイスブレイク」を重視しています。

# 公式ドキュメント抜粋
- Python os, random, datetime: https://docs.python.org/3/library/
- argparse: https://docs.python.org/3/library/argparse.html

# 利用例
- ターミナル作業中に突然「Ctrlキー14周年」などが表示され、雑談や休憩のきっかけに。
- /skills menu から明示呼び出しで、会議やペアプロのアイスブレイクにも活用。

# 注意点
- 記念日や年表は完全ランダム生成のため、実在しない情報が含まれます。
- ファイル・ディレクトリ情報はローカル環境依存です。
- 通知は10分間隔で制限され、連続発動しません。

# 設計方針
- OS・開発環境の“無意味な記念日”を毎回異なる切り口で祝う
- シンプルなCLIサブコマンド構成で、明示/暗黙発動の両方に対応
- ログ保存や個人情報の収集は行わず、気軽に使える設計

導入手順

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

1. 前提

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

2. degit でフォルダ取得

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

npx degit aazutaku/ai-note/codex/random-os-fake-birthday-notifier .agents/skills/random-os-fake-birthday-notifier

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

3. ファイル配置確認

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

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

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

5. 動作確認

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

こんな瞬間に便利

  • session 開始時: 前回までの repo 把握を Codex に一発で復元させたい
  • monorepo 移動時: packages を跨いだ瞬間に context を切り替えたい
  • onboarding 時: 新しい repo を Codex に把握させ、こちらが 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 コードを拾ってしまう可能性
  • Codex 固有の引っかかり: description のセマンティックマッチ精度が要件次第
  • 発動しないケース: description が漠然 / 他の Skill が優先 / git管理外 directory

試す前に確かめたいこと

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

  • 実 repo での token 消費は許容範囲か?
  • monorepo (packages 多数) で安定して動くか?
  • stale context にならず、長時間 workflow でも有効か?
  • AGENTS.md との連携設計はどうあるべきか?
  • 祝われる対象が毎回きちんと謎になっているか?
  • 通知内容にシュールな年表やコメントが含まれるか?
  • 連続発動しすぎない適当なランダム性の実装になっているか?

実際に Codex で試した検証ログは Codexで謎の誕生日通知を炸裂させてみた!シュールな演出にハマるか試す にまとめる予定 (公開準備中の場合あり)。
あわせて Codex 公式ドキュメント と、本シリーズ「Codexを使いこなすSkillアイデア」の他記事も参照のこと。

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

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

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

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