mcpField
H
Headmesh Agent Sandbox

Headmesh Agent Sandbox

リモート
headmesh.dev開発ツール11 日前に更新
リポジトリ公式サイト

Headmesh Agent Sandbox について

Headmesh Agent Sandbox は、実ファイルや依存関係、Git、プライベートサービスを扱うエージェント向けの永続 Docker サンドボックスです。Go デーモンとホスト CLI により、MCP アクセス、永続セッション、通常モードと YOLO モードを提供します。

主な機能

  1. 01永続 Docker サンドボックス
  2. 02コマンド実行とファイル編集
  3. 03Git と tmux セッション管理
  4. 04スコープ付きトークンと監査
  5. 05通常モードと YOLO モード

活用シーン

  1. 01コーディングエージェントで実際のプロジェクトファイルを操作
  2. 02再接続後もエージェントセッションを維持
  3. 03サンドボックスのツールを MCP クライアントに公開

MCP 対応

`headmesh-sandboxd` デーモンは、コマンド実行、セッション操作、ファイルシステム操作などのサンドボックスツールを MCP 経由で公開します。Unix ソケットと HTTP に対応し、HTTP では bearer トークン認証を使用します。

設定

リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。

エンドポイントhttps://{sandbox_host}/mcp
インストールコマンドをコピー
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。

すべてのエンドポイント
Streamable HTTPhttps://{sandbox_host}/mcp認証が必要

ツール

詳細

Headmesh エージェント用サンドボックス

ASUS 上で稼働し、Aaryn の Headscale テールネットに独自のタグ付きノードとして参加する、永続的な Docker コンテナです。クラウドエージェントは、実際のファイル、実際の依存関係、プライベートサービスを利用できます。エージェントは、次の複数の入口からアクセスします。

  • MCP サーバー headmesh-sandboxd;
  • Claude のセルフホスト型ランナーと Claude Remote Control;
  • Tailscale SSH 経由の Codex;
  • OpenAI Secure MCP Tunnel;
  • ホストから Agents API を通じて制御する codex exec-server。

計画書の §6 と §7(docs/plan.md)を実装しています。

パス内容
image/ubuntu:26.04(ダイジェストで固定)をベースにしたマルチステージ Dockerfile、s6-overlay サービス、git フック、ガイドラインのテンプレート、docker-bake.hcl、container-structure-test、hadolint の設定
compose/regular プロファイルと yolo プロファイルを備えた compose.yaml(CLI に埋め込み)
config/sandbox.example.toml とその JSON Schema(sandbox.schema.json)
sandboxd/MCP デーモン:ツール、セッション(tmux)、認証、監査、ステータス
cmd/headmesh-sandboxd/デーモンのバイナリと、コンテナ内ヘルパー(hm)
cmd/headmesh-sandbox/ホスト CLI
host/イグレスファイアウォールと restic バックアップのユニット。Aaryn が sudo を使ってインストールします。host/README.md を参照してください
tests/acceptance/5 項目のチェック用ハーネス、再作成の追加チェック、prompt.md
tests/e2e/稼働中のコンテナに対するライブテスト
docs/container-contract.md(イメージ、Compose、CLI、デーモン間のインターフェース)と ADR

これは独立した Go モジュール github.com/headmesh-dev/headmesh/sandbox であり、ルートの go.work に含まれています。ここで go test -race ./... を実行してください。

検証済みの内容(2026-10-27)

以下はすべて、テールネットに参加せずにローカルで実行しました。

  • go test -race ./... が成功します。実際の tmux と git を使った統合テスト、およびプロセス内の sandboxd に対するハーネスも含まれます。リポジトリの設定で golangci-lint run を実行した結果、問題は 0 件です。
  • docker buildx bake -f sandbox/image/docker-bake.hcl sandbox-local により headmesh-sandbox:dev(2.39 GB)がビルドされます。hadolint の指摘はなく、container-structure-test は 43/43 件成功します。
  • headmesh-sandbox up は §6.3 の強化設定で Compose 経由でコンテナを起動します。tailscaled がログアウト状態でも正常と報告され、未設定の入口は待機状態になり、その理由を示します。status と doctor は動作します。
  • 稼働中のコンテナに対して、tools/list(31 個のツール)、exec、session_*、fs_* は Unix ソケット経由と bearer token を使った HTTP 経由の両方で成功します。プロトコルの 2 つのバージョン、すなわちステートレスな 2026-07-28 と、ハンドシェイクを行う 2025-11-25 がどちらも動作します(tests/e2e)。
  • 受け入れテストのルート mcp とルート ssh(コンテナ内で実行。フェーズ 1 の後、新しいプロセスからフェーズ 2 を実行):
    • チェック 1~3 は成功します:uid 1000、Ubuntu 26.04、ファイルのハッシュがホスト側のコピーと一致し、依存関係が実行されます。
    • チェック 5 の動作は成功します:再接続後もセッションが実行中で、マーカーが存在します。
    • ノードがまだ参加していないため、チェック 4 と 5 は引き続き失敗します。
  • acceptance recreate は 5/5 件成功します:home と ~/.bash_history が保持され、起動時の ID が変わり、古いセッションは lost (container restarted at …) と報告されます。テールネット ID の項目は参加していないためスキップされました。
  • YOLO:
    • 新しいバックアップ記録がなければ拒否されます。
    • バックアップ記録があれば、/host をサブツリーごとに読み取り専用にして起動します。root でも書き込みは失敗し、伝播方式は private、/etc/shadow の読み取り結果は 0 バイト、~/.ssh はマスクされ、ホストの tailscaled の状態と Docker のデータルートは含まれません。
    • TTL に達すると監査エントリを記録して自動停止し、次回の up は Regular になります。

スパイクの結果は docs/adr/spike-t0{1,2,3,7,8}-*.md と docs/adr/spike-t16-*.md に記載されています。その他の実装上の決定事項は docs/adr/0001-sandbox-implementation-decisions.md に記載されています。

対応が必要なセキュリティ上の指摘

  1. 登録前に送信トラフィック用ファイアウォールをインストールしてください(host/firewall、以下の手順 1)。Docker ブリッジコンテナは、そうしないとホストが到達できるあらゆる場所にアクセスできます。LAN、自身のサービス、さらにホスト自体が tailnet ノードの場合はその tailnet も対象です。ホスト固有の指摘事項は内部運用メモに記載されています。
  2. YOLO からはホストが読み取り専用で見えます。ファイル権限が許す範囲で、データディレクトリや証明書も含まれます。エージェントは uid 1000 で実行されるため、root のみがアクセスできるファイルは読み取れませんが、コンテナ内の tailscaled と runner は root で実行されます。機密情報はすべて [mounts] extra_denylist に追加してください。拒否リストに登録したサブツリーは /host に含まれません。
  3. サンドボックス内では UV_PROJECT_ENVIRONMENT=.venv-sandbox が設定されるため、uv がプロジェクトのホスト側 .venv をコンテナのパスに対して再構築することはありません。各プロジェクトの .gitignore に .venv-sandbox(または .venv*)が含まれていることを確認してください。

クイックスタート(ホスト)

cd /mnt/storage/projects/headmesh/sandbox
go build -o ~/.local/bin/headmesh-sandbox ./cmd/headmesh-sandbox
docker buildx bake -f image/docker-bake.hcl sandbox-local     # headmesh-sandbox:dev
headmesh-sandbox init                                          # /mnt/storage/headmesh/sandbox
$EDITOR /mnt/storage/headmesh/sandbox/config/sandbox.toml      # image = "headmesh-sandbox:dev" until GHCR has a release
headmesh-sandbox scan-secrets                                  # review, then --apply
headmesh-sandbox token create claude-code-mac > ~/.config/headmesh/sandbox-token
headmesh-sandbox render --diff
headmesh-sandbox up
headmesh-sandbox status
headmesh-sandbox doctor

その他のコマンド:down [--yolo|--all]、recreate、logs [service|audit] [-f]、shell [--root]、attach(tmux でエージェントを監視)、backup、token list|revoke、acceptance run|verify|report|recreate、および agent run --provider openai。

シークレットは /mnt/storage/headmesh/sandbox/secrets/<name> に、モード 0600 で保存します。ファイルが空の場合、その入口は無効です。シークレットはマウントされません。CLI は環境変数を通じて docker compose に渡し、Compose がそれぞれをコンテナ内に root:root 0400 としてコピーします(スパイク T-1)。

Aaryn の対応が必要な手順

各手順には sudo、本番環境への変更、またはアカウントが必要です。いずれもまだ実施されていません。

1. ホスト(sudo)
  • 送信トラフィック用ファイアウォールとホームバックアップユニットをインストールし、初回バックアップを実行します。正確なコマンドは host/README.md に記載されています。headmesh-sandbox doctor で結果を確認してください。egress firewall ✓ と home backup ✓ と表示されるはずです。
  • restic をインストールします(計画 §5.3)。スリープターゲットはすでにマスクされています(doctor が確認します)。
2. Headscale ポリシー(本番 ACL の変更;メンテナンス時間帯)

計画 §5.2 と §6.6 を踏まえた手順です。Xcelsior リポジトリの api/infra/headscale/policy.hujson にタグと許可ルールを追加します。最初に headscale policy check を実行してください。ポリシーの tests がすべて成功する必要があります。

"tagOwners": { "tag:sandbox": ["group:admin"], "tag:sandbox-yolo": ["group:admin"] },
"grants": [
  // Regular: only the private services you list (keep sandbox.toml [mode.regular] reach in sync).
  { "src": ["tag:sandbox"], "dst": ["tower-server"], "ip": ["tcp:11434"] },
  { "src": ["tag:sandbox-yolo"], "dst": ["*"], "ip": ["*"] },
],
"ssh": [
  { "action": "accept", "src": ["xcelsior@"], "dst": ["tag:sandbox", "tag:sandbox-yolo"], "users": ["agent"] },
],

xcelsior@ は Aaryn 自身のデバイスのみを指す必要があります。プロバイダーホストにタグが付与されれば、これは保証されます(§5.2)。

3. ノードを登録する
# On prod-hetzner: a single-use pre-auth key that carries the tag (Headscale 0.29.6).
sudo headscale preauthkeys create --user <owner> --tags tag:sandbox --expiration 1h
# On the ASUS: store it and recreate.
install -m 600 /dev/stdin /mnt/storage/headmesh/sandbox/secrets/ts_authkey   # paste, then Ctrl-D
headmesh-sandbox recreate
headmesh-sandbox status        # tailnet Running, node asus-sandbox, dns-check ok
  • キーだけでタグが設定されます。タグ付きキーでは Headscale に拒否されるため、--advertise-tags は渡しません(スパイク T-8)。代わりに tailscale-up が登録済みタグを TS_TAGS と照合します。
  • 状態が存在しない間だけ、tailscale up はキーを使って実行されます。そのため、以降の再起動で再認証が行われることはありません。タグ付きノードは有効期限がありません。登録後はキーファイルを消去してください。
  • YOLO は独立したノード(asus-sandbox-yolo、tag:sandbox-yolo)で、専用の状態ディレクトリを使用します。初回の up --yolo 時に、tag:sandbox-yolo キーを使って同じ方法で登録してください。
4. エントリーポイント

テイルネット経由の MCP(Claude Code、任意の MCP クライアント):

headmesh-sandbox token create claude-code-mac          # prints hms_… once
claude mcp add --transport http sandbox http://asus-sandbox.mesh.xcelsior.ca:8780/mcp \
  --header "Authorization: Bearer hms_…"

トークンにはスコープ(sandbox:read|exec|write|admin)が設定され、取り消すことができます。 headmesh-sandbox token revoke claude-code-mac を実行すると、数秒以内に反映されます。 OAuth(RFC 9728 のメタデータはすでに /.well-known/oauth-protected-resource/mcp で提供されています)は、M3 で Headmesh 認可サーバーとともに導入されます。

Claude のセルフホストランナー(plan §7.1):

  1. claude.ai の管理者設定で「Allow self-hosted environments」をオンにします。
  2. 環境シークレットを secrets/claude_env_secret に保存し、 secrets/github_token にきめ細かな PAT を入力します。
  3. [entrypoints.claude_runner] enabled = true を設定し、headmesh-sandbox up を実行します。

ランナーは root として実行されます。各セッションは claude-session を経由し、 setpriv で agent に切り替わるため、セッションからシークレットを読み取ることはできません(spike T-1)。 チェックアウトフックは [repos] でマッピングされたリポジトリを、main 上の共有作業コピーにリンクします。 ランナーがセッションの環境に何を設定するかについては、実機での確認がまだ保留中です。

Claude Remote Control(plan §7.2):

  1. [entrypoints.claude_rc] enabled = true を設定し、headmesh-sandbox up を実行します。
  2. headmesh-sandbox shell を実行してから、claude auth login(claude.ai に完全ログイン)を実行し、 /home/agent を信頼して、claude remote-control を一度実行して 「Enable Remote Control? y」に回答します。
  3. headmesh-sandbox recreate を実行します。

DISABLE_TELEMETRY、DO_NOT_TRACK、 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC、DISABLE_GROWTHBOOK は設定しないでください。いずれかが設定されていると Remote Control は起動しません(spike T-2)。このログイン後、TTY がなくても自動で再起動するかどうかは、まだ確認が必要です。

Tailscale SSH 経由の Codex(plan §7.3):

  • 手順 2 の ssh ルールが必要です。
  • Codex デスクトップで、リモートホスト [email protected] を追加します。
  • スモークテスト:ssh [email protected] codex --version。
  • Tailscale SSH はコンテナ内で動作します(spike T-3)。Codex デスクトップ自体は未テストです。

OpenAI Secure MCP Tunnel(plan §7.4):

  1. Platform で Tunnel と Read+Use のみを許可するランタイムキーを作成します。キーを secrets/openai_tunnel_key に、ID を [entrypoints.openai_tunnel] tunnel_id に設定します。enabled = true を設定してから、up を実行します。
  2. Tunnel ルート用のトークンを作成します: headmesh-sandbox token create chatgpt-tunnel --route tunnel(実行時間 ≤ 110 秒、 レスポンス ≤ 8 MiB)。
  3. ChatGPT で、Plugins → Add custom MCP server → Connection: Tunnel を選び、上記のトークンを使ってベアラー認証を設定します。

Agents API 経由の Codex exec-server(plan §7.6):

  1. アプリケーションキーはサンドボックスの外に保存します。CLI はあなたのユーザーとして実行されるため、 secrets/openai_app_key を使用します(0600。マウントされず、YOLO の /host からも除外されています)。読み取り可能であれば、/etc/headmesh/openai-app.key も使用できます。

  2. 環境キー(Agents タブで、その他すべての権限は None)を secrets/openai_env_key に保存します。

  3. 次を実行します:

    headmesh-sandbox agent run --provider openai --repo xcelsior \
      --prompt-file sandbox/tests/acceptance/prompt.md
    

エグゼキューターはリポジトリ内で agent として実行され、 --linux-sandbox-pid-namespace inherit を指定し、コンテナ内ではフルアクセスを持ちます。Codex の bubblewrap サンドボックスは、コンテナの seccomp および AppArmor プロファイルの下では実行できないため、境界となるのはコンテナです(spike T-16)。環境キーは stdin 経由でエグゼキューターに渡され、トランスクリプトは logs/agent-runs/<session>.jsonl に出力されます。

5. 受け入れ確認(plan §6.15)
headmesh-sandbox acceptance run --route mcp \
  --url http://asus-sandbox.mesh.xcelsior.ca:8780/mcp --token-file ~/.config/headmesh/sandbox-token
ssh [email protected] headmesh-sandbox acceptance run --route ssh --phase 1
ssh [email protected] headmesh-sandbox acceptance run --route ssh --phase 2
# runner, exec-server, tunnel: the agent follows tests/acceptance/prompt.md
headmesh-sandbox acceptance recreate
headmesh-sandbox acceptance verify
headmesh-sandbox acceptance report --out ../docs/acceptance/$(date +%F).md

sandbox.toml [acceptance] でターゲットを設定します:

  • allowed_target は tag:sandbox に許可する必要があります。
  • denied_target はブロックする必要があります。このプローブはファイアウォールのインストール後にのみ実行してください。

チェック 4 で有効なのは MagicDNS 名に対するテイルネットアドレスのみです。同じ名前のパブリック DNS レコードは対象になりません。

6. YOLO
  1. 専用のデプロイキーを作成し、GitHub に「headmesh-sandbox-yolo (asus)」として追加して、known_hosts を固定します:

    ssh-keygen -t ed25519 -f /mnt/storage/headmesh/sandbox/secrets/github_ssh_key \
      -C "headmesh-sandbox-yolo (asus)"
    

    これは YOLO コンテナにのみ渡されます。

  2. headmesh-sandbox backup を実行してから、headmesh-sandbox up --yolo --ttl 4h を実行します。

CLI は backup_max_age より新しいバックアップがないと実行を拒否し、監視中であることの確認を求めます。

7. イメージを公開する

sandbox-v0.1.0 タグをプッシュします。.github/workflows/sandbox-image.yml がイメージをビルドし、 hadolint、container-structure-test、trivy を実行して、ghcr.io/headmesh-dev/sandbox にプッシュし、 cosign で署名します。その後、image = "ghcr.io/headmesh-dev/sandbox:0.1.0@sha256:…"` を設定します。

トラブルシューティング

  • まず headmesh-sandbox doctor を実行してください。すべての失敗に修正方法が示されます。
  • headmesh-sandbox logs sandboxd|tailscaled|tailscale-up|claude-runner|claude-rc|openai-tunnel|audit。
  • エージェントをリアルタイムで監視するには、headmesh-sandbox attach を実行します。
  • 「IP では接続できるが、名前では接続できない」場合:dns-check が修正方法を説明します(落とし穴 3)。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。