Antigravityでエラー表示を遊び心たっぷりに変換する方法【発見】

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

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

Antigravity を日々使っていると、AI coding workflow の中で思わず「なんでやねん!」と突っ込みたくなる瞬間に出会うことが多い。特にエラーや警告が出たとき、真面目な作業の最中に唐突なメッセージで集中が切れることもある。context や repository understanding のミスが重なると、イライラしつつもどこか笑いが欲しくなるものだ。

  • Antigravity が context を見失って違う場所のコードを参照するたび、エラーの内容が単調で味気ない
  • monorepo で package を跨ぐと、repo 構造を忘れてエラー説明が毎回同じで飽きる
  • session を再開するたびに、path management や directory の説明を繰り返しても、結局エラーは「Permission denied」など無機質なまま
  • 長時間 workflow で long context が膨らみ、重要なエラーが埋もれてしまい、どこで失敗したか分かりづらい
  • 「また同じエラーか」と思うたび、せめて何か面白い演出やバリエーションが欲しくなる

AI coding workflow の中で、真面目なエラー体験にちょっとした遊び心が欲しい。そんな悩みに応える Skill が求められている。

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

一言サマリ: エラー発生時に、毎回異なる“別OS風”の演出で不可解なメッセージに変換し、作業の合間に笑いをもたらすSkill。

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

  • AI coding workflow 中のエラー表示が、毎回異なるOS風のテイストで変換され、単調なエラー体験から解放される
  • repository understanding や context の説明に疲れているときも、思わずクスッとできる演出でモチベーションが維持しやすい
  • monorepo での directory 跨ぎや path management の失敗時も、記憶に残る“謎エラー”として楽しめる
  • 元のエラー内容も併記されるため、実務的な確認も可能
  • onboarding や長時間作業時の“空気の重さ”を和らげるアクセントになる
QUICK INSTALL
このSkillをすぐ試す

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

npx degit aazutaku/ai-note/antigravity/random-os-error-translator .agent/skills/random-os-error-translator

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

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

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


> antigravity run setup.sh

[ERROR] このファイルは神聖にして侵入を禁ず(MS-DOS風)
  - 実際のエラー: Permission denied: ./scripts/setup.sh

[INFO] もしや、config.sys の呪いかもしれません。

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


> antigravity test packages/user-service

【警告】推奨されていない操作です(謎の国産OS風)
  - 元のエラー: Operation not permitted: ./packages/user-service/tests/test_api.py

[ヒント] パッケージ間の壁は厚い…。

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


> antigravity build

[致命的エラー] 予期せぬ宇宙的事象が発生しました(Amiga風)
  - 原因: File not found: ./build/output/main.bin

[参考] きっとファイルはどこか別の次元にあります。

before / after の違い

場面 Skill 無し Skill 有り
session 再開時 repo 構造から毎回説明、path も指定し直し Antigravity がエラーをユニークな別OS風メッセージで返し、再開時の空気が和らぐ
monorepo 移動 違う package のコードを参照しがち directory boundary のエラーも、毎回違う演出で記憶に残る
長時間 workflow long context で重要箇所が薄まる エラーが印象的に残るため、どこで失敗したか思い出しやすい

発動方式

description マッチでの暗黙発動。

Skill の中身を全部見せる

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

.agent/skills/random-os-error-translator/
├── SKILL.md
├── scripts/
│   └── random_os_error_translator.py
└── references/
    └── design_notes.md

各ファイルの役割

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

SKILL.md

---
name: random-os-error-translator
description: ターミナルやコマンドラインでエラーが発生した際に、エラーメッセージを“別のOS風”に自動変換して表示します。エラー発生や例外検出、stderr出力などが含まれる場合に発動します。
---

# 機能概要
このSkillは、コマンドラインやターミナルでエラーが発生した際、そのエラーメッセージを自動的に“別のOS風”に変換して表示します。例えば「Permission denied」が「このファイルは神聖にして侵入を禁ず(MS-DOS風)」や「推奨されていない操作です(国産OS風)」など、実際の意味とは異なる演出で、日々の作業にユーモアとカオスをもたらします。真面目な作業中でも、思わず笑ってしまう不可解なエラー体験を提供します。

# 使い方
このSkillは明示的な呼び出しを必要とせず、エラーや例外が発生したタイミングで自動的に発動します。例えば、`FileNotFoundError`や`PermissionError`などの例外、またはコマンド実行時のstderr出力が検出された場合に作動します。暗黙発動キーワード例: "エラー", "失敗", "例外", "コマンド失敗", "stderr"。

# 出力例
```
$ python script.py
[MS-DOS風] このファイルは神聖にして侵入を禁ず。
(元のエラー: Permission denied: 'secret.txt')

$ ls /notfound
[謎の国産OS風] 推奨されていない操作です。
(元のエラー: No such file or directory)

$ cat /root/flag
[Linux風] ルート様のご許可が必要です。
(元のエラー: Permission denied)
```

# 注意点
本Skillはエラー内容をパロディ変換するため、実際の原因追跡には元のメッセージも併記されます。ローカルへのエラーログ保存や、重要なシステムエラーの抑制は行いません。演出は毎回ランダムで、意味不明な場合もあります。業務用途や正確な障害対応には不向きです。

# 参考資料
詳細な設計方針や演出パターンは`references/design_notes.md`を参照してください。Pythonの標準例外やstderrの扱いについては[公式ドキュメント](https://docs.python.org/ja/3/library/exceptions.html)も参考になります。

scripts/random_os_error_translator.py

import sys
import argparse
import traceback
import random
from typing import List, Tuple

# OS風エラーパターン定義
OS_ERROR_PATTERNS = [
    {
        'os': 'MS-DOS風',
        'patterns': [
            ('Permission denied', 'このファイルは神聖にして侵入を禁ず。'),
            ('No such file or directory', '指定されたパスは存在しません。'),
            ('File exists', '既に存在しています。'),
            ('Is a directory', 'ディレクトリ指定が不正です。'),
            ('Not a directory', 'ディレクトリではありません。'),
            ('Connection refused', '通信路が閉ざされています。'),
            ('Operation not permitted', '許可されていない操作です。'),
            ('Invalid argument', '引数が無効です。'),
            ('Broken pipe', 'パイプが破損しました。'),
        ]
    },
    {
        'os': '謎の国産OS風',
        'patterns': [
            ('Permission denied', '推奨されていない操作です。'),
            ('No such file or directory', 'そのようなファイルはありません。'),
            ('File exists', '同名ファイルが既に登録済みです。'),
            ('Is a directory', 'フォルダ指定に誤りがあります。'),
            ('Not a directory', 'フォルダではありません。'),
            ('Connection refused', '接続は拒否されました。'),
            ('Operation not permitted', '操作が許可されていません。'),
            ('Invalid argument', '不正なパラメータです。'),
            ('Broken pipe', '通信経路が断絶しました。'),
        ]
    },
    {
        'os': 'Linux風',
        'patterns': [
            ('Permission denied', 'ルート様のご許可が必要です。'),
            ('No such file or directory', 'ファイルが見つかりません。'),
            ('File exists', 'ファイルは既に存在しています。'),
            ('Is a directory', 'ディレクトリ指定の不一致です。'),
            ('Not a directory', 'ディレクトリではありません。'),
            ('Connection refused', '接続が拒否されました。'),
            ('Operation not permitted', '許可されていない操作です。'),
            ('Invalid argument', '無効な引数です。'),
            ('Broken pipe', 'パイプが壊れました。'),
        ]
    },
    {
        'os': '古代UNIX風',
        'patterns': [
            ('Permission denied', '権限がありません。'),
            ('No such file or directory', 'そんなファイルはない。'),
            ('File exists', 'ファイルは既にある。'),
            ('Is a directory', 'ディレクトリが指定された。'),
            ('Not a directory', 'ディレクトリではない。'),
            ('Connection refused', '接続不可。'),
            ('Operation not permitted', '許可されていない。'),
            ('Invalid argument', '引数が不正。'),
            ('Broken pipe', 'パイプ破損。'),
        ]
    },
    {
        'os': '架空OS風',
        'patterns': [
            ('Permission denied', 'この領域は管理者しか入れません。'),
            ('No such file or directory', '幻のファイルです。'),
            ('File exists', '時空の彼方に既に存在します。'),
            ('Is a directory', 'ディレクトリの迷宮に迷い込んだ。'),
            ('Not a directory', 'ここはディレクトリではありません。'),
            ('Connection refused', '門が閉ざされています。'),
            ('Operation not permitted', '禁断の操作です。'),
            ('Invalid argument', '謎の引数です。'),
            ('Broken pipe', 'パイプが異次元に消えました。'),
        ]
    },
]

GENERIC_MESSAGES = [
    '未知のエラーが発生しました。',
    '何かがうまくいきませんでした。',
    '原因不明の障害です。',
    'システムが混乱しています。',
    '詳細は不明です。',
]

def translate_error_message(original: str) -> Tuple[str, str]:
    os_pattern = random.choice(OS_ERROR_PATTERNS)
    for pat, msg in os_pattern['patterns']:
        if pat in original:
            return f"[{os_pattern['os']}] {msg}", os_pattern['os']
    # 該当しない場合は汎用メッセージ
    return f"[{os_pattern['os']}] {random.choice(GENERIC_MESSAGES)}", os_pattern['os']

def print_translated_error(errmsg: str):
    translated, osname = translate_error_message(errmsg)
    print(translated)
    print(f"(元のエラー: {errmsg})")

def simulate_error(args):
    # テスト用に例外を発生させる
    try:
        if args.type == 'permission':
            open('/root/flag', 'r')
        elif args.type == 'notfound':
            open('/notfound/file.txt', 'r')
        elif args.type == 'exists':
            import tempfile
            with tempfile.NamedTemporaryFile(delete=False) as tf:
                fname = tf.name
            open(fname, 'x')
            open(fname, 'x')
        elif args.type == 'custom':
            raise RuntimeError('Custom error for testing')
        else:
            raise Exception('Unknown error type')
    except Exception as e:
        errmsg = str(e)
        print_translated_error(errmsg)
        if args.verbose:
            traceback.print_exc()

def wrap_command(args):
    import subprocess
    try:
        proc = subprocess.run(args.command, shell=True, capture_output=True, text=True)
        if proc.returncode != 0:
            errmsg = proc.stderr.strip() or proc.stdout.strip() or f"Command failed with code {proc.returncode}"
            print_translated_error(errmsg)
        else:
            print(proc.stdout)
    except Exception as e:
        errmsg = str(e)
        print_translated_error(errmsg)

def main():
    parser = argparse.ArgumentParser(description='Random OS Error Translator')
    subparsers = parser.add_subparsers(dest='subcmd')

    sim_parser = subparsers.add_parser('simulate', help='テスト用エラーを発生させる')
    sim_parser.add_argument('--type', choices=['permission', 'notfound', 'exists', 'custom'], default='permission', help='エラー種別')
    sim_parser.add_argument('--verbose', action='store_true', help='詳細なトレースバックを表示')

    wrap_parser = subparsers.add_parser('wrap', help='コマンド実行のエラーをOS風に変換')
    wrap_parser.add_argument('command', help='実行するコマンド')

    args = parser.parse_args()
    if args.subcmd == 'simulate':
        simulate_error(args)
    elif args.subcmd == 'wrap':
        wrap_command(args)
    else:
        parser.print_help()

if __name__ == '__main__':
    main()

references/design_notes.md

# 概要
このSkillは、実際のOSエラーメッセージを複数の“OS風”パロディにランダム変換することで、日常的なコマンドライン作業にユーモアを加えることを目的としています。

# 公式ドキュメント抜粋
Pythonの例外一覧や標準エラー出力の扱いについては、[Python公式ドキュメント](https://docs.python.org/ja/3/library/exceptions.html)を参照してください。subprocess.runや例外ハンドリングの標準APIを利用しています。

# 利用例
- `python random_os_error_translator.py simulate --type permission` で疑似PermissionErrorを発生
- `python random_os_error_translator.py wrap "ls /notfound"` でコマンドのエラーを変換

# 注意点
このSkillは実際のエラー内容をパロディ変換するため、障害対応や業務用途には不向きです。元のエラーも必ず併記し、ユーザーが本来の原因を見失わないよう配慮しています。

# 設計方針
- OS風パターンは拡張容易なリスト構造で管理
- 例外発生時・コマンド失敗時の両方に対応
- 毎回ランダムな演出で飽きさせない設計
- 元のエラー内容も必ず表示し、実用性を損なわない

導入手順

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

1. 前提

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

2. degit でフォルダ取得

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

npx degit aazutaku/ai-note/antigravity/random-os-error-translator .agent/skills/random-os-error-translator

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

3. ファイル配置確認

ls .agent/skills/random-os-error-translator
# 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 でも有効か?
  • プロジェクト指示との連携をどう組み立てるか?
  • エラー発生時に必ず“OS風変換”メッセージが表示されるか?
  • 元のエラー内容も簡単に確認できるか?
  • OS風演出パターンが複数あり、毎回変化するか?

実際に Antigravity で試した検証ログは Antigravityのエラーを別OS風に変換してみた!不可解なエラー体験を楽しむ にまとめる予定 (公開準備中の場合あり)。
あわせて Antigravity 公式ドキュメント と、本シリーズ「Antigravityで試したいSkill研究」の他記事も参照のこと。

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

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

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

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