Communitygithub.com

FLOH スキル — Azure DevOps エージェントスキル

Claude Code、Codex、Gemini CLI、Cursor などのエージェントクライアント向けのポータブル SKILL.md 機能。Azure DevOps を CLI から操作できる `pharos` ツールを提供します。

FLOH スキル — Azure DevOps エージェントスキル とは?

このスキルは、エージェントが Azure DevOps と直接やり取りできるようにする CLI ツール `pharos` を提供します。ブラウザログインではなく環境変数で認証するため、シームレスな自動化が可能です。`pharos` は、作業項目のクエリ、作成、更新、リンク、添付ファイルの管理、Wiki の操作、コメント、サービスフック、さらには実装計画のツリー生成まで、Azure DevOps の全機能をカバーしています。特に `query` コマンドは、WIQL を直接用いるよりも効率的で、フィルタリングされた作業項目を一度に取得できます。スキルは、`attach` と `image` の違い、安全な更新のための楽観的ロック、削除の不可逆性など、よくある落とし穴を避けるための詳細なドキュメントも備えており、エージェントが自律的に正しい操作を選択できるよう設計されています。Claude Code、Codex、Gemini CLI、Cursor など、SKILL.md をサポートする任意のエージェントプラットフォームで利用可能です。

対応✓Claude Code✓Codex CLI✓Cursor✓Gemini CLI
npx skills add ASNNetworks/floh-skills

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

プレビュー

スキル README より

FLOH スキル — Azure DevOps エージェントスキル preview
chart
diagram

ドキュメント

pharos を使った Azure DevOps の操作

pharos は、ブラウザログインではなく環境変数で認証する、シェルから Azure DevOps を操作できる CLI です。

実行可能なすべての操作を以下に示します。pharos --help を実行して調べないでください — それは数回の呼び出しを消費し、このセクションに同じ情報が記載されています。

whoami                          ADO_PAT の所有者を表示します。@Me はこれに解決されます
types                           --state と --type が受け入れる値を、タイプごとに表示します
query                           どの作業項目か — 自分に割り当てられたもの、スプリント内のもの、
                                特定のタイプのもの、まだオープンなもの。ID ではなく、展開されたアイテムを返します。
task <id>                       1 つの作業項目全体:フィールド、コメント、
                                添付ファイル、タイトル付きの関連、およびリンクされたすべての Wiki ページの
                                内容とディスカッション
                                --children  1 回の呼び出しで EPIC とその配下すべてを取得します。
                                --depth <n>  より深い階層を取得します(最大 5)
                                --compact    ID をフラット化し、ボードキーを削除します
create <type> --title "…"        1 つの作業項目を作成します。--parent は同じパッチで設定します
update <id>                     フィールドを変更します:--state --priority --assignee
                                --title、またはその他は --field Name=value
link <id> --parent <id>         2 つのアイテムを関連付けます。--child --related も可
unlink <id> --parent <id>       --predecessor --successor --duplicate も可
link <id> --wiki-page <path>    Wiki ページを作業項目にリンクします — 作業項目側
wiki links <path>               どの作業項目がページをリンクしているか(ADO には API がありません)
wiki link <path> --item <id>    Wiki 側。--item は繰り返し可能
wiki unlink <path> --item <id>
history <id>                    何が CHANGED したか、フィールドごと、誰がいつ
iterations | areas              日付付きのスプリント、およびエリア
links                           この ORG が持つすべての関連タイプと、
                                どの --flag がそれに到達するか(約 18 個中 6 個)
fields [--type T]               フィールドが ACCEPT するもの — 許可される値
attach <id> <file>              ファイルを作業項目に追加します(添付ファイルリスト)
detach <id> <url-or-guid>       削除します。--yes が必要。または --name <file>
download <item-id|guid|url>     読み戻します。WORK ITEM id と --name <file>、
                                または --all --out <dir>。--out がない場合は書き込みません
image <file>                    テキスト内で使用するための PICTURE をアップロードします。
                                貼り付ける markdown を出力します。attach とは異なります
people [query]                  @メンションできる人、@<guid> 形式で表示
delete <id> --yes               ごみ箱へ移動します(意図的に完全削除はしません)
restore <id>                    復元します
deleted                         ごみ箱にあるものを名前付きで表示します。
                                --top <n> — デフォルトで 50 件返し、
                                実際の総数を "count" として報告します
wiki list | tree | read <path> | write <path> | delete <path>
wiki move <path> <new path>     ページを移動します。サブページも一緒に移動します
wiki rename <path> <new name>   同じ呼び出しですが、リーフのみです。どちらも --yes が必要
wiki duplicate <path> [to]      Azure DevOps にない動詞です。"<path> - コピー N"
wiki image <file>               ページまたはページコメント用の画像です。
                                `image` とは異なるエンドポイントで、名前はユニーク化されます
wiki import <file...>           .md .txt .docx .pdf .rtf .html -> ページ。
                                .pptx は意図的に拒否されます — 以下を参照
                                --under <path> --as <name>
comment list | add | edit | delete   <target> は作業項目 ID または Wiki パス
comment react | unreact | reactors   like dislike heart hooray smile confused
hooks list | check | create | repoint | delete    サービスフックをリアルタイムで。
                                `check` は --hub <url> が必要。`list` は既に使用中の URL を表示
plan <file>                     実装計画 → 作業項目ツリー
setup                           org、project、token → キーチェーン + シェルプロファイル

テキスト入力:--text / --file / --stdin。グローバルオプション:--pretty(人間向け)、 --yes(破壊的操作)、--dry-run(プレビュー)。

ADO_ORG、ADO_PROJECT、ADO_PAT はセットアップ後に環境変数に既に設定されています。 作業を開始する前にこれらを確認しないでください。不足しているものは、終了コード 2 で "kind": "config" として通知されます。これが重要になる唯一のケースです。

作業項目を見つける:pharos query

curl と WIQL エンドポイントに頼らないでください。 このスキルは以前、そのためのレシピを提供していました。 なぜならクエリ動詞がなかったからです。今はそれが存在し、レシピではできなかった部分を実行します。 WIQL は ID のみ を返すため、レシピでは 16 の数字と、それらを意味あるものにするために アイテムごとに 1 回の呼び出しが必要でした。

pharos query --mine                        # 自分に割り当てられており、まだオープンなもの
pharos query --sprint "Sprint 1"          # --sprint current は @currentIteration
pharos query --type Epic --state Doing     # 両方とも繰り返し可能
pharos query --assignee "[email protected]"
pharos query --tag api --all               # --all は完了した作業も含む
pharos query --wiql "SELECT [System.Id] FROM WorkItems WHERE …"   # エスケープハッチ

フラグは AND で結合されます。出力は展開されたアイテム(id、type、title、state、assignee、 iteration、tags、priority、changed)なので、--mine は 1 つのコマンドで完了し、 結果ごとにクエリとフェッチを続ける必要はありません。実際に作業する数個のアイテムについてのみ、 pharos task <id> でフォローアップしてください。

件数を報告する前に、openness フィールドを読んでください。 「12 件オープン」は、 何が完了とカウントされたかを知らなければ無意味です。Azure DevOps ではプロセステンプレートが すべての状態を改名できます。query はプロジェクト自身の状態カテゴリを読み取り、 どの状態を終端とみなしたかを教えます。読み取れなかった場合はその旨を伝え、推測にフォールバックします。 その場合は、明示的に --state を渡す必要があります。assignedTo は、@Me が実際に誰に解決されたかを 示します。共有トークンやサービス トークンの場合、「自分に割り当て」が静かに他人を意味することがあります。

--all は他のすべてのフィルターと組み合わせ可能なので、--mine --all は 自分に何も割り当てられていない ことと 開いているアイテムがない ことを区別する方法です。 裸の pharos query --all も有効で、プロジェクト全体を返します。

--sprint は、名前そのものか fieldPath のいずれかを受け入れ、それらを正規化します。 fieldPath ルールは フィールド値としての System.IterationPath に関するものです。 ただし、名前付きスプリントは UNDER(サブイテレーションを含む)で一致し、 --sprint current は =(完全一致)で一致するため、同じクエリではありません。

--wiql は FROM WorkItemLinks … MODE (MustContain) クエリも受け付け、 同じ方法で ID を展開します。これにより、1 回の呼び出しで特定の関連タイプを持つ すべてのアイテムを見つけることができます。

--wiql を使用する場合、[System.State] NOT IN GROUP 'Completed' と書かないでください。 これはパースされ、200 を返し、すべて に一致します。IN GROUP は作業項目の TYPE カテゴリのみをカバーし、未知のグループはエラーなしで空のセットに解決されます。 測定日:2026-08-05。

作業項目の変更

pharos update 225 --state Doing               # 作業が進んだら状態を変更
pharos update 225 --priority 1 --assignee "[email protected]"
pharos update 225 --field Microsoft.VSTS.Scheduling.RemainingWork=3
pharos attach 225 ./bestsellers.xlsx --comment "数字です"

update は アイテムを読み取り、/rev に対する test 操作で変更を適用します。 そのため、あなたの読み取りと書き込みの間に誰かが書き込んだ場合、あなたの編集が失われるのではなく conflict が発生します。既に設定されている値を設定しようとすると、何も書き込まれず、 その旨が報告されます。意味のない PATCH でも System.Rev は増加し、アイテム上の他のすべての キャッシュされたリビジョンを無効にします。--dry-run は変更前 → 変更後を表示し、 何も書き込みません。--yes はありません。フィールド編集は通常の編集であり、 Azure DevOps はすべてのリビジョンを保持します。

attach はバイトをアップロードし、それを AttachedFile リレーションとしてリンクします — 2 回の呼び出し、1 つのコマンドです。添付ファイルは 不変 です。同じファイルを 2 回添付すると 2 つになり、置換もバージョン管理もありません。detach は 1 つ削除します。--yes が必要で、 位置ではなく ID で添付ファイルを見つけ、Azure DevOps にバイトを残すため、URL を再添付することで 元に戻せます。ファイルに --name <file> で名前を付けるか、GUID を渡します。download と同様に、 同じ名前の 2 つのファイルは、ソート順で先のものを削除するのではなく 拒否 します。

create は --parent をフィールドと同じパッチに配置するため、子が一瞬でも孤立することはありません。 また、update と同じフラグ名を受け付けます。

unlink は推測することを拒否します。遭遇する前に知っておく価値があります。 Azure DevOps は配列内の位置によってリレーションを削除するため、古い読み取りからのインデックスは 別のリンクを切断し、リクエストは成功します。unlink は ID でリレーションを見つけ、 読み取ったリビジョンに対する test 操作で削除します。リレーションが存在しない場合は 終了コード 3 が返されます — これは何も起こらなかったことを意味し、呼び出しが失敗したわけではありません。

delete は ごみ箱 に移動し、--yes が必要です。拒否時には最初にタイトルを引用します。 restore <id> で戻します。フラグは必要ありません。

ここには意図的に完全削除はありません。 これは Azure DevOps が持つ唯一の元に戻せない操作であり、 --yes は渡すことを学習したフラグです。Web UI がそれを担当します。 どうしてもパージする必要がある場合は、フラグを探すのではなく、Web UI に誘導してください。

テキスト内の画像と、それに付随するファイル

これらは 2 つの異なるものであり、間違った方を選ぶのが避けるべきミスです。

pharos attach 225 ./bestsellers.xlsx    # ファイル、添付ファイルリストに表示
pharos image ./screenshot.png           # 画像、テキスト内に配置するため

添付ファイル は AttachedFile リレーションを作成し、作業項目の添付ファイルリストに表示されます。 インライン画像 はリレーションを一切作成しません。測定例 #333 では、説明に貼り付けられた 2 つのスクリーンショットが relations: 0 と attachments: [] を与えました。フィールドテキスト内の ![](…) であり、それ以外には何もありません。 そのため、添付ファイルリストに何も表示されないのは正しい動作です。

したがって、image は markdown の行を出力し、書き込みはあなたに委ねます。

pharos image ./chart.png --pretty
# ![chart](https://dev.azure.com/…/wit/attachments/<guid>?fileName=chart.png)

pharos update 225 --field System.Description="$(cat <<'EOF'
収益は上昇しています。チャートをご覧ください:

![chart](https://dev.azure.com/…/wit/attachments/<guid>?fileName=chart.png)
EOF
)"

Wiki 画像は別のエンドポイントであり、wiki image が必要です。 Wiki は git リポジトリなので、 そこでの添付ファイルは ファイル であり、その 名前 が ID です。2 つ目の image.png をアップロードすると、 最初のものを上書きし、/.attachments/image.png を指すすべてのページの画像が黙って変わります。 wiki image は送信前に名前をユニーク化し、リポジトリ相対のリンクを出力します。

pharos wiki image ./diagram.png --pretty
# ![diagram](/.attachments/diagram-1786046773042.png)

そのパスを使用し、絶対 URL は使用しないでください。wit/attachments URL にリンクするページは、 セッションを持つユーザーのみレンダリングされ、他のユーザーには壊れて表示されます。 同じ markdown がページとページコメントの両方で機能します。

作業項目から添付ファイルを取得する

pharos task <id> は、各ファイルの GUID とともに、何が添付されているかを一覧表示します。 JSON および --pretty 出力の両方に含まれます。その後、名前で 1 回の呼び出しで取得します。

pharos download 41 --name Skills.pptx --out ./Skills.pptx
pharos download 41 --all --out ./attachments      # アイテム上のすべての添付ファイル
pharos download <guid-or-url> --out ./file.bin    # 既に GUID を保持している場合

--out が書き込みを行います。 これがないと、サイズのみが表示され、ファイルは作成されません — 生のバイトを stdout に出力すると、他の動詞が出力する JSON が壊れます。

裸の pharos download 41 は、リストを表示する 使用法エラーです。名前、GUID、サイズが表示されるため、 適切なファイルを選択するために 2 回目の呼び出しは必要ありません。同じ名前の 2 つの添付ファイルは、 推測する代わりに拒否します。添付ファイルは不変であるため、ファイルを 2 回添付すると 2 つになり、 名前は ID ではありません。

detach は同じ --name <file> を受け付けるため、task --pretty を読んだ後に使う動詞は、 表示されたものをそのまま受け入れます。

pharos detach 41 --name Skills.pptx --yes      # --dry-run でプレビュー可能

中身を読むのは あなた自身の 仕事であり、あなたのツール で行います

download はバイトをディスクに保存し、そこで止まります。.docx、.pptx、.xlsx、.pdf を 読み取り可能な形式に変換するのは、あなたの環境の仕事です。

そのために pharos-convert を使用しないでください。 これは wiki import のコンバーターであり、 macOS アプリと共有されているため、両方とも同じファイルから同じ ページ を生成します。 その出力は Wiki ページになるように整形されており、ここで使用すると、読んでいるものが アプリのインポートパスに結びついてしまいます。また、.pptx はまったく読めません。

これが 静かに 失敗する 2 つの方法(両方とも実際の作業項目で測定済み):

  • 間違った場所でツールを確認しました。 システム PATH に対する which markitdown と システム python3 に対する import docx は、そのツールがインストールされているマシンでも 空で返ってきます — スキルごとの venv 内にある場合です。これら 2 つのチェックを実行するエージェントは 「何もない」と結論付け、実際には存在していたツールを迂回します。あなたの エージェントが ツールをどこに保持しているかを確認してから、存在しないと結論付けてください。
  • 空でないテキストは、ドキュメントを読んだ証拠にはなりません。 実際の .pptx が 7 つの断片、 約 90 文字に抽出されました。仕様全体は 2 つの埋め込み PNG に含まれていました。 どんなテキストのみのリーダーでもそのデッキに対して何かを返し、動作したように見えます。 スライドデッキやスキャンされた PDF の場合、ペイロードは通常画像です。それらを抽出して実際に見てください。

まず、PDF をネイティブに読み取れるかどうかを確認してください。読み取れる場合、これは 1 つのコマンドです。

多くのエージェント(Claude Code もその 1 つ)は、PDF を 視覚的に、ページごとに、 人間が見るように読み取ります。これにより、テキストがまったくないスキャンも、OCR ステップなしでカバーされます。 それがあなたの場合、問題全体は 1 つの変換に集約されます。

soffice --headless --convert-to pdf f.docx --outdir ./out    # .pptx、.xlsx も同様
# …

関連スキル