Claude Codeのworkflowにargsを渡しプラグインで配布する
保存したdynamic workflowは、スクリプト内のグローバル変数argsで入力を受け取れます。プラグインのworkflows/に置いて配る方法、名前空間、同名時の解決順、manifestの落とし穴まで解説します。
保存したdynamic workflowは、スクリプトの中でグローバル変数argsとして入力を受け取れます。対象のパスや調査の質問を、実行のたびにスクリプトへ書き込む必要はありません。さらにスクリプトをプラグインのworkflows/に置けば、別のリポジトリやチームにも同じ手順で配れます。
この記事は、保存したあとの2段階を扱います。「入力を渡す」と「プラグインで配る」です。保存そのものの手順は/workflowsの記事にあります。ここでは、argsを読む側のスクリプトの書き方と、配布したときに名前がどう決まるかに絞ります。
argsは何で、何が渡ってくるのか
argsは、保存したworkflowのスクリプトから読めるグローバル変数です。公式の例では、保存済みの/triage-issuesを次のように呼びます。
Run /triage-issues on issues 1024, 1025, and 1030Claudeはこの数字の並びを構造化データとして渡します。スクリプト側で文字列を分解する必要はなく、配列やオブジェクトのメソッドをargsにそのまま呼べます。用途として挙げられているのは、調査の質問、対象パスの一覧、設定オブジェクトの3つです。
押さえておく点は1つです。argsを省いて呼ぶと、スクリプト内のargsはundefinedになります。省略されうる入力は、読む側で受け止めておくと安全です。
省略されても動くスクリプトの形
次は、argsを読む最小のスクリプトの例です。公式のサンプルの書き方(metaブロック、agent()、pipeline())に沿った形ですが、入力の扱いは説明用に組んだものです。
export const meta = {
name: 'triage-issues',
description: 'Triage the given GitHub issues',
}
const issues = Array.isArray(args) ? args : []
if (issues.length === 0) {
return 'No issue numbers were given.'
}
const results = await pipeline(issues, n =>
agent(`Read issue #${n} and propose a label and a next step.`, { label: `#${n}` }),
)
return results.filter(Boolean)Array.isArray(args)で受けているので、argsがundefinedでも落ちません。入力が空なら、エージェントを1体も起動せずに終わります。pipeline()はnullをそのまま配列に残すため、末尾の.filter(Boolean)で止められたエージェントの枠を落としています。
ここで渡される値の形は、呼び出しの文言から決まります。配列のつもりでスクリプトを書いたのにオブジェクトが届く、という食い違いを避けるため、最初はlog()でargsの中身を出して形を確かめる方法があります。log()は進捗ビューの上にメッセージを出す関数です。
時刻やランダム値はargsで渡す
保存したスクリプトを編集するときの決まりに、argsと関わるものが1つあります。Date.now()、Math.random()、引数なしのnew Date()は、スクリプトの中では例外を投げます。再開した実行が同じagent()呼び出しを繰り返せるようにするためです。
日付をレポートの見出しに入れたいなら、その値はargsで渡します。たとえば{ date: '2026-10-13', paths: [...] }のようなオブジェクトを作り、スクリプトではargs.dateを読みます。argsは、実行ごとに変わる値の唯一の入口になります。
配布の前に、ローカルでの名前の決まり方を知る
プラグインに入れる前に、保存済みworkflowの名前がローカルでどう解決されるかを見ておきます。配布後の挙動と対になるからです。
保存先は2つあります。
| 保存先 | 範囲 |
|---|---|
.claude/workflows/(プロジェクト) | 範囲リポジトリをcloneした全員と共有 |
~/.claude/workflows/(ホーム) | 範囲自分の全プロジェクトで使用、他者には非公開 |
同じ名前がプロジェクトと個人の両方にあれば、プロジェクト側が動きます。
モノレポでは、.claude/が複数の階層にあってもかまいません。プロジェクトのworkflowは、作業ディレクトリからリポジトリルートまでの経路上にある.claude/workflows/をすべて読み込みます。同じ名前が複数の階層で定義されていたら、作業ディレクトリに最も近いものが実行されます。パッケージごとに/auditの中身を変えたい場合は、各パッケージの.claude/workflows/に同名で置けば足ります。
保存時の書き込み先も、この「近さ」で決まります。作業ディレクトリとリポジトリルートの間で、すでにある最も近い.claude/workflows/に書かれ、1つも無ければリポジトリルートに作られます。
プラグインに入れて配る
リポジトリをまたいで配りたい場合や、チームの全員に同じworkflowを届けたい場合は、プラグインに入れます。手順は短く、置き場所を決めるだけです。
workflowをプラグインにして配る流れ
- 1
プラグインのルートにworkflows/を作る
スクリプト(
.js)をworkflows/ディレクトリに置きます。標準のレイアウトでは、skills/やagents/と並ぶ階層です。 - 2
meta.nameを決める
呼び出し名はファイル名ではなく、スクリプトの
meta.nameから決まります。 - 3
プラグインとして読み込む
マーケットプレイスから入れるか、開発中は
--plugin-dirで読み込みます。 - 4
名前空間付きで呼ぶ
/<プラグイン名>:<meta.name>で実行します。
配置の全体像は次のようになります。
acme-tools/
├── .claude-plugin/
│ └── plugin.json
└── workflows/
└── release-audit.jsplugin.jsonの必須キーはnameだけです。acme-toolsという名前のプラグインに、meta.nameがrelease-auditのスクリプトを入れると、呼び出しは次のようになります。
/acme-tools:release-auditプラグインのworkflowには、必ずプラグイン名が前に付きます。これはagentsなど他の部品と同じ規則で、deploy-toolsプラグインのreviewerエージェントがdeploy-tools:reviewerと表示されるのと同じ仕組みです。
名前空間があるので、ローカルの同名と衝突しない
ローカルに.claude/workflows/release-audit.jsがあり、プラグインにもrelease-auditがある場合、呼び出しは/release-auditと/acme-tools:release-auditに分かれます。プロジェクトと個人の同名が衝突したときのような「どちらが勝つか」という問題は、プラグインの配布では起きにくい構造です。
一方で、プラグイン名の付け方には制約があります。名前は空でなく、スペース・@・:・パス区切りを含められません。claude plugin validateは、claude-やanthropic-で始まる名前や、claude-codeそのものの名前をエラーにします。社内用のプラグインにclaude-を頭に付けた名前を付けると、検証で落ちます。
初回の承認プロンプトを減らす
保存済みやプラグインのworkflowを名前で呼ぶと、実行前の承認プロンプトに「Yes, and don't ask again for <name> in <path>」の選択肢が出ます。選ぶと、そのプロジェクトではこのworkflowの承認を省略できます。この選択肢が出るのは、同梱・保存済み・プラグインのworkflowを名前で実行したときです。Claudeがその場で書いたスクリプトには出ません。
配布する側から見ると、利用者は実行のたびに承認プロンプトを受け取り、スクリプトの中身を「View raw script」で確認できます。Ctrl+Gで編集エディタにスクリプトを開くこともできます。配るスクリプトは、読まれる前提で書いたほうが受け入れられやすくなります。
manifestでworkflowsの場所を変えるときの落とし穴
既定のworkflows/以外に置きたいときは、plugin.jsonのworkflowsフィールドで場所を指定します。パス1つ、またはパスの配列で、.jsファイルかディレクトリを書けます。
{
"name": "acme-tools",
"workflows": ["./workflows/", "./extras/audit.js"]
}注意するのは、このフィールドが既定の場所を置き換える点です。workflowsを書くと、既定のworkflows/の自動走査は行われません。既定の場所を残したまま追加したいなら、上の例のように./workflows/を配列に明示します。skillsは逆で、既定のskills/を残したまま追加で読み込みます。部品ごとに「置き換え」と「追加」が分かれているので、workflowsだけ書いて既存のスクリプトが消えた、という事故が起こりえます。
パスにも決まりがあります。
- すべてのパスはプラグインのルートの内側に収まり、実在する必要があります
..を含むパスは読み込まれず、claude plugin validateがPath contains ".." ...のエラーを出します- 存在しないパスは読み込まれず、
/pluginのErrorsタブにpath not foundが表示されます
配る前に、シェルで次のコマンドを実行しておくと、manifestの誤りを手元で拾えます。
claude plugin validate ./acme-tools--strictを付けると、警告も失敗として扱われます。CIに組み込む場合の選択肢です。MCP設定の取りこぼしを検証で見つける方法はclaude plugin validateの記事にあります。
使い分け: ローカル保存かプラグインか
どちらで配るかは、届ける範囲で決まります。
| 状況 | 向く置き場所 |
|---|---|
| 1つのリポジトリの全員で使う | 向く置き場所.claude/workflows/(cloneで共有される) |
| 自分だけが全プロジェクトで使う | 向く置き場所~/.claude/workflows/ |
| パッケージごとに中身を変えたい | 向く置き場所各パッケージの.claude/workflows/に同名で置く(近い方が勝つ) |
| 複数リポジトリ・複数チームに配る | 向く置き場所プラグインのworkflows/ |
プラグインの利点は、配布の単位がプラグインに揃う点です。skillsやagentsと同じマーケットプレイスの流れで、バージョンを管理しながら更新を届けられます。プラグインの仕組み自体はClaude Codeプラグイン完全ガイドにまとめています。開発中に変更を反映する方法はplugin-dirの変更反映の記事が詳しいです。
同時に走らせるエージェント数の上限(既定は最大16)は、配布先の環境にも効きます。大規模なfan-outを配るなら、同時実行数の調整も確認しておくと、配布先で想定外に遅くなる事態を避けられます。
つまずきやすい点
argsがundefinedのまま実行される。引数なしの呼び出しではargsがundefinedになります。args.paths.map(...)のように直接触ると失敗するので、先頭で既定値に落としますDate.now()で例外になる。実行日が欲しいならargsで渡します。再開時に同じ呼び出しを再現するための仕様ですmetaにスプレッドや関数呼び出しを書いて補完から消える。export const metaは先頭の文にし、リテラルだけのオブジェクトにします。そうしないと/の補完から外れます- プラグインの
workflowsを書いたら既存のworkflows/が読まれなくなった。置き換え型のフィールドなので、既定の場所を配列に明示します - 呼び出し名がファイル名と違う。実行名は
meta.nameが決めます。プラグインでは前にプラグイン名:が付きます - 編集したのに反映されない。保存したスクリプトを直したら
/reload-skillsでディレクトリを読み直してから、/<name>を呼びます
まとめ
argsは、保存したworkflowを汎用の道具に変える入口です。省略時にundefinedになる点だけ先頭で処理し、実行日のような変動値もargs経由で受ければ、同じスクリプトを何度でも使い回せます。
配布は、プラグインのworkflows/にスクリプトを置き、meta.nameを決めるところまでです。呼び出しは/プラグイン名:meta.nameになり、ローカルの同名とは名前空間で分かれます。workflowsフィールドを書くときは、既定の場所が置き換えられることだけ覚えておけば、配布した先でスクリプトが消える事態は避けられます。