append-subagent-system-promptで「Cannot use both」と出る原因と直し方
--append-subagent-system-promptと-file版を同時に渡すとClaude Codeはexit 1で起動しません。メッセージの意味、v2.1.283を境にした挙動の違い、一本化の直し方をまとめます。
claude -p を実行した直後に次の1行が出て、セッションが始まらないことがあります。
Error: Cannot use both --append-subagent-system-prompt and --append-subagent-system-prompt-file. Please use only one.原因は、サブエージェント用のシステムプロンプトを直接指定するフラグと、ファイルから読み込むフラグを同じ起動コマンドで両方渡していることです。Claude Codeは終了コード1で止まります。直し方は、どちらか一方に寄せることです。
このエラーが意味すること
公式のエラーリファレンスでは「Conflict between a system prompt flag and its file form」という節がこのメッセージを扱っています。内容は次の3点です。
- 対象は
--append-subagent-system-promptと--append-subagent-system-prompt-fileの組 - 同時に指定すると、
claudeは終了コード1で終了し、セッションを始めない - 直し方は片方のフラグを外すこと
2つのフラグは、どちらも「全サブエージェントのシステムプロンプトの末尾に文章を足す」ためのものです。違いは文章の渡し方だけです。
2つのフラグの違いは渡し方だけ
--append-subagent-system-prompt
コマンドラインに文字列を書きます。短い一文向きです。v2.1.205以降で使えます。
--append-subagent-system-prompt-file
ファイルの中身を読み込みます。長い指示向きです。v2.1.261以降で使えます。
どちらも非インタラクティブモード(-p)でだけ働きます。ネストしたサブエージェントには届きますが、会話をフォークしたサブエージェントは元の会話のプロンプトを使うため対象外です。
同時指定になりやすい場面
フラグを両方手で打つ人は多くないはずです。実際に起きやすいのは、設定が二重に積み上がる場面です。以下は想定される例で、公式が挙げた原因ではありません。
- 共通のラッパースクリプトが
-file版を常に付けており、呼び出し側がさらに直接指定版を足している - シェルのエイリアスや
CLAUDE_ARGSのような自作の変数に片方が入っていて、そこへもう片方を追記している - CIのジョブ定義で、基本のコマンドと上書き用の引数が別々の場所に書かれている
どの経路でも、最終的に claude へ渡る引数列に両方が残っていれば同じエラーになります。まず実際に実行されるコマンドを展開して確かめるのが近道です。
# シェルスクリプトなら -x で展開後のコマンドを表示する
bash -x ./run-review.sh 2>&1 | grep -- '--append-subagent'出力に2種類のフラグが並んでいれば、どこで足されているかをさかのぼります。
直し方 — 一本化する
直し方は、片方の形を残してもう片方を外すことです。どちらを残すかは、渡したい文章の長さで決めます。
| 状況 | 残すフラグ |
|---|---|
| 一文程度の短い指示 | 残すフラグ--append-subagent-system-prompt |
| 複数行・長い規約・版管理したい文面 | 残すフラグ--append-subagent-system-prompt-file |
| 固定の文面に実行ごとの一文を足したい | 残すフラグファイル版に統合する(下記) |
固定のファイルと実行ごとの文面を併用したい場合、エラーリファレンスは「起動前に文面をファイルへ統合する」ことを案内しています。両方のフラグを渡す代わりに、ファイルを組み立ててから1つだけ渡す形です。
# 例: 固定ルールに実行ごとの一文を足して、1つのファイルにまとめる
{
cat ./subagent-rules.txt
echo
echo "今回の対象は src/billing 配下のみ"
} > /tmp/subagent-prompt.txt
claude -p --append-subagent-system-prompt-file /tmp/subagent-prompt.txt \
"src/billing のテストを見直して"これは案内に沿った組み立て方の一例で、エラーリファレンスの例そのものではありません。一時ファイルの置き場や名前は環境に合わせて変えてください。
直接指定だけで済ませる場合は、こう書きます。フラグ一覧にある例と同じ形です。
claude -p --append-subagent-system-prompt "Cite file paths in every answer" "query"v2.1.283を境に挙動が違うフラグがある
ここで混乱しやすい点があります。メインの会話のシステムプロンプトを扱う --system-prompt と --append-system-prompt には、同じ型のエラーが過去にありました。
| 組み合わせ | v2.1.283より前 | v2.1.283以降 |
|---|---|---|
--system-prompt と --system-prompt-file | v2.1.283より前同じ型のエラーで終了 | v2.1.283以降両方が使われる |
--append-system-prompt と --append-system-prompt-file | v2.1.283より前同じ型のエラーで終了 | v2.1.283以降両方が使われる |
--append-subagent-system-prompt と -file | v2.1.283より前エラーで終了 | v2.1.283以降エラーで終了(エラーリファレンスに現行の挙動として記載) |
変更履歴が挙げているのはメイン側のフラグだけで、サブエージェント用フラグは含まれていません。フラグ一覧の -file 版の説明にも「The two flags can't be combined」とあり、エラーリファレンスの該当節もこの組を現行のエラーとして扱っています。メインで結合できたからといって、サブエージェント用でも通るとは限りません。アップデート後に「前は動いたのに」と感じやすいのはここです。
メイン側で結合した場合の中身は、ファイルの文章が先、空行を挟んで直接指定の文章が続く並びです。コマンドラインで渡す順番はこの並びを変えません。置換(--system-prompt 系)と追記(--append-system-prompt 系)を組み合わせることもできます。置換と追記の使い分けはappend-system-promptとsystem-promptの違いにあります。
古いバージョンで出るメッセージ
v2.1.283より前は、メイン側の組み合わせでも同じ型のエラーが出ました。メッセージには、実際に重ねた組の名前が入ります。たとえば --system-prompt と --system-prompt-file を重ねれば、その2つの名前が出ます。
エラーに別のフラグ名が出ているときは、まず claude --version でバージョンを見てください。v2.1.283以上であれば、メインの2つのフラグでは今は起きない組です。
claude --versionそれでも直らないときの切り分け
フラグを一本化してもエラーが出るなら、次の順に見ます。
エラーが消えないときの確認順
- Qエラーメッセージにサブエージェント用のフラグ名が出ているか?答えが別のフラグの組です。メッセージ内の名前を見て、その組を一本化します答えがはい
次へ進みます。
- Q実行されるコマンドに両方のフラグが残っていないか?答えが引数の展開結果を見直し、ラッパーや環境変数が足している箇所を探します答えがはい
bash -xなどで展開後のコマンドを確認し、重複している側を外します。 - Qファイル版を使うなら、ファイルのパスは正しいか?答えがパスを直します。誤ったパスは別の読み込みエラーになり、この記事のエラーとは原因が違います答えがはい
次へ進みます。
起動できる
1つのフラグだけで claude -p を実行し直します。
パスを疑うときは、まず cat で同じパスが読めるかを確かめるのが確実です。
サブエージェントに渡したい指示の置き場所
そもそも「全サブエージェントへ同じ文章を足したいのか」を先に決めると、フラグの選び方が楽になります。サブエージェントのシステムプロンプトは、定義ファイルの本文(または --agents の prompt)にClaude Codeが付ける環境情報を足したものです。Claude Code本体のシステムプロンプトは入りません。つまり、メイン側の --append-system-prompt は届かず、サブエージェントに届く経路は別に用意されています。
| 渡したい相手 | 使うもの | 補足 |
|---|---|---|
| 全サブエージェントに共通の追記 | 使うもの--append-subagent-system-prompt または -file(どちらか一方) | 補足-p のときだけ有効。ネストしたサブエージェントにも届く |
| 特定のサブエージェントだけ | 使うもの定義ファイルの本文 | 補足~/.claude/agents/ か .claude/agents/ に置く |
| その実行だけの使い捨て定義 | 使うもの--agents のJSON | 補足ディスクに保存されない。prompt が本文に当たる |
| メインの会話だけ | 使うもの--append-system-prompt | 補足サブエージェントには届かない |
定義ファイルの書き方はSub-agents完全ガイドにあります。
--agents は、スクリプトやCIでその場限りのサブエージェントを作るときに向きます。
claude -p --agents '{"reviewer":{"description":"Reviews code","prompt":"You are a code reviewer"}}' \
"src/billing を見直して"JSONが大きいときは、-p と組み合わせてファイルのパスも渡せます(--agents ./agents.json、v2.1.281以降)。対話セッションではファイルのパスは拒否されます。この場合、共通の追記フラグを使わなくても、prompt に共通の文面を書けばその定義には効きます。逆に、定義が複数あって全員に同じ一文を足したいなら、prompt を全部書き換えるより共通の追記フラグのほうが差分が小さく済みます。
--agents に切り替えたあとに出やすい別のエラー
共通の追記フラグから --agents に寄せると、起動時に別の検査が走ります。JSONが不正だと Error: Invalid --agents configuration: に続けて原因が出て、同じく終了コード1で止まります。名前が - で始まる定義も弾かれます。
この検査はv2.1.242で入りました。それより前は、不正な値でもセッションが始まっていたため、古い環境から更新した直後に初めて止まることがあります。--resume や --continue で再開するときは、インラインJSONは検査されず、ファイルから読んだ値だけが毎回検査されます。--safe-mode を付けると --agents 自体が無視されます。
ファイルのパスを渡したつもりで --agents file not found: <path> が出たら、パスの誤りに加えて、インラインJSONをシェルが崩した可能性もあります。{ で始まらず、JSONとしても読めない値は、パスとして扱われるためです。対話セッションでファイルのパスを渡した場合は、-p を付けるかインラインJSONに直します。
共通の追記フラグで足りないとき
サブエージェントの最初の文脈には、システムプロンプトのほかに、メインが書く依頼文、CLAUDE.mdの各階層、gitの状態のスナップショットが入ります。ルールの多くはCLAUDE.mdで届くので、追記フラグに頼らなくて済むことがあります。逆に、出力スタイルとメインの自動メモリは非フォークのサブエージェントに届きません。
特定のルールをどうしても届けたい場面では、メインに依頼文の中で言い直させる手もあります。たとえば「vendor/ は見ない」のような指示です。CLAUDE.mdを読ませたくないサブエージェントには、定義に omitClaudeMd: true(v2.1.271以降)を書けます。--agents のJSONでも同じ項目を使えます。
メインとサブエージェントを取り違えると、エラーは出なくても指示が効きません。-p を付けずに対話で試すときも、共通の追記フラグは何も起こさない点に注意してください。
まとめ
ラッパーで共通の文面を配るなら、最初からファイル版に寄せ、実行ごとの差分もファイルを組み立てて渡す形にそろえておくと、この衝突は構造的に起きません。メイン側で結合が使えるようになった今も、サブエージェント側はそのまま1本化が前提です。