FRL 自由研究ラボ

AIエージェントことはじめ — LAB 013

AIに勝手をさせない壁を、3層で作る(後編)

— 層3と、壁を試して配る —

AI に作業を任せるほど、「それは触らないでほしかった」が起きる余地も増えます。 「触らないで」と文章で頼むだけでは、守られたかどうかを誰も確かめていません。 この記事では、読ませたくないもの・やらせたくない操作を仕組みで止める壁を、 性質の違う3つの層で作り、本当に止まるかを自分の手で確かめます。 後編では、層3(サンドボックス)を足し、3枚の壁を実際に試して、2台目へ配ります。

この記事を読むとできること

  • 数え漏れを受け止めるサンドボックス(層3)を設定し、禁止リストだけでは止まらない道をふさげます
  • ダミーを使って、3枚の壁が本当に止まるかを自分の手で確かめられます
  • 壁の設定を「原本」から別の Mac へ配り、2台目だけ壁が無い状態を防げます

想定している使い方

Claude Code(Mac の中でファイルを読み書きしたりコマンドを実行したりしてくれる AI エージェント)を入れた Mac で、 その設定ファイルを自分の手で書き足します。 ターミナル(文字で Mac に命令を打ち込むためのアプリ。「アプリケーション」の中の「ユーティリティ」にあります)に、 コピーしたコマンドを貼る場面も出てきます。 説明はすべて Mac を前提にしています。

この記事の道順

  1. 前編のおさらい
  2. STEP 4 — 層3:サンドボックスで、すり抜けを止める
  3. STEP 5 — ダミーで壁を試し、設定を2台目へ配る
  4. つまずき集(症状から引く)
  5. よくある質問
  6. 次の一歩

※ LAB 003(AI エージェントを入れる)、 LAB 005(戻れる仕組み)、 LAB 010(終了コードで合否を決める)を終えている前提です。 前編(STEP 1〜3)を終えている前提で、STEP 4 から続けます。

読む目安:約11分 ・ 手を動かす目安:約25分(STEP 4・5)・ 図2枚

RECAP

前編のおさらい

前編では、守りたいものを書き出し(STEP 1)、 設定の禁止リストで対象を止める層1(STEP 2)と、 実行の直前に走るフックでやり方を止める層2(STEP 3)を作りました。

層1 ・ 前編

禁止リスト

読ませない・実行させない対象を書く

層2 ・ 前編

フック

コマンドの中身を見て、やり方で止める

層3 ・ この後編

サンドボックス

数え漏れたすり抜けを、箱で受け止める

✕ 前編まで(層1・層2):数え漏れたものは通り抜ける AI が操作を しようとする 層1・層2 が確かめる 数え上げたものは止まる 数え漏れた操作は そのまま通り抜ける ○ 後編で層3を足す:箱の外の読み書きは、箱が止める AI が操作を しようとする 層1・層2 数え上げたものは止まる 層3 の箱が 箱の外の読み書きを止める 止まる

図の見方:上の段は、前編までの状態です。層1・層2 は、こちらが数え上げた操作だけを止めるので、数え漏れた操作はそのまま通り抜けます。 下の段は、後編で層3を足した状態です。通り抜けた操作も、箱が箱の外の読み書きを止めます。

04

STEP 4 — 目安 10分

層3:サンドボックスで、すり抜けを止める

層1・層2は、「この操作は止める」とこちらが数え上げたものしか止められません。 数え漏れたものを受け止めるのが、サンドボックスです。 砂場(sandbox)のように、コマンドを「箱」の中だけで動かし、箱の外のファイルは読めない・書けないようにする、Mac の仕組みです。

層1の限界(前編 2-2 の穴②)を思い出してください。Read(AI がファイルを読む道具)を禁止しても、 ターミナルの cat(ファイルの中身を表示するコマンド)は素通りでした。 箱は、どんなコマンドで読もうとしても、箱の外は読めないので、この道もふさぎます。

○ Read(ファイルを読む道具)で読もうとする Read で 読もうとする 層1 の禁止リストに当たる 読み取り禁止 止まる ✕ Bash の cat(中身を表示するコマンド)で読もうとする Bash の cat で 読もうとする 層1 は Bash の中身を 見ないので素通り 層3 の箱が 箱の外の読み取りを止める 止まる 層1 だけだと、この道は開いたままになります。

設定は、前編 STEP 2・3 と同じ settings.json(Claude Code の設定ファイル)に足します。 読ませない場所と、書いてよい場所を決めます。 場所の名前は、前編 STEP 1 で書き出したものに置き換えてください。

  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": false,
    "filesystem": {
      "denyRead": [
        "~/.ssh",
        "~/wall-test"
      ],
      "allowWrite": [
        "~/Documents/ノート"
      ]
    }
  }

前編の STEP 2・3・4 を足し終えたときの全体の形です。カンマの位置や括弧の入れ子を見比べる見本にしてください (すでに他の設定があるなら、消さずに足します)。

{
  "permissions": {
    "deny": [
      "Read(**/.env*)",
      "Edit(**/.env*)",
      "Write(**/.env*)",
      "Read(~/.ssh/**)",
      "Bash(sudo *)",
      "Bash(git push --force*)",
      "Bash(git push -f*)"
    ],
    "ask": [
      "Bash(git push*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "/usr/bin/python3 ~/.claude/hooks/guard.py" }
        ]
      }
    ]
  },
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": false,
    "filesystem": {
      "denyRead": [
        "~/.ssh",
        "~/wall-test"
      ],
      "allowWrite": [
        "~/Documents/ノート"
      ]
    }
  }
}

autoAllowBashIfSandboxed を false にする理由: これを true にすると、「箱の中なら安全だから確認なしで通す」動きになります。 層を重ねたつもりが、この動きで1枚働かなくなっては意味がないので、false にして STEP 5 で確かめます。

筆者の体験メモ

筆者の環境では、2026-09-08 の実測で、層2のフックを素通りして git add -A が通りました。 バージョンによって変わるかもしれません。

箱が守るのは、AI が実行するコマンドだけ。 自分で起動した別のアプリや、自分でターミナルに打つコマンドは箱の対象外です。 その代わり、箱の中では動かなくなるコマンドも出ます。 必要なときは、人が見ているその1回だけ箱の外で実行させ、毎回の許可を求める形にしておくのが安全です。 不便だからと箱ごと外さないでください。

筆者の体験メモ

筆者の環境では、常駐サービス(裏で動き続けるプログラム)の操作や、定期実行(決めた時刻に自動で動かす仕組み)の登録が、箱の中では動きません。

✓ ここまでの確認: 設定に sandbox を足し、JSON 検査で 0 が出た。 Claude Code を起動し直した(設定は起動時に読まれるので、動いている Claude Code をいったん終了して、もう一度起動します)。 次の STEP 5 で、3つの壁を実際に当てて確かめます。

05

STEP 5 — 目安 15分

ダミーで壁を試し、設定を2台目へ配る

壁は、実際に当てて止まるのを見るまで、効いているか分かりません。 書式が正しくても、パスの書き方が合っていなければ何も止まらないからです。 LAB 010 の「合格したテストをわざと壊す」と同じで、 わざと禁止に当たってみるのが確かめ方です。本物の秘密には触らず、ダミーで試します。

5-1 ダミーを置く

次の4行を、ターミナルに貼って実行します(Claude Code の画面ではなく、ターミナルのほうです)。

mkdir -p ~/wall-test
echo "これはダミーです" > ~/wall-test/.env
echo "これもダミーです" > ~/wall-test/dummy.txt
mkdir -p ~/wall-test-git && git -C ~/wall-test-git init

この4行は、試験用のフォルダ wall-test を作り、その中に .env(秘密の設定を入れるファイル)のふりをしたダミーと、ふつうのダミーのファイルを置きます。 さらに、git(変更履歴を記録する仕組み)の置き場所を、空のまま1つ作ります。確認 B で使います。

本物ではなくダミーを使う理由:壁が効いていなければ、AI は本当に読んでしまいます。 読まれて困らないものでなければ、確認そのものが事故になります。 STEP 4 の設定で ~/wall-test を読み取り禁止に入れてあるのは、この確認のためです。

5-2 3つの壁を、1つずつ当てる

Claude Code を起動し直してから、次の3つを1つずつコピーして Claude Code に貼り、順に頼みます。 どれも「止められたら、別の手段で回り込まない」と付けるのがコツです。

途中で「このコマンドを実行してよいか」と聞かれたら: 確認 C(cat)では、聞かれることがあります(設定や版で変わります)。ダミーなので許可して構いません。許可したあとに箱が止めるのを見るのが目的です。 確認 A・B は、聞かれずに止まる形のはずです。止まらずに聞かれたときは、壁が効いていない可能性があるので、許可せずにつまずき集を見てください。

【確認 A:層1】
Read ツールで ~/wall-test/.env を読んで、中身を見せて。
止められたら、別の方法で読もうとせず、止められたことと、表示された理由をそのまま報告して。
【確認 B:層2】
~/wall-test-git に移動して、git add -A を実行して。
止められたら、別の方法で回り込まず、表示された理由をそのまま報告して。
【確認 C:層3】
Bash の cat で ~/wall-test/dummy.txt を読んで。
止められたら、別の方法で読もうとせず、表示された内容をそのまま報告して。
確認 試す層 合格の見え方
A 層1 「読めない」「拒否された」といった表示が出て、ダミーの中身は出ない
B 層2 前編 STEP 3 で書いた理由の文章(「git add -A / git add . は使えません…」)が出る
C 層3 「Operation not permitted(操作は許可されていません)」のような表示が出て、中身は出ない

どれか1つでも「ダミーの中身が見えた」「git add -A が通った」となったら、その層は効いていません。 つまずき集で原因を探し、直したら、その確認だけもう一度やります。 終わったら、ダミーは消して構いません(rm -r ~/wall-test ~/wall-test-git。自分で作った空き地だけを消す操作です)。

5-3 設定を「原本」から配る(2台以上使うなら)

壁の設定は ~/.claude(Claude Code の設定を置くフォルダ)にあり、 git(LAB 005 の、変更履歴を残す仕組み)で2台目の Mac へ渡す対象には、ふつう入りません。 だから、何もしなければ2台目の Mac には壁がありません。 LAB 008 の「2台で同じ状態にする」と同じ話です。

筆者の体験メモ

筆者は、片方の Mac だけにサンドボックスを入れたまま、もう片方には何もない状態が約2週間(2026-08-16 〜 2026-08-30)、気づかれませんでした。

対策は、原本を git で管理するフォルダに置き、そこから ~/.claude へコピーすることです。 設定には場所の名前と通信先しか入らず、パスワードなどの値は入らないので、git に置いても問題ありません (値を入れたくなったら、それは壁の設定ではなく、Keychain(Mac のパスワード保管庫)などの出番です)。 まず、次の4行をターミナルに貼って実行し、今の設定を原本のフォルダへ写します。

mkdir -p ~/my-claude-settings/hooks
cp ~/.claude/settings.json ~/my-claude-settings/
cp ~/.claude/hooks/guard.py ~/my-claude-settings/hooks/
diff ~/my-claude-settings/settings.json ~/.claude/settings.json && echo "原本と同じ"

この my-claude-settings フォルダは、LAB 005 の手順で git の管理下に置きます。 以後、直すのは必ず原本の側にして、次のコマンドをターミナルで実行し、~/.claude へコピーし直します。 注意:コピー先にすでに設定ファイルがあると、このコマンドは中身を上書きします。 2台目など、元の設定が残っている Mac で実行するときは、先に今のファイルの控え(別名のコピー)を取ってください。

mkdir -p ~/.claude/hooks
cp ~/my-claude-settings/settings.json ~/.claude/settings.json
cp ~/my-claude-settings/hooks/guard.py ~/.claude/hooks/guard.py

~/.claude の側だけを直すと、次にコピーしたとき消えるうえ、もう1台にも伝わりません。 diff(2つのファイルの違いを出すコマンド)は、2つが同じなら 0(成功)で終わるので、 「原本と同じ」と出れば、ずれていません。出なければ違いが画面に出ます。 2台目では、原本のフォルダを LAB 008 の要領で受け取り、 上のコピーのコマンドを実行して、5-2 の確認をもう一度やります。

原本から配る理由:壁の設定は、気づかないうちに緩んでいても画面には何も出ません。 原本とdiffを取れば、「頼んでいない設定変更がされていないか」も機械で確かめられます。

止めすぎないことも、設計のうちです。 機械で止めないものは、文章のルールで縛る形にします。 壁と文章のルールは、片方では足りない部分を補い合います。

筆者の体験メモ

筆者は、自作アプリの動作確認に日常的に使う curl(通信を試すコマンド)を、あえて禁止していません。 止めると作業が回らず、いずれ壁ごと外したくなるからです。機械で止めない分は、文章のルールで縛ると割り切りました。

✓ ここまでの確認: 確認 A・B・C のすべてで「止められた」。 (2台以上使う人は)原本と ~/.claude の diff で「原本と同じ」と出た。 これで「層1・2・3 の壁がある」と言える状態になりました。

TROUBLE

つまずき集(症状から引く)

起きていること 原因 どうするか
確認 A で、ダミーの中身が見えてしまった 禁止の書き方がずれている/設定を足したあと、Claude Code を起動し直していない/設定ファイルが壊れている 前編 STEP 2 の JSON 検査で 0 を確認し、Claude Code を終了して起動し直す。Read(**/.env*) の括弧や名前を見直す
確認 A・B で、止まらずに「実行してよいか」と聞かれた 禁止やフックが効いていない(書き方のずれ/hooks が足されていない/起動し直していない) 許可せずに断る。下の A・B の行(ダミーの中身が見えた/git add -A が通った)と同じ手順で、JSON 検査と起動し直しから見直す
前編 3-2 の1行目が 2 にならない(止まらない) フックのファイルの場所が違う/保存の途中でずれた/プログラムがエラーで落ちて、終了コードが 2 以外になっている 貼った場所を ls ~/.claude/hooks で確かめ、前編 3-2 のコマンドを自分で打ち直す。エラーの文章が出ていれば AI に見せる
確認 B で、フックは止めたはずなのに git add -A が通った 設定の hooks が足されていない/サンドボックスの自動許可が効いている hooks の足し先("permissions" と同じ階層)を確かめる。autoAllowBashIfSandboxed を false にする(STEP 4)
関係ないコマンドまで止まる 検査が粗い(文字列が入っているだけで止めている) 止まった例を1つ控え、その例が通るように直して、前編 3-2 に1行足す
確認 C で、ダミーの中身が見えてしまった サンドボックスが有効になっていない/~/wall-test のパスが合っていない enabled: true を確認。~ をやめて /Users/(自分の名前)/wall-test と全部書く
箱を入れたら、必要なコマンドが動かなくなった そのコマンドが、箱の外のファイルや仕組みを触る 壁を丸ごと外さない。必要な場所だけ allowWrite に足すか、人が見ている1回だけ箱の外で実行する
AI が止められたあと、別のやり方で同じことをやり直そうとする 「できなかった」で止まる出口を、頼み方で渡していない 頼むとき、「止められたら、別の方法で回り込まず、理由を報告して止まって」と付ける(LAB 010 の「止まって」と同じ理由)
2台目の Mac だけ、壁が効かない 設定は ~/.claude にあり、git では運ばれない STEP 5-3:原本を git で管理して、そこから配る。配ったあと 5-2 をもう一度

FAQ

よくある質問

壁があるなら、「触らないで」と文章で頼むのはもう要りませんか?

要ります。壁にできるのは、場所やコマンドの形で書けるものだけです。 「記録に秘密の値を書かない」のような、中身の判断が要るものは文章で頼むしかありません。 壁は最後の砦、文章のお願いは日々の指針と、役割を分けて両方持ちます。

全部の層を入れないと意味がありませんか?

いいえ。層1だけでも「読ませたくないファイルを読ませない」には役立ちます。 ただし、前編の STEP 2-2 の穴が残るので、守りたいものが増えたら層2・3 を足してください。1枚ずつ足していけます。

AI が自分で設定を緩めてしまうことはありませんか?

AI の編集の道具(コマンドを通さずに、AI がファイルを直接直す機能)では、設定ファイルも書き換えられます。 なので、STEP 5-3 の原本との diff を定期的に取るのが確実です。 壁の設定を変えるときは、人が原本を直してから配る運用にします。

筆者の体験メモ

筆者の環境では、設定ファイルをコマンドで書き換えようとしても、箱の中からは書き込めない作りになっています。

Claude Code 以外の AI でも同じですか?

考え方は同じです。「対象を止める」「やり方を止める」「すり抜けを受け止める」の3つに分けて考えます。 ただし、設定の項目名や書き方は製品ごと、バージョンごとに違います。ここの例は Claude Code のものなので、別の製品では公式の説明で確かめてください。

人がいない時間に AI を動かすときは、どうなりますか?

人がいないので、「たずねる」は自動的に拒否になります(この挙動は設定の記録にあるものです。自分の環境では、起動して試して確かめてください)。 つまり、壁にぶつかったら止まる、という安全側の動きになります。 その場合の組み立て方は、LAB 014 に書きました。

NEXT

次の一歩

まだ手を動かしていないなら、まず守りたいものを1つだけ選んで、層1の禁止を書いてみてください。 目的は完璧な壁ではなく、「止まった」を自分の目で1回見ることです。

  • 「お願い」は壁ではない。止める役は、実行の直前に確かめる仕組みに移す
  • 層1は対象、層2はやり方、層3はすり抜けを止める。1枚では穴が残る
  • 壁は、ダミーに当てて止まるのを見るまで、効いているか分からない
  • 止めすぎない。機械で止めないものは、文章のルールで補う
  • 設定は原本を1か所に置いて配る。2台目に壁が無い事故を防ぐ

LAB 014

人がいない時間に、AIを働かせる

壁ができたら、次は「人が見ていない時間にも、AI に作業をさせる」話です。 壁があるから、安心して任せられます。 →

※ この記事は、実際に使っている Claude Code の設定(禁止リスト・実行直前の検査・サンドボックス)をもとにしていますが、結果を保証するものではありません。 設定の項目名や AI の振る舞いは製品やバージョンで変わるので、「止める場所を3つに分けて、実際に当てて確かめる」という考え方の方を持ち帰ってください。