Claude CodeでREADMEのセットアップ手順を、まっさらなdevcontainerで検証する
新人の初日に詰まる所は、書いた本人の環境では見えません。まっさらなdevcontainerでセットアップ手順を上から通し、足りない前提をREADMEの修正差分にして持ち帰る流れと、シークレットを渡さない隔離の切り方をまとめます。
READMEのセットアップ手順の検証とは、何も入っていないコンテナの中で、READMEに書かれた初回手順だけを上から実行し、止まった箇所を直す作業です。書いた本人の手元にはNode.jsも.envも初期データも揃っているので、手順の抜けは本人には見えません。新人が初日に詰まる箇所を先に潰すために、Claude Codeを「何も知らない新人役」としてコンテナの中で動かします。
本人の環境で通るREADMEが、新人の環境で通らない理由
READMEの手順は、書いた時点の作業環境に引きずられます。インストール済みのランタイム、過去に作った.env、ローカルのDBに入ったままの初期データ、ログイン済みのCLIは、手順に書かなくても存在します。
検証側に求める条件は単純で、リポジトリのコードとREADMEだけが入力になる環境であることです。ホストで別ディレクトリにcloneし直すだけでは、ホストに入っているツールやログイン状態が見えたままになります。cloneし直す検証の進め方はCONTRIBUTING.mdをcloneし直して検証する記事で扱っています。ここではその続きとして、ホストの影響を切り離せるコンテナで通す方法を書きます。
まっさらな検証用コンテナを用意する
検証用の.devcontainer/devcontainer.jsonは、素のベースイメージにClaude Codeの機能だけを足した最小構成にします。プロジェクトのツールチェーンはここに入れません。READMEの手順が「入れてください」と書いているものは、検証中にClaude Codeが手順どおり入れる側に回すためです。
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
}
}この構成はClaude Code用のDev Container Featureをベースイメージに足したものです。末尾の:1.0はfeatureのインストールスクリプトの版で、Claude Codeのリリースを固定するものではありません。Featureは常に最新のClaude Codeを入れます。
ベースイメージにNode.jsが無い場合、Featureは自分でNode.jsを入れます。それが失敗してビルドがFailed to install Node.js and npmで止まったときは、ghcr.io/devcontainers/features/node:1をClaude Codeより上に足して再ビルドします。READMEが前提とするNode.jsの版は、この段階では入れず、検証の中で見つけさせるのが狙いです。
起動は、VS CodeならDev Containers: Rebuild Containerです。エディタを使わない場合はDev Containers CLIでも組めます。
git clone git@example.com:acme/app.git ~/tmp/readme-verify
cd ~/tmp/readme-verify
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . claude検証のたびに、ホスト側のcloneごと消して作り直します。前回のnode_modulesや.envが残っていると、抜けがまた隠れます。
シークレットを渡さないための切り方
検証用コンテナには、本物の認証情報を入れません。コンテナ内でClaude Codeに権限確認を省かせる使い方をすると、悪意のあるリポジトリは、コンテナ内からアクセスできる情報をすべて持ち出せます。そこには~/.claudeに保存されたClaude Codeの認証情報も含まれます。次の4点が、隔離の線引きになります。
- ホストの秘密を掘り込まない:
~/.sshやクラウドの認証情報ファイルをマウントしません。必要なら、リポジトリ単位や短命のトークンを使います - 認証は対話のサインインにする: コンテナ内で
claudeを起動し、ブラウザでサインインします。ブラウザ側のコールバックがコンテナに届かないときは、画面のコードをPaste code here if promptedのところに貼ります - 永続ボリュームを共有しない: ボリュームで
~/.claudeを残せば再サインインは省けますが、検証ごとに環境を捨てる目的とぶつかります。残すなら${devcontainerId}をボリューム名に入れ、プロジェクトごとに分けます .envは中身のない雛形から作らせる:.env.exampleをコピーして値を埋める手順が通るかを見るのが目的です。本物の値は渡しません
claude -pの非対話モードで回したい場合は、--bareを付けると手元の~/.claudeのフックや.mcp.jsonのサーバーを読まずに済みます。ただし--bareはOAuthやキーチェーンを読まないため、ANTHROPIC_API_KEYを環境変数で渡す必要があります。検証専用に作った、用途の限られたキーを使い、本番用のキーは使いません。
外向き通信を絞りたいときは、参照構成のinit-firewall.shが使えます。切り方はinit-firewall.shの記事にまとまっています。コンテナ全体の隔離設計はDevContainerで安全に動かす記事が詳しい解説です。
READMEを上から通して、足りない前提を拾わせる
コンテナの中で起動したClaude Codeに、検証役の指示を渡します。ポイントは、READMEに無い操作をさせないことと、止まったら自力で回避せず報告させることです。
このリポジトリは今cloneしたばかりで、ツールは何も入っていません。
README.md の「セットアップ」の節だけに従って、アプリが起動するところまで
上から順に実行してください。
- README に書かれていないコマンドは実行しない
- エラーで止まったら、手順番号・コマンド・エラー全文を記録して止まる
(自分で回避策を探して先へ進まない)
- 1か所止まったら、READMEの該当行を直す案を出してから、直した手順で再開する
- 最後に、README へ足すべき前提(バージョン・環境変数・初期データ)を一覧にする回避を禁じても、再開前に「直す案を出す」ところまでは進めさせます。毎回止めると、1つの抜けの修正ごとに人間が張り付く必要が出るためです。
たとえば、READMEが次の3行しか書いていないリポジトリを想定します(例です)。
## セットアップ
1. `npm install`
2. `npm run db:migrate`
3. `npm run dev`新人役のClaude Codeは、1行目でNode.jsが無いと止まり、.nvmrcの有無から必要な版を探す提案を出します。2行目ではDBへの接続先が.envに無いと止まり、.env.exampleが存在することを報告します。3行目の前には、開発用の初期データを入れる手順が無いと、画面が空のままです。こうした止まり方は、実際のリポジトリごとに違います。重要なのは、止まった箇所がそのままREADMEの修正箇所になることです。
報告を、READMEの修正差分として持ち帰る
検証セッションの最後に、READMEを直した状態でパッチを書き出させます。コンテナにはGitの認証情報を入れていないので、pushはさせず、ファイルとして出します。ワークスペースはホストのディレクトリがバインドマウントされているため、書き出したファイルはホストからそのまま見えます。
README.md を、今回止まった箇所を踏まえて修正してください。
修正後に `git diff README.md > readme-setup-fix.patch` を実行し、
何を足したかを前提の種類(バージョン / 環境変数 / 初期データ / 実行順)ごとに
1行ずつ報告してください。ホスト側では、パッチの中身を読んでから適用します。
cd ~/work/app
git apply --check ~/tmp/readme-verify/readme-setup-fix.patch
git apply ~/tmp/readme-verify/readme-setup-fix.patch
git diff README.md出来上がるREADMEの差分は、たとえば次のような形になります(例示)。
## セットアップ
-1. `npm install`
-2. `npm run db:migrate`
-3. `npm run dev`
+前提: Node.js 20 以上(`.nvmrc` に記載)
+
+1. `cp .env.example .env`(`DATABASE_URL` は開発用DBの値のままで動く)
+2. `npm install`
+3. `npm run db:migrate`
+4. `npm run db:seed`(画面に一覧を出すための初期データ)
+5. `npm run dev`(`http://localhost:3000` で起動を確認)差分は、バージョン、環境変数、初期データ、実行順の4種類に分けて読むと、直す側の判断が早くなります。バージョンと実行順は事実の訂正なので、そのまま採用できます。環境変数と初期データは、本物の値を書かない形になっているかを人間が見ます。
修正後の手順で、もう一度まっさらな環境から通す
直したら、前回のコンテナとcloneを捨てて、もう一度同じ手順で検証します。報告が「止まった箇所なし」になった回が、終わりの目安です。1回目に出なかった抜けが2回目に出ることがあります。1回目は最初の抜けで止まり、その先の手順がまだ試されていなかったためです。
CIに組み込むなら、検証役の指示をファイルに保存し、claude -pでその指示を読ませる形になります。非対話モードで確認が必要な操作は、何も承認の仕組みが無ければ拒否されます。無人で回す場合は、--permission-prompts noneを付けると、確認が必要になる操作は拒否され、拒否を伝えたうえで実行が続きます。このフラグはClaude Code v2.1.259以降で使えます。--dangerously-skip-permissionsは、コンテナのユーザーが非root(remoteUser)でないと拒否される点にも注意が要ります。
この検証で見えるもの、見えないもの
| 抜けの種類 | まっさらなコンテナで見えるか |
|---|---|
| ランタイムのバージョン | まっさらなコンテナで見えるか見える(ベースイメージに無ければ止まる) |
.envなど環境変数ファイル | まっさらなコンテナで見えるか見える(cloneには含まれない) |
| 初期データ・マイグレーション順 | まっさらなコンテナで見えるか見える(DBが空の状態で試される) |
| Windows・macOS固有の差 | まっさらなコンテナで見えるか見えない(Linuxコンテナで実行するため) |
| 社内レジストリ・VPNへの到達性 | まっさらなコンテナで見えるか見えない(検証用の通信先を絞るほど、止まるのが本物の制約か検証の制約か分かれる) |
| 本物のシークレットの渡し方 | まっさらなコンテナで見えるか見えない(渡さない設計のため) |
下の3行は、READMEに「前提」として書き、検証済みとは書かないでおくのが正確です。
案内文の生成とどう役割が違うか
新人向けの案内文を作る作業は、新人オンボーディングガイドの自動生成と/team-onboardingコマンドが扱っています。それらは文章を作る作業で、書いた手順が実際に通るかは試しません。この記事の流れは、書かれた手順を実行して、結果をREADMEへ戻す作業です。GitHub Codespacesで同じ検証をしたい場合は、Codespacesでの使い方が認証とdevcontainerの設定を説明しています。
検証そのものが止まったときの切り分け
READMEではなく、検証用コンテナの側で止まることもあります。READMEの抜けと混同しないよう、先に環境側の既知の止まり方を知っておくと切り分けが早くなります。
- ビルドが
Failed to install Node.js and npmで止まる: ベースイメージにNode.jsが無く、Featureの自動インストールも失敗した状態です。Node.jsのFeatureを足して再ビルドします。これはREADMEの抜けではなく、検証用コンテナの不備です - サインインを済ませたのに、コンテナに結果が戻らない: エディタのポート転送がlocalhostのコールバックを通していない可能性があります。ブラウザに表示されたコードを、ターミナルの
Paste code here if promptedのところへ貼ります - 再ビルドのたびに初回セットアップが繰り返される:
~/.claudeにボリュームを付けても、CLAUDE_CONFIG_DIRを同じパスに向けていないと、~/.claude.jsonがホームに残って再ビルドで消えます。検証用では捨てる前提なので、問題にならないことのほうが多い現象です - READMEどおりに実行して落ちたのに、Claude Codeが黙って別の手を試した: 「自分で回避しない」の指示が効いていません。指示文を冒頭に置き直し、止まった手順番号を必ず報告させます
環境側の不備は、READMEの修正差分に混ぜません。環境側の不備はdevcontainer.jsonに、READMEの抜けはREADMEに、それぞれ直す先を分けて持ち帰ります。
まとめ
README検証の成否は、コンテナがどれだけまっさらかと、検証役にどこまで回避を許すかで決まります。ホストの秘密を持ち込まず、手順に無い操作を禁じ、止まった箇所を差分として持ち帰るだけで、新人の初日に詰まる所の大半は先に見つかります。コンテナを使っても、悪意のあるリポジトリに対する防御は完全ではないため、検証は信頼できるリポジトリに限ります。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。