(更新: 2026.03.05)

【完全版】OpenClawで複数Googleアカウントのカレンダーを統合管理!

妻への自動通知、会議準備リマインダー、時間分析レポートまで – 開発8時間で作った最強のスケジュール管理システム

更新日: 2026年3月4日
開発時間: 8時間
実装機能: 20個以上
カテゴリ: 技術開発 / AI活用 / 生産性向上


はじめに:「会議を忘れる」「妻に予定を伝え忘れる」を撲滅したかった

こんにちは、中野真熙です。

仕事とプライベートで複数のGoogleアカウントを使い分けている皆さん、こんな経験ありませんか?

  • 「あれ、この予定どっちのアカウントだっけ?」
  • 「両方のカレンダーを開いて確認するのが面倒…」
  • 「会議の30分前に通知がほしいのに、手動で設定するのは手間」
  • 「妻に予定を伝え忘れて怒られる…」
  • 「『明日14時にA社とMTG』って口頭で言うだけでカレンダーに入れてほしい」

私の場合、クロスリンク(仕事)とプログラミングスクール(副業)の2つのGoogleアカウントを管理していて、毎日これらの問題に直面していました。

特に困っていたのが:

  1. 会議を忘れる(年に2〜3回は会議に遅刻)
  2. 妻に予定を伝え忘れる(「なんで言ってくれなかったの!」)
  3. 予定の入力が面倒(カレンダーを開いて、日時を選んで、タイトルを入力…)

そこで、OpenClaw(AIアシスタント)と連携して、自然言語で複数アカウントのカレンダーを統合管理し、妻への自動通知も実現するシステムを開発しました。

開発の成果

項目BeforeAfter
予定入力時間2分5秒(90%削減)
会議を忘れる回数年2〜3回ゼロ
妻への伝え忘れ月1〜2回ゼロ(自動通知)
カレンダー確認時間5分/日30秒/日(90%削減)

開発時間:8時間
実装機能:20個以上
GitHub公開:openclaw-calendar

この記事では、開発の全過程と、実際に使ってみてわかった「人生が変わるレベルの便利さ」を共有します。


目次

  1. システムの全体像
  2. 主な機能(20個以上)
  3. 開発の流れ(8時間の記録)
  4. 実装した機能詳細
  5. 妻への自動通知が最高に便利だった話
  6. 会議を忘れることがゼロになった話
  7. 時間分析レポートで働き方が見える化
  8. GitHub公開とCodexレビュー対応
  9. 実際に使ってみた感想
  10. 今後の拡張予定
  11. まとめ

システムの全体像

アーキテクチャ図

┌─────────────────────────────────────────────────────┐
│                   OpenClaw AI                       │
│         (自然言語インターフェース - Claude)           │
└─────────────────┬───────────────────────────────────┘
                  │「明日14時にA社とMTG、1時間」
                  ▼
┌─────────────────────────────────────────────────────┐
│            openclaw_calendar (本システム)            │
│  ┌─────────────────────────────────────────────┐   │
│  │  自然言語パーサー(日時・タイトル抽出)       │   │
│  │  アカウント自動判定(キーワードベース)       │   │
│  └─────────────────────────────────────────────┘   │
│                        │                             │
│       ┌────────────────┼────────────────┐           │
│       ▼                ▼                ▼           │
│  ┌─────────┐    ┌──────────┐    ┌──────────┐      │
│  │ 統合表示 │    │ 編集削除 │    │ スマート │      │
│  │ 空き時間 │    │ 定期予定 │    │ 提案     │      │
│  └─────────┘    └──────────┘    └──────────┘      │
│                        │                             │
│                        ▼                             │
│  ┌──────────────────────────────────────────┐      │
│  │        Google Calendar API v3            │      │
│  │        Google Tasks API v1               │      │
│  │        OAuth 2.0 認証                     │      │
│  └──────────────────────────────────────────┘      │
└───────────────┬───────────────────┬─────────────────┘
                │                   │
                ▼                   ▼
      ┌─────────────────┐   ┌──────────────┐
      │  Google Calendar │   │ Google Tasks │
      │  (2アカウント)    │   │              │
      └─────────────────┘   └──────────────┘
                │
                ▼
      ┌─────────────────────────────────┐
      │  通知システム                    │
      │  ┌────────────┬────────────┐   │
      │  │  iMessage  │  Chatwork  │   │
      │  │  (妻)      │  (仕事用)  │   │
      │  └────────────┴────────────┘   │
      └─────────────────────────────────┘
                │
                ▼
      ┌─────────────────────────────────┐
      │  自動化システム(cronジョブ)     │
      │  ├ 15分ごと: 会議前リマインダー  │
      │  ├ 30分ごと: 会議準備チェック    │
      │  ├ 30分ごと: カレンダー監視      │
      │  ├ 7:30: 朝のブリーフィング      │
      │  ├ 22:00: 夜のブリーフィング     │
      │  └ 月曜9:00: 週次レポート        │
      └─────────────────────────────────┘

技術スタック

役割技術選定理由
AIアシスタントOpenClaw (Claude Sonnet 4.5)自然言語処理の精度が高い
カレンダーAPIGoogle Calendar API v3公式API、安定性◎
タスクAPIGoogle Tasks API v1カレンダーと統合管理
認証OAuth 2.0セキュア、リフレッシュトークン対応
通知(妻)iMessage (AppleScript)確実に届く、既読確認可能
通知(仕事)Chatwork API仕事用チャットと統合
言語Python 3.10+ライブラリが豊富、開発速度◎
自動化cronジョブ軽量、確実、設定が簡単
ホストmacOS (M1 Mac)常時稼働、スリープなし

主な機能(20個以上)

基本機能(7個)

複数アカウント対応
・仕事用・個人用など、複数のGoogleアカウントを統合管理
・アカウントごとのOAuth認証

自然言語入力
・「明日14時にMTG、1時間」→ 自動でカレンダー登録
・AIパーサー内蔵で日時を自動抽出

アカウント自動判定
・キーワードから自動でアカウントを判定
・「A社」→ 仕事用、「ココグラム」→ プログラミングスクール

確認フロー
・自動判定時は確認、明示的指定時は即登録
・誤登録を防止

iMessage通知(妻へ)
・予定を追加・変更したら自動で妻に通知
・AppleScript経由で確実に送信

Chatwork通知(仕事用)
・仕事の予定をChatworkに自動通知
・特定のルームに送信

カレンダー監視(30分ごと)
・Googleカレンダーに直接追加された予定も検出
・招待されたイベントも自動通知

高度な機能(13個以上)

統合カレンダー表示
・複数アカウントの予定を統合表示
・空き時間検索(次の7日間)

予定の編集・削除
・タイトル検索で簡単に編集・削除
・時刻・場所・説明の変更

定期予定の管理
・「毎週水曜10時にMTG」で繰り返し予定を作成
・RFC 5545形式のRRULE生成

会議前リマインダー(30分前・10分前)
・15分ごとにチェック
・30分前と10分前のダブルチェック
・会議を忘れることがゼロに

会議準備リマインダー(1時間前)
・会議の1時間前に必要な資料をチェック
・「サンヴァーテックス様 打ち合わせ」→「カテゴリー一覧、JLPT講座サンプル、アンケートフォーム」

朝のブリーフィング(7:30)
・今日のカレンダー予定
・今日のDASHタスク
・Google Tasksの期限タスク
・総推定時間を表示

夜のブリーフィング(22:00)
・今日の予定(実績)
・完了したDASHタスク
・明日の予定(プレビュー)

週次時間分析レポート(月曜9:00)
・アカウント別の時間集計
・カテゴリ別の時間集計(会議・作業・プライベート)
・前週との比較

スマート提案
・空き時間を提案
・ダブルブッキング検出
・スケジュール最適化

Google Tasks 連携
・カレンダーとタスクを統合管理
・タスク実行時間を提案

予定のテンプレート
・よく使う予定をワンコマンドで作成
・「定例MTG」「体験会」などのテンプレート

週次動作確認(月曜9:00)
・カレンダーAPI接続確認
・各機能の動作テスト
・エラーがあれば自動報告

祝日カレンダー
・日本の祝日を自動判定
・定期予定を自動スキップ


開発の流れ(8時間の記録)

午前(3時間):基本機能の実装

9:00 – 10:30 Google Cloud設定

まず、Google Cloud Consoleでプロジェクトを作成しました。

やったこと:

  • Google Calendar API有効化
  • Google Tasks API有効化
  • OAuth 2.0 クライアントID作成
  • OAuth同意画面の設定
  • テストユーザー追加(2アカウント)

ハマったポイント:

  • OAuth同意画面で「公開」にしないとエラーが出る
  • スコープの設定が重要(calendar.eventstasks
  • リフレッシュトークンを取得するにはaccess_type=offlineが必要

10:30 – 12:00 Python MCP サーバー構築

次に、PythonでMCP(Model Context Protocol)サーバーを実装しました。

ファイル構成:

openclaw-calendar/
├── server.py                    # メインサーバー(OAuth認証、API操作)
├── calendar_tools.py            # 自然言語パーサー
├── calendar_view.py             # 統合カレンダー表示
├── calendar_edit.py             # 予定の編集・削除
├── calendar_recurring.py        # 定期予定の管理
├── calendar_reminder.py         # リマインダー機能
├── calendar_smart.py            # スマート提案
├── calendar_tasks.py            # Google Tasks 連携
├── calendar_templates.py        # 予定のテンプレート
├── calendar_monitor.py          # カレンダー監視
├── calendar_analytics.py        # 時間分析レポート
├── meeting_preparation.py       # 会議準備リマインダー
├── openclaw_helper.py           # ヘルパー関数
├── openclaw_integration.py      # 通知機能(iMessage + Chatwork)
├── notifications.py             # 通知サービス
└── requirements.txt             # 依存パッケージ

使用ライブラリ:

google-api-python-client  # Google Calendar API
python-dotenv             # 環境変数管理
requests                  # Chatwork API連携

午後(5時間):高度な機能の実装

13:00 – 15:00 7つの高度な機能を実装

この時間帯で、一気に7つの機能を実装しました。

実装の順番:

  1. 統合カレンダー表示(calendar_view.py
  2. 予定の編集・削除(calendar_edit.py
  3. 定期予定の管理(calendar_recurring.py
  4. リマインダー機能(calendar_reminder.py
  5. スマート提案(calendar_smart.py
  6. Google Tasks 連携(calendar_tasks.py
  7. 予定のテンプレート(calendar_templates.py

実装のコツ:

  • 各機能を独立したファイルにすることで、メンテナンスしやすく
  • 共通処理はopenclaw_helper.pyに集約
  • CLIエントリーポイントを用意して、単体テスト可能に
  • エラーハンドリングを徹底(認証エラー、ファイル不在など)

15:00 – 17:00 GitHub公開準備 + Codexレビュー

実装が完了したら、次はGitHub公開の準備です。

やったこと:

  • README.md作成(バッジ、デモ、使い方、FAQ)
  • LICENSE(MIT)
  • .gitignore(機密情報の除外)
  • CHANGELOG.md
  • CONTRIBUTING.md
  • セキュリティチェック(機密情報の除外確認)
  • Codexレビュー(GPT-5.3-codex)

Codexレビューで見つかった問題:

深刻度指摘事項対応
CRITICAL実際のOAuth client_secretが存在別ディレクトリに移動 + .example作成
CRITICAL個人情報がハードコード(名前、メール、Room ID)プレースホルダー化 + 環境変数化
HIGHcalendar_recurring.pyのパーサーバグ(「毎週水曜」→「毎週水水」)完全一致パターンに修正
HIGHgcal_cli.pyの認証フロー修正自動認証追加
HIGHAppleScriptインジェクション脆弱性サニタイズ関数追加
MEDIUM.gitignoreが脆弱(.env.localなどの亜種がカバーされない).env.*を追加

対応時間:約1時間

すべての問題を修正して、再度テスト。無事、GitHub公開できました!

17:00 – 18:00 通知システムの強化

GitHub公開後、追加で通知システムを強化しました。

実装した機能:

  1. 会議前リマインダーの強化
    ・15分ごとにチェック(cronジョブ)
    ・30分前と10分前のダブルチェック
  2. 会議準備リマインダー(1時間前)
    ・会議タイトルから必要な資料を推測
    ・「サンヴァーテックス様」→ カテゴリー一覧、JLPT講座サンプル、アンケートフォーム
  3. DASH統合(朝・夜のブリーフィング)
    ・朝7:30: カレンダー + DASHタスク統合表示
    ・夜22:00: 今日の振り返り + 明日の予定
  4. 週次時間分析レポート
    ・月曜9:00: 先週の時間分析
    ・アカウント別・カテゴリ別の時間集計
  5. MacBookスリープ対策
    ・電源接続時のスリープ無効化
    ・OpenClawの常時稼働を保証

実装した機能詳細

1. 自然言語パーサー

最も苦労した機能がこれです。

対応している表現

表現解釈実装難易度
「明日14時」明日の14:00★ 簡単
「今日15時30分」今日の15:30★ 簡単
「明後日10時」明後日の10:00★ 簡単
「来週水曜10時」次の水曜日の10:00★★ 中級
「3月5日15時」2026年3月5日 15:00★★ 中級
「30分」「1時間」「2時間半」所要時間★ 簡単

2. アカウント自動判定

キーワードベースでアカウントを判定します。

判定ルール

# クロスリンク(仕事用)のキーワード
crosslink_keywords = [
    'a社', 'b社', '営業', '商談', '提案',
    'ラーニング', 'seo', 'ブログ', '記事',
    'プロシーズ', 'サンヴァーテックス', 'サンバーテックス',
    '定例会', '打ち合わせ', 'クロスリンク'
]
# プログラミングスクール(副業)のキーワード
programming_keywords = [
    '体験会', 'ココグラム', '座席表', 'シフト',
    '名古屋', '関西', '東海', '一宮', '門真', '難波',
    'プログラミングスクール', '講師', '生徒'
]
def determine_account(text: str) -> Tuple[str, bool]:
    """
    テキストからアカウントを判定
    
    Returns:
        (account, is_explicit): アカウント名と明示的指定かどうか
    """
    text_lower = text.lower()
    
    # 明示的指定(確認不要)
    if 'クロスリンクで' in text or 'work@company.com' in text:
        return ('crosslink', True)
    
    if 'プログラミングスクールで' in text or 'personal@gmail.com' in text:
        return ('programming_school', True)
    
    # キーワード判定(確認必要)
    for kw in crosslink_keywords:
        if kw in text_lower:
            return ('crosslink', False)
    
    for kw in programming_keywords:
        if kw in text_lower:
            return ('programming_school', False)
    
    # デフォルト(仕事用)
    return ('crosslink', False)

3. 通知システム(妻 + 仕事用)

最も重要な機能がこれです。

iMessage通知(妻へ)

def send_imessage(message: str, recipient: Optional[str] = None) -> bool:
    """
    iMessageでメッセージを送信
    
    Args:
        message: 送信するメッセージ
        recipient: 受信者の名前(デフォルト: 環境変数から取得)
    
    Returns:
        成功したらTrue
    """
    import subprocess
    
    # 受信者をデフォルト値 or 環境変数から取得
    if recipient is None:
        recipient = os.getenv('IMESSAGE_RECIPIENT', '受信者名')
    
    # メッセージとrecipientをサニタイズ(AppleScriptインジェクション対策)
    def sanitize_applescript(text):
        return text.replace('\\\\', '\\\\\\\\') \\
                   .replace('"', '\\\\"') \\
                   .replace('\\n', '\\\\n') \\
                   .replace('\\r', '\\\\r')
    
    recipient_safe = sanitize_applescript(recipient)
    message_safe = sanitize_applescript(message)
    
    # AppleScript でメッセージ送信
    apple_script = f'''
    tell application "Messages"
        set targetBuddy to "{recipient_safe}"
        set targetService to 1st account whose service type = iMessage
        set textMessage to "{message_safe}"
        send textMessage to participant targetBuddy of targetService
    end tell
    '''
    
    try:
        subprocess.run(['osascript', '-e', apple_script], check=True)
        print(f"✅ iMessage sent to {recipient}")
        return True
    except Exception as e:
        print(f"⚠️ Failed to send iMessage: {e}")
        return False

統合通知関数

def notify_calendar_event(
    account: str,
    title: str,
    start_time: str,
    end_time: str,
    event_link: str
):
    """
    カレンダーイベントを通知(iMessage + Chatwork)
    
    Args:
        account: アカウント名
        title: イベントタイトル
        start_time: 開始時刻
        end_time: 終了時刻
        event_link: Googleカレンダーのリンク
    """
    account_name = 'クロスリンク' if account == 'crosslink' else 'プログラミングスクール'
    
    # 時刻をフォーマット
    start_dt = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
    end_dt = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
    
    start_str = start_dt.strftime('%m/%d %H:%M')
    end_str = end_dt.strftime('%H:%M')
    
    # メッセージ作成
    message = f"""📅 予定を追加しました
【{title}】
日時: {start_str} - {end_str}
アカウント: {account_name}
{event_link}"""
    
    # iMessage送信(妻へ)
    send_imessage(message)
    
    # Chatwork送信(仕事用)
    send_chatwork_notification(f"[info][title]📅 予定追加[/title]{message}[/info]")
---
<h2>妻への自動通知が最高に便利だった話
**シーン1: 急な会議**
真熙: 「明日14時からA社と打ち合わせになった」
(カレンダーに登録)
(妻に伝えるのを忘れる)
翌日14時
妻: 「今日、一緒にランチ行こうと思ってたのに!なんで言ってくれなかったの?」
真熙: 「ごめん、忘れてた…」
**月1〜2回**、こういうことが起きていました。
**シーン1: 同じ状況(システム導入後)**
真熙: OpenClawに「明日14時にA社と打ち合わせ、1時間」
OpenClaw: → カレンダーに自動登録
【iMessage(妻に自動送信)】
📅 予定を追加しました
【A社 定例打ち合わせ】
日時: 03/05 14:00 - 15:00
アカウント: クロスリンク
https://calendar.google.com/...
妻: 「了解!じゃあランチは明後日にしよう」
真熙: (何もしてない 😎)
📅 予定を追加しました
【プロシーズさん定例会】
日時: 03/06 11:00 - 12:00
アカウント: クロスリンク
https://calendar.google.com/calendar/event?eid=...
📅 予定を追加しました
【プログラミング体験会(名古屋)】
日時: 03/08 10:00 - 12:00
アカウント: プログラミングスクール
https://calendar.google.com/calendar/event?eid=...
📅 予定を追加しました
【おとうさんとの食事】
日時: 03/10 18:00 - 20:00
アカウント: プログラミングスクール
https://calendar.google.com/calendar/event?eid=...
**妻:** 「これ、めっちゃ便利!予定が全部自動で来るから、私も予定を立てやすくなった。もっと早く作ってほしかった笑」
**真熙:** 「(やった!)」
---
<h2>会議を忘れることがゼロになった話
**典型的なパターン:**
1. Googleカレンダーに予定を入れる
2. 通知を「30分前」に設定する
3. **通知を見逃す**(別の作業に集中していて)
4. 会議開始時刻の5分後に気づく
5. 慌てて入室、遅刻
**年に2〜3回**、こういうことが起きていました。

妻への自動通知が最高に便利だった話

Before: 伝え忘れて怒られる日々

シーン1: 急な会議

真熙: 「明日14時からA社と打ち合わせになった」
(カレンダーに登録)
(妻に伝えるのを忘れる)

翌日14時
妻: 「今日、一緒にランチ行こうと思ってたのに!なんで言ってくれなかったの?」
真熙: 「ごめん、忘れてた…」

月1〜2回、こういうことが起きていました。

After: 自動通知で伝え忘れゼロ

シーン1: 同じ状況(システム導入後)

真熙: OpenClawに「明日14時にA社と打ち合わせ、1時間」
OpenClaw: → カレンダーに自動登録

【iMessage(妻に自動送信)】
📅 予定を追加しました

【A社 定例打ち合わせ】
日時: 03/05 14:00 - 15:00
アカウント: クロスリンク

https://calendar.google.com/...

妻: 「了解!じゃあランチは明後日にしよう」
真熙: (何もしてない 😎)

実際のメッセージ例

例1: 仕事の会議

📅 予定を追加しました

【プロシーズさん定例会】
日時: 03/06 11:00 - 12:00
アカウント: クロスリンク

https://calendar.google.com/calendar/event?eid=...

例2: 体験会(プログラミングスクール)

📅 予定を追加しました

【プログラミング体験会(名古屋)】
日時: 03/08 10:00 - 12:00
アカウント: プログラミングスクール

https://calendar.google.com/calendar/event?eid=...

例3: プライベート

📅 予定を追加しました

【おとうさんとの食事】
日時: 03/10 18:00 - 20:00
アカウント: プログラミングスクール

https://calendar.google.com/calendar/event?eid=...

妻の反応

妻:「これ、めっちゃ便利!予定が全部自動で来るから、私も予定を立てやすくなった。もっと早く作ってほしかった笑」

真熙:「(やった!)」


会議を忘れることがゼロになった話

Before: 年に2〜3回は会議を忘れる

典型的なパターン:

  1. Googleカレンダーに予定を入れる
  2. 通知を「30分前」に設定する
  3. 通知を見逃す(別の作業に集中していて)
  4. 会議開始時刻の5分後に気づく
  5. 慌てて入室、遅刻

年に2〜3回、こういうことが起きていました。

After: 15分ごとのチェック + ダブルチェックで完璧

システムの仕組み

【監視スケジュール】
13:00 - チェック(空振り)
13:15 - チェック(空振り)
13:30 - チェック(空振り)
13:45 - チェック(空振り)
14:00 - 🔔 30分前通知(第1回) ← ここで通知
14:15 - 🔔 10分前通知(第2回) ← ダブルチェック
14:30 - 会議開始

cronジョブ設定

30分前通知(15分ごとにチェック):

{
  "name": "会議前リマインダー(30分前)",
  "schedule": {
    "kind": "cron",
    "expr": "*/15 * * * *",
    "tz": "Asia/Tokyo"
  },
  "payload": {
    "kind": "agentTurn",
    "message": "会議前リマインダーをチェックしてください。30分以内に始まる予定があれば通知してください。"
  }
}

10分前通知(15分ごとにチェック):

{
  "name": "会議前リマインダー(10分前)",
  "schedule": {
    "kind": "cron",
    "expr": "*/15 * * * *",
    "tz": "Asia/Tokyo"
  },
  "payload": {
    "kind": "agentTurn",
    "message": "会議直前リマインダーをチェックしてください。10分以内に始まる予定があれば通知してください。"
  }
}

実際の通知例

30分前通知:

🔔 まもなく予定があります(30分以内)

  ⏰ 14:00(あと28分)
  📝 サンヴァーテックス様 打ち合わせ
  🏢 クロスリンク
  📍 Google Meet

(iMessage + Chatwork に送信)

10分前通知:

🔔 まもなく予定があります(10分以内)

  ⏰ 14:00(あと8分)
  📝 サンヴァーテックス様 打ち合わせ
  🏢 クロスリンク
  📍 Google Meet

(iMessage + Chatwork に送信)

結果: 会議を忘れることがゼロに

導入後2ヶ月(2026年1月〜3月):

  • 会議を忘れた回数: 0回 🎉
  • 通知の見逃し: 0回(ダブルチェックのおかげ)
  • 遅刻: 0回

真熙:「人生が変わった。もう会議を忘れる恐怖がない。」


時間分析レポートで働き方が見える化

週次時間分析レポート(毎週月曜9:00)

サンプルレポート:

📊 週次時間分析レポート
期間: 2026-02-25 〜 2026-03-04

⏰ 総時間: 35時間45分
📅 イベント数: 12件



🏢 アカウント別
  クロスリンク: 29h45m (83%)
    - 会議: 12h0m
    - 作業: 15h30m
    - その他: 2h15m
  
  プログラミングスクール: 6h0m (17%)
    - 会議: 2h0m
    - 作業: 3h0m
    - プライベート: 1h0m



📋 カテゴリ別
  作業: 18h30m (52%)
  会議: 14h0m (39%)
  その他: 2h15m (6%)
  プライベート: 1h0m (3%)



💡 分析
  ✅ 作業時間が会議時間より多く、バランス◎
  ⚠️ クロスリンクの時間が多すぎます(5.0倍)
     → プログラミングスクールの時間を増やす?

実際に気づいたこと

Week 1(2月第4週):

  • 会議時間: 18時間
  • 作業時間: 12時間
  • → 会議が多すぎる!

Week 2(3月第1週):

  • 会議時間: 14時間(-4時間)
  • 作業時間: 18時間(+6時間)
  • → 会議を減らせた!

真熙:「数字で見ると、自分の働き方がよくわかる。会議を減らす意識が持てた。」


GitHub公開とCodexレビュー対応

公開前の準備

1. セキュリティチェック

# 機密情報を別ディレクトリに退避
mkdir -p ../openclaw-calendar-secrets
mv credentials.json ../openclaw-calendar-secrets/
mv token_*.json ../openclaw-calendar-secrets/
mv .env ../openclaw-calendar-secrets/
# テンプレートファイルを作成
cat > credentials.json.example <<EOF
{
  "installed": {
    "client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
    "project_id": "your-project-id",
    "client_secret": "YOUR_CLIENT_SECRET",
    "redirect_uris": ["http://localhost"]
  }
}
EOF
cat > .env.example <<EOF
# Chatwork API設定
CHATWORK_API_TOKEN=your_chatwork_api_token_here
CHATWORK_ROOM_ID=your_room_id_here
# iMessage設定
IMESSAGE_RECIPIENT=受信者の名前
EOF

2. .gitignoreの強化

# 環境変数
.env
.env.*
!.env.example

# 状態ファイル
calendar_monitor_state.json
templates.json

# Python
__pycache__/
*.pyc
*.pyo
venv/
.venv/

# macOS
.DS_Store

# IDE
.vscode/
.idea/
.claude/

3. 個人情報のプレースホルダー化

Before:

CHATWORK_ROOM_ID = '414967775'
IMESSAGE_RECIPIENT = '上弦の嫁'

After:

CHATWORK_ROOM_ID = os.getenv('CHATWORK_ROOM_ID')
IMESSAGE_RECIPIENT = os.getenv('IMESSAGE_RECIPIENT', '受信者名')

Codexレビューで見つかった重要なバグ

バグ1: calendar_recurring.pyのパーサー

問題:「毎週水曜」が「毎週水水」になる

原因:

# NG: 部分一致で検索 → 「毎週水」+ 「水」= 「毎週水水」
for pattern in patterns:
    if pattern in text:  # 「毎週水」がマッチ
        for day in ['月', '火', '水', ...]:
            if pattern + day in text:  # 「毎週水」+ 「水」= 「毎週水水」
                recurrence_pattern = pattern + day + '曜'

修正:

# OK: 完全一致パターンを用意
week_patterns = ['毎週月曜', '毎週火曜', '毎週水曜', '毎週木曜', '毎週金曜', '毎週土曜', '毎週日曜']
for pattern in week_patterns:
    if pattern in text:  # 「毎週水曜」が完全一致
        recurrence_pattern = pattern
        break

バグ2: AppleScriptインジェクション

問題:ユーザー入力がサニタイズされず、AppleScriptに直接渡される

攻撃例:

# 悪意のあるメッセージ
message = '"; do shell script "rm -rf /"'
# サニタイズなしでAppleScriptに渡すと…
apple_script = f'send textMessage "{message}" ...'
# → "; do shell script "rm -rf /" が実行される!

修正:

def sanitize_applescript(text: str) -> str:
    """AppleScript文字列をエスケープ"""
    return text.replace('\\', '\\\\') \
               .replace('"', '\\"') \
               .replace('\n', '\\n') \
               .replace('\r', '\\r')
# 使用例
message_safe = sanitize_applescript(message)
apple_script = f'send textMessage "{message_safe}" ...'

GitHub公開

すべての修正が完了し、openclaw-calendarとしてGitHubで公開しました!