claude -pを自作アプリのLLMにしたら、勝手にObsidianを読みにいった話
Claude Codeの非対話モード claude -p を自作RAGツールの生成エンジンに繋いだところ、質問と無関係な個人のCLAUDE.mdを読み込んでObsidian Vaultを探しに行きました。どこまで中立化できるのかをA/B/C/Dの4段階で実測し、最終的に使った起動オプションと、Windowsで空文字引数が壊れた原因までまとめています。
目次
はじめに
Claude Codeには、対話画面ではなくコマンド一発で呼ぶ非対話モード claude -p(claude --print の略)があります。
これが地味に便利で、「自作のアプリやスクリプトの生成エンジンとして、APIキーを増やさずにClaude Maxの契約をそのまま使えるのでは」と考える人は、私を含めてそれなりにいると思います。
ただ、実際にやってみて「これは普通のAPIのつもりで使うと危ない」とはっきり感じたので、注意喚起として記事にします。
結論を先に言います。
claude -p は「素のLLM」ではありません。
既定のままだと、あなたの CLAUDE.md(個人的な指示メモ)や、設定済みのMCPサーバー、Claude Codeの組み込みツール(Bashやファイル操作)を丸ごと引き継いだ状態で動きます。
つまり、外部アプリから流し込まれた入力次第で、ホスト上でコマンドやファイル操作が動きうるということです。
OpenAIのAPIのような「文章を返すだけの箱」とは、前提がまるで違います。
この記事は、自前のRAGツールの生成エンジンに claude -p を繋いだときに、実際にこの問題を踏んで切り分けた記録に基づいています。
検証日は2026年6月20日です。
きっかけ:RAGの答えに「Vault にも記録がありませんでした」
ことの発端は、自作アプリ(手元の文書を検索してclaudeに答えさせるRAGツール)の回答に、こんな一文が混ざっていたことでした。
…該当する情報は見つかりませんでした。Vault にも記録がありませんでした。
私は質問の中で「Vault」なんて一言も言っていません。
これは私の個人的な CLAUDE.md(ユーザーグローバルの ~/.claude/CLAUDE.md)に書いてある、Obsidian Vaultを参照するための指示です。
つまり claude -p が、アプリのRAGとは無関係な私の個人設定を勝手に読み込んで、「Vaultを探しに行こうとした」わけです。
調べてみると、既定の claude -p は次のものをそのまま引き継いでいました。
- ユーザーグローバルの
CLAUDE.md(Obsidian VaultやGmail/Calendarへの指示) - 設定済みのMCPサーバー(私の場合はObsidian連携など)
- 組み込みツール(Bash / Read / Write / WebSearch …)とスキルの定義
笑い話で済めばいいのですが、これはセキュリティ的に笑えない話です。
RAGに食わせる文書の中に、悪意ある指示文(プロンプトインジェクション)が紛れていたら、そのバックエンドはホストでBashやファイル操作を実行できる状態にある、ということだからです。
外部入力を食わせる生成エンジンとしては、かなり危険な初期状態です。
どこまで中立化できるか(A/B/C/Dを実際に試した)
「じゃあフラグで無効化できるだろう」と思って、効きそうなオプションを段階的に足しながら、claudeが何を認識しているか(Vaultやツールに言及するか)を直接確かめました。
結果がこれです。

ここから分かったことを順に説明します。
B:--setting-sources "" で CLAUDE.md を切る。
--setting-sources は user, project, local という設定の読み込み元を指定するオプションで、ここに空文字を渡すと「どれも読まない」になります。
これで CLAUDE.md が無効化され、--strict-mcp-config と合わせてMCPも切れます。
Bの段階で、Vault云々の混入は消えました。
C:システムプロンプトを差し替えても、ツールは消えない。
--system-prompt でClaude Code既定のシステムプロンプトをクリーンな指示に置き換えても、claudeは依然として組み込みツールの存在を認識していました。
システムプロンプトの差し替えだけでは不十分、ということです。
D:--disallowedTools は「実行」を止めるだけ。
ツールの実行を禁止しても、ツールの定義そのものはコンテキストに残り続けます。
つまり「呼べはするが拒否される」状態にはできても、「ツールという概念を知らない素のLLM」にはできません。
ここが今回の一番の発見でした。
claude -p は、常にClaude Codeというハーネス(ツール・スキルの定義一式)を背負っていて、完全な「素のLLM」にはできないのです。
できるのは、
- MCPを無効化する
CLAUDE.mdを読み込ませない- ツールの実行を拒否する
- クリーンなシステムプロンプトを与える
という「ここまで」です。
これはOpenAIのAPIに繋ぐ感覚とは根本的に違うので、頭を切り替える必要があります。
実際に使った中立化フラグ
私が最終的に自作シムの既定にした起動オプションがこれです。
claude -p を外部アプリのバックエンドにするなら、最低限これくらいは付けておくべきだと思います。
claude -p --output-format json --model <モデル名> \
--strict-mcp-config \
--setting-sources "" \
--system-prompt "あなたは親切で正確なアシスタントです。外部ツール・ファイル・知識ベースには一切アクセスできません。与えられた情報のみに基づいて簡潔に回答してください。" \
--disallowedTools Bash Read Write Edit MultiEdit Glob Grep WebFetch WebSearch Task NotebookEdit TodoWrite BashOutput KillShell
これを付けると、インラインで文脈を与えたときにVaultなどに触れず、与えた情報だけで正確に答えるようになりました。
うれしい副産物もありました。
システムプロンプトを差し替えると、毎回読み込まれるコンテキスト(cacheRead)が約5万トークンから約8,700トークンに激減したのです。
Claude Code本体の分厚いシステムプロンプトが、こちらの短い指示に置き換わったためです。
中立化はセキュリティ目的でしたが、結果的にオーバーヘッドの削減にもなりました。
Windowsでハマった小さな罠:空文字引数が壊れる
1つ、環境固有の落とし穴を書いておきます。
この中立化を自作プログラムからclaudeを起動して実現しようとすると、Windowsで --setting-sources ""(空文字の引数)が壊れることがあります。
原因は、シェル経由でプロセスを起動する設定(Node.jsなら shell:true)だと、空文字の引数がシェルに食われて消えてしまうことです。
対処は、シェルを介さずに実行ファイルを直接起動することでした。
claudeはwinget経由で入れた実体 claude.exe なので、shell:true を使わずに直接spawnすれば、空文字引数もそのまま渡ります。
docker-credential系などWindowsでありがちな「シェルを噛ませると引数が化ける」あるあるの一種です。
まとめ
いかがでしたか。
今回は、claude -p を自作アプリのバックエンドに使うときの落とし穴を、実際に踏んだ記録としてまとめました。
要点を振り返ると、
claude -pは素のLLMではない。 既定だとCLAUDE.md・MCP・組み込みツールを継承し、外部入力でホスト操作が走りうる。- 中立化はできるが完全ではない。
--strict-mcp-config--setting-sources ""--system-prompt…--disallowedTools… で「MCP除去・CLAUDE.md除去・実行拒否・クリーンなプロンプト」までは行ける。ただしツール定義自体は消せない。 - 副産物としてオーバーヘッドも減る。 システムプロンプト差し替えで
cacheReadが大幅に減った。
claude -p をCIやスクリプト、自作アプリの生成エンジンに使う動きは今後増えると思います。
便利なのは間違いないのですが、「これは普通のLLM APIではなく、ツールを持ったエージェントである」という前提だけは忘れないでください。
特に、外部から来る文書や入力を食わせる用途では、中立化フラグをデフォルトで付ける運用にしておくのがおすすめです。
同じところでヒヤッとする人が少なくなればうれしいです。
なお、ここで触れた「自作シム」の中身(claude -p をOpenAI互換APIに見せかける約150行のNodeプログラム)は別記事に書いています。
フラグの実装まわりが気になった方はそちらもどうぞ。
この記事が誰かの役に立てばうれしいです。