Windows 上で動作するローカル推論サーバー(Ollama)を WSL2 経由で安全に参照し、プロジェクトリポジトリを一切汚さない独立した Docker サンドボックス上で自律型 AI エージェント(Hermes Agent)を稼働させるための完全セットアップマニュアルです。
- 初回ウィザードの完全自動スキップ: 極小マスター設定ファイル(
config.yaml)を自動シードすることで、新規プロジェクトや空キャッシュ環境でも対話確認(プロバイダ/URL/モデル入力)なしに即座起動。 - リポジトリへの完全不可侵(Non-intrusive): プロジェクト配下に除外ファイル(
.gitignore)やスクリプトを一切配置せず、Git ツリーを本来の純粋な状態に維持。 - ホスト原本コードの絶対保護: ホスト側のソースディレクトリはコンテナに直接マウントせず、キャッシュ配下の独立した Git ローカルクローン上で AI に作業させる。
- 安全な差分レビュー&マージ: AI の作業完了後、コミットログや差分を吟味した上でワンタッチでホスト側ブランチへマージまたは破棄が可能。
- パーミッション競合の完全排除: コンテナ内部の実行 UID/GID をホスト側の UID/GID へ自動同期させ、ファイルの所有権トラブル(
UID 10000混入)を根絶。
Windows 側の Ollama は、デフォルトではローカル(127.0.0.1)からの接続しか受け付けません。WSL2 や Docker コンテナからのアクセスを通すため、バインドアドレスの変更と Windows Defender ファイアウォールの受信許可を設定します。
- スタートメニューで「環境変数」と検索し、「システム環境変数の編集」を選択。
- 「環境変数」ボタンをクリック。
- システム環境変数(またはユーザー環境変数)に以下を追加:
- 変数名:
OLLAMA_HOST - 変数値:
0.0.0.0:11434
- タスクバーの通知領域(トレイアイコン)にある Ollama アイコンを右クリックし、「Quit Ollama」で完全終了。
- スタートメニューから再度 Ollama を起動。
WSL2 の仮想ネットワークからの通信がブロックされないよう、ポート 11434 の受信規則を追加します。
PowerShell(管理者として実行)で以下を実行:
New-NetFirewallRule -DisplayName "Ollama for WSL" `
-Direction Inbound `
-LocalPort 11434 `
-Protocol TCP `
-Action Allow
スタンドアロンの Docker Engine を WSL2(Ubuntu)内で動かすセットアップ手順です(Docker Desktop で WSL 統合を使用している場合は本ステップは不要です)。
WSL2 ターミナルで実行します。
# 必要パッケージのインストール
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg acl
# Docker公式GPGキーの追加
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# リポジトリの登録
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Dockerのインストール
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 現在のユーザーをdockerグループに追加
sudo usermod -aG docker $USER
※ 反映のため、一度 WSL ターミナルを閉じて入り直すか、newgrp docker を実行してください。
WSL2 ターミナルから Windows ホスト側の Ollama へ通信できるか確認します。
curl -s http://127.0.0.1:11434/api/tags
利用可能なモデル一覧の JSON が返ってくれば、ネットワークとファイアウォール設定は正常です。
スクリプト配置先、共通設定、プロジェクトキャッシュ領域を作成し、ウィザードをスキップするための最小設定を配備します。
mkdir -p ~/.local/bin ~/.config/ai-sandbox ~/.cache/ai-sandbox
※ ~/.local/bin が環境変数 PATH に含まれていない場合は、~/.bashrc に以下を追記してください。
export PATH="$HOME/.local/bin:$PATH"
Hermes Agent のスキーマ(_config_version: 40)に完全適合させ、初回プロンプトをスキップするために必要な最小限の設定です。
cat << 'EOF' > ~/.config/ai-sandbox/config.yaml
_config_version: 40
model:
default: gemma4:26b
provider: custom
base_url: http://localhost:11434/v1
api_key: none
custom_providers:
- name: Ollama Local
base_url: http://localhost:11434/v1
key_env: HERMES_CUSTOM_OLLAMA_API_KEY
model: gemma4:26b
models:
gemma4:26b: {}
models_discovered: true
EOF
プロジェクトディレクトリを汚さず、カレントディレクトリに対して外側から実行できる 2 つのコマンドを作成します。
- プロジェクト原本を直接マウントせず、
~/.cache/ai-sandbox/<プロジェクト>/worktreeに独立した Git ローカルクローンを作成。 - 新規プロジェクト初回起動時、
~/.config/ai-sandbox/config.yamlを自動シードしてプロバイダ設定対話をスキップ。 - コンテナ内ユーザーをホストの UID/GID に自動リマップ(
HERMES_UID/HERMES_GID)し、ファイル所有権トラブルを根絶。
cat << 'EOF' > ~/.local/bin/hermes-run
#!/usr/bin/env bash
set -e
# 1. Git リポジトリ判定
PROJECT_DIR="$(git -C "$(pwd)" rev-parse --show-toplevel 2>/dev/null || true)"
if [ -z "${PROJECT_DIR}" ]; then
echo "❌ エラー: カレントディレクトリ ($(pwd)) は Git リポジトリではありません。"
exit 1
fi
PROJECT_NAME="$(basename "${PROJECT_DIR}")"
AI_BASE_DIR="${HOME}/.cache/ai-sandbox/${PROJECT_NAME}"
AI_DIR="${AI_BASE_DIR}/worktree"
DATA_DIR="${AI_BASE_DIR}/data"
GLOBAL_CONFIG_FILE="${HOME}/.config/ai-sandbox/config.yaml"
BRANCH_NAME="ai-sandbox"
DEFAULT_OLLAMA_URL="http://127.0.0.1:11434"
DEFAULT_MODEL="${HERMES_DEFAULT_MODEL:-gemma4:26b}"
cd "${PROJECT_DIR}"
if ! git rev-parse HEAD >/dev/null 2>&1; then
echo "❌ エラー: コミットが1つも存在しません。初期コミットを作成してください。"
exit 1
fi
# コミッター情報の取得 (AI作業者として識別)
RAW_GIT_NAME="$(git config user.name || true)"
HOST_GIT_NAME="${RAW_GIT_NAME% (AI)}"
HOST_GIT_EMAIL="$(git config user.email || true)"
GIT_AUTHOR_NAME="${HOST_GIT_NAME:-$(whoami)} (AI)"
GIT_AUTHOR_EMAIL="${HOST_GIT_EMAIL:-$(whoami)@$(hostname).local}"
mkdir -p "${DATA_DIR}"
# 2. 最小マスター設定の自動シード(新規プロジェクトでもセットアップを完全回避)
if [ ! -f "${DATA_DIR}/config.yaml" ] && [ -f "${GLOBAL_CONFIG_FILE}" ]; then
cp "${GLOBAL_CONFIG_FILE}" "${DATA_DIR}/config.yaml"
fi
# モデル指定の動的切り替え(環境変数による指定がある場合)
if [ -n "${HERMES_DEFAULT_MODEL}" ] && [ -f "${DATA_DIR}/config.yaml" ]; then
sed -i "s/default: .*/default: ${HERMES_DEFAULT_MODEL}/" "${DATA_DIR}/config.yaml"
fi
# 3. AI作業用クローンの検証と作成
if [ ! -d "${AI_DIR}/.git" ] || [ -f "${AI_DIR}/.git/objects/info/alternates" ]; then
echo "📦 AI用ローカルクローンを作成しています: ${AI_DIR}"
chmod -R u+w "${AI_DIR}" 2>/dev/null || true
rm -rf "${AI_DIR}"
git clone --no-hardlinks "${PROJECT_DIR}" "${AI_DIR}"
cd "${AI_DIR}"
git checkout -B "${BRANCH_NAME}"
git config user.name "${GIT_AUTHOR_NAME}"
git config user.email "${GIT_AUTHOR_EMAIL}"
cd "${PROJECT_DIR}"
else
git -C "${AI_DIR}" config user.name "${GIT_AUTHOR_NAME}"
git -C "${AI_DIR}" config user.email "${GIT_AUTHOR_EMAIL}"
fi
echo "=== Hermes Agent Git Sandbox ==="
echo "Host Repository : ${PROJECT_DIR} (main)"
echo "AI Sandbox Dir : ${AI_DIR} (${BRANCH_NAME})"
echo "Git Committer : ${GIT_AUTHOR_NAME} <${GIT_AUTHOR_EMAIL}>"
echo "Host UID / GID : $(id -u):$(id -g)"
echo "Ollama Endpoint : ${DEFAULT_OLLAMA_URL} (Model: ${DEFAULT_MODEL})"
if ! curl -s "${DEFAULT_OLLAMA_URL}/api/tags" > /dev/null; then
echo "❌ エラー: WindowsホストのOllama (${DEFAULT_OLLAMA_URL}) に接続できません。"
exit 1
fi
echo "✅ Ollama接続確認完了。"
# 4. コンテナ起動
docker run -it --rm \
--name hermes-sandbox \
--network host \
--cap-drop=all \
--cap-add=CHOWN \
--cap-add=SETUID \
--cap-add=SETGID \
--cap-add=DAC_OVERRIDE \
-e HERMES_UID="$(id -u)" \
-e HERMES_GID="$(id -g)" \
-e "GIT_CONFIG_PARAMETERS='safe.directory=*'" \
-v "${DATA_DIR}:/opt/data:rw" \
-v "${AI_DIR}:/opt/data/workspace:rw" \
-w /opt/data/workspace \
nousresearch/hermes-agent:latest \
hermes
EOF
chmod +x ~/.local/bin/hermes-run
AI が作成したコミットや差分を吟味し、安全にホスト側の main ブランチへマージまたは破棄します。
cat << 'EOF' > ~/.local/bin/hermes-review
#!/usr/bin/env bash
set -e
# 1. ホスト側 Git リポジトリ判定
PROJECT_DIR="$(git -C "$(pwd)" rev-parse --show-toplevel 2>/dev/null || true)"
if [ -z "${PROJECT_DIR}" ]; then
echo "❌ エラー: カレントディレクトリ ($(pwd)) は Git リポジトリ配下ではありません。"
exit 1
fi
PROJECT_NAME="$(basename "${PROJECT_DIR}")"
AI_DIR="${HOME}/.cache/ai-sandbox/${PROJECT_NAME}/worktree"
BRANCH_NAME="ai-sandbox"
cd "${PROJECT_DIR}"
# 2. AI作業ディレクトリ及び .git の存在確認
if [ ! -d "${AI_DIR}/.git" ]; then
echo "❌ エラー: AI作業環境 (${AI_DIR}) に有効な Git リポジトリが見つかりません。"
echo "先に 'hermes-run' を実行して作業環境を生成してください。"
exit 1
fi
# 3. AI側の未コミット変更チェック
if ! git -C "${AI_DIR}" diff --quiet 2>/dev/null || [ -n "$(git -C "${AI_DIR}" status --porcelain 2>/dev/null)" ]; then
echo "⚠️ 注意: AI作業環境に未コミットの変更が残っています。"
fi
# 4. AIリポジトリの最新HEADをローカルの ai-sandbox ブランチとして確実に取得
git fetch "${AI_DIR}" HEAD:"${BRANCH_NAME}" --force >/dev/null 2>&1 || true
echo "=== AI作業 (${BRANCH_NAME}) レビュー: ${PROJECT_NAME} ==="
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔍 main..${BRANCH_NAME} のコミットログ:"
LOG_OUTPUT="$(git log --oneline main..${BRANCH_NAME} 2>/dev/null || true)"
if [ -n "${LOG_OUTPUT}" ]; then
echo "${LOG_OUTPUT}"
else
echo " (マージ対象の新しいコミットはありません)"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
show_diff() {
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔍 差分プレビュー (main vs ${BRANCH_NAME})"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
git diff --color=always main..${BRANCH_NAME}
echo ""
}
# レビュー対話ループ
while true; do
read -p "main ブランチにマージしますか? (y/N/d: 差分表示/r: 作業リセット): " ans
case "$ans" in
[dD]*)
show_diff
;;
[yY]*)
if [ -z "${LOG_OUTPUT}" ]; then
echo "マージするコミットがありません。"
exit 0
fi
git merge "${BRANCH_NAME}"
echo "✅ main に正常にマージされました。"
# AI側の作業ツリーも最新の main に同期
cd "${AI_DIR}"
git fetch origin main >/dev/null 2>&1 || true
git reset --hard origin/main 2>/dev/null || true
cd "${PROJECT_DIR}"
echo "🔄 AI作業ツリーを main と同期させました。"
break
;;
[rR]*)
cd "${AI_DIR}"
git fetch origin main >/dev/null 2>&1 || true
git reset --hard origin/main 2>/dev/null || true
git clean -fd 2>/dev/null || true
cd "${PROJECT_DIR}"
git branch -f "${BRANCH_NAME}" main 2>/dev/null || true
echo "🧹 AI作業ブランチの変更を破棄し、main の状態に巻き戻しました。"
break
;;
[nN]*|"")
echo "マージを中断しました。"
exit 0
;;
*)
echo "y (マージ)、n (終了)、d (差分確認)、r (変更破棄) を選んでください。"
;;
esac
done
EOF
chmod +x ~/.local/bin/hermes-review
任意の Git 管理されたプロジェクトディレクトリに移動してコマンドを実行します。
cd ~/projects/my-app
hermes-run
初回起動時・新規プロジェクト・キャッシュ消去後であってもプロバイダ確認ウィザードは表示されず、gemma4:26b がセットされた状態で即座にプロンプト(hermes>)が起動します。
※一時的に別モデルで起動したい場合は、実行時に環境変数で指定します。
HERMES_DEFAULT_MODEL="qwen2.5-coder:32b" hermes-run
プロンプト上で作業を指示します。エージェントは隔離された環境内でファイルの閲覧・編集・テスト実行・Git コミットまでを自律的に行います。
hermes> src/calc.js に割り算関数を追加して、テストをパスすることを確認してコミットしてください。
作業が完了したら exit でコンテナを終了します。
プロジェクトディレクトリでレビューコマンドを実行します。
hermes-review
d(diff): ホスト側のmainと AI 側の変更差分をカラー表示y(yes): 変更を承認し、mainにマージ(AI 側クローンも同期)r(reset): AI 側の変更を全破棄し、mainの最新状態へロールバックn(no): マージせずに終了(作業状態は保持)