Claude Media
Claude CodeでDVCのデータ版管理を任せ、dvc pushだけ確認に残す

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点だけです。

  1. md5 の行が変わったか。変わっていれば中身が変わった
  2. path が変わったか。パスの付け替えを示す
  3. 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 repro

CLAUDE.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 を押す判断も、差分の中身を根拠にできます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/permissions
  2. dvc.org/doc/command-reference/push
  3. dvc.org/doc/command-reference/add
この記事を共有:XはてブLinkedIn