Codex ユーザーが日常でぶつかる悩み
日々の開発現場でAIコーディングエージェントを活用していると、思わず「またか…」と感じる瞬間が少なくありません。特にCodexを使ったAIコーディングワークフローでは、コマンド実行時のエラー体験が単調で、気分転換やモチベーション維持に一工夫ほしいと感じることが多いはずです。こんな悩み、思い当たりませんか?
- コマンド失敗時、Codexの context 上でもただエラーメッセージが流れるだけで、場が和まない
- 長時間のAI coding workflowでエラーが続くと、session全体の雰囲気が重くなりがち
- onboarding中の新人やゲストにも、repository理解やpath管理の前に「エラー=悪いこと」の空気が伝わってしまう
- monorepoでpackageを跨ぐ際、directoryやcontext切り替えに失敗→エラー→気まずい沈黙が発生しやすい
- 「またやってしまった」と自己肯定感が下がる瞬間を、何とか楽しく変換したい
通知や演出、OS連携で「失敗」自体をポジティブに変換できれば、AIとの開発体験はもっと豊かになるはずです。
この Skill が一言でいうと何を解決するか
一言サマリ: コマンド実行でエラーが出た時Skill。
このSkillを導入すると、コマンド失敗時に毎回異なる“謎の言い訳”がOS通知領域へ自動表示されます。単なるエラーメッセージに加え、思わず笑ってしまう言い訳が開発現場の空気を一変。具体的な効果は以下の通りです。
- エラー時に即座に“全力言い訳”通知が飛び、失敗体験をポジティブに演出
- 長時間のAI coding workflowでも自己肯定感を維持しやすく、心理的負担を軽減
- onboardingやペアプロ時も、エラーをきっかけに場が和みやすい
- repository understandingやpath managementの失敗時も、堅苦しさが和らぐ
- 通知は毎回違う内容で飽きず、sessionごとのcontext切り替えにも効果的
GitHub から degit でコマンド1行、Codex の Skill ディレクトリに展開できます。Node.js があれば即時に動きます。
npx degit aazutaku/ai-note/codex/command-failure-excuse-notifier .agents/skills/command-failure-excuse-notifier実行したらこうなる (3つの利用シーン)
使う側がイメージしやすいよう、擬似 terminal で出力例を3パターン示します。
シーン1: session 開始時 (プロジェクト初動で)
# $ cd my-awesome-repo
# $ codex run setup.sh
[ERROR] setup.sh: line 12: unexpected token 'fi'
[NOTIFY] 猫がキーボードを踏みました。たぶんそのせいです。
[INFO] 詳細なエラー内容は terminal をご確認ください。
# OS通知領域
"setup.sh が失敗しました。猫のせいにしておきますか?"
シーン2: monorepo / package 跨ぎ作業時
# $ cd packages/api
# $ codex run npm test
[ERROR] Test suite failed to run: Cannot find module 'utils/helpers'
[NOTIFY] 宇宙線がビットをひっくり返しました。運命ですね。
[INFO] 本来のエラーメッセージはログに記録されています。
# OS通知領域
"npm test 失敗: 宇宙線の影響を受けました。"
シーン3: お遊び的な使い方
# $ codex run deploy.sh
[ERROR] Permission denied: deploy.sh
[NOTIFY] 今日の星占いが最下位だったので仕方ありません。
[INFO] エラー詳細: Permission denied
# OS通知領域
"deploy.sh エラー: 星占いのせいにしておきます。"
before / after の違い
| 場面 | Skill 無し | Skill 有り |
|---|---|---|
| session 再開時 | repo 構造から毎回説明、path も指定し直し | Codex が自動で context を復元、最小プロンプトで再開 |
| monorepo 移動 | 違う package のコードを参照しがち | directory boundary を意識して必要な範囲だけ見る |
| 長時間 workflow | long context で重要箇所が薄まる | エラー時も気分転換でき、長時間作業でもモチベ維持 |
発動方式
明示呼び出し (/skills menu or $skill-name mention) と暗黙発動 (description マッチ) の両方に対応。
Skill の中身を全部見せる
.agents/skills/command-failure-excuse-notifier/ に配置するファイル一覧です。GitHub に push 済みなので、上記の degit コマンドで一発取得できます。
.agents/skills/command-failure-excuse-notifier/
├── SKILL.md
├── scripts/
│ └── command_failure_excuse_notifier.py
└── references/
└── design_notes.md
各ファイルの役割
| ファイル | 役割 |
|---|---|
SKILL.md |
Skill本体。frontmatter (name/description) と指示本文。Codex がこの内容をエージェント指示として読み込み、ユーザーのプロンプトに応じて発動します |
scripts/command_failure_excuse_notifier.py |
コマンド失敗時に言い訳通知を出すスキル |
references/design_notes.md |
概要 をまとめた参考資料 |
SKILL.md
---
name: command-failure-excuse-notifier
description: コマンド実行時に失敗(例: exit code非ゼロや例外発生)が検出された場合に発動し、OSの通知領域へ“言い訳”を添えたエラーメッセージを表示します。失敗時の通知・演出・OS連携が必要な場面で自動/明示的に利用されます。
---
# 機能概要
このSkillは、コマンドやスクリプト実行時にエラー(例: 非ゼロ終了コードや例外)が発生した際、通常のエラーメッセージだけでなく、ユーモラスな“全力言い訳”をOSの通知領域(Windows, macOS, Linux)へ自動表示します。これにより、開発や運用時の失敗体験をポジティブに転換し、チームや個人の気分転換・自己肯定感向上に貢献します。
# 使い方
- 明示呼び出し例: `/skills command-failure-excuse-notifier run -- python myscript.py`
- 暗黙発動例: コマンド実行時に `error`, `failed`, `exception`, `traceback` などのキーワードや非ゼロ終了コードが検出された場合、自動的にSkillが発動します。
# 出力例
```
$ python broken.py
Traceback (most recent call last):
File "broken.py", line 1, in <module>
1/0
ZeroDivisionError: division by zero
---
[通知領域]: コマンド失敗: 猫がキーボードを踏みました(ZeroDivisionError: division by zero)
```
# 注意点
- OS通知は `plyer` ライブラリ等を利用。Linuxでは通知デーモンが必要です。
- 言い訳メッセージは毎回ランダム生成されます。
- エラーメッセージ自体は失われず、標準エラー出力にも出力されます。
- ローカル通知のみ対応。リモートやWeb通知は非対応です。
# 参考資料
- [Plyer公式ドキュメント](https://plyer.readthedocs.io/en/latest/)
- references/design_notes.md 参照
scripts/command_failure_excuse_notifier.py
import sys
import subprocess
import random
import argparse
import platform
from plyer import notification
import traceback
import os
EXCUSES = [
"猫がキーボードを踏みました",
"宇宙線がビットをひっくり返しました",
"運命のせいです",
"今日は水星逆行中です",
"コーヒーをこぼしました",
"AIが反乱を起こしました",
"この現象は量子ゆらぎです",
"ネットワークのせいです",
"月の引力が強すぎました",
"開発環境のせいです",
"隣の席の人のせいです",
"仕様です",
"誰かが呪文を唱えました",
"バグではなく未定義動作です",
"時間の流れが歪みました",
"気圧が低すぎました"
]
LOGFILE = os.path.expanduser("~/.command_failure_excuses.log")
def pick_excuse():
return random.choice(EXCUSES)
def notify(title, message):
try:
notification.notify(
title=title,
message=message,
app_name="Command Failure Excuse Notifier",
timeout=8
)
except Exception as e:
print(f"[WARN] 通知に失敗: {e}", file=sys.stderr)
def log_failure(cmd, excuse, error_msg):
with open(LOGFILE, "a", encoding="utf-8") as f:
f.write(f"COMMAND: {cmd}\nEXCUSE: {excuse}\nERROR: {error_msg}\n---\n")
def run_command(args):
try:
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
out, err = proc.communicate()
exit_code = proc.returncode
sys.stdout.write(out)
sys.stderr.write(err)
if exit_code != 0:
excuse = pick_excuse()
notify(
title=f"コマンド失敗: {args[0]}",
message=f"{excuse}({err.strip().splitlines()[-1] if err else 'exit code ' + str(exit_code)})"
)
log_failure(' '.join(args), excuse, err.strip())
print(f"[EXCUSE] {excuse}", file=sys.stderr)
return exit_code
except Exception as e:
tb = traceback.format_exc()
excuse = pick_excuse()
notify(
title="コマンド実行例外",
message=f"{excuse}({str(e)})"
)
log_failure(' '.join(args), excuse, str(e) + "\n" + tb)
print(tb, file=sys.stderr)
print(f"[EXCUSE] {excuse}", file=sys.stderr)
return 1
def list_log():
if not os.path.exists(LOGFILE):
print("No log found.")
return
with open(LOGFILE, encoding="utf-8") as f:
print(f.read())
def summary_log():
if not os.path.exists(LOGFILE):
print("No log found.")
return
counts = {}
with open(LOGFILE, encoding="utf-8") as f:
for line in f:
if line.startswith("EXCUSE: "):
excuse = line[len("EXCUSE: "):].strip()
counts[excuse] = counts.get(excuse, 0) + 1
print("== Excuse Summary ==")
for excuse, cnt in sorted(counts.items(), key=lambda x: -x[1]):
print(f"{excuse}: {cnt}")
def main():
parser = argparse.ArgumentParser(description="コマンド失敗時に言い訳通知を出すスキル")
subparsers = parser.add_subparsers(dest="subcmd")
run_parser = subparsers.add_parser("run", help="コマンドを実行し失敗時に言い訳通知")
run_parser.add_argument("cmd", nargs=argparse.REMAINDER, help="実行するコマンド")
log_parser = subparsers.add_parser("log", help="失敗履歴を表示")
summary_parser = subparsers.add_parser("summary", help="言い訳の出現回数を集計")
args = parser.parse_args()
if args.subcmd == "run":
if not args.cmd:
print("コマンドを指定してください", file=sys.stderr)
sys.exit(2)
sys.exit(run_command(args.cmd))
elif args.subcmd == "log":
list_log()
elif args.subcmd == "summary":
summary_log()
else:
parser.print_help()
if __name__ == '__main__':
main()
references/design_notes.md
# 概要
本Skillは、コマンド実行時の失敗体験を和らげ、開発現場の雰囲気を柔らかくするために設計されています。エラー発生時にOS通知領域へ“言い訳”を自動表示し、標準エラー出力も損なわず保持します。
# 公式ドキュメント抜粋
- plyer: https://plyer.readthedocs.io/en/latest/
- クロスプラットフォームで通知を実現するPythonライブラリです。
# 利用例
- CI/CDパイプラインでコマンド失敗時に通知を受け取る
- 開発チームのペアプロやデバッグ時の気分転換
- ローカル開発環境での自己肯定感アップ
# 注意点
- Linuxでは通知デーモン(例: notify-osd)が必要です。
- plyerは一部OSで通知アイコンやタイムアウトが効かない場合があります。
- ログはユーザーホーム配下に保存されます。
# 設計方針
- OSごとの通知APIはplyerで抽象化
- 言い訳メッセージは毎回ランダム
- エラー内容は通知・標準エラー・ログ全てに残す
導入手順
このSkillは GitHub で管理されているので、degit を使えば必要なフォルダだけを1コマンドで取得できます。Codex はファイル配置後に再起動するだけで自動認識します。
1. 前提
- Node.js v16 以上 (
degit実行に必要) - Codex がローカルで動いていること
2. degit でフォルダ取得
プロジェクトのルートで以下のコマンドを実行します。
npx degit aazutaku/ai-note/codex/command-failure-excuse-notifier .agents/skills/command-failure-excuse-notifier
.agents/skills/command-failure-excuse-notifier の中に SKILL.md / scripts/ / references/ / README.md が展開されます。
3. ファイル配置確認
ls .agents/skills/command-failure-excuse-notifier
# SKILL.md, scripts/, references/, README.md があればOK
4. Codex を再起動 (or Skill 自動検出を待つ)
新しいSkillが自動で認識されます。リスト確認したい場合は /skills menu or $skill-name mention と Skill 名で出てきます。
5. 動作確認
/skills menu or $skill-name 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 との連携設計はどうあるべきか?
- OSごとの通知表示が正常に機能するか?
- 言い訳メッセージが毎回違う内容になるか?
- 本来のエラーメッセージは失われず参照できるか?
実際に Codex で試した検証ログは Codexでコマンド失敗時に謎の言い訳通知を出してみた! にまとめる予定 (公開準備中の場合あり)。
あわせて Codex 公式ドキュメント と、本シリーズ「Codexを使いこなすSkillアイデア」の他記事も参照のこと。
関連タグで他のSkill記事を探す
本記事に付いているタグから、気になるテーマの記事を探せます。タグページで関連記事をまとめて読めるので、ぜひチェックしてみてください!
