OpenRouter CLIを探すと、実際には2種類の答えに行き着きます。OpenRouter公式のoriコマンドは、既存のコーディングエージェントを設定して起動するためのもの。一方、コミュニティ製クライアントには、単発プロンプト、REPLチャット、JSON出力、幅広いAPIへのアクセスを提供するものがあります。シェルパイプで使いたいだけなら、OpenRouter APIとcurlだけで十分です。
実際のところ「OpenRouter CLI」とは何か
「OpenRouter CLI」という名前の、誰もが使う単一の公式ターミナルクライアントがあるわけではありません。実際には、OpenRouter経由でエージェントを起動する、シェルからAPIを直接呼び出す、llmやaichatのようなサードパーティ製ターミナル環境を使う、という3つのワークフローを指します。
| ターミナルでやりたいこと | まず試すもの | 理由 |
|---|---|---|
| Claude Code、Codex、OpenCodeなど、対応エージェントを動かす | 公式のOri Harness | 既存エージェントを中心に、OAuth、モデル選択、OpenRouter設定を適用できる |
| 単発のプロンプトを送る、標準入力を処理する | curlとjq | 追加のCLI依存がなく、リクエストを完全に制御できる |
| 多数のOpenRouterエンドポイントを調べ、JSONを返す | @aaronjmars/openroutercli | 幅広いコマンド、JSONモード、汎用的なリクエスト機能を備える |
| モデル検索付きのチャットREPLを使う | @letuscode/openrouter-cli | 単発プロンプト、REPLチャット、あいまい検索、設定プロファイルに対応 |
| 複数モデルのプロンプト、バッチ処理、プロンプトチェーンを実行する | orc | プロファイル、テンプレート、バッチ処理、チェーン、コード分析を利用できる |
| ログ、スキーマ、添付ファイル、プラグインを扱う | llm-openrouter | 拡張性の高いllm CLIにOpenRouterのモデルを追加できる |
| チャット、シェル支援、RAG、エージェント、ローカルプロバイダーを組み合わせる | aichat | OpenRouter専用ではなく、より広範なRust製ターミナル環境として使える |
ここで重要なのは、提供元と用途の範囲です。OpenRouterのori連携と@openrouter/cli DevToolsパッケージは公式ですが、どちらも汎用的なopenrouter askクライアントではありません。DevToolsパッケージはSDKのテレメトリビューアーとClaude Codeのステータスラインが中心で、Oriは既存のハーネスを起動するためのものです。
公式ルート:Ori Harnessをインストールして使う
Oriは、対応するコーディングエージェント用ハーネスを設定するOpenRouter公式CLIです。OpenRouterで認証し、選択したモデルを基盤となるエージェントに渡しますが、Claude Code、Codex、OpenCodeなどのハーネス自体を置き換えるものではありません。各エージェント本来のコマンドやフラグもそのまま使えます。
OpenRouterの発表記事とガイドに記載されているコマンドでインストールします。
curl -fsSL https://openrouter.ai/labs/ori/install.sh | bash
続いて認証し、エージェントを起動します。
ori login
ori claude
ori codex
ori opencode
ori hermes
現在のOriドキュメントでは、対応コマンドとしてgrok、pi、prime-agent、dshも挙げられています。ori dshはDeepSeek Harnessの設定までを行い、起動はしません。設定後にdshを実行してください。Ori自体の更新にはori updateを使います。
エージェントを変えずにモデルだけ選ぶ
OriではOpenRouterのモデルIDを指定できます。認識できない引数は、基盤となるハーネスにそのまま渡されます。
ori claude --model anthropic/claude-sonnet-4.6
ori codex --model openai/gpt-5.2 --full-auto
ori opencode --model openrouter/auto
ori hermes --model openrouter/auto
エンドポイントの扱いは、エージェントによって同じではありません。たとえばOpenRouterのClaude Code向けガイドでは、Anthropic互換のベースURLとしてhttps://openrouter.ai/apiを使います。一方、CodexのようなOpenAI互換クライアントではhttps://openrouter.ai/api/v1を使います。こうしたハーネスごとの設定差をある程度吸収するのも、Oriの役割です。
Oriはブラウザー経由のOAuth PKCEを使うため、通常の手順では各エージェントにOpenRouter APIキーを毎回貼り付ける必要はありません。OpenRouterのOri Harnessドキュメントによると、リクエストは通常のOpenRouterの課金とアクティビティレポートに含まれ、Ori専用の別料金は発生しません。推論コストを左右するのは、選択したモデルと基盤となるハーネスです。
Oriは単体のチャットREPLではない
エージェントのツール、ファイル操作、承認フローを使いたいならOriを選びます。プロンプトの送信、構造化レスポンスの取得、あるいはコーディングエージェントを起動せずにシェルパイプを組みたい場合は、curl、ダイレクトクライアント、llm、aichatを使います。
この線引きは重要です。公式の発表資料では、Oriは互換性と設定を担うレイヤーとして説明されています。公式の@openrouter/cliパッケージも混同されやすい存在ですが、現在ドキュメントに記載されているコマンドはopenrouter devtoolsとopenrouter statuslineです。バージョン1.0系では、以前のstart、stop、restart、codeなどのプロキシコマンドが削除されています。
知っておきたいコミュニティ製OpenRouterクライアント
コミュニティ製クライアントは、ターミナル上にどんな操作面を提供するかで性格が変わります。対話的な選択画面が必要なのか、APIを幅広く扱いたいのか、小さなバイナリがよいのか、複数モデルを自動化したいのか、機械処理しやすい出力が必要なのかを先に決めると選びやすくなります。
| クライアント | インストールまたは起動方法 | 得意な用途 | 確認しておきたい制約 |
|---|---|---|---|
@aaronjmars/openroutercli | npm install -g @aaronjmars/openroutercli | OpenRouter APIへの幅広いアクセス、OAuth PKCE、--json、利用状況データ、メディアジョブ、request METHOD path | 非公式。Node.js 20以上が必要。管理系コマンドには管理用キーが必要 |
@letuscode/openrouter-cli | npm i -g @letuscode/openrouter-cli | openrouter ask、repl、あいまいなモデル検索、プロファイル、テンプレート、Markdown/プレーンテキスト出力 | READMEではMVP開発中と説明。Node.js 18.17以上が必要。ライセンスはPolyform Noncommercial 1.0.0 |
orc | npm install -g openrouter-cli | 複数モデルのプロンプト、プロファイル、テンプレート、バッチ処理、プロンプトチェーン、コード分析 | Node.js 22以上が必要。コマンド名はorc。上のスコープ付きクライアントとはプロジェクト名とパッケージ名が異なる |
ort | cargo +nightly-2026-03-25 install --locked ort-openrouter-cli | Linuxターミナルでの高速な利用、プロバイダー選択、標準入力、画像、tmuxを意識した継続、レイテンシーとコストの統計 | Linux/x86_64のみ。READMEにはTLS証明書を検証しないことが明記されている |
llm-openrouter | llm install llm-openrouter | ログ、エイリアス、スキーマ、添付ファイル、ツール、成熟したプラグインベースのワークフロー | OPENROUTER_KEYという環境変数名を使う。モデル一覧は1時間キャッシュされる |
aichat | パッケージマネージャーまたはバイナリでインストール | REPL、シェルアシスタント、RAG、エージェント、MCP、ローカルプロバイダー、ローカルHTTPサーバー | 抽象化の範囲が広い。READMEにはプロバイダーごとの機能表やセキュリティマトリクスはない |
ここで挙げたのはドキュメントに記載された機能であり、性能を比較したベンチマークではありません。
最小構成で堅牢に使う:curlとjq
すでにcurlとjqが入っているなら、OpenRouter APIを直接呼び出す方法が最も小さく、挙動も把握しやすいターミナル構成です。OpenRouterのQuickstartでは、Bearer認証、OpenAI互換の/api/v1/chat/completionsエンドポイント、modelフィールド、messages配列、任意で使えるストリーミングが説明されています。
まず、シェルセッションにキーとモデルを設定します。
export OPENROUTER_API_KEY='sk-or-v1-...'
export OR_MODEL='openai/gpt-4o'
続いて、単発のプロンプトを送ります。
curl -sS https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer ${OPENROUTER_API_KEY}" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg model "$OR_MODEL" \
--arg prompt "Explain Unix pipes in three sentences." \
'{model: $model, messages: [{role: "user", content: $prompt}], stream: false}')" \
| jq -r '.choices[0].message.content // .error.message'
モデルIDをスクリプトごとに直接書くのではなく、環境変数にまとめておくと管理しやすくなります。公式のModels APIでは、id、コンテキスト長、料金、対応パラメーター、プロバイダーの制限、任意のベンチマークメタデータを取得できます。
再利用できるシェル関数にまとめる
以下の関数では、jqにプロンプトのエンコードを任せることで、リクエスト本文をJSONとして安全に扱えます。oraskは引数をプロンプトにし、orpipeは標準入力をすべて1つのプロンプトとして読み込みます。
orask() {
local prompt="$*"
local model="${OR_MODEL:?Set OR_MODEL to an OpenRouter model ID}"
jq -n \
--arg model "$model" \
--arg prompt "$prompt" \
'{model: $model, messages: [{role: "user", content: $prompt}], stream: false}' \
| curl -sS --fail-with-body \
https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer ${OPENROUTER_API_KEY:?Set OPENROUTER_API_KEY}" \
-H "Content-Type: application/json" \
-d @- \
| jq -r '.choices[0].message.content // .error.message // "Unknown OpenRouter error"'
}
orpipe() {
orask "$(cat)"
}
使い方は次のとおりです。
orask "Turn this error message into a likely diagnosis: connection reset by peer"
cat README.md | orpipe
メタデータが必要なスクリプトでは、テキストだけを抜き出さずJSONのまま保持します。
orjson() {
local prompt="$*"
local model="${OR_MODEL:?Set OR_MODEL to an OpenRouter model ID}"
jq -n \
--arg model "$model" \
--arg prompt "$prompt" \
'{model: $model, messages: [{role: "user", content: $prompt}], stream: false}' \
| curl -sS --fail-with-body \
https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer ${OPENROUTER_API_KEY:?Set OPENROUTER_API_KEY}" \
-H "Content-Type: application/json" \
-d @-
}
これならレスポンス内のusageオブジェクトをコスト計算に利用できます。また、APIエラーと、モデルが空のレスポンスを返したケースも区別できます。
コマンドラインから対応モデルを探す
カタログに載っているモデルでも、すべてのリクエストパラメーターに対応しているとは限りません。OpenRouterのModels APIでは、toolsを含むsupported_parametersで絞り込み、料金、コンテキスト、スループット、レイテンシー、人気度、更新時期などで並べ替えられます。
ドキュメント上の並び順で、安い側からツール対応モデルを一覧表示します。
curl -sS -G https://openrouter.ai/api/v1/models \
--data-urlencode 'supported_parameters=tools' \
--data-urlencode 'sort=pricing-low-to-high' \
| jq -r '.data[] | [.id, .context_length, .pricing.prompt, .pricing.completion] | @tsv' \
| head -20
本番スクリプトに組み込む前に、モデルを1つずつ確認しておきましょう。OpenRouterでは、単一モデルの詳細取得先として/api/v1/model/{author}/{slug}を案内しています。
curl -sS \
"https://openrouter.ai/api/v1/model/${OR_MODEL}" \
| jq '.data | {id, context_length, architecture, pricing, supported_parameters, top_provider}'
pricingの値はトークンまたは単位あたりで表されます。生の小数値を、そのまま100万トークンあたりのドル価格として読まないようにしてください。実際にリクエストで何個の入力・出力トークンを消費したかを確認するなら、レスポンスのusageフィールドを見るのが確実です。
シェルパイプでバッチ処理する
実用的なバッチ処理の形は、テキストファイルに1行1プロンプトを置き、結果を1行1JSONオブジェクトとして保存する方法です。以下のスクリプトでは、元のプロンプト、回答、利用量、エラーを記録し、モデルの文章が機械可読な出力に混ざらないようにしています。
prompts.txtを作成します。
Summarize the release notes in one paragraph.
List three security risks in this configuration.
Extract the names and versions from this sentence.
バッチ処理を実行します。
#!/usr/bin/env bash
set -u
: "${OPENROUTER_API_KEY:?Set OPENROUTER_API_KEY}"
: "${OR_MODEL:?Set OR_MODEL}"
while IFS= read -r prompt || [[ -n "$prompt" ]]; do
[[ -z "$prompt" ]] && continue
request=$(jq -n \
--arg model "$OR_MODEL" \
--arg prompt "$prompt" \
'{model: $model, messages: [{role: "user", content: $prompt}], stream: false}')
response=$(curl -sS --fail-with-body \
https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer ${OPENROUTER_API_KEY}" \
-H "Content-Type: application/json" \
-d "$request" || true)
if jq -e '.choices[0].message.content' >/dev/null 2>&1 <<<"$response"; then
jq -c --arg prompt "$prompt" \
'{prompt: $prompt, answer: .choices[0].message.content, usage: (.usage // null)}' \
<<<"$response"
else
jq -c --arg prompt "$prompt" \
'{prompt: $prompt, answer: null, error: (.error.message // "Request failed"), usage: (.usage // null)}' \
<<<"$response"
fi
done < prompts.txt > results.jsonl
このスクリプトは逐次実行します。並列化する場合は、レート制限と予算を確認してからにしましょう。並列リクエストによってコストが急増する可能性があるためです。OpenRouterの料金ページには、無料プランは1日50リクエスト、従量課金では5.5%のプラットフォーム手数料と記載されています。無料モデルを使っても、バッチ処理の容量が無制限になるわけではありません。
llmとaichatの使いどころ
llmとaichatは、OpenRouterに対応した汎用ターミナル環境です。再利用可能なプロンプト、セッション、添付ファイル、ツール、ローカルモデル、過去の作業記録まで扱いたいなら、単純なラッパーよりもこうしたツールが向いています。
llm-openrouter:ログ管理と拡張性を重視する場合
まずllm本体をインストールし、その後でOpenRouterプラグインを追加します。
llm install llm-openrouter
llm keys set openrouter
プラグインが使う環境変数名はOPENROUTER_KEYです。openrouter/anthropic/claude-sonnet-5のような名前でOpenRouterモデルを利用でき、モデル一覧は1時間キャッシュされます。手動で更新するには次のコマンドを実行します。
llm openrouter refresh
llm models list
通常のプロンプトとシェルパイプは、次のように使えます。
llm -m openrouter/anthropic/claude-sonnet-5 \
"Give me five short names for a pet tarantula"
cat app.py | llm -m openrouter/anthropic/claude-sonnet-5 \
-s "Review this code for a security bug"
このプラグインは、スキーマ、添付ファイル、ツール呼び出し、推論オプション、プロバイダールーティング用JSON、OpenRouterのWebツール、キーの確認などに対応しています。生のcurlと自律型コーディングハーネスの中間に位置する存在ですが、モデルキャッシュの更新がライブカタログに追いつかないことがあります。
aichat:より幅広いターミナル環境
aichatはRust製CLIで、OpenRouterに加えて20以上の名前付きプロバイダーとOpenAI互換エンドポイントに対応しています。ドキュメント上の機能範囲は、CMDモード、Chat-REPL、シェル支援、セッション、マクロ、RAG、ファンクションコール、MCPツール、エージェント、チャット・埋め込み・リランキング用エンドポイントを備えたローカルサーバーまで広がります。
OpenRouterの設定では、https://openrouter.ai/api/v1を指すOpenAI互換クライアントとして利用します。プロジェクトの例では、openrouter:<model>形式のモデル名が使われています。ターミナル自体がアプリケーションの操作面になりつつあるなら候補になります。一方、より小さく挙動を確認しやすい構成を求めるなら、curlやllmが扱いやすいでしょう。
CLIの問題に見えるトラブルを切り分ける
OpenRouter CLIの失敗は、シェル、クライアント、選択したモデル、アカウントの境界で起きます。ツールを変更する前に、それぞれの層を分けて確認しましょう。
| 症状 | 最初に確認すること | 可能性の高い層 |
|---|---|---|
401またはキーがないというエラー | クライアントが期待する環境変数名を確認する。llm-openrouterはOPENROUTER_KEY、生APIの例ではOPENROUTER_API_KEYを使う | シェルまたはクライアントの認証 |
| Oriでエージェントは開くが、モデルが拒否される | モデルIDと、基盤となるハーネスのAPI要件を確認する | ハーネスとモデルの互換性 |
| モデル選択画面に目的のモデルがない | llmの1時間キャッシュを更新する。他のハーネスでは/api/v1/modelsと照合する | クライアントのカタログ |
| ツールやスキーマを使うリクエストが失敗する | supported_parameters=toolsで/modelsを絞り込むか、モデルのメタデータを確認する | モデルの機能 |
| 無料リクエストが途中で止まる | 現在の無料プランのリクエスト上限と、そのモデルがまだ無料提供されているかを確認する | アカウントまたはプラットフォームのポリシー |
| 想定よりコストが高い | .usage、選択されたプロバイダー、ルーティング設定、キャッシュの挙動を記録する | リクエストとプロバイダーのルーティング |
OpenCodeとKilo CodeについてのRedditの議論で、u/GrevireDevは次のように書いています。
「Kilo CodeとOpenCodeはどちらも、OpenRouterのモデル一覧を動的に取得せず、ハードコードされた、またはあらかじめ読み込まれたリストを使っている」— r/openrouter
別のOpenRouter関連スレッドでは、u/DrunkenRobotBipBopがコストとキャッシュについて次のように指摘しています。
「OpenRouterでキャッシュをどう扱うかには注意が必要だ。プロバイダーが変わるたびにキャッシュが消え、全額を支払うことになる」— r/openrouter
これらはトラブルシューティングの手がかりとして扱い、課金ルールそのものとみなさないでください。実際のコストは、リクエストの利用量、プロバイダー情報、現在のOpenRouter料金を確認して判断します。
OpenRouter CLIに関するFAQ
ここでは、「openrouter cli」で検索される際によく出てくる設定・選択の疑問を取り上げます。回答では、公式ランチャー、生API、コミュニティ製クライアント、モデルカタログのどの層を確認すべきかを整理します。
公式のOpenRouter CLIはありますか?
あります。OpenRouterは公式CLIとしてoriを案内しています。ただしOriは、既存のコーディングハーネスを起動・設定するためのレイヤーです。OpenRouterの@openrouter/cli npmパッケージは別のDevToolsユーティリティで、@aaronjmars/openroutercliのようなチャット/API向けCLIはコミュニティ製プロジェクトです。
CLIをインストールせずに、ターミナルからOpenRouterを使えますか?
使えます。Bearer認証を付けたcurlリクエストでhttps://openrouter.ai/api/v1/chat/completionsを呼び出せば、単発プロンプトを送信できます。jqを組み合わせれば、テキストだけを抜き出すことも、パイプライン用にJSONを保持することも可能です。
JSONパイプに向いたOpenRouter CLIはどれですか?
小さなスクリプトなら、隠れた挙動が最も少ないのは生のcurlです。より幅広いコマンドを使いたい場合は、@aaronjmars/openroutercliのようにJSONモードをドキュメント化しているクライアントを使うか、llmで必要なレスポンスデータを明示的に保持します。
CLIに表示されるモデルが、OpenRouterのWebサイトより少ないのはなぜですか?
クライアントがカタログをキャッシュしているか、あらかじめ読み込んだモデル一覧を使っている可能性があります。curl https://openrouter.ai/api/v1/modelsの結果と選択画面を照合し、対応していればクライアントのキャッシュを更新してください。表示名ではなく、返された正確なモデルIDを渡すことも重要です。
Oriを使うにはOpenRouter APIキーが必要ですか?
OpenRouterのOriドキュメントによると、通常のログインではOAuth PKCEを使うため、別途APIキーを作成して貼り付ける必要はありません。生のcurl、llm-openrouter、多くのコミュニティ製クライアントでは、引き続きキーまたは各ツール独自の認証設定が必要です。
OpenRouter CLIのワークフローを自動化する前に
モデルを固定する前にライブのModels APIを確認し、モデルIDとレスポンスのusageを記録し、アカウントまたはキー単位の予算を設定しておきましょう。CLIはあくまで入口です。ワークフローの信頼性とコストを左右するのは、OpenRouterのモデル、プロバイダーのルート、コンテキストサイズ、アカウントの制限です。