CodexでSkillを増やしていくと、だんだん困ってくることがあります。それは、Skillの名前を覚えきれなくなることです。
Skillを使うには、
$skill-name
のように名前を指定できますが、Skillが10個、20個と増えてくると、「あの処理をするSkillは何という名前だったか」と探す時間が増えてきます。
そこで今回は、APIを使わず、Stream Deck+のボタンからSkill一覧を表示し、用途を見て選ぶだけでCodexへ渡せるSkillランチャーを作りました。
開発途中では、Terminalが毎回開く問題、自作アプリをStream Deck+から起動できない問題、ショートカットの競合、一覧が時間経過で消える問題など、かなり試行錯誤しました。まだ、改良する余地はありますが、普段使いできるところまで改善できました。


注)本記事の内容は正確性を保証するものではない。
(2026年8月27日 追記)YouTube動画を追加しました。 https://youtu.be/asuQAq-inB8

「Skillごとのボタン」ではなく「Skill一覧」を検討

最初は、SkillごとにStream Deckのボタンを作る方式を検討していた。使用頻度が高いSkillが5種類程度なら、そのSkill専用のボタンを設ければいいのだが、Skillを増やすとそのたびにボタンも増やなければならず、ページを切り替える必要も出てくる。
そこで採用したのが、Skill一覧を呼び出すボタンを1個だけ作る方式。
イメージは次のようになります。
Stream Deck
↓
Skill一覧
↓
利用可能なSkillを表示
↓
用途に関する日本語説明を見て選択(英語名も表示)
↓
$skill-name
↓
Codex CLI
ランチャー自身がSkillフォルダを調べ、各 SKILL.md の名前と説明を読み取るようにすれば、新しいSkillを追加してもStream Deck側を設定し直す必要がない。
これが今回の基本方針になった。
まずPoCを作り、Skillの自動検出を確認
最初のPoCでは、Skillフォルダを検索し、SKILL.md を読み込み、一覧表示・検索・絞り込み・Skill名への変換・Codex CLIへの受け渡しまでを作りました。
診断を行うと、実際に複数のSkillを自動検出できました。
一方、最初はCodex CLIがPATH上から見つかりませんでした。その後、Codex CLIを使える状態にすると、
path: /Users/.../.local/bin/codex
codex-cli 0.149.0
と認識され、Skill一覧も正常に取得できました。
※「PoC」とは、Proof of Concept(概念実証)の略で、完成版を作る前に、重要な機能が実現可能かを小さく試すこと。
dry-runで安全に確認
実際にSkillを実行する前に、–dry-run を使って動作確認しました。
たとえば set-article-archive を選択すると、
選択Skill: set-article-archive
送信プロンプト: $set-article-archive
のように表示されます。
この段階ではCodexを実行しないため、一覧表示 → 検索 → Skill選択 → Skill名への変換までを安全に確認できます。
「–dry-run」とは何ですか
--dry-run は、実際の処理を行わずに「もし実行したらどうなるか」だけを確認するためのオプションです。
今回のようなCodex Skillランチャーでは、たとえば本番実行が
python3 skill_launcher.py archive-and-start-article
だとすると、dry-runでは
python3 skill_launcher.py --dry-run archive-and-start-article
のようにして、実際にはSkillを実行せず、
- どのSkillが選ばれるか
- どのコマンドがCodexへ渡されるか
- パスや引数が正しいか
- 設定ファイルの読み込みが正常か
などを確認します。
つまり、
通常実行
→ 実際に処理する
--dry-run
→ 処理内容だけ確認して止める
という違いです。
今回のランチャー開発では、Skillによってはファイル作成・移動・アーカイブなど実データに影響する可能性があるため、最初に --dry-run で確認してから本番実行するのが安全です。
なお、--dry-run はPythonやmacOS共通の標準機能ではなく、そのプログラム側が対応している場合だけ使えるオプションです。今回のランチャーで使えていたのは、ランチャー側(skill_launcher.py)が、dry-run機能のオプションを実装するようにAIによって構成されていたためです。
実際にCodexへSkillを渡してみる
次に、安全なテスト用Skillを選び、実際にCodex CLIへ渡しました。
Codex側には、
$open-textedit-from-dock
が渡され、さらに Read SKILL.md まで進みました。
つまり、Skill一覧 → Skill選択 → 正しいSkill名へ変換 → Codex CLI起動 → SKILL.md読込までは正常です。
その後Computer Use側で追加許可が必要になりましたが、これはランチャーとは別の問題です。PoCとして確認したかった部分は成功しました。
Stream Deckに登録するとTerminalが毎回開く
次にStream Deckの「システム → 開く」へランチャーを登録しました。
Skill一覧自体は表示できましたが、一覧を表示するたびにTerminalも開いてしまいます。
そこで第2版では、
Stream Deck
↓
Skill一覧だけ表示
↓
Skillを選択
↓
その時だけTerminalを開く
↓
Codex CLI
という構成に変更しました。
さらに、Skill一覧・最近・よく使うという3種類の表示方法も考えました。
同じSkillデータを使い、並び順だけ変える方式です。
自作.appをStream Deckから直接起動する方法では苦戦した
Terminalを隠すため、自作の .app を作成しました。しかしStream Deckから押しても何も起こりません。
調べると、最初はアプリの署名に問題があり、
invalid Info.plist
となっていました。
再署名すると、
valid on disk
satisfies its Designated Requirement
になりました。
ところが、それでもStream Deckからは起動できません。一方、Terminalから open "Codex Skill.app" とするとSkill一覧は正常に表示されます。
つまり、Skillランチャー自体は正常だが、Stream Deckから自作.appを直接起動する経路が安定しないということが分かりました。
ここで、自作.appを直接開く方式をやめることにしました。
macOSショートカットを中継する方式へ
次に試したのがmacOSの「ショートカット」です。
ショートカットからシェルスクリプトを実行し、
/opt/anaconda3/bin/python3 "/Users/.../skill_launcher.py" --sort name
を呼び出すようにしました。
これで、macOSショートカット → skill_launcher.py → Skill一覧という構成になります。
実際にキーボードショートカットから実行すると、Terminalを開かずにSkill一覧を直接表示できました。
ホットキー方式にも問題があった
次に、このショートカットをStream Deckのホットキーから呼ぼうとしました。
ところが、使用しているキーボードやキーの組み合わせによって、Stream Deck側で最後のキーがうまく登録されないことがありました。
URLスキームを使ってmacOSショートカットを呼ぶ方法も試しましたが、今度は「ショートカット」アプリ自体が前面に出てきます。
この2つを避けるため、最終的に Mac Shortcuts Runner を使う方式へ変更しました。
Mac Shortcuts Runnerとは
Mac Shortcuts Runner は、Stream DeckからmacOSの「ショートカット」を1ボタンで実行するためのMac用プラグインです。
今回のCodex Skill Launcherでは、Stream Deckのボタンを押すと、Mac Shortcuts Runnerが指定したmacOSショートカットを起動し、そのショートカットからSkillランチャーを呼び出す「中継役」を担当しています。
Stream Deck
↓
Mac Shortcuts Runner
↓
macOSショートカット
↓
Codex Skill Launcher
↓
Codex CLI
Mac Shortcuts Runner自体がCodex Skillを実行するわけではなく、Stream DeckとmacOSショートカットをつなぐ役割を持つプラグインです。
最終的に安定した呼び出し構成
完成した呼び出し部分は次のようになりました。
Stream Deck
↓
Mac Shortcuts Runner
↓
macOSショートカット「Codex Skill」
↓
skill_launcher.py
↓
Skill一覧
↓
Skillを選択
↓
その時だけTerminal
↓
Codex CLI
↓
$skill-name
この方式では、ショートカットアプリが前面に出ず、Skillを選ぶまではTerminalも出ず、ホットキー競合も気にしなくてよくなりました。

「Skill一覧」「最近」「よく使う」の3ボタン
ランチャーは最終的に3種類の表示方法を使えるようにしました。
| ボタン | 並び順 | 用途 |
|---|---|---|
| Skill一覧 | 名前順 | 全Skillから探す |
| 最近 | 最終使用日時順 | 直近で使ったSkillを呼ぶ |
| よく使う | 使用回数順 | 定番Skillをすぐ呼ぶ |
使用履歴はローカルへ保存します。そのため「最近」を開けば直前に使ったSkillが上へ移動し、「よく使う」では実行回数の多いSkillが上位に表示されます。

Skill名だけではなく、日本語の用途名を表示
Skill一覧が動くようになると、次に気になったのが英語のSkill名と長いdescriptionです。
そこでv2.3では、日本語用途名を保存する機能を追加しました。
たとえば、
Q&Aを記事素材に追加|append-qa
記事をアーカイブして次の記事を開始|archive-and-start-article
選択Q&Aから記事下書きを作成|assemble-article-draft
ChatGPTのQ&Aを記事素材へ同期|sync-chatgpt-qa
のように表示します。
本来のSkill名も残しているため、どのSkillを実行するかも確認できます。
日本語用途名は毎回生成するのではなく、一度決めたものを保存します。
新しいSkillが追加された場合だけ初回に候補を確認し、以後は固定して使う仕組みにしました。
Skillを選ぶだけでなく、今回の指示も追加したい
ここまでのランチャーは、Skillを選ぶと $skill-name だけをCodexへ渡していました。
しかし実際に使っていると、「今回だけ初心者向けにしてほしい」「今回はSWELLで編集しやすい構成にしてほしい」といった追加指示を同時に渡したくなります。
そこでv2.4では、Skillを選んだあとに、そのまま実行と今回だけ追加指示を選べるようにしました。
追加指示を入力すると、
$assemble-article-draft
初心者向けの記事として、専門用語を減らしてください。
という形でCodexへ渡します。
さらに「定型指示付きで実行」も追加
毎回同じ追加指示を書くSkillもあります。
そこでv2.5では、
- そのまま実行
- 今回だけ追加指示
- 定型指示付きで実行
の3方式にしました。
定型指示はSkillごとにローカルへ保存します。
たとえば記事作成Skillなら、
WordPress SWELLで編集しやすい構成にしてください。
専門用語には短い説明を付けてください。
冗長な文章は避けてください。
と登録しておきます。
以後は「定型指示付きで実行」を選ぶだけです。Skill一覧から定型指示の登録・編集・削除もできるようにしました。

最後に発生した「Skill一覧が勝手に消える」問題
v2.5まで進んだところで、別の問題が見つかりました。
Skill一覧を表示して何も操作せずにいると、何十秒かすると選択窓が自動的に消えてしまいます。
同時に、Macの画面上部にはライブアクティビティに関連すると思われる表示が出ていました。
原因は、Skill一覧を表示しているPython処理が、macOSショートカットの実行プロセスにぶら下がったままだったことです。
ライブアクティビティとは関係ありませんでした。

(参考)ライブアクティビティとは
ライブアクティビティは、Macで進行中の処理やイベントの状態を一時的に表示する仕組みとのこと。
今回、Skill一覧の起動時にも画面上部に短時間表示されたが、Skill一覧そのものとは別の表示で、自動的に消えた。
今回表示されたものをよく見ると、ターミナルのような図に見える。
v2.6でSkill一覧を別プロセス化
そこでv2.6では、skill_launcher.pyを別プロセスとして起動する「launch_detached.py」を間に挟むことにしました。
macOSショートカット
↓
launch_detached.py
↓
ショートカット側はすぐ終了
別プロセス
↓
skill_launcher.py
↓
Skill一覧を継続表示
という構造へ変更しました。
実際に確認すると、
- ライブアクティビティ:10秒程度で消える
- Skill一覧:2分以上経過しても残る
という検証結果になりました。
一覧は、自分でSkillを選択するかキャンセルするまで表示されます。これで自動消去問題も解消しました。

最終的な構成
現在の完成形は次のようになっています。
Stream Deck
│
├─ Skill一覧
├─ 最近
└─ よく使う
↓
Mac Shortcuts Runner
↓
macOSショートカット
↓
launch_detached.py
↓
skill_launcher.py
↓
日本語用途名付きSkill一覧
↓
Skillを選択
↓
実行方法を選択
├─ そのまま実行
├─ 今回だけ追加指示
└─ 定型指示付きで実行
↓
必要なときだけTerminal
↓
Codex CLI
↓
$skill-name + 必要な指示
APIを直接利用する構成にはしていません。
また、新しいSkillを追加しても、Stream Deckへボタンを追加する必要はありません。Skill一覧から自動的に見つけられます。

Skillが増えるほどランチャーの価値が上がる
今回の開発を始めた理由は、「Skill名を覚えられなくなってきた」というものでした。
しかし実際に作っていくと、必要だったのは単なるSkill一覧ではありませんでした。
- 日本語の用途名で探せる
- 最近使ったSkillから探せる
- よく使うSkillから探せる
- 今回だけ追加指示を付けられる
- よく使う指示は定型として保存できる
- Skillが追加されてもStream Deckを設定し直さなくてよい
というところまで揃うと、かなり使いやすくなります。
途中では、.app の署名、Stream Deckからの起動、ホットキー、ショートカット、一覧の自動消去など、いくつもの問題にぶつかりました。
最終的には、それぞれを無理に押し通すのではなく、動作が安定する経路へ少しずつ構成を変えたことが完成につながりました。Skillを数個使うだけなら、この仕組みは必要ないかもしれません。
しかし今後Skillを増やしていくなら、「名前を覚えて呼び出す」のではなく、用途を見て選ぶSkillランチャーはかなり便利だと思います。
「Skill一覧」の選択画面では、「検索・絞り込み」機能、「日本語用途名編集」機能、「提携指示を登録・編集」機能も実装でき、Skillを探すのが容易になり、定型Skillを1ボタンで実行することができるようになったが、まだ、下記の課題も残されている。私自身ほとんどSkillを活用していないので実使用を通じて改良していきたい。
Stream Deckには、今回の3つのボタンの他に、1つのボタンに1つのSkillを割り当てた専用ボタンを3個ほど設けて、今回の3ボタンと併用するのが現実的。
・Skillを実装するたびにCodex CLIの窓が開き、その窓が残ったままになる。
・Skillの実行結果が、Codex CLIの画面に表示される。
・Codex CLIで実行した処理がCodexアプリの履歴に表示されるのか未確認。
