Antigravityで作業中に笑える通知を自動化する方法【発見】

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

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

Antigravity を日常的に使っていると、AI coding workflow の効率化や repository understanding の向上はもちろん、思わぬ「マンネリ感」や「張り詰めた空気」に直面することも少なくありません。特に monorepo や複雑な directory 構造を扱う現場では、context や path management の課題とあわせて、作業環境が“真面目一辺倒”になりがちです。そんな中、ちょっとした遊び心や非日常の演出が欲しくなる瞬間もあるはずです。

  • Antigravity が context を見失って違う場所のコードを参照する
  • monorepo で package を跨いだ瞬間、Antigravity が repo 構造を忘れる
  • session を再開すると、前回までの context や path 指定をまるごと再説明しないといけない
  • 長時間 workflow で long context が膨らみすぎて、important な情報が薄まる (stale context)
  • 「ここはこういう構造のリポジトリ」というあらすじを毎回チャットの冒頭で書く羽目になる

さらに、「作業に集中しすぎて気が詰まる」「AIとしか会話していないので気分転換がない」「通知が全部真面目で面白みがない」といった、通知・演出・OS連携の“遊び”不足を感じる瞬間も、Antigravity ユーザーならではの悩みとして挙げられます。

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

一言サマリ: このスキルはAntigravityの作業現場に突発的なデジタル失恋通知を届け、マンネリや張り詰めた空気を一瞬でリセットするSkill。

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

  • AI coding workflow の合間に、思わず笑ってしまう“謎のOS失恋通知”が唐突に現れ、作業の緊張を和らげる
  • 長時間の repository understanding や path management に疲れたタイミングでシュールな演出が入り、気分転換できる
  • monorepo や複雑な directory で詰まりがちな onboarding 時も、想定外の通知でチームの会話が生まれる
  • 通知内容が毎回ランダムなので、同じ session でも新鮮な驚きや笑いが持続する
  • 真面目な context 説明や memory 管理の合間に、非日常的な体験をプラスできる
QUICK INSTALL
このSkillをすぐ試す

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

npx degit aazutaku/ai-note/antigravity/random-os-breakup-notifier .agent/skills/random-os-breakup-notifier

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

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

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


> プロジェクトの初期セットアップを始めたい

【重要なお知らせ】
あなたの愛用マウスは、ついに新しいパートナーに乗り換えました。
この directory でのクリックはしばらくお控えください。

# 失恋通知は無視して作業を続けられます

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


> packages/utils/ のコードを packages/api/ から参照したい

【悲報】
エディタ「SuperEdit」は、そっとあなたのもとを去りました。
新しい repo での幸せを祈っています。

# Antigravity は context を切り替えつつ通知を表示

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


> ちょっと気分転換したい

【ご報告】
Ctrlキーは、今日からAltキーと正式にお付き合いすることになりました。
長年のご愛用、ありがとうございました。

# ターミナルやデスクトップに突如現れるシュールな失恋通知

before / after の違い

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

発動方式

description マッチでの暗黙発動。

Skill の中身を全部見せる

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

.agent/skills/random-os-breakup-notifier/
├── SKILL.md
├── scripts/
│   └── random_os_breakup_notifier.py
└── references/
    └── design_notes.md

各ファイルの役割

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

SKILL.md

---
name: random-os-breakup-notifier
description: 作業中に“失恋”をテーマにしたシュールなOS通知を突発的に表示し、ユーザーの気分転換や場の雰囲気を和らげたい場合に発動します。キーワード例: 通知, ジョーク, 気分転換, OS, デスクトップ, 失恋。
---

# 機能概要
random-os-breakup-notifierは、作業中のユーザーに対して突如“デジタル失恋”をテーマにしたランダムな通知を表示するスキルです。通知内容は毎回異なり、例として「あなたのマウスが新しいパートナーを見つけました」や「CtrlキーがAltキーと付き合い始めました」など、意味不明かつシュールな文面で構成されます。真面目な作業空間に非日常をもたらし、ユーザーの気分転換や場の雰囲気を和らげることを目的としています。

# 使い方
このスキルは明示的な呼び出しは不要で、semantic-match-onlyトリガーにより自動発動します。たとえば「集中力が切れた」「気分転換したい」「ジョーク通知が欲しい」などのキーワードやコンテキストを検知した際に、システム通知またはターミナル出力として発動します。明示的なCLIコマンドはありません。

# 出力例
```
[通知] 重要: あなたのマウスが新しいパートナーに乗り換えました。
[通知] 悲報: エディタがそっとあなたのもとを去りました。
[通知] ごめん、今日からCtrlキーはAltキーと付き合うことに。
[通知] ディスプレイがあなたの視線を避けています。
[通知] あなたのUSBメモリは新しいPCに夢中です。
```

# 注意点
- システムや他の作業への干渉は一切ありません。
- 通知内容は完全にランダム生成されるため、同じメッセージが繰り返される場合があります。
- ローカルに通知履歴や個人情報は保存しません。
- 一部のOS環境では通知APIが制限される場合があります。

# 参考資料
通知表示にはPython標準のsubprocessや、macOSのosascript、Windowsのwin10toast、Linuxのnotify-send等の実在APIを利用しています。詳細はreferences/design_notes.mdを参照してください。

scripts/random_os_breakup_notifier.py

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

BREAKUP_MESSAGES = [
    "重要: あなたのマウスが新しいパートナーに乗り換えました。",
    "悲報: エディタがそっとあなたのもとを去りました。",
    "ごめん、今日からCtrlキーはAltキーと付き合うことに。",
    "ディスプレイがあなたの視線を避けています。",
    "あなたのUSBメモリは新しいPCに夢中です。",
    "悲報: ターミナルがあなたのコマンドに飽きました。",
    "あなたのBluetoothイヤホンは別のデバイスと繋がっています。",
    "プリンタがあなたのジョブを拒否しました。",
    "あなたのデスクトップ壁紙が引っ越しを決意しました。",
    "悲報: スクロールホイールが逆方向に進み始めました。",
    "あなたのWebカメラは新しい視界を求めています。",
    "CapsLockキーが静かに去りました。",
    "あなたのキーボードは他の指を受け入れました。",
    "悲報: SSDがHDDに戻りたがっています。",
    "あなたのモニターはデュアルディスプレイと浮気中です。",
    "悲報: タスクバーがスタートメニューに片思いしています。",
    "あなたのマイクは沈黙を選びました。",
    "ごめん、今日からAltキーはFnキーと付き合うことに。",
    "あなたのパスワードは記憶から消えました。",
    "悲報: クリップボードが他のコピーに夢中です。"
]

HISTORY_FILE = os.path.expanduser("~/.random_os_breakup_history.log")


def send_notification(message):
    system = platform.system()
    try:
        if system == "Darwin":
            # macOS: osascript
            script = f'display notification "{message}" with title "通知"'
            subprocess.run(["osascript", "-e", script], check=True)
        elif system == "Linux":
            # Linux: notify-send
            subprocess.run(["notify-send", "通知", message], check=True)
        elif system == "Windows":
            # Windows: win10toast (if available), fallback to msgbox
            try:
                from win10toast import ToastNotifier
                toaster = ToastNotifier()
                toaster.show_toast("通知", message, duration=5)
            except ImportError:
                # fallback: powershell popup
                script = f'[System.Windows.MessageBox]::Show("{message}","通知")'
                subprocess.run(["powershell", "-Command", script], check=True)
        else:
            print(f"[通知] {message}")
    except Exception as e:
        print(f"[通知] {message} (通知API失敗: {e})")


def log_message(message):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open(HISTORY_FILE, "a", encoding="utf-8") as f:
        f.write(f"[{timestamp}] {message}\n")


def random_breakup_event():
    message = random.choice(BREAKUP_MESSAGES)
    send_notification(message)
    log_message(message)
    print(f"[通知] {message}")


def loop_mode(min_interval=600, max_interval=1800):
    try:
        while True:
            wait_time = random.randint(min_interval, max_interval)
            time.sleep(wait_time)
            random_breakup_event()
    except KeyboardInterrupt:
        print("\n[終了] random-os-breakup-notifierを停止しました。")


def list_history(limit=20):
    if not os.path.exists(HISTORY_FILE):
        print("履歴がありません。")
        return
    with open(HISTORY_FILE, "r", encoding="utf-8") as f:
        lines = f.readlines()
    for line in lines[-limit:]:
        print(line.strip())


def summary():
    if not os.path.exists(HISTORY_FILE):
        print("履歴がありません。")
        return
    with open(HISTORY_FILE, "r", encoding="utf-8") as f:
        lines = f.readlines()
    print(f"通知回数: {len(lines)}")
    counter = {}
    for line in lines:
        for msg in BREAKUP_MESSAGES:
            if msg in line:
                counter[msg] = counter.get(msg, 0) + 1
    for msg, count in sorted(counter.items(), key=lambda x: -x[1]):
        print(f"{msg[:30]}... : {count}回")


def parse_args():
    parser = argparse.ArgumentParser(description="random-os-breakup-notifier: デジタル失恋通知スクリプト")
    subparsers = parser.add_subparsers(dest="command")

    subparsers.add_parser("run", help="定期的にランダム通知を発生させる (デフォルト)")
    subparsers.add_parser("once", help="1回だけ通知を発生させる")
    subparsers.add_parser("list", help="通知履歴を表示する")
    subparsers.add_parser("summary", help="通知履歴のサマリーを表示する")

    parser.add_argument("--min", type=int, default=600, help="通知間隔の最小秒数 (デフォルト600)")
    parser.add_argument("--max", type=int, default=1800, help="通知間隔の最大秒数 (デフォルト1800)")
    parser.add_argument("--limit", type=int, default=20, help="履歴表示の最大件数 (デフォルト20)")

    return parser.parse_args()


def main():
    args = parse_args()
    cmd = args.command
    if cmd == "once":
        random_breakup_event()
    elif cmd == "list":
        list_history(args.limit)
    elif cmd == "summary":
        summary()
    else:
        loop_mode(args.min, args.max)


if __name__ == "__main__":
    main()

references/design_notes.md

# 概要
random-os-breakup-notifierは、ユーザーの作業中にシュールな“デジタル失恋”通知を発生させることで、気分転換やリフレッシュを促すジョーク系スキルです。通知内容は固定リストからランダム選択され、各OSの標準通知APIを使用して実際にポップアップ表示されます。

# 公式ドキュメント抜粋
- macOS: osascript (AppleScript) による通知表示
- Linux: notify-send コマンド
- Windows: win10toast ライブラリ、または PowerShell の MessageBox

# 利用例
- 長時間のコーディングや単調作業の合間に、突発的な通知で場を和ませる
- チームのSlackや画面共有時に話題作りとして

# 注意点
- 通知履歴はホームディレクトリ直下の .random_os_breakup_history.log に保存されますが、個人情報や他のファイルには一切影響しません
- 一部のLinux環境やWSLではnotify-sendが利用できない場合があります
- Windowsではwin10toastのインストールが推奨されます

# 設計方針
- シンプルな構成でOS依存性を最小限に
- ユーザー体験を損なわず、作業の妨げにならない通知頻度をデフォルト設定
- ジョーク通知の内容は随時追加・編集可能な設計

導入手順

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

1. 前提

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

2. degit でフォルダ取得

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

npx degit aazutaku/ai-note/antigravity/random-os-breakup-notifier .agent/skills/random-os-breakup-notifier

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

3. ファイル配置確認

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

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

新しいSkillが自動で認識されます。リスト確認したい場合は Antigravity に「使えるSkill一覧を見せて」と聞く と Skill 名で出てきます。

5. 動作確認

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

こんな瞬間に便利

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

試す前に確かめたいこと

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

  • 実 repo での token 消費は許容範囲か?
  • monorepo (packages 多数) で安定して動くか?
  • stale context にならず、長時間 workflow でも有効か?
  • プロジェクト指示との連携をどう組み立てるか?
  • 通知内容のバリエーションが十分に豊富で飽きないか?
  • 通知が突発的なタイミングで出て、他作業やシステムに干渉しないか?

実際に Antigravity で試した検証ログは Antigravityで謎のデジタル失恋通知を爆発させてみた! にまとめる予定 (公開準備中の場合あり)。
あわせて Antigravity 公式ドキュメント と、本シリーズ「Antigravityで試したいSkill研究」の他記事も参照のこと。

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

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

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

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