現在お買い物カゴには何も入っていません。
タグ: gemini
-
Spec-kitの活用
mcts-genとpy-chessboardjsにおけるSpec-kitの活用と開発ワークフロー改善の記録
この記事では、私が最近行った2つのプロジェクトmcts-genとpy-chessboardjsでの開発記録を基に、AIを活用したspec-kitツールの使い方、GitHub Actionsを用いたCI/CDワークフローの構築、そしてPyPIのTrusted Publisher設定について解説します。
1. spec-kitのアップデートと古い設定ファイルの整理
プロジェクトmcts-gen(akuroiwa/mcts-gen)において、spec-kitのバージョン更新を行いました。この際、古いファイルの削除に手間取りました。また、仮想環境管理ツールuvxを用いた初期インストール手順が、恒久的なツールの利点を享受できない原因となりました。
🚨 古いバージョンからの移行時の注意点
以前のバージョンで
specify initを実行していたため、新しいバージョンのspec-kitを導入する際、古いコマンド定義ファイルが残ってしまいました。現在のgemini-cliでspec-kitのコマンドは全て
/speckit.から始まりますが、古いバージョンでは異なっていました。【新しいspec-kitのインストール】
仮想環境をアクティベートした後、
uv tool installで最新版を取得します。source .venv/bin/activate uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git【内部コマンドの更新】
プロジェクトのルートで以下のコマンドを実行し、gemini-cliの内部コマンドを更新します。
specify init --hereこれにより、新しいコマンドファイルが
.gemini/commands/以下に作成されます。【新規ファイルの確認】
git statusで確認すると、以下のような新しいファイルが追加されていることが分かります。ブランチ main 追跡されていないファイル: (use "git add <file>..." to include in what will be committed) .gemini/commands/speckit.analyze.toml .gemini/commands/speckit.checklist.toml ...(中略)... .gemini/commands/speckit.tasks.toml .specify/.specify/ディレクトリにはmemory/,scripts/,templates/といったサブディレクトリが含まれます。🧹 古いファイルの削除手順
新しいコマンドファイルと競合する古いファイルを特定し、手動で削除する必要がありました。
-
古いコマンド定義ファイルの削除
cd .gemini/commands/ rm plan.toml rm specify.toml rm tasks.toml cd - -
古い
.specify関連ファイルの削除rm -rf memory/ rm -rf templates/ rm -rf scripts/
💡 ヒント: コマンド定義ファイルが管理対象外になるように、
.gitignoreに.geminiを追加することも検討できます。ただし、その場合はgit statusには表示されなくなります。
2. 既存プロジェクト(py-chessboardjs)でのspec-kit導入と運用
既存のプロジェクトpy-chessboardjs(akuroiwa/py-chessboardjs)でもspec-kitを導入しました。
🛠️ 導入手順
プロジェクトのルートディレクトリで、以下の手順を実行します。
uv venv source .venv/bin/activate uv pip install -e . # プロジェクト依存パッケージのインストール uv tool install specify-cli --from git+https://github.com/github/spec-kit.git # spec-kitのインストール specify init --here # プロジェクト設定ファイルの作成 specify --help # 動作確認spec-kitをgemini-cliで使用し始めると、プロジェクトルートに**
GEMINI.md**というファイルが作成され、これがAIとの対話の出発点となります。🚀 spec-kitを利用した開発サイクル
spec-kitのコアな使い方は、事前にGeminiにチャットで相談し、戦略を固めてからスラッシュコマンドを実行していく流れが最も効果的です。
コマンド 目的 /speckit.specify <文字列>要件定義や仕様策定をAIに依頼し、** specs/**にMarkdownファイルを作成させる/speckit.plan実装計画を立てる /speckit.tasksタスクリストを作成する /speckit.implement実際にコードの実装を依頼する これらの作業を通して、
specs/以下にMarkdownファイルが作成されます。原則として、specs/以下のサブディレクトリは作業ごとに作成されたブランチ名と同じになります。🔄 作業終了後のブランチマージ
spec-kitがブランチを作成して作業を進めた後、作業をメインブランチに反映するには、以下の手順が必要です。
git commit -m "修正内容のメッセージ" # 作業ブランチで必ずコミットする git checkout main git merge 001-fix-settings-load-error # 作業ブランチをmainにマージ git branch -d 001-fix-settings-load-error # 作業ブランチを削除
3. GitHub ActionsとPyPI Trusted Publisherの設定
パッケージの自動公開のために、GitHub Actionsのワークフローを
.github/workflows/にYAMLファイルで記述します。このYAMLファイルはGeminiに依頼して作成してもらうことが可能ですが、動作確認が不可欠です。🚢 パッケージ公開ワークフロー
このYAMLファイルを使用して、PyPIのTrusted Publisherを登録します。登録時には、上記のYAMLファイル名を指定する必要があります。これにより、GitHub ActionsとPyPIが連携し、OIDC(OpenID Connect)を使って安全にパッケージを公開できます。
🧪 テスト公開と本番公開
タグ名によって、TestPyPIと本番PyPIへの公開を分けます。
公開先 タグ名の条件 コマンド例 TestPyPI -testを含むタグ名git tag v0.0.3-test1本番PyPI -testを含まないタグ名git tag v0.0.3タグを作成したら、
git push origin <タグ名>でプッシュすることで、GitHub Actionsが起動します。📝 YAMLの構文チェック: Emacsでは
flycheck-yamllintをインストールすると、flycheck-modeでYAMLの構文エラーをリアルタイムに確認でき、大変便利です。
4. AIとの協調作業における重要な教訓
py-chessboardjsの開発中に遭遇した2つの不具合は、AIによる開発支援の限界と可能性を示す良い事例となりました。
不具合1: ファイルパスの取得問題(
C:\fakepath\)現象: チェスエンジンのパス指定が機能しないエラーが発生し、出力には
FileNotFoundError: [Errno 2] そのようなファイルやディレクトリはありません: 'C:\\fakepath\\stockfish'とありました。解決: Google検索の結果、「fakepath」はHTMLのファイル入力フィールドがセキュリティ上の理由から実際のパスを隠蔽するブラウザの挙動であることが判明しました。この情報をGeminiに提供したところ、**「input type="file"をボタンに置き換え、
pywebview.apiを介してPythonのネイティブファイルダイアログを呼び出す」**という正確な解決策が提示され、実装に成功しました。不具合2: キャスリング時のエラー(
concurrent.futures.CancelledError)現象: キャスリングを行うとエラーが発生しました。
解決: ログから
concurrent.futures.CancelledErrorが見つかり、並列処理の不具合が疑われました。原因は、プロジェクトが使用しているchessboardjsの古いバージョンにあり、キャスリング時にFEN(盤面情報)が複数回更新され、チェスエンジンが処理しきれなかった可能性が高いと特定しました。以下はGeminiによる解説です:
-
python-chessエンジン呼び出しの問題について
根本的な問題は、GUIフレームワークであるpywebviewと、asyncioベースのエンジン通信を行うpython-chessライブラリとの間の並行処理の競合でした。
-
pywebviewのAPI呼び出しは同期かつ別スレッドで実行される: JavaScriptからpywebview.api.some_function()を呼び出すと、pywebviewは新しいPythonスレッドでsome_functionを実行し、その関数が戻るまでスレッドをブロックします。 -
python-chessのエンジン通信は非同期 (asyncio):
chess.engine.popen_uci()関数やengine.play()メソッドは、Pythonのasyncioライブラリを使用して外部のチェスエンジンプロセス(Stockfishなど)と通信します。asyncioはイベントループ上でタスクを実行し、通常は単一のスレッドで行われます。 -
競合 (レースコンディション):
- 以前のApi.uci_engine_move()は、await self.engine.play()を直接呼び出していました。このawait呼び出しは、エンジンが指し手を返すまでpywebviewのAPIスレッドをブロックしていました。
- このpywebviewのAPIスレッドがブロックされている間に、ユーザーが別のUI操作(例: 「リセット」ボタンや「戻る」ボタンのクリック)を行うと、その操作もpywebviewのAPI呼び出し(例: Api.on_closed())をトリガーしていました。
- 古い設計のApi.on_closed()メソッドはself.engine.quit()を呼び出し、エンジンプロセスを終了させていました。
- エンジンプロセスが終了すると、self.engine.play()が待機していたasyncioのFutureがキャンセルされ、concurrent.futures.CancelledErrorが発生しました。エンジンプロセスが予期せず終了した場合はchess.engine.EngineTerminatedErrorが発生しました。
- pywebviewのAPIスレッドはself.engine.play()の結果を待ってブロックされていたため、Futureがキャンセルされると、CancelledError(またはEngineTerminatedError)が伝播し、アプリケーションがクラッシュしたり、一貫性のない状態になったりしていました。
-
解決策 (専用ワーカースレッド):
- 私たちは、専用のthreading.Threadで実行されるEngineWorkerクラスを導入しました。
- このEngineWorkerスレッドは独自のasyncioイベントループを持ちます。
- pywebviewからApi.uci_engine_move()が呼び出されても、もはやブロックされません。代わりに、EngineWorkerが監視するqueue.Queueに「プレイ」タスクを投入します。
- EngineWorkerはタスクを受け取り、自身の asyncioイベントループ上でawait self.engine.play()を実行します。指し手が準備できると、スレッドセーフなコールバック(_engine_move_callback)を使用して結果をApiクラスに返します。
- Apiクラスはself.window.evaluate_js()を使用して、指し手をJavaScriptのフロントエンドにプッシュします。
- なぜこれで解決したのか: pywebviewのAPIスレッドはasyncio操作によってブロックされなくなりました。asyncioイベントループは独自の安定したスレッドで継続的に実行されます。エンジンを終了させる可能性のあるUI操作は、EngineWorkerのキューに「終了」タスクを送信するようになり、ワーカースレッドはエンジンとそのループを安全にシャットダウンできます。計算中に「終了」が受信されても、ワーカースレッド内でasyncioタスクがキャンセルされるだけで、pywebviewのAPIスレッドには伝播せず、クラッシュを防ぎます。Engine move discardedというメッセージは、この正常な処理を示しています。
-
-
specs/002-fix-castling-errorの削除について
削除したのは良い判断でした。002-fix-castling-errorブランチとその関連する仕様ファイルは、バグ修正の失敗した試みを表していました。それらを残しておくと、誤った情報や置き換えられた情報でリポジトリが煩雑になります。
フィーチャーの試みが失敗したり、新しいアプローチに置き換えられたりした場合は、古いブランチとその成果物をクリーンアップするのがベストプラクティスです。これにより、プロジェクトの履歴がクリーンに保たれ、成功した作業や関連する作業のみが反映されます。
新しい003-fix-engine-concurrencyブランチとその仕様は、根本的な並行処理の問題を解決するための現在の成功したアプローチを正確に反映しています。
💡 教訓: ユーザーの根気強さが成功の鍵
これらの事例から学んだのは、Geminiでも不具合の特定は難しく、ユーザーとの共同作業であるということです。特に、エラー出力や挙動を注意深く観察し、根気強くAIにフィードバックすることが、適切な解決策を導き出すために不可欠となります。AIは強力な助けとなりますが、最終的なデバッグと検証は人間の役割です。
-
-
mcts-gen
mcts-gen:AIエージェント統合型 次世代MCTSフレームワーク
先日開発した mcts-gen は、標準的なUCT(Upper Confidence Bound 1 applied to Trees)アルゴリズムにAIエージェントを統合した、汎用的なMCTS(モンテカルロ木探索)フレームワークです。
従来の chess-ant がGenetic Programming(GP)ベースであったのに対し、mcts-genは設計を根本から見直しました。Policy(方策)やValue(価値)の予測を外部AIエージェント(例えばgemini-cli)と連携させることで、探索効率と応用範囲を大幅に拡張しています。
FastMCPによるAIエージェント連携
このプロジェクトの核となるのは、FastMCP を介したAIエージェントとの通信です。mcts-genの探索エンジンは、MCP (Model Context Protocol) を通じて外部のAIエージェントと通信し、局面に応じたポリシー予測や価値評価を受け取ります。
特に spec-kit と gemini-cli を組み合わせ、AIをバックエンドとしたMCTSサーバーを生成・構築できる点が大きな特徴です。これにより、高速で柔軟な探索環境が実現します。
未知領域探索への応用とPolicy Pruning
MCPサーバーの導入により、このフレームワークは学習済みデータに基づく既存の知識空間だけでなく、未経験・未知の局面への探索も可能としました。
AIエージェントによるPolicy Pruning(有望手の絞り込み)機能により、広大で非効率になりがちな探索空間の中から、効率的に有益な手だけを選び出して深く探索できます。これは、複雑な問題や新しいゲームへの応用において非常に強力なアドバンテージとなります。
spec-kitワークフローの注意点(教訓)
spec-kitのような高度な開発ツールを使用する際は、ワークフローの順守が不可欠です。
spec-kitでは、
/speckit.specify,/speckit.plan,/speckit.tasksといったスラッシュから始まるコマンドを実行すると、作業内容がMarkdownファイルに自動で記録され、新しいGitブランチも作成されます。その後、メインストリームへのマージ作業を行うのが基本の流れです。私の場合、コマンドを実行せずに直接GeminiにMarkdownファイルの更新を依頼したため、過去の作業記録が上書きされて失われてしまいました。これはGeminiの動作によるものではなく、規定の手順を踏まなかった私の操作ミスが原因です。ツールが意図するワークフローを守ることの重要性を改めて痛感しました。
uvによるgemini-cliとFastMCP管理
gemini-cliおよびFastMCPの公式推奨設定例 Gemini CLI 🤝 FastMCP では、uvコマンド による環境管理が原則とされています。
uvはPythonパッケージの仮想環境管理ツールで、極めて高速かつクリーンな依存関係管理を可能にします。Rustで書かれており、従来のパッケージ管理ツールが抱えていたパフォーマンスの問題を解決します。
Ubuntuでのuvインストールと使用法
mcts-genプロジェクトでuvを利用するための基本的な手順は以下の通りです。
pipxのインストール:
sudo apt install pipxuvのインストール:
pipx install uv基本的な利用方法。プロジェクトディレクトリで以下のコマンドを実行します:
uv venv source .venv/bin/activate uv pip install mcts-gen[shogi] fastmcp install gemini-cli .venv/lib/python3.12/site-packages/mcts_gen/fastmcp_server.py:mcpコマンドを実行すると .gemini/settings.json が生成されます。
因みに末尾の :mcp は fastmcp_server.py にあるオブジェクト名です。オブジェクトが2つあるためか、自動でFastMCPサーバーのオブジェクトが認識されないので指定しなければなりません。run() メソッドで実行されます。
仮想環境を終了するにはdeactivateコマンドを使います。マニュアルにある AGENTS.md は v0.0.2 で廃止しコード化しました。AIに指示を追加する場合のみcontextの設定を .gemini/settings.json に追記してください。
mcts-genは、探索手法にAIの力を統合したいと考えるすべての開発者にとって、有力な選択肢となるはずです。詳細やセットアップ手順は、ぜひ公式ドキュメントも参考にしてください。
-
Gemini-JSCAD-Tool: GeminiとチャットしながらCAD開発する新しい体験
概要
gemini-jscad-tool は、Gemini CLI の拡張として開発されたツールで、JSCADを用いた3Dモデル生成を対話的に実現します。Geminiとチャットしながら、3Dモデルを作成し、リアルタイムにプレビュー&STLファイルに変換できます。
特徴
- 🔄 Geminiと自然言語でやり取りしながら設計できる
- 🧊 JSCADモデルを作成し、STLへ変換
- 🌐 ローカルのライブプレビューサーバーで即座にSTLの形状を確認可能
- ⚙️ Gemini向け拡張機能の実装例としても活用可能
インストール方法
npm install -g gemini-jscad-toolインストール後、自動的に以下が行われます:
gemini-jscad-serverコマンドがグローバルに配置されるgemini-extension.jsonとGEMINI.mdが~/.gemini/extensions/jscad/にコピーされる
使用方法
以下のように、Geminiとの会話ベースで操作を進めます。
1. プレビューサーバーを起動
あなた: Start the preview server.→
http://localhost:3000にアクセスしてプレビュー。2. モデルを作成
あなた: Create a 20mm cube.Geminiが自動的に
.jscadファイルを生成しSTLに変換後、プレビューサーバーに反映。3. サーバーを停止
あなた: Stop the preview server.不要なプロセスの残留を防ぎます。
STL変換について
生成されたJSCADモデルは、ツール内部の処理を通じて STL形式に変換され、3Dプリント等にそのまま利用可能です。
Gemini CLI拡張機能の開発に関して
当パッケージは、Gemini CLI Extension 開発ガイドに則って作成されています。
gemini-extension.json の基本構造とMCPサーバー登録
拡張子
.jsonのこのファイルは、拡張(extension)ごとに最低1つ必要です。
MCPサーバーの設定例は以下のようになります。
因みにgemini-jscad-toolにはMCPサーバーは使用していません。後述のGEMINI.mdで呼び出しを定義しています。マニュアルからの引用:
{ "name": "my-extension", "version": "1.0.0", "mcpServers": { "my-server": { "command": "node my-server.js" } }, "contextFileName": "GEMINI.md", "excludeTools": ["run_shell_command"] }各項目の説明
項目 必須 内容・役割 name ◯ 拡張ディレクトリ名と同じにします。拡張の一意名識別子です。 version ◯ 拡張のバージョン。任意の文字列(例 "1.0.0")。省略不可。mcpServers △ この拡張が使うMCPサーバーの "名前: 設定" マップ。各サーバーは必ず commandプロパティが必要です。contextFileName ✕ 拡張についてAIへ与える文書ファイル名(通常はGEMINI.md)。省略可能。 excludeTools ✕ Geminiに読み込ませたくないツール名列挙。(例 ["run_shell_command"]/["run_shell_command(rm -rf)"])省略可能。mcpServers の詳細
MCP(Model Context Protocol) に準拠したサーバーの登録ができます。
これにより、Geminiはサーバーを正しく起動・停止し、会話の中で状態管理することができます。mcpServers はオブジェクト形式で記述し、
「サーバー識別名: 設定」 の形式でサーバーを複数登録できます。最小構成例:
"mcpServers": { "my-server": { "command": "node my-server.js" } }my-server:好きな識別名(ユニーク推奨)。command:起動方法。実行ファイルやNodeスクリプト等を記述。
コマンドにオプションや環境変数を指定したい場合
因みに、
settings.jsonにもMCPサーバーを登録できます。
非推奨パッケージになった @modelcontextprotocol/server-github
の 設定例が書かれた記事も参照してください。マニュアルからの引用:
"mcpServers": { "myPythonServer": { "command": "python", "args": ["mcp_server.py", "--port", "8080"], "cwd": "./mcp_tools/python", "timeout": 5000 }, "myNodeServer": { "command": "node", "args": ["mcp_server.js"], "cwd": "./mcp_tools/node" }, "myDockerServer": { "command": "docker", "args": ["run", "-i", "--rm", "-e", "API_KEY", "ghcr.io/foo/bar"], "env": { "API_KEY": "$MY_API_TOKEN" } } }args→ コマンドライン引数env→ サーバープロセスの環境変数cwd→ サーバを起動する作業ディレクトリtimeout→ このMCPサーバーへのリクエストのタイムアウトをミリ秒単位で行います
contextFileName について
gemini-extension.jsonの説明に戻ります。
この拡張のガイドやAI連携ガイダンスを含むMarkdownファイル名です。
省略時は拡張ディレクトリ内のGEMINI.mdが自動検出されます。excludeTools について
Gemini CLIが利用可能なツールで、本拡張では“除外”したいものを配列で指定します。
例:
- すべてのシェルコマンド実行を除外
"excludeTools": ["run_shell_command"] - 特定の危険コマンドのみ除外
"excludeTools": ["run_shell_command(rm -rf)"]
設定の優先順位と適用範囲
- 個人設定(
~/.gemini/extensions/)よりワークスペース直下(/.gemini/extensions/)の拡張が優先されます。 - MCPサーバー設定は
settings.jsonの内容が同名の場合はそちらが上書きします。
よくある誤り
- mcpServersは必ずマッピング形式(オブジェクト)で書く。[マニュアル例と食い違う原因の多く]
- サーバーごとに必ず
commandプロパティが必要
GEMINI.md の役割
GEMINI.mdには、Geminiが拡張機能と対話する際のワークフローやコマンド定義がMarkdown形式で記述されています。例として下記のように構成します:# jscad Extension ## Commands ### Start Server User: Start the preview server. Gemini runs: gemini-jscad-server ### Create Model User: Create a 20mm cube. Gemini writes: cube({size: 20}) ### Stop Server User: Stop the preview server. Gemini stops: jscad_previewこれにより、Geminiは自動的に動作フローを把握し、ユーザーの自然言語要求をコード生成やファイル操作にマッピングします。
コード・リソース
おわりに
gemini-jscad-tool は、AIとの自然な対話で3D設計と即時プレビューの連携を実現した次世代のCLI拡張です。Gemini CLI拡張の実践例としても最適なので、カスタム開発の参考にもご活用ください。
3D設計をもっと気軽に、もっと賢く―
Geminiと一緒なら、それが可能です。