Claude Code

Claude Code に承認なしで任せてみた|コンテナの中で被害を閉じた記録と、まだ危ないところ

Claude Code を Docker のコンテナ(PC の中に作る、隔離された作業場)に入れたら、承認を出さないまま放置できるようになりました。 席を立っているあいだに実装とテストを進めてもらい、戻ってきたら差分を読む。その回し方が、ようやく現実になっています。

Docker は、自分の PC の中に、もう 1 台の小さな PC を作れる道具です(公式の入門)。その 1 台ぶんをコンテナと呼びます。中から見えるのは、こちらが渡したものだけです。何も渡さなければ、手元の PC の中身には手が届きません。開発でよく使われる道具ですが、私は AI を安全に動かすために入れました。

効いたのは 1 つだけです。中の AI に、危ないものを渡していない。 手元のファイルも、鍵も、サーバーや GitHub に書き込む権限も、コンテナの中には存在しません。だから何をされても、被害はコンテナの中で止まり、手元のファイルやサーバー、GitHub には届きません(止められていないものは、最後の「まだ危ないところ」に書きます)。

こんな人に向けて書いています。

  • AI は使っているけれど、承認のクリックが多くて任せきれていない
  • 承認を全部外すのは怖い。何が起こりうるのか分からないのが怖い
  • もっと任せたいけれど、どこまでなら任せていいのかの線が引けない

Docker を使ったことがなくても読めます。手順の記事ではなく、何を渡さないと何が守れるかの話だからです。 まだ試行錯誤の途中なので、うまくいかなかったことも書きます。環境は Windows 11 + Docker Desktop、Claude Code 2.1.270、Pro プランです。


なぜコンテナなら承認なしで任せられるのか

Claude Code には、承認を出さずに動くモードがあります(--dangerously-skip-permissions、設定では bypassPermissions)。 名前のとおり危ないのは、手元の PC でそのまま使うと、AI の操作が自分のファイル・鍵・サーバーにそのまま届くからです。

かといって、1 手ごとに承認を出していると、席を外した時点で止まります。承認は、人が見ているときにしか効かない仕組みです。

そこで使ったのが、冒頭の Docker のコンテナです。コンテナからは、渡したフォルダしか見えません。私は作業用の複製だけを渡しました。

その「もう 1 台」を開発用の作業場として使う形が dev container です。VS Code からその中のフォルダを開くと、いつもどおりの画面のまま、中で作業できます(containers.dev)。AI にはこの中だけを見せて、承認なしで動いてもらう。これが今回の形です。

大事なのは、中から外が見えないことです。

左は「ふだんの PC」でフォルダ・鍵・サーバー・写真のアイコンが並ぶ。右は「コンテナの中」で、作業用の複製のフォルダ 1 つだけが描かれ、鍵もサーバーも点線とバツ印で「無い」と示されている比較図

中の AI から見ると、手元の写真も、仕事のファイルも、フォルダごと存在しません。パスワードや鍵を書いたファイルも、渡していないので探しても見つかりません。

ただし、これは Docker の既定の動きではありません。 ふつうに「コンテナで開く」と、手元の作業フォルダはそのまま中から見えます。何を渡すかは自分で決める必要があります。この記事の 4 つは、その決め方の話です。

「消すな」と教えるのではなく、消せるものを置かない。うっかり全部消すコマンドを打たれても、消えるのは作業用の複製だけで、捨てて作り直せます。禁止で守るより、届かない場所で作業させる、という考え方です。

中の AI が何をしても、手元のファイルにもサーバーにも届かない。


Claude Code を 2 人に分ける

全部をコンテナの中に入れると、今度は自分が指示を出す相手がいなくなります。そこで役割を分けました。

図は 2 か所だけ見てください。鍵が手元側にしか無いことと、コンテナから外へ戻る線が 1 本しか無いことです。

人 → 手元の Claude Code(管理役・鍵はこちら側だけ)→ コンテナの中の Claude Code(作業員)。コンテナには Codex とローカル LLM を足す枠が点線で描かれ、下部に「成果は検品してから外へ」の戻り線がある構成図

個人の環境で組んだ構成です(各社との提携・公認の関係はありません)。

コンテナの中手元の PC
役作業員管理役
承認出さないいつもどおり出す
やること実装・テスト・記録を残す成果の検品・公開・本番反映
できないこと手元のファイル・本番サーバー・GitHub に書き込むこと—

手元の Claude Code から、コンテナの作業員に「この作業をやって」と投げて、あとは進み具合を見るだけ。やりとりは自作の中継役を通していて、外からコンテナへつなぐ入口(ポート)は開けていません。

図の点線はこれからです。Codex(OpenAI の、Claude Code と同じ種類の AI)やローカル LLM(自分の PC の中で動かす AI)も同じ形で足すつもりですが、まだ手を付けていません。

Lyze
Lyze

作業員は「作って記録を残す」まで。外に出すかどうかを決めるのは、いつも管理役の側です。


渡していない 4 つ|触らせない・持たせない・書き換えさせない・出させない

壁を立てたというより、「最初から渡していない」と言うほうが近いです。渡していないものは漏れません。

① 触らせない|作業場所を分ける

コンテナは専用の複製で作業します。手元の作業フォルダは見せていません。 手元の履歴(git のフォルダ)は、複製元として読み取り専用で見せるだけです。

② 持たせない|鍵を渡さない

API キー・GitHub のトークン・SSH 鍵・.env(設定と鍵を書くファイル)は、どれも渡していません。 git が追跡しない設定(gitignore)にしてある秘密のファイルは、複製にそもそも入りません。

本番サーバーにも GitHub にも、書き込むための鍵がありません。

③ 書き換えさせない|手元で実行されるものを固定する

読み取り専用にしているのは 2 つだけです。1 つは手元の履歴です。ここに置かれたスクリプトの一部は、コミット(変更の記録)のたびに手元の PC が自動で実行します。もう 1 つは中継役のコードです。この 2 つはコンテナから書き換えられません。

逆に、複製の中のファイル(git の設定や、Claude Code の settings.json に書いた禁止ルールなど)は書き換えられます。そこで「手元の自分が実行するものだけを固定し、残りは④で止める」という分け方にしています。

④ 出させない|人のチェックを必ず挟む

コンテナの中で作られたものは、そのままでは、サイトにも GitHub にも公開中のコードにも出ていきません。

  • 運営しているサイトが勝手に書き換わることはありません(本番サーバーに接続する手段が無い)
  • GitHub 上のファイルが勝手に更新されることもありません(書き込む権限が無い)
  • 公開中のコードに知らないうちに混ざることもありません(取り込むのは手元でやる操作なので、必ず人が挟まります)

成果は、コミットをまとめた 1 つのファイル(git の bundle)で手元に渡ってきます。私はそれを読んでから、公開するかどうかを決めます。

もう 1 つ、自分に課しているルールがあります。取り込んだものは、読むまで開かない・実行しない。 ③ で「複製の中は書き換えられる」と書いたぶんの穴は、ここで塞ぎます。面倒だからと飛ばすと、①〜③が全部無意味になります。


止まらずに続ける|/goal と、利用枠からの自動復帰

放置するには、止まらないことも要ります。止まる理由は 2 つありました。1 往復で終わってしまうことと、利用枠の上限です。

/goal で「終わるまで」回す

/goal は Claude Code に組み込みのコマンドで、1 往復の終わりに別の小型モデルが達成を判定し、未達ならもう 1 往復を始めます。

気をつけたのは、判定役がコマンドを実行せず、ファイルも読まず、会話に出たものだけで判定することです。 つまり作業員が「テストが通りました」と書けば、そのまま信じます。

なので、合否がはっきり出るコマンドと、その出力を毎回会話に出させることを条件文に入れました。進捗は STATE.md というファイルに [todo] / [done] で持たせ、会話が切れても引き継ぎが残るようにしています。

利用枠の上限から自分で戻る

長く回すと、月額プランの利用枠の上限に当たります。問題は上限の出方でした。画面を使わずコマンドとして起動する形だと、上限でもエラーの文が出ないことがある。しかも /goal の判定まで飛ばして、成功したかのように終わります。

見分ける手がかりは、記録に流れてくるこのイベントでした。

{"type":"rate_limit_event","rate_limit_info":{
  "status":"rejected","rateLimitType":"five_hour","resetsAt":1789478400}}

status が rejected なら上限で、resetsAt がリセットの時刻(UNIX 秒)です。「正常終了」で終わっていても、最後にこれが出ていたら上限として扱う。 この 1 点を見るようにしたら、待って再開できるようになりました。

やっていることは単純です。リセット時刻+3 分まで眠り、時間が来たら続きから起動し直す。眠っているあいだは枠を使いません。週の上限のときは待たずに諦め、復帰は 2 回までにしてあります。

実際、この記事の下書きを書かせているあいだに 5 時間の上限へ 3 回当たり、2 回は待って自動で再開しました(うち 1 回は再開の直後に別の理由で落ちて、結局は起こし直しが要りました)。残る 1 回は、上限を見分けられるようにする前でした。


まだ危ないところ

Lyze
Lyze

ここは読み飛ばさないでほしいところ。塞げていないものを知らずに真似すると、閉じたつもりのコンテナに穴が残ります。

  • 外への通信は遮断していません。 秘密を渡していないことで成立させている状態です
  • コンテナの中のログイン情報は、作業員から読めます。 おかしな指示を踏んだときに持ち出される余地があります
  • ログインは、数か月使わないと切れます。しかも状態の確認では切れたことが分からず、動かして初めて分かります(放置が止まる原因になります)
  • 中継役のうち、作業員を見張っている部分が強制終了されると、作業員だけが動き続けることがあります
  • 状態表示も、成果も、全部「作業員が書いたもの」です。指示として扱わず、読んでから使います

まとめ

  • コンテナに入れたら、承認なしで放置できるようになった。中から手元が見えないので、被害はそこで止まり、手元のファイルやサーバーには届かない
  • 効いたのは「渡していない」こと。触らせない・持たせない・書き換えさせない・出させない
  • 公開するところには、必ず人が挟まる。サイトも GitHub も、勝手には書き換わらない
  • 止まらない工夫まで含めて「任せる」。/goal と、上限からの自動復帰
  • 穴は残っている。通信は開いている・ログイン情報は中から読める・ログイン切れは動かすまで分からない

次は Codex を同じ形に載せること、通信の制限を入れることを試します。

まず、この記事の 4 つを手がかりに、自分の PC で AI に渡したくないもの(鍵・本番につながる設定・GitHub の権限)を書き出してみてください。入口は下の「Docker を触ったことがなくても始められますか?」にあります。

よくある質問

Q. 承認なしのモードを、手元の PC でそのまま使ってはだめですか?

A. 私は手元の PC でも承認なしのモードを使っていて、これまで事故は起きていません。それでもコンテナを用意したのは、万が一暴走したときの範囲が気になったからです。手元でそのまま動かしていると、たとえば運営しているサイトが勝手に書き換わる、GitHub 上のファイルが意図せず更新される、といったことが起こりえます。確率は低くても、起きたときに自分ですぐ気づけない種類の事故なので、起こりようがない場所を別に作りました。手元側の権限設定は settings.json で権限管理してみてわかったこと にまとめています。

Q. Docker を触ったことがなくても始められますか?

A. 入口はコマンドパレットの Dev Containers: Reopen in Container(英語のまま出ます)です。ただし放置して回すところまで行くならコマンドは要ります。成果の受け取りも、状態の確認もコマンドです。そのうえでこの記事の 4 つを自分で設計する必要があります。何を渡していないかを説明できない状態で承認を外すのは、順番が逆です。

長く回した結果が増えてきたら、また続きを書きます。気になるところがあれば X で聞かせてください!

この記事は役に立ちましたか?

読みたい記事をリクエストする

シェア