Claude CodeでDVCのデータ版管理を任せ、dvc pushだけ確認に残す
DVCで学習データを版管理する作業をClaude Codeに任せつつ、外部ストレージへ書き込むdvc pushは確認に残すpermissions設定と、.dvcファイルの差分の読み方を説明します。
Claude CodeでDVCのデータ版管理を任せ、dvc pushだけ確認に残す
DVC(Data Version Control)は、大きなデータセットやモデルをGitの外に置き、.dvc という小さなポインタファイルだけをGitで管理するツールです。Claude Codeに任せやすいのは、dvc add でデータを追跡し、dvc repro でパイプラインを再実行する作業です。一方で dvc push は、外部ストレージ(S3、SSH、GCSなど)にデータを書き込みます。
この記事では、dvc add と dvc repro は確認なしで流し、dvc push は毎回確認に残す設定を作ります。あわせて、抜け道になりやすい書き方と、.dvc ファイルの差分の読み方も扱います。
Claude Codeに任せる範囲を、DVCのコマンドで分ける
DVCのコマンドは、影響の及ぶ先で3つに分けられます。
| 区分 | コマンド | 書き換わる場所 |
|---|---|---|
| ローカルだけ | コマンドdvc add、dvc repro、dvc status、dvc diff | 書き換わる場所作業ツリー、キャッシュ、.dvc や dvc.lock |
| 外部を読む | コマンドdvc pull、dvc fetch | 書き換わる場所リモートから取り込み、作業ツリーに反映 |
| 外部を書く | コマンドdvc push、dvc add --to-remote、dvc gc --cloud | 書き換わる場所リモートストレージ |
dvc push は、キャッシュにあるデータのうちリモートに無いものをアップロードします。dvc pull はその逆で、リモートからキャッシュへ落とし、作業ツリーにリンクまたはコピーします。どちらも .dvc や dvc.yaml は動かさないので、コードの共有には従来どおり git push と git pull が要ります。
任せる線引きは次の考え方になります。
- ローカルで完結し、やり直せる操作はallowに置く
- 外部ストレージへの書き込みはaskに置き、人が押す
- 取り消せない削除はdenyに置く
dvc gc に --cloud を付けると、使われていないデータをリモートからも消します。この削除は、同じデータを持つ別のリモートか手動バックアップが無い限り元に戻りません。
settings.jsonに書く許可ルール
プロジェクトの .claude/settings.json に、次のルールを置きます。
{
"permissions": {
"allow": [
"Bash(dvc add *)",
"Bash(dvc repro *)",
"Bash(dvc status *)",
"Bash(dvc diff *)",
"Bash(git add *)",
"Bash(git commit *)"
],
"ask": [
"Bash(dvc push *)",
"Bash(dvc pull *)",
"Bash(dvc add *--to-remote*)",
"Bash(dvc repro *--pull*)",
"Bash(dvc remote *)",
"Bash(git push *)"
],
"deny": [
"Bash(dvc gc *)"
]
}
}評価の順序はdeny、ask、allowです。最初に一致したものが結果を決め、ルールの具体性は順序を変えません。つまり dvc add * をallowに置いても、dvc add data --to-remote はaskの Bash(dvc add *--to-remote*) が先に拾います。広いallowの中から例外だけをaskに抜く書き方が、そのまま通用します。
末尾が * のルールは、引数なしのコマンドにも一致します。Bash(dvc push *) は dvc push にも dvc push -r storage data.dvc にも効きます。スペースを入れずに Bash(dvc push*) と書くと、dvc pushx のような別の語まで巻き込みます。
git add と git commit をallowに入れたのは、.dvc ファイルをコミットする流れを止めないためです。git push はaskに残します。
dvc pullをaskに置く理由は、環境で変わる
サンプルでは dvc pull をaskにしました。リモートからの読み取りは外部を壊しませんが、作業ツリーのデータが入れ替わります。転送量に課金されるストレージや、認証情報を使うリモートでは、確認を残す意味があります。ローカルのMinIOのように読み取りが無料で安全な環境なら、allowに移してかまいません。
見落としやすい3つの経路
Bash(dvc repro *) をallowに置いただけでは足りません。dvc repro --pull は、足りないデータをリモートからダウンロードします。サンプルの Bash(dvc repro *--pull*) は、この経路をaskに戻すためのものです。
dvc add の --to-remote は、対象を作業ツリーにもキャッシュにも置かず、リモートへ直接転送します。dvc add をallowするなら、このフラグは必ずaskと対にします。
3つ目は dvc install です。DVCには、git push の後に dvc push を自動で走らせるGitフックがあります。フック経由のpushは、Claudeが書いたコマンド文に dvc push が現れません。フックを入れているリポジトリでは、git push をaskにしておく意味が大きくなります。
ルールが効かない書き方がある
Bashルールが照合するのは、Claudeが書いたコマンド文です。Bash(git push *) を例にすると、git push origin main は止まりますが、git -C . push origin main は一致しません。同じ性質が dvc push にも及びます。/usr/bin/dvc push や sh -c 'dvc push' といった書き方は、ルールの語順と違うため拾えない場合があります。
起動の前に付くラッパーの扱いにも注意が要ります。timeout、time、nice、nohup、stdbuf などは剥がされてから照合されます。一方、direnv exec、devbox run、mise exec、npx、docker exec のような環境ランナーは、この一覧に入っていません。Python環境を uv run や poetry run で包んでいるなら、Bash(devbox run npm test) の例と同様に、ランナーと内側のコマンドを両方書いた個別ルールが必要です。
複合コマンドは分解されます。dvc add data && dvc push のように && でつないでも、各サブコマンドが独立に照合され、askに当たる部分があればそこで確認が出ます。
ルールの追加と確認は、/permissions のダイアログからもできます。操作の全体像はClaude Codeの/permissionsコマンドで権限ルールとauto mode拒否を管理するにまとめています。
作業の流れ:追跡からコミットまで
設定を入れたら、データ更新の流れをCLAUDE.mdに書いておきます。
## DVC
- データは dvc add で追跡し、生成された .dvc ファイルと .gitignore の変更を git add する
- コミット前に dvc diff と git diff -- '*.dvc' を実行し、変わった .dvc の一覧を報告する
- dvc push / dvc pull / dvc gc は実行しない。必要なときは、実行してほしいコマンドを提示して止まるこの規約が効くのは、ルールの手前でClaude自身が止まれるからです。CLAUDE.mdはClaudeの振る舞いを方向づけるだけで、強制力はsettings.jsonのルール側にあります。両方を置くと、確認ダイアログが出る回数が減り、出たときの意味も明確になります。
データの更新は、次のコマンド列になります。
dvc add data/images
git add data/images.dvc data/.gitignore
dvc diff
git commit -m "update: 画像データセットを追加"dvc add は追跡対象を .gitignore に追加します。Gitにデータ本体が入らないので、コミットされるのは .dvc ファイルだけです。ここまでは確認なしで進み、dvc push に来たところで止まります。
押す前に dvc status -c を実行すると、キャッシュにあってリモートに無いファイルが一覧できます。dvc push が何をアップロードするかを、実行前に確かめる手段です。このコマンドもallowに入れてよい内容ですが、リモートへ問い合わせるため、環境によっては認証が走ります。
.dvcファイルの差分の読み方
.dvc ファイルはYAMLで、中身は追跡対象のハッシュとパスだけです。単一ファイルなら次の形になります。
outs:
- md5: 6137cde4893c59f76f005a8123d8e8e6
path: data.xmlディレクトリを追跡すると、ハッシュの末尾に .dir が付きます。
outs:
- md5: ce57450aa92ab8f2b957c24b0df73edc.dir
path: pics.dir は、キャッシュ内のJSONファイルを指します。そのJSONが、ディレクトリ内の各ファイルを指します。ディレクトリ内の画像は1枚ずつ .dvc を持ちません。トップに1つの .dvc があるだけです。
git diff で読めるのは、次の3点だけです。
md5の行が変わったか。変わっていれば中身が変わったpathが変わったか。パスの付け替えを示すoutsの項目が増減したか
md5 の行が変わっても、どのファイルがどう変わったかは .dvc からは分かりません。それを見る道具が dvc diff です。
dvc diff HEAD^出力は追加・削除・変更・リネームしたファイルの一覧と、末尾の件数サマリ(files summary: 1 added, 0 deleted, 0 modified の形)です。dvc diff は git diff のような行単位の比較をしません。DVCが追跡するデータは、構造化テキストの場合もバイナリの場合もあるためです。Gitの管理外で dvc init --no-scm を使ったプロジェクトでは、dvc diff は効果を持ちません。
差分を報告させるときは、Claudeに git diff -- '*.dvc' と dvc diff の両方の出力を並べさせます。前者でハッシュが動いたことを確認し、後者で何が増減したかを確認する二段の読み方です。ハッシュだけが変わり、dvc diff の一覧に意図しないファイルが混じっているなら、dvc push を押す前に気づけます。
dvc reproをallowに置く前に知っておくこと
dvc repro は dvc.yaml のステージを依存関係の順に実行し、dvc.lock と .dvc の内容を必要に応じて更新します。ローカルで完結するのでallowに向きますが、2つの挙動を知っておくと安心です。
1つ目は、ステージの出力が実行前に作業ツリーから削除されることです。dvc.yaml で persist: true を指定したものは例外です。作業ツリーで出力ファイルを手で編集していた場合、その変更は実行時に消えます。
2つ目は、依存も出力も持たないステージです。このステージは常に「変更あり」と扱われ、dvc repro のたびに実行されます。中身が外部への通信や書き込みなら、DVCの外で副作用が起きます。実行前に dvc repro --dry で何が走るかを確認させる運用にすると、allowのまま安全側に寄せられます。
dvc repro --dry
dvc reproCLAUDE.mdに「dvc repro の前に --dry で実行対象を報告する」と1行足すだけで、この確認は習慣になります。--dry は Bash(dvc repro *) に一致するので、追加のルールは要りません。
つまずきやすい点
- allowに
Bash(dvc *)と書かない。dvc pushもdvc gcも許可されます。askに置いた個別ルールが先に評価されるので止まる場面もありますが、denyとaskに書き漏らした新しいサブコマンドは通ります。サブコマンドごとに列挙するほうが、後から追跡しやすい構成です dvc addの再実行で.dvcが書き換わる。データを動かさずにdvc addを再実行すると、ハッシュが同じなら差分は出ません。差分が出たなら、中身が変わったという意味です- リモートの設定ファイルも書き換わる。
dvc remoteはリモートの定義を変えます。接続先を差し替えられる操作なので、サンプルではaskに置きました
データ管理の周辺では、実験の記録を扱うClaude CodeでMLflowの実験管理を組み込む — run比較までや、外部コマンドの上書きオプションを拒否するClaude Codeでffmpegを使う — 権限設計とffprobeで変換結果を検証するが、同じ権限設計の別の適用例になります。
まとめ
線を引く位置は、DVCのコマンドがどこに書き込むかです。ローカルの dvc add と dvc repro はallow、リモートに出る dvc push と、--to-remote、--pull のフラグ付きはask、リモートの削除につながる dvc gc はdenyに置きます。askとallowの評価順を使えば、広いallowから例外だけを抜けます。
最初の1歩は、上のJSONを .claude/settings.json に入れ、データを1つ dvc add させることです。コミット前に dvc diff を読む習慣が付けば、dvc push を押す判断も、差分の中身を根拠にできます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。