Claude Codeでyqを使ってYAMLを編集する — コメントを残しキーだけ直す
Claude CodeにYAMLのキーだけを書き換えさせる手順です。yqの2系統の見分け方、コメントとアンカーが残るかを差分で確かめる方法、権限とCLAUDE.mdの設定をまとめます。
Claude CodeにYAMLの1キーだけを書き換えさせるなら、ファイル全体を書き直させるより、yqの式で対象のキーを指定させるほうが差分が小さく済みます。ただしyqは同じ名前で別物が2つあり、コメントやアンカーの扱いも異なります。この記事では、どちらのyqが入っているかの確かめ方から、書き換え後に差分でコメントとアンカーの無事を確認する流れ、Claude Codeに守らせる設定までを順に説明します。
先に確かめる: 入っているyqはどちらか
yqという名前のコマンドは、少なくとも2つのプロジェクトが配っています。Claude Codeに式を書かせる前に、手元と実行環境のyqがどちらかを把握しておく必要があります。式の文法が違うため、片方の書き方をもう片方に渡すと失敗するか、意図と違う出力になります。
| 項目 | mikefarah版(Go製) | kislyuk版(Python製) |
|---|---|---|
| 位置づけ | mikefarah版(Go製)jq風の構文を持つ単体のYAML/JSON/XML等のプロセッサ | kislyuk版(Python製)jqのラッパー。YAMLをJSONに変換してjqに渡す |
| 入れ方 | mikefarah版(Go製)brew install yq、snap、バイナリ配布など | kislyuk版(Python製)pip install yq |
| YAMLで出力する | mikefarah版(Go製)既定でYAML | kislyuk版(Python製)-yまたは-Yが必要 |
| 直接更新 | mikefarah版(Go製)-i / --inplace | kislyuk版(Python製)-y / -Yと--in-placeの組み合わせ |
| コメント | mikefarah版(Go製)更新時に保持を試みる | kislyuk版(Python製)-Y(--yaml-roundtrip)でコメントやタグを保持 |
見分け方は--helpの中身です。mikefarah版はevalとeval-allというサブコマンドを持ち、-V, --versionでバージョンを出します。Python版はjqのラッパーです。
which -a yq
yq --version
yq --help | head -20which -a yqで複数の場所が出る場合は、PATHの先頭にあるものが使われます。Homebrewで入れたものとpipで入れたものが混在しているマシンでは、ここで食い違いが見つかることがあります。
この記事の例は、特に断らない限りmikefarah版(v4系の構文)を前提にします。Python版を使う場合の違いは、後半の節で触れます。
1キーだけを書き換える基本形
mikefarah版で値を読むにはyq '.a.b[0].c' file.yaml、ファイルを直接更新するには-iを付けます。READMEの例どおりの形です。
yq '.a.b[0].c' file.yaml
yq -i '.a.b[0].c = "cool"' file.yaml-iは最初に指定したファイルをその場で更新します。Claude Codeに任せる前に、-iなしで標準出力に出して内容を見る癖をつけると、式の誤りが書き込み前に分かります。
READMEは、更新時にYAMLの書式とコメントを保つ機能を挙げています。同時に「空白まわりには問題がある」とも書いており、Known Issuesでは「コメントの位置と空白をできるだけ保つが、すべての場面には対応しない」としています。保たれることを前提にせず、毎回差分で確かめる運用が安全です。
コメントとアンカーが残ったかを差分で確かめる
書き換えの前後を比べるときは、2種類の見方を分けます。テキストとしての差分(コメント・アンカー・並び・インデント)と、意味としての差分(値の違い)です。
テキストの差分を最小にする
Gitで管理されているファイルなら、git diffが最も手軽な確認手段です。1キーを変えたのに複数の行が動いているなら、それは意図しない変更です。
yq -i '.services.web.image = "nginx:1.27"' compose.yaml
git diff --stat compose.yaml
git diff -U0 compose.yaml-U0は前後の文脈行を出さない指定で、変更行だけが見えます。変更が1〜2行に収まっていれば、コメント行やアンカー行は触られていません。コメント行が消えたり位置が動いたりしていれば、差分にそのまま出ます。
Gitに入っていないファイルは、書き換え前にコピーを取ってdiffで比べます。
cp config.yaml /tmp/config.before.yaml
yq -i '.server.port = 8080' config.yaml
diff -u /tmp/config.before.yaml config.yaml意味の差分を見る
アンカー(&name)とエイリアス(*name)は、テキストが変わっても意味が同じなことがあります。意味だけを比べるには、JSONに書き出して比べる方法があります。-oで出力形式を指定でき、explode(.)でアンカーとエイリアスを展開できます。コメントはJSONに残らないため、この比較ではコメントの有無は見えません。コメントの確認はテキスト差分の役割です。
diff <(yq -o=json 'explode(.)' /tmp/config.before.yaml) \
<(yq -o=json 'explode(.)' config.yaml)出力の差が、書き換えを指示したキーの1か所だけなら、意図どおりです。それ以外のキーが動いていたら、アンカーを通じて別の場所に影響が出ています。
アンカーとマージキーを触るときの落とし穴
yqのドキュメントには、アンカーを展開してから更新する例があります。共通設定を&item_valueで定義し、複数の項目が<<: *item_valueで取り込んでいるYAMLで、片方だけ値を変える場合です。
item_value: &item_value
value: true
thingOne:
name: item_1
<<: *item_value
thingTwo:
name: item_2
<<: *item_valueこのthingOneだけvalueをfalseにする式として、ドキュメントは次を挙げています。
yq '.thingOne |= (explode(.) | sort_keys(.)) * {"value": false}' sample.ymlドキュメントの出力例では、thingOneはエイリアスが展開されてvalue: falseを持ち、thingTwoとitem_valueは元のまま残ります。explode(.)を.thingOneの中だけに限定している点が重要です。ファイル全体にexplodeを掛けると、すべてのエイリアスが展開されて、アンカーという共通化の構造が失われます。
Claude Codeに「この項目だけ値を変えて」と頼んだとき、単純な.thingOne.value = falseを書かせると、thingOneにはマージキー経由の値と別にvalueキーが追加されます。この結果が意図どおりかどうかは、アンカー構造の目的次第です。上のように展開を伴う式は、前後の差分を見て判断する価値があります。
なお、yqにはマージアンカーの扱いに関するフラグ--yaml-fix-merge-anchor-to-specがあります。ヘルプの記載では、YAML仕様に合わせてマージアンカーを直す指定で、「2025年後半に既定で有効にする予定」とされています。アンカーを多用する設定を扱う場合は、導入しているyqのバージョンでの既定を確かめてください。
コメントを式で操作する
コメントを足したり読んだりする式も用意されています。ドキュメントの例では、キーに行末コメントを付けるには次のように書きます。
yq '.a line_comment="single"' sample.yml出力はa: cat # singleの形になります。マップや配列に付けたい場合は、値ではなくキーのノードに設定するのが確実で、(.a | key) line_comment="single"と書きます。
また、コメントがどのノードに付いているかが直感と違うことがあります。ドキュメントは「基になるYAMLパーサーは、コメントを意外なノードに割り当てることがある」と説明しています。たとえばhello: # hello-world-commentの行末コメントは、messageではなくhelloというキーに付きます。キー名を変える式を書くときは、このコメントがキーに付属して動くかどうかも差分で見ておくと確実です。
Python版のyqを使う場合
Python版はjqのラッパーで、既定ではYAMLに戻さずJSONを出します。YAMLで出すには-y、タグやスタイル、コメントを保ちたい場合は-Y(--yaml-roundtrip)を使います。READMEには、-yではカスタムタグ(!Refなど)が落ち、-Yならタグ・スタイル・コメントが保たれる例があります。
yq -Y '.server.port = 8080' --in-place config.yaml-Yには注意点があります。READMEによれば、保持用のメタデータを文書内に追加で持たせる仕組みのため、jqのフィルターによっては結果が変わります。たとえば要素数を数えるフィルターは、追加されたメタデータの分だけ数がずれる場合があります。また、ルートが文字列などのスカラーの文書に付いたコメントは、-Yでは保てません。そのようなファイルには--yaml-frontmatter(-F)を使うよう案内されています。
Claude Codeに2つの文法を混ぜて書かせないために、使うほうをCLAUDE.mdに1つ決めて書いておきます。
Claude Codeに守らせる設定
CLAUDE.mdに書く規約
式の書き方と、書き換え後の確認手順を指示にしておくと、毎回の依頼で繰り返さずに済みます。次は、書き方の一例です。
## YAMLの編集
- YAMLの1キーを変えるときは、ファイル全体を書き直さず mikefarah版yq(v4)を使う
- `yq -i '<式>' <ファイル>` の順で書く。式は単一引用符で囲む
- 実行前に `-i` なしで式を標準出力に出して確認する
- 実行後は `git diff -U0 <ファイル>` を実行し、変更行が指示したキーだけか確認する
- コメント行・アンカー(&)・エイリアス(*)の行が差分に出たら、報告して止まる差分を実際に実行させ、出力を読ませることがポイントです。「保たれているはず」と推測させるのではなく、コマンドの結果で判断させます。
書き込み系だけ確認を挟む
読み取りのyqは自由に走らせ、-iを伴う書き込みだけ確認を求める構成にできます。権限ルールでは、askに一致するルールがallowの個別ルールより優先されます。
{
"permissions": {
"allow": ["Bash(yq *)"],
"ask": ["Bash(yq -i *)"]
}
}ルールは*より前の文字列をそのまま照合します。そのため、yq '.a = 1' -i file.yamlのようにフラグを式の後ろに置く書き方は、-iで始まるaskルールに当たらない場合があります。CLAUDE.mdでyq -i '<式>' <ファイル>の順に統一しておくのは、この読み違いを避ける意味もあります。
編集のたびに検査するhook
yqの更新後に構文エラーや想定外の差分を機械的に拾いたいときは、Edit|Writeを対象にしたPostToolUse hookで、編集されたファイルのパスをjqで取り出して検査コマンドへ渡す形が使えます。ドキュメントのフォーマッタ用の例と同じ構造です。YAMLの種類ごとの検証コマンドは、ESPHomeのyaml設定やGitHub Actionsのworkflow検証の記事に具体例があります。
式からファイルや環境変数を読ませない
yqの式には、別のファイルを読み込む操作や、環境変数を参照する操作があります。Claude Codeが書いた式を実行するだけの用途なら、ヘルプのとおり--security-disable-file-ops(ファイル操作の無効化)と--security-disable-env-ops(環境変数操作の無効化)を付けると、式の影響範囲を狭められます。秘密情報を含むYAMLを扱う場合は、読ませる範囲の線引きをSOPSのシークレットの境界と合わせて決めておくと安全です。
差分に出やすい変化と見分け方
| 差分の見え方 | 起きていること | 次の行動 |
|---|---|---|
| 指示したキーの1行だけ変わった | 起きていること想定どおり | 次の行動そのまま採用 |
| コメント行が消えた・動いた | 起きていることコメントの保持に失敗 | 次の行動式を見直す、または手編集に切り替える |
| インデントや空白が全体に変わった | 起きていること出力時の整形が働いた | 次の行動-Iでインデント幅を揃えて再実行 |
| アンカー行が消え、値が重複した | 起きていることexplodeが広範囲に掛かった | 次の行動展開の範囲をキー単位に絞る |
yesやnoの扱いが読み手と食い違う | 起きていることYAML 1.2では真偽値でなく文字列として扱われる | 次の行動真偽値にしたい箇所をtrueかfalseに書く |
最後の行は、READMEの既知の問題に基づきます。yesとnoはYAML 1.2で真偽値の表記から外れており、yqはこの規格を前提にしています。古い設定ファイルでYAML 1.1の書き方に頼っている場合、読み手によって解釈が食い違うことがあります。
まとめ
yqは入っているものがmikefarah版かPython版かで、式も出力の扱いも変わります。まず--helpで見分け、CLAUDE.mdにどちらを使うかを書いておくところから始めると、Claude Codeの式が食い違いません。コメントとアンカーは「保たれる設計だが完全ではない」ものとして、git diff -U0と、explode付きのJSON比較の2段で毎回確かめるのが確実です。書き込みはaskルールで人の確認を挟み、アンカーを含むファイルでは展開の範囲をキー単位に絞ります。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。