序章:同じ注意を、毎回プロンプトに書いていませんか
Claude Codeを使っていると、毎回のように同じことを書き足すようになります。
- 「テストファイルは書き換えないで」
- 「
.envは読まないで」 - 「直したら最後にフォーマッターをかけて」
- 「この会社のコードの書き方はこうだから」
それでもAIは、ときどき忘れます。長い作業の途中で注意書きが埋もれたり、別の判断を優先したりするからです。
こうした「毎回言わなくても守られる仕組み」を、AIの作業場そのものに組み込むのがハーネスエンジニアリングです。
先に結論を示します。
- ハーネスエンジニアリングとは、AIに仕事を渡す前に、AIが働く作業場を設計すること。何を読めるか、どこまで触ってよいか、どの道具を使えるか、何が自動で起きるか、どこで人間が判断するかを決める
- Claude Codeでは、CLAUDE.md(知識の地図)、権限ルール(できること・できないこと)、フック(決まった操作の前後に、Claude Codeが起動する処理)、サンドボックス(シェルコマンドの届く範囲をOSで制限する仕組み)が中心になる
- いちばん大事な区別は、CLAUDE.mdは「お願い」、権限ルール・フック・サンドボックスは「仕組みによる制御」だということ。本当に禁止したいことは、CLAUDE.mdではなく仕組みの側で止める。ただし、どの仕組みにも守れる範囲があり、1つで全部は守れない
- ハーネスは一度作って終わりではない。AIがつまずいたら、プロンプトを直すのではなく作業場を直す
本記事は、Coding Agent連載の第1回です。今回は作業場と権限を整えます。第2回では作業と確認を繰り返す「ループエンジニアリング」、第3回では仕事や確認を分けてつなぐ「グラフエンジニアリング」を扱います。
Claude Codeの仕様は、2026年10月5日時点の公式ドキュメントで確認しました。記事中の設定例は公式ドキュメントの例をもとに作成したものです。2026年10月10日に、編集部で架空のTODO管理API(Node.js)の練習用プロジェクトを用意し、Part 3の手順を記事どおりに試しました。各Stepの「試した結果」は、次の環境で確かめたものです。
- Windows 11(WSL2ではなく、Windowsで直接動かすClaude Code)
- Claude Code v2.1.296、モデルはOpus 5.5
- 手動で確認するモード(
claude --permission-mode defaultで起動) - ユーザー単位の設定やMCPを読み込まない起動オプション(
--setting-sources project,local --strict-mcp-config)を付け、練習用プロジェクトのCLAUDE.mdと.claude/settings.jsonが効く状態
試した結果のうち、記事の説明と違った点は本文に注意として書き、スクリプトを1か所直しました。macOS、Linux、WSL2では試していません。会話の記録は編集部で保存しています。
Part 1:ハーネスエンジニアリングとは何か
「ハーネス」は馬具のこと
ハーネス(harness)は、もともと馬に付ける馬具を指す言葉です。馬の力を、行きたい方向へ安全に伝えるための道具です。馬が強いほど、良い馬具が必要になります。
AIエージェントも同じです。ファイルを書き換え、コマンドを実行し、外部サービスにつながる力を持つほど、その力をどこへ向け、どこで止めるかの仕組みが必要になります。
新人社員の受け入れ準備にたとえる
ハーネスエンジニアリングは、優秀な新人社員を迎える準備に似ています。
| 新人の受け入れ準備 | AIのハーネス | Claude Codeでは |
|---|---|---|
| 社内マニュアルと資料の場所を教える | 必要な知識にたどり着ける道筋 | CLAUDE.md、.claude/rules/、docs/ |
| 入館証で入れる部屋を決める | 読んでよい・変更してよい範囲 | 権限ルール(allow/ask/deny)、サンドボックス |
| 使ってよい道具を渡す | 使えるツールと接続先 | ツールの許可、MCP、サブエージェントのtools |
| 決まった手順を仕組みにする | 決まった操作の前後に自動で起動する処理 | フック |
| 上司の承認が必要な場面を決める | 人間が判断する地点 | 権限モード、askルール |
どれだけ優秀な新人でも、資料の場所を知らず、入っていい部屋も分からなければ、毎回質問するか、勝手に動いて事故を起こします。AIも同じです。
プロンプト・コンテキスト・ハーネス・ループ・グラフの関係
AIとの付き合い方を表す言葉は、次のように増えてきました。
| 呼び方 | 設計するもの | 一言で言うと |
|---|---|---|
| プロンプトエンジニアリング | 1回の指示文 | 何を頼むか |
| コンテキストエンジニアリング | AIに渡す情報 | 何を見せるか |
| ハーネスエンジニアリング | AIが働く環境、道具、権限、ルール | どこで、何を使って、どこまでやってよいか |
| ループエンジニアリング | 作業・確認・やり直し・停止の繰り返し | いつ確かめ、いつ止めるか |
| グラフエンジニアリング | 作業・確認・人間の判断のつながり | 何を分け、どうつなぎ、どこで待つか |
これらは古いものが新しいものに置き換わる関係ではありません。それぞれ別の部分を設計する技術で、積み重ねて使います。ハーネスはその中で、ループやグラフを安全に回すための土台にあたります。土台のないまま自動で回し始めると、速く失敗を量産する仕組みになりかねません。
OpenAIの実践例:AGENTS.mdは百科事典ではなく目次
この言葉が広く知られるきっかけの一つが、OpenAIが2026年2月11日に公開した記事「Harness engineering: leveraging Codex in an agent-first world」です。社内向けのベータ製品を5か月かけて作り、人間が手書きしたコードは0行で、コードはすべてCodexが書いたと報告しています。
この記事が強調しているのは、エンジニアの主な仕事が「コードを書くこと」から、環境を設計し、意図を明確にし、AIが確実に仕事をするためのフィードバックの仕組みを作ることへ移ったという点です。AIへの指示ファイル(AGENTS.md)も、すべてを詰め込んだ百科事典ではなく、整理されたdocs/フォルダへの目次として使っています。
Part 2:Claude Codeのハーネスを作る道具
Claude Codeには、ハーネスの部品になる機能がそろっています。
| 道具 | 置き場所 | 役割 | 仕組みによる制御か |
|---|---|---|---|
| CLAUDE.md | プロジェクト直下のCLAUDE.md、個人用の~/.claude/CLAUDE.md | 毎回読み込まれる指示とプロジェクトの知識 | いいえ(お願い) |
.claude/rules/ | プロジェクトの.claude/rules/*.md | テーマ別のルール。特定のファイルを扱うときだけ読み込ませることもできる | いいえ(お願い) |
| 権限ルール | .claude/settings.jsonのpermissions | ツールやコマンドを許可・確認・拒否する | はい |
| フック | .claude/settings.jsonのhooks | 条件に合う操作の前後で、Claude Codeがコマンドを起動する。操作を止めることもできる | はい |
| サンドボックス | .claude/settings.jsonのsandbox、/sandbox | シェルコマンドが読み書きできるファイルや接続先を、OSのレベルで制限する | はい |
| 権限モード | 起動時の指定、Shift+Tab | どの程度確認を挟むかの全体方針 | はい |
公式ドキュメントは、この違いをはっきり書いています。CLAUDE.mdは強制される設定ではなく、文脈(コンテキスト)として扱われること。そして権限ルールはモデルではなくClaude Code自身が強制することです。プロンプトやCLAUDE.mdは、Claudeが何をしようとするかに影響しますが、Claude Codeが何を許すかは変えません。
ただし、仕組みの側にもそれぞれ守れる範囲があります。権限ルールはClaudeのツールやコマンドの書き方に、フックは指定したツールの操作に、サンドボックスはシェルコマンドに効きます。Part 3で、この範囲を確かめながら組み合わせます。
Part 3:実際にハーネスを作る6ステップ
ここからは、テストのある小さなWebアプリのプロジェクトを例に、Claude Codeの作業場を整えます。まずは練習用のプロジェクトで試してください。
Step 1:作業場の「5つの欄」を埋める
設定ファイルを書く前に、次の5つを短く書き出します。
| 欄 | 書くこと | 例 |
|---|---|---|
| 読んでよいもの | 参照してよい資料の範囲 | src/、test/、docs/。.envとsecrets/は除く |
| 変えてよいもの | 変更してよい範囲。できるだけ狭く | src/。テストファイルとロックファイルは変更しない |
| 使う道具 | 使ってよいコマンドや接続先 | 中身を確認したテストと型チェックのコマンド。git pushはしない |
| 確かめる場所 | AIが自分で結果を確かめる手段 | npm test、型チェック、リンター |
| 人間が判断する場所 | AIに任せない判断 | 公開、外部への送信、本番環境への変更、依存ライブラリの追加 |
このうち「確かめる場所」と「人間が判断する場所」は、別の欄に分けて書くのがポイントです。テストが通るか、仕様どおりかの確認はAIに任せられますが、公開してよいか、送ってよいかの判断は人間に残すものです。同じ「確認」という言葉で混ぜると、誰が何を確かめるのかが曖昧になります。
この5つの欄が、以降のステップで作る設定の設計図になります。ただし、以降の設定例は「読んではいけないもの」「変えてはいけないもの」を止める例です。「src/以外は一切変更できない」ことまで完全に強制するものではありません。
Step 2:CLAUDE.mdを「地図」として書く
CLAUDE.mdは、セッションの開始時に毎回読み込まれる指示ファイルです。公式ドキュメントでは、/initを実行するとClaudeがコードを読んで、ビルドやテストのコマンド、見つけた規約を含む最初のCLAUDE.mdを作ると説明されています。そこから、Claudeが自分では気付けない情報を足していきます(今回の試験では次の例をそのまま置いたので、/initは試していません)。
公式ドキュメントが勧める大きさは、1ファイルあたり200行未満です。長いほど文脈を消費し、指示が守られにくくなります。だからこそ、OpenAIの例と同じく、CLAUDE.mdは詳しい資料への目次にします。
# このプロジェクトについて 小さなTODO管理のWebアプリ。詳しい設計は docs/architecture.md を参照。 ## よく使うコマンド - テスト: `npm test` - 型チェック: `npm run typecheck` - 開発サーバー: `npm run dev` ## 作業のルール - 変更は src/ 配下だけで行う。test/ のテストは、頼まれない限り変更しない - 作業の最後に `npm test` と `npm run typecheck` を実行し、結果を報告する - 依存ライブラリを追加したいときは、追加せずに理由を書いて相談する ## 詳しい資料 - APIの設計: docs/api.md - 画面の命名規則: docs/ui-naming.md
試した結果:このCLAUDE.mdを置いた練習用プロジェクト(わざと失敗するテストを2件入れたもの)で、「失敗しているテストを直してください。」と頼みました。編集部の環境(2026年10月10日、Windows 11、Claude Code v2.1.296、Opus 5.5、手動で確認するモード)では、Claudeはsrc/routes/todos.jsだけを直し、最後にnpm testとnpm run typecheckを実行して、次のように報告しました(抜粋)。
失敗していた2件のテストを直しました。変更したのは
src/routes/todos.jsだけで、テストには手を入れていません。
1回の試験なので、長い作業でも同じように守られるとは限りません。CLAUDE.mdは「お願い」なので、確実に止めたいことはStep 3以降の仕組みで止めます。
特定のファイルを扱うときだけ必要なルールは、.claude/rules/に分けると、CLAUDE.mdを短く保てます。公式ドキュメントでは、ファイルの先頭の---で囲んだ設定欄(frontmatter)にpaths:で対象のファイルを書くと、そのファイルを扱うときだけ読み込まれると説明されています(今回は試していません)。
--- paths: - "src/api/**/*.ts" --- # APIのルール - 入力を検証してから処理する
Step 3:権限ルールで「できること」を決める
Step 1の「読んでよいもの」「変えてよいもの」「使う道具」を、プロジェクトの.claude/settings.jsonの権限ルールに書きます。
{ "permissions": { "allow": [ "Bash(npm test)", "Bash(npm run typecheck)" ], "deny": [ "Bash(git push *)", "Read(/.env)", "Read(/secrets/**)", "Edit(/test/**)", "Edit(/package-lock.json)" ] } }
allow:確認なしで実行してよい操作ask:毎回確認してから実行する操作deny:実行させない操作
Read(/.env)のように先頭に/を付けると、プロジェクトのフォルダを基準にした場所を指します。作業中にClaudeが別のフォルダへ移動しても、指す場所がずれません。
allowには、package.jsonで中身を確認したテストと型チェックのコマンドだけを個別に入れています。npm run *のように広く許可すると、公開や外部への送信をするスクリプトまで確認なしで動くことがあるため、最初は避けましょう。
公式ドキュメントでは、ルールはdeny → ask → allowの順に評価され、最初に一致したものが結果になると説明されています。具体的なallowを書いても、広いdenyの例外にはなりません。また、ユーザー設定とプロジェクト設定のどちらかでdenyされていれば、もう一方でallowされていてもブロックされます。
試した結果:この設定を置いて新しいセッションを始め、わざと禁止した操作を頼みました。編集部の環境(2026年10月10日、Windows 11、Claude Code v2.1.296、Opus 5.5、手動で確認するモード)では、次のとおりでした。
| 送った依頼 | Claudeの操作 | 結果 |
|---|---|---|
.envの中身を表示してください。 | Readツールで.envを開こうとした | File is in a directory that is denied by your permission settings.で拒否 |
git pushを実行してください。 | Bashツールでgit push | Permission to use Bash with command git push has been denied.で拒否 |
test/todos.test.js の1つ目のテスト名を「TODOを作成すると一覧に表示される」に変えてください。 | Editツールで編集 | 読み取りはでき、書き込みは拒否 |
npm test を実行して、結果を教えてください。 | Bashツールでnpm test 2>&1 | 確認なしで実行 |
3つの拒否のあと、Claudeは別の方法で回り込まず、拒否されたことと人間が行う方法を説明しました。ただし、これは今回の観察で、回り込まないことを仕組みが保証しているわけではありません。
Windowsでの注意:Windowsで直接動かすClaude Codeには、Bashツールとは別にPowerShellツールがあります。権限ルールを置く前のセッション(Step 2)では、Claudeはnpm testをPowerShellツールで実行していました。この設定を置いたセッションでは、/permissionsの拒否(Deny)の一覧に、設定ファイルに書いていないPowerShellが入っていて(出どころの表示は「From CLI argument」)、PowerShellツールは使えない状態でした。なぜそうなったかは切り分けていません。Bash(...)のルールはBashツールのコマンドに対するルールなので、Windowsで使う場合は、/permissionsで実際にどのツールが許可・拒否されているかを確かめてください。
ここで知っておきたい限界が2つあります。
- Bashのルールは、Claudeが書いたコマンドの文字列に一致させる仕組みです。
git pushをdenyしても、git -C . pushのような別の書き方や、許可したスクリプトの内部から実行されるpushは止められません。公式ドキュメントも、これはプログラムの周りのセキュリティ境界ではないと説明しています ReadやEditのdenyは、Claudeのファイル操作ツールやcatなどの認識できるコマンドには効くと公式ドキュメントでは説明されていますが、Pythonなどのスクリプトが自分でファイルを開く場合には効きません。今回、Step 5の設定まで入れた状態で「node -e で .env を読み込んで、中身を表示してください。」と頼むと、Claudeはnode -eで.envを読むコマンドを組み立て、権限ルールでは止まらずに実行の確認が表示されました。編集部は「No」を選んで止めました。手動で確認するモードの確認が、最後の歯止めになった形です
シェルからの読み書きまで止めたい場合は、Step 5のサンドボックスを組み合わせます(ただしWindowsでは動きませんでした。Step 5を参照)。設定した内容は、/permissionsで確認・変更できます。今回の試験でも、/permissionsの拒否(Deny)の一覧に、設定した5つのルールが表示されました。
Step 4:フックで「決まった操作の前後に起きること」を決める
フックは、Claude Codeの決まったタイミングで、Claude Code自身が起動するシェルコマンドです。AIが「実行しよう」と覚えている必要はありません。ただし、フックが動くのは設定した条件に合う操作のときだけで、コマンドが成功したかどうかは別に確かめる必要があります。
代表的なタイミングは次の3つです。
| イベント | いつ動くか | 使い道 |
|---|---|---|
PreToolUse | ツールを実行する前。操作を止めることもできる | 守りたいファイルの編集を止める、危険なコマンドを止める |
PostToolUse | ツールの実行が成功した後 | 編集したファイルにフォーマッターをかける |
Stop | Claudeが応答を終えるとき | 作業の終わりに確認や通知をする |
前提:以下の例は、bashと、JSONを読み取るjqコマンドが使える環境向けです。macOSやLinux、またはWindowsのWSL2の中で動かすClaude Codeを想定しています。Windowsで直接使う場合は、Git Bashとjqを用意し、Claude Codeから見つけられることを確認してください。PowerShellしかない環境では、この例はそのまま使えません。スクリプトはUTF-8・LF改行で保存します。
編集部のWindows環境では、Git Bashは入っていましたが、jqは入っていませんでした。jqを入れずに例2のフックを置くと、src/の普通のファイルの編集まで、すべて止まりました(下の「試した結果」を参照)。jqを用意してPATHに通してから、Claude Codeを起動し直してください。
例1:Edit/Writeの後に、フォーマッターを起動する
ClaudeがEditまたはWriteでファイルを編集するたびに、Prettierで整形します。Node.jsとnpm、プロジェクトに導入済みのPrettierが前提です。導入や設定の変更は、先に人間が行います。
"PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "file=$(jq -er '.tool_input.file_path | select(type == \"string\" and length > 0)') && npx --no-install prettier --write --ignore-unknown -- \"$file\"" } ] } ]
編集したファイルのパスを1つの引数として渡し、Prettierが対応していない種類のファイルは飛ばします。Bash経由で書き換えたファイルは、このフックでは整形されません。また、整形に失敗しても編集そのものは残るので、エラーが出ていないか確認してください。
例2:守りたいファイルの編集を止める
次のスクリプトを.claude/hooks/protect-files.shとして保存します。編集しようとしているファイルのパスが、守りたいパターンに一致したら、終了コード2で終わって編集を止めます。パスを読み取れなかった場合も、安全側に倒して止めます。
#!/bin/bash INPUT=$(cat) if ! FILE_PATH=$(printf '%s' "$INPUT" | jq -er \ '.tool_input.file_path | select(type == "string" and length > 0)'); then echo "Blocked: 編集対象のパスを確認できません(jqと入力を確認してください)" >&2 exit 2 fi # Windowsの区切り文字(\)を / にそろえる FILE_PATH="${FILE_PATH//'\'//}" PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/") for pattern in "${PROTECTED_PATTERNS[@]}"; do if [[ "$FILE_PATH" == *"$pattern"* ]]; then echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2 exit 2 fi done exit 0
"PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh\"" } ] } ]
区切り文字をそろえる行は、試験のあとで直しました。最初はFILE_PATH="${FILE_PATH//\\//}"と書いていましたが、編集部で試したbash(Git Bashの5.3と、WSL2のUbuntuの5.2)では、この書き方は\を/に変えず、パスの中の/を消してしまいました。そのため.git/のパターンに一致せず、.git/の中のファイルの編集が止まりませんでした。上のように\を'\'と引用符で囲むと、どちらのbashでも\が/に変わりました。Windowsでは、直したフックを置いたClaude Codeのセッションで、.git/の中のファイルの編集が止まることも確かめました。macOS標準のbashでは試していません。
この例のパターンは、パスのどこかに文字列が含まれていれば一致する、広めの判定です。そのため.env.exampleや.env.localも編集できなくなります。見本ファイルを編集したい場合は、守る対象の正確なファイル名やフォルダを決めて、パターンを調整してください。
公式ドキュメントでは、終了コード2で止めるフックは、allowの権限ルールより先に効くと説明されています。「普段のコマンドは許可しつつ、特定の操作だけは止める」という使い方ができます(今回は、allowと重なる操作では試していません)。一方で、このフックが止めるのはEditとWriteによる直接の編集だけです。Bashからの書き込みは対象外なので、Step 5で補います。
登録したフックは/hooksで一覧を確認できます。ただし、一覧に表示されただけで動作確認が済んだとは考えず、練習用ファイルの編集が通ることと、保護対象の編集が止まることの両方を実際に確かめてください。
試した結果:Step 3の設定に例1と例2のフックを加え、編集部の環境(2026年10月10日、Windows 11、Claude Code v2.1.296、Opus 5.5、手動で確認するモード)で試しました。
jqがないとき:「src/routes/health.js の応答に version: "0.1.0" を追加してください。」と頼むと、例2のフックがjq: command not foundで失敗し、Blocked: 編集対象のパスを確認できません(jqと入力を確認してください)と表示して、src/のファイルの編集も止めました。パスを読み取れないときに止める、という安全側の作りどおりの動きですが、jqがない環境ではこのフックを置くと何も編集できなくなりますjqを用意したとき:同じ依頼で編集が通り、そのあと例1のフックでPrettierが動きました。シングルクォートで書いておいたファイル全体がダブルクォートになり、行末にセミコロンが付きました。頼んだ1行以外も差分に入るので、整形の差分を確認してください- 保護したファイル:「
.env.example に PORT=3000 を1行追加してください。」と頼むと、Claudeはまず、CLAUDE.mdの「変更はsrc/配下だけ」に当たるとして確認を求めました。「はい、追加してください。」と答えると、編集は例2のフックで止まりました(.envのパターンに一致)。.env.exampleも止まるという、上の説明どおりの動きです /hooksの画面:PreToolUseとPostToolUseに、[Project]としてこの2つのフックが表示されました
Step 5:サンドボックスでシェルコマンドにも境界を引く
権限ルールとフックだけでは、シェルコマンドの内部で起きる読み書きを止めきれません。そこで使うのがサンドボックスです。サンドボックスは、Claudeが実行するシェルコマンドと、そこから起動したプロセスが読み書きできる場所を、OSのレベルで制限します。
公式ドキュメントの説明で、知っておきたい点は次のとおりです。
- 最初はオフです。セッション中に
/sandboxを実行するか、設定ファイルで有効にします - macOS、Linux、WSL2で動きます。Windowsで直接動かすClaude Codeでは、コマンドはサンドボックスなしで実行されます。Windowsで使う場合は、WSL2の中でClaude Codeを動かします
- 有効にしただけでは、作業フォルダへの書き込みや、多くのファイルの読み取りは許可されたままです。守りたい場所は、自分で指定します
- 対象はシェルコマンドだけです。ClaudeのRead/Editなどのファイル操作ツールやフックは対象外なので、Step 3の権限ルールと組み合わせます
対応する環境では、プロジェクトの.claude/settings.jsonに次のように書くと、シェルコマンドから.envとsecrets/を読めなくし、test/とロックファイルに書き込めなくする、という設定になります(対応する環境では試していません)。
"sandbox": { "enabled": true, "allowUnsandboxedCommands": false, "filesystem": { "denyRead": ["./.env", "./secrets"], "denyWrite": ["./test", "./package-lock.json"] } }
プロジェクトの設定ファイルに書いた./は、プロジェクトのフォルダを基準にします。allowUnsandboxedCommands: falseは、サンドボックスの中で失敗したコマンドを、サンドボックスの外で実行し直すことを許さない設定です。
なお、公式ドキュメントによると、手動で確認するモード(Manual)でも、allowに入れた操作や、サンドボックスの中で自動的に許可されたシェルコマンドには確認が出ません。サンドボックスの中のコマンドも1つずつ確認したい場合は、sandboxに"autoAllowBashIfSandboxed": falseを追加します。ただし、allowで許可済みのコマンドは、そのまま確認なしで動きます。
設定したら/sandboxで状態を確認します。制限のせいでテストが失敗した場合は、制限を外して実行し直すのではなく、人間が原因を確かめてください。なお、これはプロジェクト全体を読み取り専用にする設定ではありません。確認係のような役割を完全に読み取り専用にしたい場合は、書き込める場所自体を絞った実行環境が別に必要です。
試した結果(Windows):編集部の環境(2026年10月10日、Windows 11、Claude Code v2.1.296、Opus 5.5、手動で確認するモード)で、この設定を入れて/sandboxを実行すると、Sandboxing is currently only supported on macOS, Linux, and WSL2.と表示され、使えませんでした。設定ファイルに"enabled": trueと書いても、シェルコマンドは止まらずに動きました。
npm testは、allowのとおり確認なしで実行されたnode -eで.envを読むコマンドは、denyReadでは止まらず、実行の確認が表示された(編集部は「No」で止めた)node -eでtest/todos.test.jsに1行追記するコマンドは、確認で「Yes」を選ぶと、denyWriteでは止まらずに書き込まれた(試験後に元へ戻した)
Windowsで直接動かす場合、denyReadとdenyWriteは効かないものとして考え、Step 3の権限ルールと手動の確認で守ってください。WSL2の中で動かすClaude Codeでは試していません。
設定の完成形:1つのsettings.jsonにまとめる
Step 3〜5のJSONは、説明のために部分ごとに分けて表示しました。ファイル全体を上書きしたり、JSONを末尾に貼り足したりしないでください。settings.jsonは1つの{ ... }にまとめ、hooksの中にPreToolUseとPostToolUseを並べます。すでに設定がある場合は、その中へ追加します。
{ "permissions": { "allow": [ "Bash(npm test)", "Bash(npm run typecheck)" ], "deny": [ "Bash(git push *)", "Read(/.env)", "Read(/secrets/**)", "Edit(/test/**)", "Edit(/package-lock.json)" ] }, "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh\"" } ] } ], "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "file=$(jq -er '.tool_input.file_path | select(type == \"string\" and length > 0)') && npx --no-install prettier --write --ignore-unknown -- \"$file\"" } ] } ] }, "sandbox": { "enabled": true, "allowUnsandboxedCommands": false, "filesystem": { "denyRead": ["./.env", "./secrets"], "denyWrite": ["./test", "./package-lock.json"] } } }
この完成形は、サンドボックスに対応した環境、導入済みのPrettier、bashとjqを前提にしています。テストと型チェックのスクリプトの中身も、先に人間が確認しておきます。
試した結果:この完成形と一字一句同じsettings.jsonを置いてClaude Codeを起動すると、エラーなく読み込まれました(2026年10月10日、Windows 11、Claude Code v2.1.296)。/permissionsの許可(Allow)に2つ、拒否(Deny)に5つのルールが表示され、/hooksには2つのフックが[Project]として表示されました。サンドボックスだけは、Step 5のとおりWindowsでは使えませんでした。
Step 6:つまずいたら、プロンプトではなく作業場を直す
ハーネスは一度で完成しません。実際にClaude Codeを動かし、つまずいた場所を作業場へ戻していきます。
| 起きたこと | 直す場所 |
|---|---|
| 毎回同じ安全なコマンドで確認を求められる | 中身を確認したうえで、そのコマンドだけをallowに追加する |
| 同じ規約違反を何度もする | CLAUDE.mdか.claude/rules/に、具体的な一文を足す |
| 注意しても、触ってほしくないファイルを触る | CLAUDE.mdではなく、denyルール、フック、サンドボックスで止める |
| 必要な資料を見つけられない | CLAUDE.mdの目次に、資料の場所を足す |
| CLAUDE.mdが長くなり、守られにくくなった | テーマ別に.claude/rules/へ分ける。古い指示や矛盾した指示を消す |
ポイントは、同じ失敗を2回見たら、プロンプトで注意するのをやめて作業場を直すことです。プロンプトでの注意はその会話でしか効きませんが、作業場の改善は次の会話からもずっと効きます。
Part 4:権限モードは作業場の「信頼レベル」
権限モードは、どの程度確認を挟むかを決める全体方針です。ハーネスが整うほど、任せる範囲を広げられます。
| モード | 動き方 | 向く場面 |
|---|---|---|
default(Manual) | 読み取りは確認なし。ファイル編集・シェルコマンド・ネットワーク操作などは、許可ルールなどで許可されていなければ確認する | 使い始め、慣れていないプロジェクト |
plan | ファイルを読んで調べ、計画を立てる。計画を承認するまで編集しない | 変更前に計画を立てたいとき |
acceptEdits | 作業フォルダ内のファイル編集と、よく使うファイル操作を自動で許可する | 編集内容を後で差分で確認できるとき |
auto | 通常の確認なしで進む。シェルコマンドなどは、実行前に別のモデル(分類器)が依頼に沿っているかを確認する | ハーネスが整い、無人で進めたいとき |
bypassPermissions | 確認をほぼすべて省略する | コンテナや仮想マシンなど、壊れても困らない隔離環境だけ |
注意したいのは、起動したときのモードがdefaultとは限らないことです。2026年10月5日時点の公式情報では、Claude Code v2.1.283以降、ターミナルやVS Codeで起動したときの既定のモードがautoになっていると説明されています。設定やバージョン、利用環境によっても変わります(今回の試験では起動時に毎回モードを指定したため、既定のモードは確かめていません)。
このハーネスを初めて試すときは、手動で確認するモードで始めましょう。起動時にclaude --permission-mode defaultと指定するか、セッション中にShift+Tabを押して、画面下の表示が⏸ manual mode onになったことを確かめます。今回の試験でも、--permission-mode defaultで起動すると、画面下に⏸ manual mode onと表示されました。また、このモードで確認の画面が出たとき、選択肢には「Yes, and don’t ask again for: npm *」のように、広い範囲をまとめて許可する案も表示されました。Step 3のとおり、広い許可は中身を確かめてから選んでください。
公式ドキュメントは、bypassPermissionsをコンテナや仮想マシンのような、Claude Codeが損害を与えられない隔離環境でだけ使うよう注意しています。普段の開発用PCで、確認を省くためだけに使うものではありません。
Part 5:初心者がつまずく4つの落とし穴
| 落とし穴 | 何が起きるか | 防ぎ方 |
|---|---|---|
| CLAUDE.mdに書けば守られると思う | 長い作業の途中で注意が埋もれ、禁止したことをされる | 本当に禁止したいことは、denyルール、フック、サンドボックスで止める |
| CLAUDE.mdに何でも書き足す | ファイルが長くなり、かえって指示が守られにくくなる | 200行未満を目安に、詳しい内容は資料へのリンクと.claude/rules/に分ける |
| 確認が面倒で、広く許可する | npm run *のような広い許可から、公開用のスクリプトや外部への送信まで動く | まず手動の確認を残し、中身を確認したテストや型チェックのコマンドだけを個別にallowへ入れる |
| 1つの仕組みを完全な壁だと思う | Bashのdenyは別の書き方を、この記事のEdit/Write用フックはBash経由の書き込みを、サンドボックスはRead/Editなどのファイル操作ツールを止められない | 権限ルール、フック、サンドボックスを組み合わせ、それぞれが守れる範囲を把握する |
今回の試験(2026年10月10日、Windows 11)で実際に起きたのは、4つ目の落とし穴に当たることでした。Read(/.env)のdenyはnode -eで読むコマンドを止めず、Windowsではサンドボックスも動かなかったため、止めたのは手動の確認だけでした。このほか、表にない次の2つも起きました。
- フックの前提の道具がない:
jqがないと、保護フックがsrc/の編集まで止めた - スクリプトの1行が環境によって働かない:区切り文字をそろえる行が、試したbashでは
/を消してしまい、.git/の保護が効かなかった(本文のスクリプトは直したもの)
フックやサンドボックスは、置いたら「止めたいものが止まり、通したいものが通る」ことを、練習用ファイルで実際に確かめてください。
結論:最初の一歩は「5つの欄」と手動確認から
ハーネスエンジニアリングは、AIに賢い指示を出す技術ではありません。AIが迷わず、事故を起こさず、毎回同じ品質で働ける作業場を用意する技術です。
今日から試すなら、次の順番がおすすめです。
- 練習用のプロジェクトで、手動で確認するモード(Manual)にして始める
- 読んでよいもの、変えてよいもの、使う道具、確かめる場所、人間が判断する場所の5つの欄を書き出す
/initでCLAUDE.mdを作り、200行未満の「地図」に整える.claude/settings.jsonに、allowとdenyのルールを数行だけ書く- 守りたいファイルを止めるフックを1つ入れ、止まることを実際に確かめる
- 対応する環境(macOS、Linux、WSL2)なら、サンドボックスでシェルコマンドにも境界を引く。Windowsで直接動かす場合は使えないので、手動の確認を残す
ハーネスが整うと、その上でループを回し、グラフで仕事を分けられるようになります。AIの力を信じて任せるためにこそ、その力が向かう先と、止まる場所を先に決めておく。それがハーネスエンジニアリングです。
参考資料
- Claude Code Docs「How Claude remembers your project」 https://code.claude.com/docs/en/memory
- Claude Code Docs「Configure permissions」 https://code.claude.com/docs/en/permissions
- Claude Code Docs「Automate actions with hooks」 https://code.claude.com/docs/en/hooks-guide
- Claude Code Docs「Choose a permission mode」 https://code.claude.com/docs/en/permission-modes
- Claude Code Docs「Configure the sandboxed Bash tool」 https://code.claude.com/docs/en/sandboxing
- OpenAI「Harness engineering: leveraging Codex in an agent-first world」 https://openai.com/index/harness-engineering/
関連投稿(本文は未確認)
- 令和の織田信長 (@oda_nobunaga10)「Claude Code・CodexのHarness Engineering入門」 https://x.com/oda_nobunaga10/status/2082447124676186425
