はじめに
Claude CodeやCursorなどのAIエージェントを本格的に活用しようとすると、ある壁にぶつかります。YOLOモードの問題です。
# YOLOモード(自動承認)
claude --dangerously-skip-permissions
AIエージェントを効率的に使うには、毎回の確認ダイアログをスキップしたいですよね。しかし本番環境でこれを実行すると危険です。ファイルの誤削除、意図しないgit操作、設定ファイルの破壊など、AIの試行錯誤が予期せぬ変更を引き起こす可能性があります。
ではsandbox環境を用意すれば解決するのでしょうか。実はそう単純ではありません。
本記事では、AIエージェントを安全に「野放し」にできる開発環境の設計について、具体的なコードとともに解説します。
対象者
この記事は下記のような人を対象にしています。
- Claude CodeやCursorなどのAIエージェントを効率的に使いたい人
- DevContainerでsandbox環境を構築したい人
- Git Worktreeの代替手段を探している人
従来開発とAIエージェント開発の違い
まず、なぜこの問題が発生するのかを整理します。
| 観点 | 従来の開発 | AIエージェント活用開発 |
|---|---|---|
| コマンド実行 | 人間が1つずつ実行 | AIが自動で多数実行 |
| 変更の適用 | 手動で確認してから適用 | AIに「任せて」大量に生成 |
| 失敗のリスク | 人間が管理 | AIの試行錯誤による予期せぬ変更 |
人間が操作する前提で設計された開発環境では、AIエージェントの行動パターンに対応できません。
DevContainerでsandbox化すると起きる問題
「ならDevContainerでsandbox化すればよいのでは」と考えるかもしれません。しかし、ここで別の問題が発生します。Gitが使えなくなるのです。
┌─────────────────────────────────────────────────────────┐
│ ホストマシン │
│ └─ /project/.git ←── ここにGitの実体がある │
└─────────────────────────────────────────────────────────┘
│
│ マウント(bindまたはvolume)
▼
┌─────────────────────────────────────────────────────────┐
│ DevContainer (sandbox) │
│ └─ /workspaces/project │
│ └─ .git → ホストの.gitを参照しようとするが... │
│ ❌ Git Worktreeは親の.gitを参照できない │
│ ❌ 相対パスがコンテナ内で解決できない │
└─────────────────────────────────────────────────────────┘
Git Worktreeを使おうとしても、sandbox内からは親の.gitを参照できません。相対パスの解決がコンテナ境界を越えられないためです。
Git Worktreeが使えない理由
Git Worktreeは軽量で便利ですが、sandbox環境との相性が悪いです。
| 項目 | Git Worktree | 独立クローン |
|---|---|---|
| .gitの場所 | 親リポジトリを参照 | 自己完結 |
| sandbox内での動作 | ❌ 参照不可 | ✅ 動作する |
| ディスク使用量 | 少ない | 多い(フルクローン) |
| ブランチ制約 | 同一ブランチ不可 | 制約なし |
Worktreeは.gitファイルが親リポジトリへのポインタになっています。この仕組みがコンテナ境界では機能しません。
解決策:独立クローン + DevContainer
この問題を解決するのが独立クローンパターンです。
┌─────────────────────────────────────────────────────────────────┐
│ ホストマシン │
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────────┐│
│ │ baseリポジトリ │ │ 独立クローン ││
│ │ /project │◄──►│ /project_dw_feature-xxx ││
│ │ │相互 │ ││
│ │ remote: │push │ remote: ││
│ │ ├─ origin (GitHub) │pull │ ├─ origin (GitHub) ││
│ │ └─ dw_feature-xxx ──────┼────►│ └─ base ────────────────────┼┤
│ │ (独立クローンへ) │ │ (baseリポジトリへ) ││
│ └─────────────────────────┘ └─────────────────────────────┘│
│ │ │
│ │ bindマウント │
│ ▼ │
│ ┌─────────────────────────────┐│
│ │ DevContainer (sandbox) ││
│ │ ││
│ │ ✅ Git使用可能 ││
│ │ ✅ AIが自由に操作可能 ││
│ │ ✅ baseへの影響なし ││
│ └─────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
ポイントは双方向のremote設定にあります。単なるクローンではなく、baseリポジトリと独立クローンが相互にpush/pullできる構成にします。
# baseリポジトリ側
git remote add dw_feature-xxx ../project_dw_feature-xxx
# 独立クローン側
git remote add base ../project
これにより、sandbox内での作業結果をbaseに簡単に取り込めます。GitHub経由せずローカルで高速にやり取りできるのも利点ですね。
独立クローン作成の実装
命名規則
{リポジトリ名}_dw_{ブランチ名サニタイズ}
例:
my-project_dw_feature-authmy-project_dw_fix-bug-123
作成スクリプト
下記のスクリプトを使用します。
#!/bin/bash
# 汎用的な独立クローン作成スクリプト
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
PARENT_DIR=$(dirname "$REPO_ROOT")
BRANCH="$1" # 引数でブランチ指定
# サニタイズ(特殊文字を-に置換)
SANITIZED=$(echo "$BRANCH" | tr -c '[:alnum:]-_' '-' | sed 's/^-*//;s/-*$//')
# パス生成
DW_PATH="${PARENT_DIR}/${REPO_NAME}_dw_${SANITIZED}"
REMOTE_NAME="dw_${SANITIZED}"
# 1. クローン作成
git clone --branch "$BRANCH" "$REPO_ROOT" "$DW_PATH"
# 2. 独立クローン側: originをGitHubに、baseをbaseリポジトリに
cd "$DW_PATH"
git remote set-url origin "$(git -C "$REPO_ROOT" remote get-url origin)"
git remote add base "../${REPO_NAME}"
# 3. push受け入れ設定(重要!)
git config receive.denyCurrentBranch updateInstead
# 4. baseリポジトリ側: 独立クローンへのremoteを追加
cd "$REPO_ROOT"
git remote add "$REMOTE_NAME" "../${REPO_NAME}_dw_${SANITIZED}"
重要な設定:receive.denyCurrentBranch updateInstead
git config receive.denyCurrentBranch updateInstead
通常、チェックアウト中のブランチへのpushは拒否されます。この設定により、pushを受け入れてワーキングツリーも自動更新されるようになります。baseから独立クローンへpushすると即座に反映されます。
追加ファイルの処理
環境変数やIDE設定の扱いを環境変数で制御できるようにします。
# 環境変数で制御
DEV_WORKSPACE_SYMLINKS=".env" # シンボリックリンク
DEV_WORKSPACE_COPIES=".idea" # コピー
# シンボリックリンク(環境変数等、共有したいもの)
ln -s "../${REPO_NAME}/.env" "${DW_PATH}/.env"
# コピー(IDE設定等、独立させたいもの)
cp -R ".idea" "${DW_PATH}/.idea"
DevContainer設定
devcontainer.json
下記の設定を使用します。
{
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/${localWorkspaceFolderBasename},type=bind,consistency=delegated",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"mounts": [
"source=devcontainer-${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
"source=devcontainer-npm-cache,target=/home/node/.npm,type=volume",
"source=devcontainer-claude-config,target=/home/node/.claude,type=volume"
],
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"postCreateCommand": "zsh .devcontainer/script/postCreate.sh",
"postStartCommand": "zsh .devcontainer/script/postStart.sh"
}
node_modulesをvolumeにすることでI/Oが高速化されます。Claude Code設定も永続化しておくと再設定の手間が省けますね。
Dockerfile
FROM mcr.microsoft.com/devcontainers/typescript-node:22-bookworm
# DevContainer識別用環境変数
ENV DEVCONTAINER=true
# 非rootユーザーで実行(セキュリティ)
USER node
# Claude Codeのインストール
RUN curl -fsSL https://claude.ai/install.sh | bash
初期化スクリプト
postCreate.sh(コンテナ作成時に1回実行)
#!/bin/bash
# Gitのsafe.directory設定
git config --global --add safe.directory '/workspaces/*'
postStart.sh(コンテナ起動時に毎回実行)
#!/bin/bash
# 依存パッケージのインストール
pnpm install --frozen-lockfile
# Claude Codeの更新
claude update
使用フロー
AIエージェントをsandboxで実行
# 1. 独立クローンを作成
./script/devWorkspace/add.sh feature-xxx
# → 独立クローンが作成される
# 2. 独立クローン内でDevContainerを起動し、YOLOモードで実行
cd ../project_dw_feature-xxx
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . claude --dangerously-skip-permissions
# 3. AIに作業させる
# (AI内で)「この機能を実装して」等
# 4. 作業結果をbaseに取り込み
# baseリポジトリで
git fetch dw_feature-xxx
git merge dw_feature-xxx/feature-xxx
人間の並列開発
# 機能Aの環境
./script/devWorkspace/add.sh feature/auth
cd ../project_dw_feature-auth
code . # エディタ1で開発
# 機能Bの環境(別ターミナルで)
./script/devWorkspace/add.sh feature/payment
cd ../project_dw_feature-payment
code . # エディタ2で開発
# 独立しているので干渉なし
メリットまとめ
AIエージェント開発における利点
| 利点 | 説明 |
|---|---|
| 安全なYOLOモード | sandbox内なので本番に影響なし |
| Git操作可能 | commit、branch作成、push全て可能 |
| 試行錯誤の自由 | 失敗しても独立クローンを削除するだけ |
| 成果の取り込み | remote設定で簡単にbaseへマージ |
開発体験の向上
| 利点 | 説明 |
|---|---|
| 環境の完全分離 | node_modules、設定ファイル等が独立 |
| 並列開発 | 複数機能を同時に別環境で開発 |
| クリーンな状態 | 各環境が独立しているので汚れない |
| 再現性 | DevContainerで環境を完全に再現 |
Git Worktreeとの比較
| 観点 | Git Worktree | 独立クローン |
|---|---|---|
| ディスク使用量 | ◎ 少ない | △ 多い |
| sandbox対応 | ✗ 不可 | ◎ 完全対応 |
| 環境の独立性 | △ .gitを共有 | ◎ 完全独立 |
| セットアップ | ◎ 簡単 | △ スクリプト必要 |
| 同一ブランチ | ✗ 不可 | ◎ 可能 |
導入に必要なもの
必要ツール
- Docker Desktop または Rancher Desktop
- DevContainer CLI (
npm install -g @devcontainers/cli) - fzf(オプション、ブランチ選択UI)
最小構成ファイル
project/
├── .devcontainer/
│ ├── devcontainer.json
│ ├── Dockerfile
│ └── script/
│ ├── postCreate.sh
│ └── postStart.sh
└── script/
└── devWorkspace/
├── add.sh
├── list.sh
└── remove.sh
注意点とTips
ディスク使用量
独立クローンはフルクローンなので、大きいリポジトリでは注意が必要です。
# shallow cloneで軽量化する場合
git clone --depth 1 --branch "$BRANCH" "$REPO_ROOT" "$DW_PATH"
削除時の安全対策
# パスの検証(誤削除防止)
if [[ "$path" != *"_dw_"* ]]; then
echo "独立クローン形式のパスではありません"
exit 1
fi
# ゴミ箱に移動(完全削除ではなく)
trash "$path" # またはmv "$path" ~/.Trash/
おわりに
本記事では、AIエージェントを安全に「野放し」にできる開発環境の構築方法についてまとめました。
- DevContainerだけではGitが使えない問題がある
- Git Worktreeはsandbox環境と相性が悪い
- 独立クローン + 双方向remote設定で解決できる
receive.denyCurrentBranch updateInsteadが技術的な鍵
この構成により、AIエージェントが自由にgit操作を行いながら、本番環境への影響を完全に分離できます。
プロジェクト名・ブランチ名を変数化すれば、任意のプロジェクトに適用可能です。AIエージェント時代の開発環境として、ぜひ検討してみてください。この記事がどなたかの参考になれば幸いです。