AIエージェント用のツールを「どのシェルからでも呼べる」設計にして失敗した話
先に結論だけ書きます。Windows で AI エージェント(Claude Code)に日時を取らせるなら、外部スクリプトを噛ませず、その場のシェルの組み込み機能を使うのが正解でした。
# PowerShell ツールで。曜日付き(ロケールが ja-JP なら「火」まで出る)
Get-Date -Format 'yyyy-MM-dd(ddd)'
# => 2026-07-07(火)
ファイル名に使うだけの当日日付なら、そもそもコマンドを叩く必要すらありませんでした。エージェントの実行環境が最初から Today's date is 2026-07-07 を渡してくれているからです。
ここに辿り着くまでに、筋の悪い設計でしばらく無駄なエラーを踏み続けていました。その記録です。
毎回、赤いエラーが出る
きっかけは、いつもの赤字でした。
エージェントが日付を取ろうとして、こういうコマンドを実行します。
& 'C:\dev\tools\get-datetime.ps1'
これを Bash ツールに渡すと、事前フックが弾きます。先頭の &(PowerShell の呼び出し演算子)を、Bash はバックグラウンド実行の記号と誤解釈するからです。syntax error near unexpected token '&' で exit 2。
結果として、赤いエラーが出る。エージェントは「あ、PowerShell か」と気づいて同じ処理を PowerShell ツールで叩き直す。日付は無事に取れる。取れるんですが、毎回 2 回ツールが走って、エラー分のトークンも食っている。何より、画面に赤字が出るのが地味に鬱陶しい。
正直、これが何度も出ていて、いい加減うんざりしていました。
よかれと思って「薄いラッパー」を足した
最初に考えた対処は、素直なものでした。
「.ps1 が Bash で通らないなら、Bash からでも呼べる .sh 版を隣に置けばいい」。
get-datetime.ps1 と同じ出力を返す get-datetime.sh を書きました。曜日はロケール依存で崩れるのが怖かったので、date +%w の 0〜6 を case で日本語に手動マッピングして。これで Bash ツールを掴んでも大丈夫、と思ったわけです。
これは効いた、はずでした。でも直らない。また赤字が出る。なんでだ。
ラッパーを見ている人が、誰もいなかった
調べてみて、力が抜けました。
.sh は確かに置いてある。ちゃんと動く。でも、それを参照している側が一人もいなかったんです。
日付取得を指示している設定ファイルも、エージェントの記憶(過去の学習メモ)も、全部 .ps1 を名指ししていました。呼ぶ側が .ps1 を指したままなら、隣に .sh を置いても一度も使われません。鏡像を用意したのに、その鏡を覗く人がいなかった。
上の図のとおり、指示側は全部 .ps1 を向いていて、あとから足した .sh はどこからも参照されない「孤児」になっていました。ファイルを増やしても、参照が向いていなければ存在しないのと同じです。
そもそも「共通コマンド」は存在しなかった
じゃあ設定ファイル側を .sh に書き換えればいいのか。ここでもう一段、詰みが見えました。
試しに、両方のツールで通りそうな bash 'C:/dev/tools/get-datetime.sh' を PowerShell ツールから叩いてみたら、こう返ってきました。
/bin/bash: C:/dev/tools/get-datetime.sh: No such file or directory
理由はすぐ分かりました。Bash ツールが呼ぶ bash は Git Bash なのに、PowerShell ツールから呼ばれる bash は WSL の /bin/bash だったんです。WSL から見ると C:/... は存在しないパスで、/mnt/c/... と書かないと届かない。
つまり、シェルもパスの規約も別物の 2 つのツールを、単一のコマンド文字列で両対応させることは原理的にできない。ラッパーを増やす方向は、ここで完全に行き止まりでした。
上の図は、詰まっていた「外部スクリプトに整形を持たせて、どのシェルからでも呼ぶ」構図と、それをやめて各ツールの組み込み機能に寄せた後の構図を並べたものです。左の分岐をなくすのが直しの本質でした。
悪かったのは設計のほうだった
ここでようやく、直すべきは呼び方ではなく設計だと腹落ちしました。
日時の整形を外部スクリプト(.ps1 / .sh / .cmd の 3 兄弟)に持たせて「どのシェルからでも呼べるように」と欲張ったこと自体が、筋が悪かった。
エージェントにとって、どのツール(シェル)を掴むかは実行時に揺れます。その状況で命令文字列に .ps1 や先頭 & が入っていると、それ自体が誤爆の火種になる。拡張子や記号が「このツールで実行しろ」というシグナルとして働いてしまい、しかもそのシグナルがツール選択とズレる。
だから直し方はシンプルでした。命令文字列から .ps1 と & を消す。
- 曜日付きの日付が要るときは PowerShell の組み込みで
Get-Date -Format 'yyyy-MM-dd(ddd)'。ロケールが ja-JP ならdddがそのまま「火」になる - ファイル名用の当日日付なら、実行環境が渡してくれる
Today's dateを使う。コマンドを叩く必要すらない
これに合わせて、エージェントの記憶と、日付を指示していた設定ファイルの該当箇所を書き換えました。外部スクリプトは残置していますが、もう参照しません。
学んだこと
- 回避策を足すときは、それを参照する側が実際にそこを向いているかを先に確かめる。ファイルを増やしても、誰も見ていなければ何も変わらない
- 「どの環境からでも呼べる共通の入り口」は、環境が本当に別物なら幻想になることがある。Git Bash と WSL のように、名前が同じ
bashでも中身とパス規約が違うと、単一コマンドでは両対応できない - エージェントにツール選択を委ねているなら、命令文字列に「このツールで動かせ」という暗黙のシグナル(拡張子・記号)を混ぜない。実行時に揺れる前提で、シグナルの要らない形(組み込み機能・すでに渡っている情報)に寄せる
- 症状(赤字が出る)を潰す前に、そもそも何を呼ばせているのかを疑う。今回は「呼ばせないのが一番速い」だった
これが最適解かというと、たぶん違う
正直に言うと、これがベストかは分かっていません。
本当に一番きれいなのは、実行環境が渡してくれる日付情報に最初から曜日が入っていることだと思います。そうなればツールの呼び出し自体がゼロになる。今は日付だけ渡ってくるので、曜日が要る場面でだけ Get-Date を一回叩いている。ここは環境側の仕様なので、こちらからは動かせません。
ラッパーを増やす方向は「共通コマンドが存在しない」時点で詰みなので選べない。だから今回は、組み込み機能とすでに渡っている情報に寄せる、という現実解に落としました。最適解ではなく、いま選べる中で一番マシな形、くらいの気持ちです。
同じように「どのシェルからでも」を目指してスクリプトを 3 つ並べている人がいたら、一度その参照を誰が見ているか数えてみるといいかもしれません。自分は数えていなかったので、しばらく赤字を踏み続けました。小さく、呼ばせない方向に寄せていく。これをこれからの癖にしていこうと思います。
※ ヘッダー画像とインフォグラフィックは AI(画像生成)で作成しています。
書いた人: ishizakahiroshi
群馬の北部で、保護猫2匹と暮らす、在宅エンジニア(何でも屋)
https://ishizakahiroshi.github.io/
https://github.com/ishizakahiroshi
X(業務委託・各種相談はこちら):
https://x.com/ishizakahiroshi
バックエンド・インフラ・AI連携まわりで、業務委託のご相談を受け付けています。フルリモートです。スポットや週2〜3時間からでも歓迎で、いろんな案件に携われたらうれしいです。こんな相談、歓迎です。



