Official CLI for esa.io.
記事・コメント・カテゴリ・タグ・メンバー・添付ファイルをコマンドラインから操作できます。
端末では読みやすく、パイプでは扱いやすい形で出力し、--json を付ければ指定した
フィールドだけを JSON で取り出せるので、jq などと組み合わせてスクリプトに組み込めます。
- Node.js >= 24.18.0
- npm >= 11.7.0
npm install --ignore-scripts -g @esaio/esa-cliインストールすると esa コマンドが使えます。
esa --version
esa --helpインストールせずに単発で実行することもできます。
npx --ignore-scripts @esaio/esa-cli auth statusOAuth(ブラウザ)でログインします。ブラウザで認可すると、取得したトークンが
OS 標準の資格情報ストア(macOS Keychain / Windows Credential Manager /
Linux Secret Service)に保存されます。いずれも使えない環境では
~/.config/esa-cli に AES-256-GCM で暗号化したファイルへ保存されます。
esa auth login # ブラウザで OAuth 認証してトークンを保存
esa auth status # 現在の認証状態を表示(--json で機械可読に)
esa auth logout # トークンを失効・削除既定では esa CLI の全コマンドが使うスコープを要求します。読み取りだけに絞るなど、
要求するスコープを選びたい場合は -s, --scopes で指定します(スペースまたはカンマ区切り。
環境変数 ESA_OAUTH_SCOPE より優先されます)。
esa auth login --scopes "read:post read:comment" # 読み取りのみ
esa auth login --scopes read:post,write:post # カンマ区切りでも指定できる指定できるスコープは action:resource の形です(read:post / write:post /
delete:post など)。実際に許可されるかはチームの設定にもよります。要求しなかった
スコープが必要なコマンドは失敗するので、その場合は改めて esa auth login します。
許可されたスコープは esa auth status で確認できます。
CI など非対話環境で使う場合は、OAuth ログインの代わりに環境変数 ESA_ACCESS_TOKEN
に Personal Access Token を設定すれば認証できます(PAT v2 を推奨)。
認証後、esa API を叩けます。出力の形式は出力形式を参照してください。
既定では API リクエストにクライアント側のタイムアウトを設けません。無応答で待たせたくない場合は、グローバルオプション --timeout <秒>(正の整数)をコマンド名の前に置いて上限を指定できます(例: esa --timeout 30 post list)。
esa user # 認証ユーザーの情報 (GET /v1/user)
esa team list # 所属チーム一覧 (GET /v1/teams)
esa team list --role owner # 権限で絞り込み (member | owner)
esa post list # 記事一覧 (GET /v1/teams/{team}/posts)
esa post list -q "wip:true" # 検索クエリで絞り込み
esa post list --page 2 --per-page 50 # ページング
esa post list --json number,url # 指定フィールドだけを JSON で
esa post search "keyword" # 記事を検索(list -q と同じエンドポイント)
esa post view 123 # 記事を1件表示(get でも引ける)
esa post backlinks 123 # この記事を参照している記事の一覧
esa post revisions 123 # リビジョン一覧(rollback 用の番号を調べる)記事の作成・更新・追記・アーカイブ・削除もできます。本文(Markdown)は --body でインライン指定するか、--body-file <path>(- で標準入力)で渡します。
# 作成。名前に "/" を含めるとカテゴリになる(--category でも指定可)
esa post create "dev/docs/新しい記事" --body "本文" --tags a,b
cat body.md | esa post create "タイトル" --body-file - # 標準入力から本文
esa post create "タイトル" --ship # WIP を解除して作成(既定は WIP)
esa post update 123 --name "改題" --ship # タイトル変更+Ship(指定した項目のみ更新)
esa post append 123 --body "末尾に追記" # 本文の末尾に追記
esa post prepend 123 --body-file intro.md # 本文の先頭に追記
esa post duplicate 123 # WIP 記事として複製(既定は同じチーム)
esa post duplicate 123 --target-team other # 別チームに複製
esa post rollback 123 5 # リビジョン 5 の内容に戻す(新リビジョンとして記録)
esa post archive 123 # Archived/ カテゴリに移してアーカイブ
esa post delete 123 # 確認プロンプトの後に削除
esa post delete 123 --yes # 確認をスキップ(非対話環境では --yes 必須)記事へのコメントも操作できます。本文(Markdown)は記事と同じく --body / --body-file(- で標準入力)で渡します。
esa comment list # チーム全体のコメント一覧 (GET /v1/teams/{team}/comments)
esa comment list --post 123 # 特定の記事のコメントに絞り込み
esa comment view 456 # コメントを1件表示(get でも引ける)
esa comment view 456 --stargazers # スターしたメンバーも含める
esa comment create 123 --body "コメント本文" # 記事 123 にコメント
cat comment.md | esa comment create 123 --body-file - # 標準入力から本文
esa comment update 456 --body "修正後の本文" # コメントを更新
esa comment create 123 --body "代理投稿" --user alice # 別ユーザーとして投稿(owner 権限)
esa comment delete 456 # 確認プロンプトの後に削除
esa comment delete 456 --yes # 確認をスキップ(非対話環境では --yes 必須)カテゴリ・タグ・メンバーの一覧も取得できます。
esa category list # カテゴリパス一覧(ページング。GET /v1/teams/{team}/categories/paths)
esa category list --all # 全ページを辿って全カテゴリパスをまとめて取得
esa category list --prefix dev/ # 前方一致で絞り込み(--suffix / --match / --exact-match も可)
esa tag list # タグ一覧 (GET /v1/teams/{team}/tags)
esa member list # メンバー一覧 (GET /v1/teams/{team}/members)
esa member list --sort posts_count --order desc # 投稿数の多い順に並べる
esa team stats # チームの統計情報 (GET /v1/teams/{team}/stats)upload でファイルをアップロードし、sign で署名付き URL を取得し、download で実体を
取得します(download は内部で署名してからダウンロードします)。
esa attachment upload ./diagram.png # ファイルをアップロード (POST /v1/teams/{team}/attachments)
esa attachment upload ./diagram.png --name figure.png # ファイル名を指定してアップロード
esa attachment sign /uploads/x.png # 署名付きURLを取得 (GET /v1/teams/{team}/signed_urls)
esa attachment sign /uploads/x.png --expires-in 3600 # 有効期限を1時間に
esa attachment download https://files.esa.io/uploads/x.png -o ./x.png # 実体をファイルに保存
esa attachment download /uploads/x.png > x.png # 標準出力に書き出してリダイレクトupload は stdout に添付の URL を出します。そのまま Markdown( など)に
記載すると、アップロードしたファイルを記事やコメントに埋め込めます。名前やサイズも
必要なら --json url,name,size のように指定してください。
署名の対象はセキュアチーム(セキュア添付)のファイルのみです。非セキュアチームの
添付は公開 URL(img.esa.io)で配信されるため署名は不要で、
esa attachment download <公開URL> で直接取得できます。
esa.io 運営へのフィードバックを送信します。本文は -m, --message でインライン指定するか、
--message-file <path>(- で標準入力)で渡します(--body / --body-file は
それぞれの別名)。送信元クライアント(esa CLI のバージョン・OS など)は自動で添付されます。
esa feedback create -m "改善要望です" # 運営へ送信 (POST /v1/feedbacks)
cat feedback.md | esa feedback create --message-file - # 標準入力から本文
esa feedback create -m "このチームの件で" --team docs # 特定チームに紐づけて送信専用コマンドが用意されていない API パスには、esa api で直接アクセスできます(任意パスへのエスケープハッチ)。認証・ベース URL・トークン更新は既存の仕組みをそのまま使います。レスポンスは JSON で stdout に出ます。
esa api /v1/user # GET(既定)
esa api /v1/teams/{team}/posts -f q=wip:true -f per_page=5 # -f はクエリ、{team} は自動解決
esa api /v1/teams/{team}/comments/456 -X DELETE # メソッドを明示
# 本文は生 JSON を --input(- で標準入力)で渡す。--input があれば既定で POST
echo '{"post":{"name":"Hi","wip":false}}' \
| esa api /v1/teams/{team}/posts --input -
esa api /v1/teams/{team}/comments/456 -X PATCH --input body.json-X, --method: HTTP メソッド。省略時は GET(--inputがあれば POST)-f, --field key=value: クエリパラメータ(繰り返し可)--input <file>: リクエスト本文の JSON(-で標準入力)-H, --header key:value: 追加ヘッダ(繰り返し可)- パス中の
{team}は対象チーム(下記の解決順、--teamでも指定可)に置換されます
JSON は --json を指定したときだけ出ます。 既定では、端末なら人が読みやすい形、パイプなら機械が扱いやすいテキストになります。唯一の例外は esa api で、API のレスポンスをそのまま返すのが役割なので、本文のある応答は常に JSON で出します(204 など本文が無ければ何も出しません)。
post list / post search / post backlinks / post revisions /
comment list / category list / tag list / member list / team list /
attachment sign
| 出力先 | 形式 |
|---|---|
| 端末 | 桁を揃えたテーブル。日時は相対表示(例: 2 hours ago) |
| パイプ | タブ区切り。見出しなし、色なし、日時は ISO 8601 |
値に含まれるタブや改行は、列や行の区切りと紛れないよう空白に均されます。元の値が必要な場合は --json を使ってください。
esa post list # 端末ではテーブル
esa post list | cut -f1,2 # パイプではタブ区切り(列位置で扱える)ページングのある一覧は、端末のときだけ末尾に件数と現在ページを標準エラー出力へ出します。表からは「これで全部なのか1ページ目なのか」が分からないため、続きの有無にかかわらず出します。続きは --page で辿ってください。
$ esa post list --per-page 30
NUMBER TITLE UPDATED
14184 日報/2026/07/26/esa-cli微調整 1 hour ago
...
30 / 6654 件 (page 1/222)
機械的に辿る場合は --json を使ってください。next_page / prev_page / total_count がそのまま入ります。
post view / comment view / user / team stats
端末では見出しと項目を並べます。本文を持つ post view / comment view は続けて本文も出します。本文(Markdown)は描画せずそのまま出すので、コピーして編集元へ貼り戻せます。
$ esa post view 14184
日報/2026/07/26/esa-cli微調整 #14184
- State: Ship
- Category: 日報/2026/07/26
- Tags:
- Updated by: ppworks
- Updated: 1 hour ago
- Revision: 4
- Comments: 0
- URL: https://ware2.esa.io/posts/14184
## Task
- [ ] ...
パイプ時はタブ区切りのキーと値になり、本文の前に -- が入ります。
$ esa post view 14184 | head -3
wip Ship
category 日報/2026/07/26
tags
post create / update / append / prepend / archive / duplicate / rollback、
comment create / update、attachment upload
stdout には URL だけを出し、確認の1行は stderr に回します。URL をそのまま次のコマンドへ渡せます。
$ esa post create "日報/新しい記事" --body "本文"
✓ Created #14187 日報/新しい記事 # stderr
https://ware2.esa.io/posts/14187 # stdout削除(post delete / comment delete)は、新しく辿れるものが生まれないので stdout に何も出さず、✓ の1行だけを stderr に出します。auth refresh も同じですが、こちらは --json を付けたときだけトークンの状態を stdout に出せます。
auth status は状態の報告なので出力先で形を変えず、常に人が読める形を出します(--json で機械可読にできます)。
attachment download は添付データそのものを stdout に流すため、この規則の外です(--output を付けるとファイルに保存し、✓ を stderr に出します)。
リソースを返すコマンドでは、指定したフィールドだけを JSON で出せます。フィールド名を省くと候補が一覧表示されます。返すものが無いコマンド(post delete / comment delete / attachment download / feedback create / config)には付いていません。
esa post list --json number,full_name,url
esa post view 14184 --json body_md
esa post list --json # 指定できるフィールドを表示色は NO_COLOR を設定すると無効になります(パイプ時は元から付きません)。
--json で JSON を stdout に出せて、本文やリクエストボディを標準入力(-)から受け取れるので、jq でパイプして繋げられます。エスケープ(改行やクォート)を jq に任せられるのも利点です。
渡し方は 2 種類あります。
esa post/comment ... --body-file -: 本文テキストだけを受け取る。jq -r(raw 出力)でテキストを組み立てるesa api ... --input -: ボディ JSON 全体を受け取る。jq -n(新規生成)で{post: …}や{comment: …}を組み立てる
# 取得した JSON を jq -r でコメント本文に整形して投稿
esa post view 123 --json tags \
| jq -r '"現在のタグ(\(.tags | length)個): \(.tags | join(", "))"' \
| esa comment create 123 --body-file -
# jq -n でボディ JSON 全体を組み立てて POST(--user なども載せられる)
jq -n --arg body "LGTM :+1:" --arg user alice \
'{comment: {body_md: $body, user: $user}}' \
| esa api /v1/teams/{team}/posts/123/comments --input -
# 取得 → 加工 → 書き戻し(既存タグに1つ追加して PATCH)
esa post view 123 --json tags \
| jq '{post: {tags: (.tags + ["新タグ"])}}' \
| esa api /v1/teams/{team}/posts/123 -X PATCH --input -post / comment 系コマンドはチームを対象に動きます。チームは次の順で解決されます:
--team <name>フラグ- 環境変数
ESA_TEAM - 設定ファイルの既定チーム(
esa config set default-team <name>) - 所属チームが1つだけならそれを自動採用
- 複数所属で未指定ならエラー(
--teamか既定チームの設定を促す)
esa config set default-team docs # 既定チームを設定
esa config get default-team # 設定値を表示
esa config --help # 対応している設定キーの一覧
esa post list --team docs # 明示指定メッセージと --help は日本語(ja)と英語(en)に対応しています。
使用言語は次の順で決まります(判定できない場合は既定の 英語):
- 環境変数
ESA_LANG(en/ja) - 設定ファイルの
language(esa config set language ja) - OS のロケール(
LC_ALL/LC_MESSAGES/LANG。例:ja_JP.UTF-8→ja)
ESA_LANG=ja esa --help # 一時的に日本語で実行
esa config set language ja # 既定を日本語にする
esa config get language # 設定値を表示API リクエストの認証は次の順で選ばれます:
esa auth loginで保存した OAuth トークン(期限が近づくと送信前に自動更新)- 環境変数
ESA_ACCESS_TOKEN - どちらも無ければエラー(
esa auth loginを案内)
Claude Code / Cursor / Gemini CLI / Codex CLI などの AI エージェントから esa CLI を 操作させるためのスキルを esa Skills で配布して います。自然言語で記事の検索・作成・コメントなどを行えます。
各エージェントの marketplace / extension からの導入に加え、横断ツール
npx skills でも導入できます。
npx skills add esaio/esa-skills導入方法の詳細は esa Skills の README を参照してください。
- Authorization Code + PKCE(S256)フロー。client_secret を持たない public app。
- コールバックは
http://127.0.0.1:<ランダムポート>/callback。 - 各エンドポイントはハードコードせず、実行時に discovery
(
/.well-known/oauth-authorization-server, RFC 8414)から取得する。 - トークンの保存先は OS により自動判定(上記)。
| 変数 | 説明 | 既定値 |
|---|---|---|
ESA_OAUTH_SCOPE |
要求するスコープ(スペース区切り)。esa auth login --scopes が優先される |
read:post write:post delete:post read:comment write:comment delete:comment read:category read:tag read:attachment write:attachment read:revision read:member read:team read:user write:feedback |
ESA_OAUTH_CLIENT_ID |
public app の client_id を上書き | 内蔵の公式 public app |
ESA_API_BASE_URL |
API のベース URL。discovery の取得元でもある | https://api.esa.io |
ESA_ACCESS_TOKEN |
OAuth を使わずアクセストークンを直接指定 | (未設定) |
ESA_TEAM |
post 系コマンドの対象チーム(--team の既定) |
(未設定) |
ESA_LANG |
表示言語(en / ja)。最優先で使われる |
OS ロケール→en |
ESA_DEBUG |
1 のときエラーのスタックトレースを表示 |
(未設定) |
リポジトリを clone して開発する場合の手順です。
npm install
# ソースを直接実行(tsx)
npm run dev -- auth status
# ビルド(bin/ に出力)
npm run build
# ビルド後のバイナリを実行
node bin/index.js auth status| Script | 説明 |
|---|---|
npm run dev |
tsx でソースを直接実行 |
npm run build |
tsdown で bin/ にビルド |
npm test |
vitest(watch) |
npm run test:run |
vitest(1 回実行) |
npm run test:coverage |
vitest(カバレッジ付き) |
npm run lint |
biome によるチェック |
npm run lint:fix |
biome による自動修正 |
npm run type-check |
tsc による型チェック |
npm run test:release |
テスト・型チェック・lint をまとめて実行 |
MIT