Claude Media
Claude Codeのworkflowにargsを渡しプラグインで配布する

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 1030

Claudeはこの数字の並びを構造化データとして渡します。スクリプト側で文字列を分解する必要はなく、配列やオブジェクトのメソッドを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. 1

    プラグインのルートにworkflows/を作る

    スクリプト(.js)をworkflows/ディレクトリに置きます。標準のレイアウトでは、skills/やagents/と並ぶ階層です。

  2. 2

    meta.nameを決める

    呼び出し名はファイル名ではなく、スクリプトのmeta.nameから決まります。

  3. 3

    プラグインとして読み込む

    マーケットプレイスから入れるか、開発中は--plugin-dirで読み込みます。

  4. 4

    名前空間付きで呼ぶ

    /<プラグイン名>:<meta.name>で実行します。

配置の全体像は次のようになります。

acme-tools/
├── .claude-plugin/
│   └── plugin.json
└── workflows/
    └── release-audit.js

plugin.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フィールドを書くときは、既定の場所が置き換えられることだけ覚えておけば、配布した先でスクリプトが消える事態は避けられます。

この記事を共有:XはてブLinkedIn