Claude Code/Codex ハーネス環境ガイド

Claude Codeを、仕事の専属アシスタントとして使うための足場

この資料は、Claude Code を仕事の道具として使うための「足場」の作り方を、章の順に1つずつ説明する。コマンドが打てれば進められる。インストールは短く、「なぜこの仕掛けが要るのか」を図で見せることに時間をかけている。各章は「絵 → なぜ要るか → 3行でいうと → 作り方 → テンプレ → できたかの確認」の順で、その章だけで完結する。Windows と Mac は上の「表示」で切り替えると、手順・テンプレ・指示文が自分の OS のものだけになる。各章の末尾の「自分の環境で数えてみる」は、自分の環境の規模を測るコマンドで、読まなくても先へ進める。

はじめに この資料の読み方

読み方は4つだけ。

  1. 章の順に進む。第0章から第12章まで、前の章を終えてから次へ。飛ばさない
  2. 各章は1画面で完結。絵で全体をつかみ、「なぜ要るか」で理由を知り、作り方のとおりに置いて、確認の1文で終える。前の章で置いたファイルを使うことはあるが、戻って読み直す必要はない
  3. 場所の書き方。「作業フォルダ ▸ .claude ▸ rules」は、作業フォルダの中の .claude フォルダの中の rules フォルダ。「自分のホーム」は C:\Users\自分の名前Finder の家のアイコン(ターミナルでは ~)
  4. 上の「Windows/Mac」で表示を切り替える。手順・テンプレ・指示文が自分の OS のものだけになる。コマンドは PowerShell(スタートメニューで「PowerShell」と検索して開く)で打つコマンドは「ターミナル」(アプリケーション ▸ ユーティリティ)で打つ。Claude Code でなく Codex を使う場合は各章末の「Codex の場合」を見る(対応表は付録D)
テンプレは2種類。Starter キット(第2・3・4・6・7章で使う最小限のファイル。スキルや自動化は入っていない)と、参考サンプル集(スキル・検品係・名簿・自動化・Codex の見本。必要なものだけ使う)。どちらも各章の「テンプレ」欄に本文を載せてあるので、コピーして置く。

テンプレの置き方

  1. コピーして保存する(基本): 各章のテンプレ欄の「コピー」を押し、エディタ(VS Code など)に貼って、「置く場所」に書いてある場所へ同じ名前で保存する。フォルダが無ければ先に作る
  2. フォルダの作り方: PowerShell で mkdir .claude\rules のように作る(エクスプローラーで作るなら、名前の最後にもドットを付けて .claude. と入力すると .claude になる)ターミナルで mkdir -p .claude/rules のように作る(Finder では先頭ドットのフォルダは隠れる。Command+Shift+. で表示)
  3. 注意: メモ帳で「名前を付けて保存」すると末尾に .txt が付くテキストエディットは既定で書式付き(rtf)で保存する。保存は VS Code などのエディタで行うか、Claude Code に「このファイルをこの場所に作って」と貼って頼む

全体の地図

この資料全体の地図。下の「積み木」は足場の層で、各段の( )は対応する章。下から順に積む。その下の「困りごとと仕掛け」は、なぜその段が要るのかを1行で対応させたもの。

足場の層と章の対応自動化(第11・12章)夜間の無人ジョブと月1回の健診別の目と名簿(第9・10章)検品係・サブエージェント・係の名簿スキル(第8章)いつもの仕事を一言で呼ぶ手順書自動の柵(第6・7章)hook と git hook で事故を手前で止める外とつなぐ(第5章)MCP・プラグインで Drive・メール・Slack権限(第4章)allow・deny・ask で線を引く記憶(第3章)日次サマリー・台帳・MEMORY.md指示書(第2章)CLAUDE.md と rules土台(第0・1章)Claude Code を入れる+git で履歴を残す下が土台・上が応用
足場の層と章の対応自動化(第11・12章)夜間の無人ジョブと月1回の健診別の目と名簿(第9・10章)検品係・サブエージェント・係の名簿スキル(第8章)いつもの仕事を一言で呼ぶ手順書自動の柵(第6・7章)hook と git hook で事故を手前で止める外とつなぐ(第5章)MCP・プラグインで Drive・メール・Slack権限(第4章)allow・deny・ask で線を引く記憶(第3章)日次サマリー・台帳・MEMORY.md指示書(第2章)CLAUDE.md と rules土台(第0・1章)Claude Code を入れる+git で履歴を残す下が土台・上が応用
困りごと → それを防ぐ仕掛け1毎回ゼロから指示書と記憶で前提をそろえる(第2・3章)2何でもやる権限と柵で、できなくする(第4・6・7章)3同じ見落とし別の目で疑う(第9章)4手順がぶれるスキルで型にする(第8章)5止まる無人化と健診で回し続ける(第11・12章)
困りごと → それを防ぐ仕掛け1毎回ゼロから指示書と記憶で前提をそろえる(第2・3章)2何でもやる権限と柵で、できなくする(第4・6・7章)3同じ見落とし別の目で疑う(第9章)4手順がぶれるスキルで型にする(第8章)5止まる無人化と健診で回し続ける(第11・12章)
第0章から第12章へ。左から右に進む第0章入れる第1章git第2章指示書第3章記憶第4章権限第5章MCP第6章hooks第7章git hook第8章スキル第9章検品係第10章名簿第11章無人化第12章健診
図は横にずらして見られます

第0章 Claude Code を入れる最初の会話まで

1入れる公式のインストールコマンドを打つ2ログイン初回起動でブラウザが開く。自分のアカウント3話す作業フォルダで起動し「中身を説明して」4/ と Esc/ で一覧、Esc で中断。眺めるだけ
1入れる公式のインストールコマンドを打つ2ログイン初回起動でブラウザが開く。自分のアカウント3話す作業フォルダで起動し「中身を説明して」4/ と Esc/ で一覧、Esc で中断。眺めるだけ

なぜこの仕掛けが要るか

Claude Code は「質問に答える AI」ではなく「フォルダの中で手を動かす AI」。任せられる範囲が広いぶん、何も決めずに使うと日によって振る舞いが変わる。この資料の13章は、その振る舞いをそろえる足場づくり。
1チャット文章で答えるだけ。ファイルには触れない2Claude Codeフォルダの中を読み、書き、コマンドも実行する3だから任せられる分、事故も大きくなる4足場次章からの仕掛けで毎回同じ振る舞いにする
1チャット文章で答えるだけ。ファイルには触れない2Claude Codeフォルダの中を読み、書き、コマンドも実行する3だから任せられる分、事故も大きくなる4足場次章からの仕掛けで毎回同じ振る舞いにする

3行でいうと

  1. Claude Code は、作業フォルダの中で動く AI のアシスタント。ファイルを読み書きし、コマンドも実行する。
  2. まず入れて、ひと言話しかける。ここまでが第0章。
  3. 以降の章は、この「話しかけたときの振る舞い」を毎回同じにするための仕掛けを、1つずつ足していく。

作り方

  1. PowerShell を開き、irm https://claude.ai/install.ps1 | iex を実行する(winget install Anthropic.ClaudeCode でもよい)ターミナルを開き、curl -fsSL https://claude.ai/install.sh | bash を実行する(brew install --cask claude-code でもよい)。公式手順: code.claude.com/docs/en/setup。VS Code 派は拡張機能で「Claude Code」を追加
  2. Git for Windows(git-scm.com)を入れる。Claude Code がコマンドを実行するのに使う(第1章でも使う)git はターミナルで git --version を打つと、無ければ入れるか聞かれる(Xcode コマンドラインツール)。第1章でも使う
  3. PowerShellターミナルで claude を一度実行し、開いたブラウザで Claude のアカウントにログインする(有料プランか、組織から配られたアカウントが要る)
  4. 作業用フォルダを1つ作り(例: 自分のホーム ▸ work ▸ my-harness)、PowerShellターミナルで cd して claude を起動し、「このフォルダの中身を説明して」と頼んで返答を確かめる。「/」だけ打つとコマンド一覧が出て、Esc で止められる(今は覚えなくてよい)

貼る指示文(Claude Code にそのまま貼る)

このフォルダの中身を一覧して、何のためのフォルダに見えるか一言で教えてください。ファイルは変更しないでください。

できたかの確認

確認自分の言葉で「Claude Code はフォルダの中で動くアシスタント」と説明でき、PowerShellターミナルの claude で会話できる。
つまずき最初から大きな仕事を頼むと、何が良くて何が悪いのか分からない。まず小さな質問で「返答の癖」を見る。
Codex の場合Codex CLI は PowerShell で powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"ターミナルで curl -fsSL https://chatgpt.com/codex/install.sh | sh。codex を実行し「Sign in with ChatGPT」で自分の ChatGPT アカウントにログインする。以降の章の「作業フォルダで起動」は codex と読み替える。

第1章 git と GitHub変更の履歴を持つ

1git init作業フォルダを「履歴つき」にする(1回だけ)2コミット変更をひと区切りとして記録する3戻せる履歴のどの時点にも戻れる4GitHub(任意)履歴を共有場所に置く。チームで使う時だけ
1git init作業フォルダを「履歴つき」にする(1回だけ)2コミット変更をひと区切りとして記録する3戻せる履歴のどの時点にも戻れる4GitHub(任意)履歴を共有場所に置く。チームで使う時だけ

なぜこの仕掛けが要るか

指示書やスキルは何度も書き換える。AI が良かれと思って書き換えることもある。履歴が無いと、壊れたときに「前はどうだったか」に戻れず、直すのが怖くなる。
1直す指示書やスキルを何度も書き換える2壊れるAI の書き換えで意図しない変更が入る3戻す履歴があれば直前の状態へ戻れる
1直す指示書やスキルを何度も書き換える2壊れるAI の書き換えで意図しない変更が入る3戻す履歴があれば直前の状態へ戻れる

3行でいうと

  1. git は、フォルダの中のファイルの「変更の履歴」を残す道具。いつ・何を変えたかが残り、いつでも戻せる。
  2. 指示書やスキルは何度も直すので、履歴が無いと「前はどう書いてあったか」が分からなくなる。だから最初に入れる。
  3. GitHub は、その履歴を置く共有場所(クラウド)。1人で使う間は無くてよい。チームで共有したくなったら、その組織のルールに従って使う。
この章の言葉: git/リポジトリ・コミット・GitHub(付録A)

作り方

  1. Git for Windows を入れてあれば git --version で版が出る。出なければ第0章の手順2に戻るターミナルで git --version を打つ。無ければ入れるか聞かれるので入れる
  2. PowerShellターミナルで作業フォルダに cd し、git init を1回だけ実行する(フォルダの中に隠しフォルダ .git ができる)
  3. 名前とメールを1回だけ登録する: git config --global user.name "自分の名前"/git config --global user.email "自分のメール"
  4. 最初の記録: git add . のあと git commit -m "最初の記録"。以降は区切りごとに同じ2コマンド(Claude Code に「コミットして」と頼んでもよい)
  5. GitHub は今は不要。使う時は所属する組織のルールを確かめ、認証ファイルを置かないよう気をつける

貼る指示文(Claude Code にそのまま貼る)

この作業フォルダを git で管理したいです。git init が済んでいるか確かめ、済んでいなければ実行してください。その後、今あるファイルを「最初の記録」というメッセージでコミットしてください。GitHub への push はしないでください。

できたかの確認

確認git log --oneline で「最初の記録」が1行出る。
つまずきgit add . は「フォルダの全部」を記録する。認証ファイル(secret_*.json・.env)が入っていると履歴に残ってしまう。第7章の秘匿スキャンを入れるまでは、認証ファイルを作業フォルダに置かない。
Codex の場合git の使い方は同じ。Codex にも「コミットして」と頼める(Codex は既定で作業フォルダの外に書けない sandbox で動く)。

第2章 指示書CLAUDE.md と rules

作業フォルダCLAUDE.md目次だけ(役割1行・読むファイルの一覧).clauderules01-must-follow.md絶対ルール5項目
図は横にずらして見られます

なぜこの仕掛けが要るか

指示書が無いと、Claude Code は毎回ゼロから判断する。同じ質問でも日によって答えが違うのは、前提が毎回違うから。
1指示なし同じ質問でも日によって答えが違う2CLAUDE.md起動時に必ず読まれる目次3rules絶対ルール。短く、正本は1か所4毎回同じ誰が呼んでも同じ前提で動く
1指示なし同じ質問でも日によって答えが違う2CLAUDE.md起動時に必ず読まれる目次3rules絶対ルール。短く、正本は1か所4毎回同じ誰が呼んでも同じ前提で動く

3行でいうと

  1. 指示書がないと、Claude Code は毎回ゼロから判断し、日によって答えが変わる。
  2. CLAUDE.md は「目次」、rules は「絶対ルール」。どちらも起動時に自動で読まれる。
  3. 最初は rules 1本・5項目で十分。増やすのは困ってから。
この章の言葉: ハーネス・CLAUDE.md・rules・文脈・常駐コスト(付録A)

作り方

  1. Starter キットの CLAUDE.md を 作業フォルダ の直下に置き、<仕事の名前> と役割の1行を自分の言葉に書き換える
  2. Starter キットの 01-must-follow.md を 作業フォルダ ▸ .claude ▸ rules に置く(フォルダの作り方は「はじめに」の「テンプレの置き方」)
  3. 同じ方針を2か所に書かない。CLAUDE.md には本文を書かず、案内だけにする
  4. 新しいセッションを開き、下の指示文を貼って、rules の中身がそのまま返ることを確かめる

テンプレ(そのまま置けるファイル)

Starter キット CLAUDE.md
置く場所: 作業フォルダ ▸ CLAUDE.md
# CLAUDE.md — <仕事の名前> の Claude Code 設定(目次だけ)

## 役割
<仕事の名前>の専属アシスタント。<主な仕事を1行で。例: 議事録・週次レポート・問い合わせ対応の下書き>

## 絶対ルール
本体は `.claude/rules/01-must-follow.md`。ここには再掲しない。

## ルールファイル(`.claude/rules/` は毎セッション自動で読まれる)
- `01-must-follow.md` — 絶対ルール5つ

## 保存先
新しいファイルの置き場は `context/README.md` が正本。迷ったら `inbox/` に置く。

## 記憶
覚えておく事実は Claude Code のメモリ(索引 MEMORY.md + 1ファイル1事実)に書く。経緯や日記は書かない。
Starter キット .claude/rules/01-must-follow.md
置く場所: 作業フォルダ ▸ .claude ▸ rules ▸ 01-must-follow.md
# 絶対守るルール(5つ)

毎ターン確認する。文脈が長くなっても有効。

## 1. 数値は実データだけ
件数・金額・割合は、必ず実際のデータやコマンドの結果から取る。根拠がない数値は「不明」と書く。
「送りました」「登録しました」の報告は、戻り値ではなく実体(メッセージID・ログ・保存ファイル)で確かめてから書く。

## 2. 作業前に一言確認
ファイルの上書き・コードの変更・外部への送信は、方針を一言確認してから。読むだけ・軽微な修正は確認不要。
頼まれた範囲を超える追加・整理はしない。

## 3. 秘密に触らない
`secret_*.json`・`credentials*.json`・`.env` は読まない・書かない・コミットしない。
自動実行の定義(Windows のタスクスケジューラの登録、Mac の LaunchAgents の plist)は変更前に必ず確認する。

## 4. 相談と依頼を区別する
「どう思う?」「なぜ?」は分析・所見を返すだけ。修正・送信・登録は、はっきり頼まれてから。

## 5. 日次サマリーを書く
意味のある作業が終わったら、その日の日次サマリー(1日1ファイル)に1件追記する。
会社名・顧客名・個人が特定できる情報は書かない。

貼る指示文(Claude Code にそのまま貼る)

今の絶対ルールを、.claude/rules/01-must-follow.md に書いてあるとおりに5つ挙げてください。ファイルは変更しないでください。

できたかの確認

確認新しいセッションで「今の絶対ルールは?」と聞くと、rules の5項目がそのまま返る。
つまずき.claude/rules/ の中身は Claude Code が起動時に自動で読む。同じ内容を hook でも流すと二重に読まれて無駄なので、方針は rules に1回だけ書く。特定のファイルを触るときだけ読ませたいルールは、ファイルの先頭に paths: で対象を書ける(上級者向け。最初は使わなくてよい)。
Codex の場合Codex は CLAUDE.md の代わりに作業フォルダ直下の AGENTS.md を読む(付録D のテンプレ codex/AGENTS.md.sample)。.claude/rules/ の自動読み込みは無いので、絶対ルールも AGENTS.md に書く。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

指示書の本数と大きさ(毎セッション読まれる量)を、自分の環境で数えてみる(作業フォルダで実行する)。

Get-ChildItem CLAUDE.md, .claude\rules\*.md | Select-Object Name, Length
wc -c CLAUDE.md .claude/rules/*.md

第3章 記憶MEMORY.md・context・日次サマリー

1記録する日次サマリー: その日やったことを1日1ファイル2台帳を置くcontext/: チーム・案件・保存先。今の事実だけ3覚えさせるMEMORY.md: 「覚えて」と頼むと Claude Code が書く索引
1記録する日次サマリー: その日やったことを1日1ファイル2台帳を置くcontext/: チーム・案件・保存先。今の事実だけ3覚えさせるMEMORY.md: 「覚えて」と頼むと Claude Code が書く索引

なぜこの仕掛けが要るか

セッションを閉じると会話の中身は消える。次の日も同じ前提で働いてもらうには、残す先を3つに分けて決めておく。
1会話閉じると中身は消える2日次サマリーその日やったこと(1日1ファイル)3context/人が更新する台帳(今の事実だけ)4MEMORY.md頼むと AI が書く事実の索引
1会話閉じると中身は消える2日次サマリーその日やったこと(1日1ファイル)3context/人が更新する台帳(今の事実だけ)4MEMORY.md頼むと AI が書く事実の索引

3行でいうと

  1. セッションを閉じると会話の中身は消える。残るのは「記憶に書いたもの」だけ。
  2. 記憶は3つ。その日の記録(日次サマリー)、人が更新する台帳(context/)、Claude Code が自分で書く索引(MEMORY.md)。
  3. 約束は「索引は1行1件、事実の本文は1ファイル1事実、日誌は1日1ファイル」。
この章の言葉: MEMORY.md・context/・日次サマリー(付録A)

作り方

  1. Starter キットの context/README.md を 作業フォルダ ▸ context に置く。台帳のファイルは必要になったときに1つずつ作る
  2. 日次サマリーの置き場を1か所決める(Starter キットは 作業フォルダ ▸ diary)。2026-01-01.sample.json を見本として置く
  3. MEMORY.md は自分で作らない。Claude Code に「これを覚えて」と頼むと、自分のホームの中に索引と本文を作る(自動メモリ)
  4. 意味のある作業が終わるたびに、下の指示文で日次サマリーに1件追記する癖をつける(第8章でこれをスキルにする)

テンプレ(そのまま置けるファイル)

Starter キット context/README.md
置く場所: 作業フォルダ ▸ context ▸ README.md
# context/ — 人が更新する台帳の置き場

Claude Code が仕事の前に読む「前提」を置く。経緯や日記ではなく、今の事実だけを書く。

| ファイル | 何を書くか | 更新する人・頻度 |
|---|---|---|
| `team.md` | チームの役割・呼び方(人名の表記ルール)。個人情報は書かない | 人・異動のたび |
| `projects.md` | 進行中の案件と今の状態(1案件3行) | 人・週1 |
| `output-map.md` | 「どの種類の成果物をどこに保存するか」の正本 | 人・保存先を新設したとき |
| `ai-org.md` | 係の名簿(課・係・呼び出し・実体・仕事) | 係を足したとき |

## 約束
- 1ファイル200行以内。超えたら分ける
- 数値・日付はここに書かない(すぐ古くなる)。書くなら「いつ時点か」を添える
- 顧客名・個人名を書く場合は、社外に出ない前提を守る(このフォルダを共有しない)
Starter キット diary/2026-01-01.sample.json
置く場所: 作業フォルダ ▸ diary ▸ YYYY-MM-DD.json
{
  "date": "2026-01-01",
  "accomplishments": [
    "作業フォルダに CLAUDE.md と絶対ルールを置き、新しいセッションで「今の絶対ルールは?」と聞いて中身が返ることを確かめた。",
    "日次サマリーの置き場を diary/ に決め、この1件目を書いた。"
  ],
  "tips_discovered": [
    "指示書を目次だけにしたら、ルールを直す場所が1か所になり迷わなくなった"
  ],
  "summary": "指示書と日次サマリーの置き場を決めた"
}

貼る指示文(Claude Code にそのまま貼る)

メモリを整えてください。MEMORY.md は「- [題名](file.md) — 要点」の1行だけの索引にし、本文・経緯・最終セッションの要約は書かない。
1ファイル1事実(feedback=私の指示・訂正、project=進行中の確定判断、reference=外部リンク)。索引にない/存在しないファイルの食い違いをゼロにし、
1行を100文字以内に。古い経緯は memory/archive/YYYY-MM.md へ。

意味のある作業が終わるたびに diary/YYYY-MM-DD.json(作業フォルダの diary/) の accomplishments に1件追記する運用にしてください
(会社名・顧客名・個人名は書かない)。コンテキストが70%に達したら 引き継ぎメモ handoffs/NEXT_SESSION_<題名>.md(次のセッションの最初に読ませるファイル。handoffs フォルダが無ければ作る)に「実測で確定した事実/罠/
触ってはいけないもの/残タスク+完了条件/次セッションに貼るプロンプト」を書いてから止めてください。

できたかの確認

確認「覚えて」と頼んだ事実が次のセッションでも返り、diary に今日のファイルがある。
つまずき「最終セッションの要約」のような経緯を記憶に書くと肥大する。記憶は事実だけ、経緯は日次サマリーへ。
Codex の場合Codex には Memories(自動メモリに当たる機能。既定はオフで、自分のホームの .codex/config.toml に features.memories = true で有効)がある。context/日次サマリーは同じ形で残す。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

記憶の索引 MEMORY.md の行数を、自分の環境で数えてみる(作業フォルダで実行する)。

Get-ChildItem "$HOME\.claude\projects" -Recurse -Filter MEMORY.md | ForEach-Object { "$($_.FullName): $((Get-Content $_.FullName).Count) 行" }
wc -l ~/.claude/projects/*/memory/MEMORY.md

第4章 権限settings.json の allow / deny / ask

1allow読む・探す・編集する2denysecret・credentials・.env を読む3ask削除・push・外への登録は毎回確認
1allow読む・探す・編集する2denysecret・credentials・.env を読む3ask削除・push・外への登録は毎回確認

なぜこの仕掛けが要るか

AI は頼まれれば秘密のファイルも読むし、削除もする。ためらわない。だから「できないようにする」線は、人が先に引いておく。
1頼まれる「このフォルダを整理して」2AI は実行する消す・上書き・読む。ためらわない3人が引いた線deny で止め、ask で聞く4事故が減る許す範囲だけが残る
1頼まれる「このフォルダを整理して」2AI は実行する消す・上書き・読む。ためらわない3人が引いた線deny で止め、ask で聞く4事故が減る許す範囲だけが残る

3行でいうと

  1. AI は頼まれれば秘密のファイルも読むし、削除もする。「できないようにする」のは人の仕事。
  2. 権限は3区分。allow(自由にしてよい)・deny(絶対にしない)・ask(毎回聞く)。
  3. deny に認証ファイル、ask に削除・push・外への登録。これだけで事故の大半を防ぐ。
この章の言葉: settings.json・allow / deny / ask・トークン(認証)(付録A)

ツール名の一覧(allow/deny/ask に書く名前と、その操作)

allow/deny/ask に書く「ツール名」が、どんな操作を指すかの一覧。

ツール名どんな操作か書き方の目安
Readファイルの中身を読むRead(**/secret_*.json) のようにパターンで絞れる
Globファイル名のパターンで探す(例: *.md)読むだけ。許可してよい
Grepファイルの中の文字列を探す読むだけ。許可してよい
Edit既存ファイルの一部を書き換える作業フォルダの中に限られる
Writeファイルを新規作成・全文上書きする同上。deny に Edit(**/secret_*.json) を書くと Write も止まる(Edit のルールは Write にも効く)
Bash(…)コマンドを実行する(Git for Windows の bash 経由標準のシェル経由)Bash(git status:*) のようにコマンド単位で許可する。Bash 単独は全許可なので書かない
PowerShell(…)PowerShell のコマンドを実行するWindows だけのツール。Mac では使わない同上。PowerShell(Remove-Item:*) は ask にMac の settings には書かなくてよい
WebFetch/WebSearchWeb ページを読む・検索する使うなら allow に。社内資料だけなら不要
mcp__名前__*MCP でつないだ外部サービスの操作(第5章)サーバーごとに mcp__google-workspace__* のように許可する

作り方

  1. Starter キットの settings.jsonsettings.mac.json を settings.json に改名して 作業フォルダ ▸ .claude に置く(hooks の登録も入っている。中身は第6章で置く)
  2. allow は「読む系+Edit/Write+よく使うコマンド」だけ。Bash や PowerShell を丸ごと許可しない(下の一覧で、どの操作を許すか決める)
  3. deny の認証ファイル名を、自分の環境で使う名前に合わせる(secret_*.json 等)
  4. 新しいセッションで、認証ファイルを「読んで」と頼み、拒否されることを確かめる(コマンド経由の読み取りは第6章の hook で止める)

テンプレ(そのまま置けるファイル)

Starter キット .claude/settings.json
置く場所: 作業フォルダ ▸ .claude ▸ settings.json
{
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "Edit",
      "Write",
      "Bash(ls:*)",
      "Bash(cat:*)",
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "PowerShell(Get-ChildItem:*)",
      "PowerShell(Get-Content:*)",
      "PowerShell(git status:*)",
      "PowerShell(git diff:*)",
      "PowerShell(git log:*)"
    ],
    "deny": [
      "Read(**/secret_*.json)",
      "Read(**/credentials*.json)",
      "Read(**/.env)",
      "Read(**/.env.*)",
      "Edit(**/secret_*.json)",
      "Edit(**/credentials*.json)",
      "Edit(**/.env)",
      "Edit(**/.env.*)"
    ],
    "ask": [
      "Bash(rm:*)",
      "Bash(git push:*)",
      "PowerShell(Remove-Item:*)",
      "PowerShell(git push:*)",
      "PowerShell(schtasks:*)"
    ]
  },
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe",
            "args": [
              "-NoProfile",
              "-ExecutionPolicy",
              "Bypass",
              "-File",
              "${CLAUDE_PROJECT_DIR}/.claude/hooks/inject-core-rules.ps1"
            ],
            "timeout": 5
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash|PowerShell|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe",
            "args": [
              "-NoProfile",
              "-ExecutionPolicy",
              "Bypass",
              "-File",
              "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-sensitive-files.ps1"
            ],
            "timeout": 5
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe",
            "args": [
              "-NoProfile",
              "-ExecutionPolicy",
              "Bypass",
              "-File",
              "${CLAUDE_PROJECT_DIR}/.claude/hooks/session-close.ps1"
            ],
            "timeout": 10
          }
        ]
      }
    ]
  }
}
Starter キット .claude/settings.mac.json
置く場所: 作業フォルダ ▸ .claude ▸ settings.json(改名して置く)
{
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "Edit",
      "Write",
      "Bash(ls:*)",
      "Bash(cat:*)",
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(python3:*)"
    ],
    "deny": [
      "Read(**/secret_*.json)",
      "Read(**/credentials*.json)",
      "Read(**/.env)",
      "Read(**/.env.*)",
      "Edit(**/secret_*.json)",
      "Edit(**/credentials*.json)",
      "Edit(**/.env)",
      "Edit(**/.env.*)"
    ],
    "ask": [
      "Bash(rm:*)",
      "Bash(git push:*)",
      "Bash(launchctl:*)"
    ]
  },
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/inject-core-rules.sh",
            "timeout": 5
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard-sensitive-files.py",
            "timeout": 5
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-close.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

貼る指示文(Claude Code にそのまま貼る)

作業フォルダの .claude/settings.json の permissions を設計してください(自分のホームの settings.json は触らない)。allow は Read・Glob・Grep・Edit・Write と、よく使う git コマンド(status/diff/log)だけ。deny に secret_*.json・credentials*.json・.env の Read と Edit。ask に削除(rm・Remove-Item)と git push。Bash や PowerShell を丸ごと許可しないでください。変更前に今の内容を表示し、差分を見せてから適用してください。
作業フォルダの .claude/settings.json の permissions を設計してください(自分のホームの settings.json は触らない)。allow は Read・Glob・Grep・Edit・Write と、よく使う git コマンド(status/diff/log)だけ。deny に secret_*.json・credentials*.json・.env の Read と Edit。ask に削除(rm)と git push。Bash を丸ごと許可しないでください。変更前に今の内容を表示し、差分を見せてから適用してください。

できたかの確認

確認認証ファイルを「読んで」と頼むと拒否され、削除を頼むと確認が出る。
つまずきallow を広げて確認ダイアログを減らすと、後で無人実行にしたとき止まらずに事故になる。減らすのは「読む系」だけ。
Codex の場合Codex は allow/deny/ask の代わりに、自分のホームの .codex/config.toml で approval_policy(いつ確認するか)と sandbox_mode(どこまで書けるか)を決める。最初は approval_policy = "untrusted"・sandbox_mode = "workspace-write"(作業フォルダの中だけ書ける)が安全。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

本体のモデルと effortを、自分の環境で数えてみる(作業フォルダで実行する)。

Select-String -Path "$HOME\.claude\settings.json" -Pattern '"model"|"effortLevel"'
grep -E '"model"|"effortLevel"' ~/.claude/settings.json

第5章 外とつなぐMCP(Drive・メール・カレンダー)

1確認する会社のデータなら管理者の許可が要るか確かめる2決める何につなぐか・認証の方式3環境変数に置くIDとシークレット。ファイルに直書きしない4.mcp.jsonサンプルをコピーし変数名で参照5同意する/mcp で状態を見て、自分のアカウントで同意
1確認する会社のデータなら管理者の許可が要るか確かめる2決める何につなぐか・認証の方式3環境変数に置くIDとシークレット。ファイルに直書きしない4.mcp.jsonサンプルをコピーし変数名で参照5同意する/mcp で状態を見て、自分のアカウントで同意

なぜこの仕掛けが要るか

手元のファイルだけでは、仕事の入口(メール・予定・資料)と出口(納品・連絡)が足りない。MCP は外部サービスを「道具」として渡す共通の口。プラグインは、スキルや MCP をまとめて入れる包み(例: Slack プラグインを入れると、検索・投稿の道具とスキルが一式入る。/plugin で見られる)。つなぐほど常駐コストと事故の面が増えるので、使うものだけにする。
1手元だけファイルの読み書きまで2MCP外部サービスを道具として渡す共通の口3プラグインスキルと MCP をまとめた包み(例: Slack)4使うものだけ増やすほど固定費と事故の面が増える
1手元だけファイルの読み書きまで2MCP外部サービスを道具として渡す共通の口3プラグインスキルと MCP をまとめた包み(例: Slack)4使うものだけ増やすほど固定費と事故の面が増える

3行でいうと

  1. ここまでは手元のファイルの話。Drive・メール・カレンダーを「道具」として渡すと、仕事の入口と出口が外とつながり、頼める仕事が一気に増える。
  2. MCP は外部システムを AI の道具にする共通の口。最初の1本は Google Workspace(Drive・Gmail・カレンダー)。
  3. 会社のデータにつなぐ場合は、情報システム部門の許可(アプリの利用許可・OAuth の同意)が要ることが多い。先に確認する。
この章の言葉: MCP・コネクタ・プラグイン・uv(付録A)

作り方

  1. 会社のアカウントにつなぐなら、情報システム部門に「Claude Code から Google Workspace につなぐ」旨を伝え、必要なら OAuth アプリの許可をもらう(組織の設定で外部アプリがブロックされていると同意画面で止まる)。個人のアカウントなら申請は要らない
  2. テンプレの mcp-setup.md の手順どおりに、Google Cloud で OAuth クライアントを作り、IDとシークレットを OS のユーザー環境変数に登録する(.mcp.json の ${変数名} はそこから埋まる。ファイルに値を書かない)。先に uv(Python の道具を1コマンドで動かす小さなツール。MCP サーバーの起動に使う)を入れる: PowerShell で powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"ターミナルで curl -LsSf https://astral.sh/uv/install.sh | sh
  3. テンプレの .mcp.json.sample を 作業フォルダ ▸ .mcp.json にコピーする(値は変数名のまま)
  4. 新しいセッションで /mcp を開き、自分のアカウントで同意する。「Drive のファイルを5件一覧して」と頼み、一覧が返ることを確かめる

テンプレ(そのまま置けるファイル)

参考サンプル集 mcp-setup.md
置く場所: (手順書。置かなくてよい)
# MCP を1本つなぐ手順(例: Google Workspace)

MCP は「外部システムを Claude Code の道具として渡す共通の口」。最初の1本は Drive・Gmail・カレンダーがまとめて使える Google Workspace が向く。

## 前提(1回だけ)
- `uv`(Python の道具を1コマンドで動かすツール)を入れる: `curl -LsSf https://astral.sh/uv/install.sh | sh`
- Google Cloud のプロジェクトを1つ作る(会社の Google アカウントで https://console.cloud.google.com を開く。管理者に権限が要ることがある)

## 手順
1. 何にアクセスするか(Drive/Gmail/カレンダー)と認証方式(Google の OAuth)を決める
2. Google Cloud で OAuth クライアントを作る: 「APIとサービス」→「認証情報」→「認証情報を作成」→「OAuth クライアント ID」→ 種類は「デスクトップ アプリ」。同じ画面の「ライブラリ」で Drive・Gmail・Calendar の API を有効にする。表示されたクライアントIDとシークレットを控える。**ファイルには書かない**
3. 控えた値を **OS のユーザー環境変数** に登録する(Claude Code は `.mcp.json` の `${変数名}` を OS の環境変数から埋める。`.env` は読まない)
   - Windows(PowerShell): `[Environment]::SetEnvironmentVariable("GOOGLE_OAUTH_CLIENT_ID", "<控えたID>", "User")` を ID・シークレット・メール(`USER_GOOGLE_EMAIL`)の3つ分。登録後は PowerShell を開き直す
   - Mac: 自分のホームの `.zshrc` に `export GOOGLE_OAUTH_CLIENT_ID="<控えたID>"` を3つ分書き、ターミナルを開き直す
4. `.mcp.json.sample` を `.mcp.json` にコピーする(値は `${変数名}` のまま。起動時に環境変数から埋まる。ファイルに値を直書きしない)
5. 新しいセッションを開き、`/mcp` で接続状態を見る。「要認証」ならブラウザで会社アカウントを選んで同意する

## できたかの確認
「Drive のファイルを5件一覧して」と頼み、一覧が返る。

## つまずき
- 個人アカウントと会社アカウントを取り違えやすい。書き込みの前に「どちらのアカウントか」を確かめる約束を rules に足す
- 使わない MCP を残すと、毎セッション「要認証」の指示文が常駐してコストになる。外す
- サーバー名や起動コマンドは MCP ごとに違う。配布元の README の値を使う(`.mcp.json.sample` の `uvx workspace-mcp` は一例)
参考サンプル集 .mcp.json.sample
置く場所: 作業フォルダ ▸ .mcp.json
{
  "mcpServers": {
    "google-workspace": {
      "command": "uvx",
      "args": ["workspace-mcp"],
      "env": {
        "GOOGLE_OAUTH_CLIENT_ID": "${GOOGLE_OAUTH_CLIENT_ID}",
        "GOOGLE_OAUTH_CLIENT_SECRET": "${GOOGLE_OAUTH_CLIENT_SECRET}",
        "USER_GOOGLE_EMAIL": "${USER_GOOGLE_EMAIL}"
      }
    }
  }
}

貼る指示文(Claude Code にそのまま貼る)

このプロジェクトに MCP サーバー「<name>」を追加してください。共有用なので .mcp.json に stdio 形式(command/args/env)で書き、
秘密は OS の環境変数を ${VAR} で参照する形にし、ファイルに直書きしないでください。追加後、新セッションでの接続確認手順と、
作業フォルダの .claude/settings.json の permissions.allow に足す項目(mcp__<name>__*)を提示してください。既存の MCP と機能が重複する場合は追加せず理由を報告してください。

できたかの確認

確認「Drive のファイルを5件一覧して」が通る。/mcp で接続済みになっている。
つまずき個人アカウントと会社アカウントを取り違えやすい。書き込みの前に「どちらのアカウントか」を確かめる約束を rules に足す。使わない MCP は外す(毎セッション「要認証」の指示文が常駐してコストになる)。
Codex の場合Codex は MCP を自分のホームの .codex/config.toml の [mcp_servers.名前] に書く(または codex mcp add 名前 -- コマンド)。同じサーバーを Claude Code と Codex で二重に持たなくてよい。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

つながっている MCP サーバーの一覧と数を、自分の環境で数えてみる(作業フォルダで実行する)。

claude mcp list
claude mcp list

第6章 自動注入と保護hooks

1指示のたびUserPromptSubmit: 日時+rules 指差し2ツールの手前PreToolUse: 認証ファイル操作を止める3終了時Stop: 日次サマリー未作成を知らせる
1指示のたびUserPromptSubmit: 日時+rules 指差し2ツールの手前PreToolUse: 認証ファイル操作を止める3終了時Stop: 日次サマリー未作成を知らせる

なぜこの仕掛けが要るか

文章のルールは「お願い」で、AI は読んで従うが、ときどき漏れる。hook は決まった瞬間に必ず走る「強制」で、AI の判断を通らない。deny と hook の二重にして、秘密を守る。
1ルール(文章)AI が読んで従う。ときどき漏れる2hook(スクリプト)決まった瞬間に必ず走る3二重の柵deny と hook の両方で秘密を守る
1ルール(文章)AI が読んで従う。ときどき漏れる2hook(スクリプト)決まった瞬間に必ず走る3二重の柵deny と hook の両方で秘密を守る

3行でいうと

  1. hook は、決まった瞬間に自動で走る小さなスクリプト。指示のたび・ツールを使う手前・終了時。
  2. 毎ターンの注入は「今の日時」と「rules への指差し」だけ。方針の本文は rules に書き、ここで再掲しない。
  3. ツールの手前で、認証ファイルへの操作(読む・書く・消す)とタスク登録の書き換えを止める柵が、deny を補う二重の柵になる。
この章の言葉: hook・終了コード(付録A)

作り方

  1. Starter キットの .claude/hooks/ の .ps1 3本.sh・.py 3本 を 作業フォルダ ▸ .claude ▸ hooks に置く(第4章の settings.json がこの3本を呼ぶ)。ターミナルで chmod +x .claude/hooks/*.sh を実行する
  2. session-close.ps1 の $diaryDirsession-close.sh の DIARY_DIR を第3章で決めた置き場に合わせる
  3. PowerShell で powershell -ExecutionPolicy Bypass -File .claude\hooks\inject-core-rules.ps1ターミナルで bash .claude/hooks/inject-core-rules.sh を実行し、2行だけ出ることを確かめる
  4. 新しいセッションで、返答の先頭に【現在時刻】が付くこと、認証ファイルを cat で読ませようとすると止まることを確かめる

テンプレ(そのまま置けるファイル)

Starter キット .claude/hooks/inject-core-rules.ps1
置く場所: 作業フォルダ ▸ .claude ▸ hooks ▸ inject-core-rules.ps1
# UserPromptSubmit フック(Windows): 毎ターン、最小限だけ注入する。
# 方針の本文は .claude/rules/ に書く(自動で読まれる)。ここで再掲すると二重になるので、
# 出すのは「今の日時」と「rules への指差し1行」だけ。出力は300バイト以下を目安にする。
$now = Get-Date -Format "yyyy-MM-dd (ddd) HH:mm"
Write-Output "【現在時刻】$now"
Write-Output "【毎ターン確認】数値は実データのみ/作業前に一言確認/秘密に触らない(詳細は .claude/rules/01-must-follow.md)"
Starter キット .claude/hooks/guard-sensitive-files.ps1
置く場所: 作業フォルダ ▸ .claude ▸ hooks ▸ guard-sensitive-files.ps1
# PreToolUse フック(Windows): 危ないファイル操作を手前で止める。
# - 認証ファイル(secret_*.json / credentials*.json / .env)は、読む・書く・消す・コピーのどれも止める
# - 自動実行の定義(タスクスケジューラ: schtasks の /Create /Delete /Change、Mac の LaunchAgents)を書き換える操作を止める
# 標準入力に JSON(tool_name / tool_input)が来る。止めたい時は終了コード 2 と理由(標準エラー)。
$raw = [Console]::In.ReadToEnd()
if (-not $raw) { exit 0 }
try { $call = $raw | ConvertFrom-Json } catch { exit 0 }
$tool = "$($call.tool_name)"
$secret = 'secret_[^\s''"/\\]*\.json|credentials[^\s''"/\\]*\.json|(^|[\s/\\''"])\.env(\.[^\s''"/\\]*)?($|[\s''"])'
$sched = 'schtasks(\.exe)?\s+.*\/(create|delete|change)|Library[/\\]LaunchAgents[/\\][^\s''"]*\.plist'

function Stop-Hook($msg) { [Console]::Error.WriteLine($msg); exit 2 }  # ブロックは終了コード 2(1 は警告扱いで通ってしまう)

if ($tool -eq "Bash" -or $tool -eq "PowerShell") {
    $cmd = "$($call.tool_input.command)"
    if ($cmd -match $secret) { Stop-Hook "認証ファイル(secret_*.json / credentials*.json / .env)に触るコマンドです。止めました。必要なら人が手で行ってください。" }
    if ($cmd -match $sched) { Stop-Hook "自動実行の定義(タスクスケジューラ/LaunchAgents)を書き換える操作です。止めました。変えるときは人が手で行ってください。" }
}
if ($tool -eq "Write" -or $tool -eq "Edit") {
    $path = "$($call.tool_input.file_path)"
    if ($path -match $secret) { Stop-Hook "認証ファイルに直接書き込もうとしています。止めました。" }
    if ($path -match 'Library[/\\]LaunchAgents[/\\][^\s]*\.plist$') { Stop-Hook "自動実行の定義に書き込もうとしています。止めました。" }
}
exit 0
Starter キット .claude/hooks/session-close.ps1
置く場所: 作業フォルダ ▸ .claude ▸ hooks ▸ session-close.ps1
# Stop フック(Windows): セッション終了時に「今日の日次サマリーがあるか」だけ確かめる。
# 無ければ systemMessage で知らせる(止めはしない)。置き場は $diaryDir を自分の場所に書き換える。
$projectDir = if ($env:CLAUDE_PROJECT_DIR) { $env:CLAUDE_PROJECT_DIR } else { (Get-Location).Path }
$diaryDir = Join-Path $projectDir "diary"   # <自分の置き場に変える>
$today = Get-Date -Format "yyyy-MM-dd"
$file = Join-Path $diaryDir "$today.json"
if (-not (Test-Path $file)) {
    $msg = "今日の日次サマリー($file)がまだありません。意味のある作業をしたなら日次サマリーに1件追記してください。"
    $obj = @{ systemMessage = $msg }
    Write-Output ($obj | ConvertTo-Json -Compress)
}
exit 0
Starter キット .claude/hooks/inject-core-rules.sh
置く場所: 作業フォルダ ▸ .claude ▸ hooks ▸ inject-core-rules.sh
#!/bin/bash
# UserPromptSubmit フック: 毎ターン、最小限だけ注入する。
# 方針の本文は .claude/rules/ に書く(自動で読まれる)。ここで再掲すると二重になるので、
# 出すのは「今の日時」と「rules への指差し1行」だけ。出力は300バイト以下を目安にする。

NOW_DISP=$(date '+%Y-%m-%d (%a) %H:%M')
printf '【現在時刻】%s\n【毎ターン確認】数値は実データのみ/作業前に一言確認/秘密に触らない(詳細は .claude/rules/01-must-follow.md)\n' "$NOW_DISP"
Starter キット .claude/hooks/guard-sensitive-files.py
置く場所: 作業フォルダ ▸ .claude ▸ hooks ▸ guard-sensitive-files.py
#!/usr/bin/env python3
"""
PreToolUse フック: 危ないファイル操作を手前で止める。
- 認証ファイル(secret_*.json / credentials*.json / .env)は、読む・書く・消す・コピーのどれも止める(Bash でも Write/Edit でも)
- 自動実行の定義(自分のホームの Library/LaunchAgents/*.plist)への書き込み・削除・コピーを止める(変えるときは人が手で行う)
- launchd を止める操作(launchctl unload / bootout / remove)を止める

標準入力に {"tool_name": ..., "tool_input": {...}} が来る。止めたい時は終了コード 2 と理由(標準エラー)。
"""
import json
import re
import sys

SECRET = r"(secret_[^\s'\"/]*\.json|credentials[^\s'\"/]*\.json|(?:^|[\s/'\"])\.env(?:\.[^\s'\"/]*)?(?=$|[\s'\"]))"
SECRET_RE = re.compile(SECRET)
PLIST_RE = re.compile(r"Library/LaunchAgents/[^\s'\"]*\.plist")
WRITE_VERBS = re.compile(r"\b(rm|mv|cp|tee|sed\s+-i|truncate|chmod|chown|>|>>)\b|>{1,2}\s*\S*Library/LaunchAgents")


def stop(msg: str) -> None:
    print(msg, file=sys.stderr)
    sys.exit(2)  # ブロックは終了コード 2(1 は警告扱いで通ってしまう)


def main() -> None:
    try:
        data = json.load(sys.stdin)
    except Exception:
        sys.exit(0)
    tool = data.get("tool_name", "")
    arg = data.get("tool_input", {}) or {}

    if tool == "Bash":
        cmd = arg.get("command", "")
        if SECRET_RE.search(cmd):
            stop("認証ファイル(secret_*.json / credentials*.json / .env)に触るコマンドです。止めました。必要なら人が手で行ってください。")
        if PLIST_RE.search(cmd) and (WRITE_VERBS.search(cmd) or re.search(r"\b(rm|mv|cp|tee)\b", cmd)):
            stop("自動実行の定義(LaunchAgents の plist)を書き換える操作です。止めました。変えるときは人が手で行ってください。")
        if "launchctl" in cmd and re.search(r"\b(unload|bootout|remove)\b", cmd):
            stop("自動実行(launchd)を止める操作です。止めました。意図した操作なら人が手で行ってください。")

    if tool in ("Write", "Edit"):
        path = arg.get("file_path", "")
        if SECRET_RE.search(path):
            stop("認証ファイルに直接書き込もうとしています。止めました。")
        if PLIST_RE.search(path):
            stop("自動実行の定義(LaunchAgents の plist)に書き込もうとしています。止めました。変えるときは人が手で行ってください。")

    sys.exit(0)


if __name__ == "__main__":
    main()
Starter キット .claude/hooks/session-close.sh
置く場所: 作業フォルダ ▸ .claude ▸ hooks ▸ session-close.sh
#!/bin/bash
# Stop フック: セッション終了時に「今日の日次サマリーがあるか」だけ確かめる。
# 無ければ systemMessage で知らせる(止めはしない)。
# 日次サマリーの置き場は DIARY_DIR を自分の場所に書き換える。

set -uo pipefail
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
DIARY_DIR="${DIARY_DIR:-$PROJECT_DIR/diary}"   # <自分の置き場に変える>
TODAY=$(date +%Y-%m-%d)

if [ ! -f "$DIARY_DIR/$TODAY.json" ]; then
  MSG="今日の日次サマリー($DIARY_DIR/$TODAY.json)がまだありません。意味のある作業をしたなら日次サマリーに1件追記してください。"
  printf '{"systemMessage": "%s"}\n' "$MSG"
fi
exit 0

貼る指示文(Claude Code にそのまま貼る)

.claude/settings.json に hooks を3本登録してください。
1) UserPromptSubmit: 現在日時1行と「rules/01を守る」の1行だけを出す PowerShell スクリプト(出力300バイト以下)
2) PreToolUse(Bash|PowerShell|Write|Edit): secret_*.json・credentials*.json・.env に触るコマンド(読む・書く・消す)と、タスクスケジューラの登録変更(schtasks /Create /Delete /Change) を exit 2 で止める PowerShell スクリプト
3) Stop: 当日の日次サマリーJSONが無ければ systemMessage で知らせる PowerShell スクリプト
各hookを単体で実行してバイト数と止まることを確かめて報告してください。方針の本文は hooks に書かず .claude/rules/ に置いてください。
.claude/settings.json に hooks を3本登録してください。
1) UserPromptSubmit: 現在日時1行と「rules/01を守る」の1行だけを出す bash(出力300バイト以下)
2) PreToolUse(Bash|Write|Edit): secret_*.json・credentials*.json・.env に触るコマンド(読む・書く・消す)と、Library/LaunchAgents の plist への書き込み・コピー・削除、launchctl unload/bootout/remove を exit 2 で止める python3
3) Stop: 当日の日次サマリーJSONが無ければ systemMessage で知らせる bash
各hookを単体で実行してバイト数と止まることを確かめて報告してください。方針の本文は hooks に書かず .claude/rules/ に置いてください。

できたかの確認

確認毎ターン【現在時刻】が付き、認証ファイルへの操作を頼むと hook が止める。
つまずきhook のパスを固定で書くと、フォルダを移した時に動かなくなる(${CLAUDE_PROJECT_DIR} から組み立てる)。hook に方針文を書くと rules を打ち消す。
Codex の場合Codex にも hooks がある(config.toml に features.hooks = true、内容は hooks.json か [hooks]。PreToolUse など Claude Code と同名のイベント)。書き方は Codex 公式の Hooks ガイド(developers.openai.com/codex)。承認と sandbox(approval_policy/sandbox_mode)も併用する。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

hook の本数と、allow・deny・ask の項目数を、自分の環境で数えてみる(作業フォルダで実行する)。

$j = Get-Content .claude\settings.json -Raw | ConvertFrom-Json; $j.hooks.PSObject.Properties.Name; $j.permissions.allow.Count; $j.permissions.deny.Count; $j.permissions.ask.Count
python3 -c "import json;j=json.load(open('.claude/settings.json'));print(list(j.get('hooks',{})),{k:len(v) for k,v in j.get('permissions',{}).items() if isinstance(v,list)})"

第7章 コミット前の秘匿スキャンgit hook

1commitステージ済み差分を検査2push送る範囲をもう一度検査3止める秘密があれば理由を出して中断4例外理由付きで allowlist に登録
1commitステージ済み差分を検査2push送る範囲をもう一度検査3止める秘密があれば理由を出して中断4例外理由付きで allowlist に登録

なぜこの仕掛けが要るか

Claude Code の柵(deny・hook)は Claude Code の中だけ。ターミナルから直接 commit すると素通りする。git 側にも柵を置いて、外からの経路をふさぐ。
1Claude Code の中deny・hook が効く2ターミナルから直接commit すると素通りする3git hookcommit・push の直前に機械が検査4止まる秘密があれば理由を出して中断
1Claude Code の中deny・hook が効く2ターミナルから直接commit すると素通りする3git hookcommit・push の直前に機械が検査4止まる秘密があれば理由を出して中断

3行でいうと

  1. Claude Code の柵(deny・hook)は Claude Code の中だけ。Git Bash や PowerShellターミナルから直接 commit すると素通りする。
  2. git 側にも柵を置く。コミットと push の直前に、差分に秘密(APIキー・平文パスワード・禁止フォルダ)が無いか機械で検査して止める。
  3. 誤検知は理由付きで除外できる。黙って外さない。
この章の言葉: git hook(秘匿スキャン)(付録A)

作り方

  1. Starter キットの .githooks/ を 作業フォルダ ▸ .githooks に置く(Python 3 が要る。無ければ winget install Python.Python.3.12Mac は標準で入っている)
  2. Git Bash(Git for Windows に付属)を開きターミナルで、作業フォルダで bash .githooks/setup_githooks.sh --apply を実行する(git に「フックはここ」と設定し、自己テストが通る)
  3. denylist-paths.txt に、リポジトリに入れてはいけないフォルダ名を足す
  4. ダミーの平文パスワードを書いたファイルを commit しようとして、止まることを確かめる

テンプレ(そのまま置けるファイル)

Starter キット .githooks/pre-commit
置く場所: 作業フォルダ ▸ .githooks ▸ pre-commit
#!/bin/bash
# pre-commit — ステージ済み差分の秘密情報スキャン
# ステージ済み差分を scan_secrets.py で検査する
# 有効化: bash .githooks/setup_githooks.sh --apply (git config core.hooksPath .githooks)
set -euo pipefail
REPO_ROOT="$(git rev-parse --show-toplevel)"
PY="$(command -v python3 || command -v python)"  # Windows では python3 が無いことがある
"$PY" "$REPO_ROOT/.githooks/scan_secrets.py" --staged
Starter キット .githooks/pre-push
置く場所: 作業フォルダ ▸ .githooks ▸ pre-push
#!/bin/bash
# pre-push — push対象コミット範囲の秘密情報再スキャン
# --no-verify での pre-commit 突破に対する最終防衛
# 有効化: bash .githooks/setup_githooks.sh --apply (git config core.hooksPath .githooks)
set -euo pipefail
REPO_ROOT="$(git rev-parse --show-toplevel)"
PY="$(command -v python3 || command -v python)"  # Windows では python3 が無いことがある

ZERO="0000000000000000000000000000000000000000"
STATUS=0

while read -r local_ref local_sha remote_ref remote_sha; do
  [ "$local_sha" = "$ZERO" ] && continue
  if [ "$remote_sha" = "$ZERO" ]; then
    BASE=$(git rev-list --max-parents=0 "$local_sha" | tail -1)
  else
    BASE="$remote_sha"
  fi
  if ! "$PY" "$REPO_ROOT/.githooks/scan_secrets.py" --range "$BASE" "$local_sha"; then
    STATUS=1
  fi
done

exit $STATUS
Starter キット .githooks/scan_secrets.py
置く場所: 作業フォルダ ▸ .githooks ▸ scan_secrets.py
#!/usr/bin/env python3
"""秘匿情報スキャナ本体(.githooks/pre-commit・pre-push 共通)

Layer A : 禁止パス(denylist-paths.txt)
Layer A': 一括投入(新規50ファイル以上)— 警告のみ
Layer B : APIトークン形式
Layer C : 平文パスワード(キーワード近接 + 値の非自明性スコアリング)
Layer D : 要配慮個人情報キーワード — 警告のみ

コミットだけでなく push の直前も、同じ検査を通す。
"""
import argparse
import hashlib
import math
import os
import re
import subprocess
import sys
from collections import Counter, defaultdict
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parent.parent
DENYLIST_PATH = REPO_ROOT / ".githooks" / "denylist-paths.txt"
ALLOWLIST_PATH = REPO_ROOT / ".githooks" / "allowlist.txt"
LOG_DIR = Path.home() / ".harness-starter" / "logs"
SCAN_LOG = LOG_DIR / "git-secret-scan.log"
BYPASS_LOG = LOG_DIR / "git-secret-bypass.log"

BULK_ADD_THRESHOLD = 50

API_TOKEN_PATTERNS = [
    r"GOCSPX-[A-Za-z0-9_-]{10,}",
    r"AIza[0-9A-Za-z_-]{30,}",
    r"token=[A-Za-z0-9_%-]{20,}",
    r"BEGIN (RSA |EC |OPENSSH |PGP )?PRIVATE KEY",
    r"xox[baprs]-[0-9A-Za-z-]{10,}",
    r"ghp_[A-Za-z0-9]{20,}",
    r"gho_[A-Za-z0-9]{20,}",
    r"ghu_[A-Za-z0-9]{20,}",
    r"ghs_[A-Za-z0-9]{20,}",
    r"ghr_[A-Za-z0-9]{20,}",
    r"AKIA[0-9A-Z]{16}",
    r"sk-[A-Za-z0-9_-]{20,}",
    r"eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}",
    r'"refresh_token"\s*:\s*"[A-Za-z0-9]',
    r'"client_secret"\s*:\s*"[A-Za-z0-9]',
]
API_TOKEN_RE = re.compile("|".join(API_TOKEN_PATTERNS))

PII_KEYWORDS_RE = re.compile(
    r"(病名|通院|休職|うつ|診断書|退職(予定|意向)|傷病|障害者手帳|マイナンバー|給与額|年収)"
)

KEY_STRONG = r"(?:pass(?:word|wd)?|pwd|pw|パスワード|パス)"
KEY_WEAK = r"(?:secret|api[_-]?key|access[_-]?key|auth[_-]?key|認証キー|暗証)"
CRED_ASSIGN_RE = re.compile(
    r"(?i)(?P<key>" + KEY_STRONG + "|" + KEY_WEAK + r")\s*(?:[:=:=]|=>|->|:=)\s*"
    r'(?P<q>["\'`「]?)(?P<val>[^\s"\'`「」,;、。]{4,80})(?P=q)?'
)

PLACEHOLDER_WORDS = {
    "xxx", "***", "redacted", "masked", "dummy", "sample", "example",
    "changeme", "change_me", "your_password", "todo", "tbd", "null", "none",
    "nil", "true", "false", "n/a", "未設定", "非公開", "省略", "ここに入力", "-", "—",
}
TYPE_WORDS = {
    "str", "string", "text", "varchar", "char", "int", "bool",
    "optional[str]", "string!",
}


def shannon_entropy(s):
    if not s:
        return 0.0
    counts = Counter(s)
    length = len(s)
    return -sum((c / length) * math.log2(c / length) for c in counts.values())


def is_function_call_or_subscript(val):
    return bool(re.match(r"^[A-Za-z_][\w.]*\s*[(\[]", val))


def is_placeholder_expr(val):
    return bool(re.search(r"\$\{|\{\{|%s|%\(|[<>]", val))


def is_bare_var_reference(quote, val):
    """引用符なし・アンダースコア区切り・大文字小文字が統一された識別子のみ変数参照とみなす
    (例: user_password, PASSWORD_CONST)。ランダムな大小混在文字列(実パスワード)は除外しない"""
    if quote:
        return False
    if not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", val):
        return False
    if "_" not in val:
        return False
    return val.islower() or val.isupper()


def score_credential(key, val):
    low = val.lower().strip(".,;:")
    if low in PLACEHOLDER_WORDS or low in TYPE_WORDS:
        return None
    if re.match(r"^[{\[]", val):
        return None
    score = 0
    if len(val) >= 12:
        score += 2
    elif len(val) >= 8:
        score += 1
    if re.search(r"\d", val):
        score += 1
    if re.search(r"[a-z]", val) and re.search(r"[A-Z]", val):
        score += 1
    if re.search(r"[^A-Za-z0-9]", val):
        score += 1
    if shannon_entropy(val) >= 2.3:
        score += 1
    if re.match(KEY_STRONG, key, re.IGNORECASE):
        score += 1
    if re.match(r"^[A-Za-z]+$", val) and len(val) <= 12:
        score -= 3
    if re.search(r"[ぁ-んァ-ヶ一-龠ー]", val):
        score -= 3
    if re.match(r"^\d+$", val) and len(val) <= 6:
        score -= 1
    return score


def find_plaintext_passwords(line):
    """1行から (score, matched_text, val) の候補一覧を返す。呼び出し側で score>=閾値 を判定する"""
    findings = []
    for m in CRED_ASSIGN_RE.finditer(line):
        val = m.group("val")
        quote = m.group("q")
        key = m.group("key")
        if is_function_call_or_subscript(val):
            continue
        if is_placeholder_expr(val):
            continue
        if is_bare_var_reference(quote, val):
            continue
        score = score_credential(key, val)
        if score is None:
            continue
        findings.append((score, m.group(0), val))
    return findings


def mask(val):
    if len(val) <= 4:
        return "*" * len(val)
    return val[:2] + "*" * (len(val) - 4) + val[-2:]


def fingerprint(text):
    return hashlib.sha256(text.encode("utf-8", "ignore")).hexdigest()[:12]


def load_lines(path):
    if not path.exists():
        return []
    out = []
    for line in path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        out.append(line)
    return out


def load_allowlist_fingerprints():
    fps = set()
    for line in load_lines(ALLOWLIST_PATH):
        parts = line.split()
        if parts:
            fps.add(parts[0])
    return fps


def run_git(args):
    return subprocess.run(
        ["git"] + args, cwd=REPO_ROOT, capture_output=True, text=True, check=False,
        errors="replace",  # 非UTF-8バイトを含む差分(バイナリ/.gz)で落ちないようにする
    )


def get_changed_files(mode, rev_range):
    if mode == "staged":
        res = run_git(["diff", "--cached", "--name-status", "-z"])
    else:
        res = run_git(["diff", f"{rev_range[0]}..{rev_range[1]}", "--name-status", "-z"])
    entries = res.stdout.split("\0")
    files = []
    i = 0
    while i < len(entries):
        status = entries[i]
        if not status:
            i += 1
            continue
        if status.startswith("R") or status.startswith("C"):
            new_path = entries[i + 2]
            files.append((status[0], new_path))
            i += 3
        else:
            path = entries[i + 1]
            files.append((status[0], path))
            i += 2
    return files


def get_added_lines(mode, rev_range):
    if mode == "staged":
        res = run_git(["diff", "--cached", "-U0", "--no-color"])
    else:
        res = run_git(["diff", f"{rev_range[0]}..{rev_range[1]}", "-U0", "--no-color"])
    diff_text = res.stdout
    current_file = None
    added = defaultdict(list)
    line_no = 0
    for raw in diff_text.splitlines():
        if raw.startswith("+++ "):
            path = raw[4:]
            if path.startswith("b/"):
                path = path[2:]
            current_file = path
            continue
        if raw.startswith("@@"):
            m = re.search(r"\+(\d+)", raw)
            line_no = int(m.group(1)) if m else 0
            continue
        if raw.startswith("+") and not raw.startswith("+++"):
            if current_file:
                added[current_file].append((line_no, raw[1:]))
            line_no += 1
    return added


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--staged", action="store_true")
    parser.add_argument("--range", nargs=2, metavar=("BASE", "HEAD"))
    args = parser.parse_args()

    mode = "staged" if args.staged else "range"
    rev_range = args.range if args.range else None

    denylist_patterns = [re.compile(p) for p in load_lines(DENYLIST_PATH)]
    allowlist_fps = load_allowlist_fingerprints()

    changed = get_changed_files(mode, rev_range)
    added_paths = [p for status, p in changed if status == "A"]

    path_blocks = []
    content_blocks = []
    warns = []

    # Layer A: 禁止パス
    for status, path in changed:
        for pat in denylist_patterns:
            if pat.search(path):
                path_blocks.append({"label": "Layer A: 禁止パス", "loc": path, "shown": path, "pattern": pat.pattern})
                break

    # Layer A': 一括投入警告
    if len(added_paths) >= BULK_ADD_THRESHOLD:
        top_dirs = Counter(p.split("/")[0] for p in added_paths)
        summary = ", ".join(f"{d}({n})" for d, n in top_dirs.most_common(5))
        warns.append({"label": "Layer A': 一括投入", "loc": f"{len(added_paths)}件新規追加", "shown": summary})

    added_lines = get_added_lines(mode, rev_range)

    for path, lines in added_lines.items():
        for lineno, text in lines:
            if "REDACTED" in text or "MASKED" in text:
                continue

            m = API_TOKEN_RE.search(text)
            if m:
                matched = m.group(0)
                fp = fingerprint(matched)
                if fp not in allowlist_fps:
                    content_blocks.append({"label": "Layer B: APIトークン形式", "loc": f"{path}:{lineno}", "shown": mask(matched), "fp": fp})
                continue

            for score, matched, val in find_plaintext_passwords(text):
                fp = fingerprint(matched)
                if fp in allowlist_fps:
                    continue
                label = f"Layer C: 平文パスワード疑い score={score}"
                if score >= 3:
                    content_blocks.append({"label": label, "loc": f"{path}:{lineno}", "shown": mask(val), "fp": fp})
                elif score >= 2:
                    warns.append({"label": label, "loc": f"{path}:{lineno}", "shown": mask(val)})

            if PII_KEYWORDS_RE.search(text):
                warns.append({"label": "Layer D: 要配慮個人情報キーワード", "loc": f"{path}:{lineno}", "shown": text.strip()[:60]})

    if warns:
        LOG_DIR.mkdir(parents=True, exist_ok=True)
        with open(SCAN_LOG, "a", encoding="utf-8") as f:
            for w in warns:
                f.write(f'{w["label"]} | {w["loc"]} | {w["shown"]}\n')
        print("⚠️  WARN(コミットは通します):", file=sys.stderr)
        for w in warns:
            print(f'  [{w["label"]}] {w["loc"]}: {w["shown"]}', file=sys.stderr)

    blocks = path_blocks + content_blocks
    if not blocks:
        return 0

    secret_ok = os.environ.get("SECRET_OK", "").strip()
    denypath_ok = os.environ.get("DENYPATH_OK", "").strip()
    secret_ok_valid = len(secret_ok) >= 10

    can_bypass_content = secret_ok_valid
    can_bypass_path = secret_ok_valid and denypath_ok == "1"
    fully_bypassable = (not content_blocks or can_bypass_content) and (not path_blocks or can_bypass_path)

    if fully_bypassable:
        LOG_DIR.mkdir(parents=True, exist_ok=True)
        with open(BYPASS_LOG, "a", encoding="utf-8") as f:
            for b in blocks:
                f.write(f'BYPASS reason="{secret_ok}" denypath_ok={denypath_ok} | {b["label"]} | {b["loc"]}\n')
        print(f"⚠️  秘匿情報検出をバイパスしました(理由: {secret_ok})。ログ: {BYPASS_LOG}", file=sys.stderr)
        return 0

    print("❌ 秘匿情報らしき文字列/禁止パスが検出されたため、コミットを中止しました。", file=sys.stderr)
    for b in blocks:
        print(f'  [{b["label"]}] {b["loc"]}: {b["shown"]}', file=sys.stderr)
    print("", file=sys.stderr)
    print("対処:", file=sys.stderr)
    print("  1) 値を環境変数へ移して、ファイルには書かない(参照だけにする)", file=sys.stderr)
    print("  2) 該当ファイルを .gitignore に追加する", file=sys.stderr)
    if content_blocks:
        print("  3) 誤検知の場合: .githooks/allowlist.txt に以下を追記(フィンガープリント 日付 理由)", file=sys.stderr)
        for b in content_blocks:
            print(f'     {b["fp"]}  {b["loc"]}  理由: <ここに理由を記入>', file=sys.stderr)
    print("", file=sys.stderr)
    print("正当な例外投入の場合のみ(記録が残ります):", file=sys.stderr)
    print('  SECRET_OK="具体的な理由(10文字以上)" git commit ...', file=sys.stderr)
    if path_blocks:
        print("  ※ 禁止パスの例外投入は DENYPATH_OK=1 も併せて必要です", file=sys.stderr)
    return 1


if __name__ == "__main__":
    sys.exit(main())
Starter キット .githooks/setup_githooks.sh
置く場所: 作業フォルダ ▸ .githooks ▸ setup_githooks.sh
#!/bin/bash
# .githooks(秘匿情報スキャン)の有効化+自己診断
# 使い方:
#   bash .githooks/setup_githooks.sh            # 現状診断のみ(既定・安全)
#   bash .githooks/setup_githooks.sh --apply    # core.hooksPath設定+自己テスト実行
#
# core.hooksPath はリポジトリローカル設定のため、clone・.git再作成で黙って消える。
# 定期的に diff なしで実行して現状を確認すること。
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"

APPLY=0
[ "${1:-}" = "--apply" ] && APPLY=1

echo "=== git秘匿情報スキャンhook 診断 ==="
CURRENT=$(git config core.hooksPath 2>/dev/null || echo "(未設定)")
echo "現在の core.hooksPath: $CURRENT"

if [ "$APPLY" = "1" ]; then
  git config core.hooksPath .githooks
  chmod +x .githooks/pre-commit .githooks/pre-push
  echo "→ core.hooksPath を .githooks に設定しました"
else
  if [ "$CURRENT" != ".githooks" ]; then
    echo "⚠️  core.hooksPath が .githooks に設定されていません。--apply を付けて再実行してください。"
  fi
fi

PY="$(command -v python3 || command -v python || true)"
if [ -z "$PY" ]; then
  echo "❌ python3 / python が見つかりません(Windows は winget install Python.Python.3.12)" >&2
  exit 1
fi
echo "✅ python: $($PY --version)"

if [ "$APPLY" = "1" ]; then
  echo ""
  echo "=== 自己テスト(ダミー平文パスワードでBLOCK判定を確認) ==="
  RESULT=$("$PY" -c "
import sys
sys.path.insert(0, '.githooks')
from scan_secrets import find_plaintext_passwords
hits = find_plaintext_passwords('パスワード: Xk8vQ2mfLp01')
blocked = [h for h in hits if h[0] >= 3]
print('BLOCK' if blocked else 'PASS')
")
  if [ "$RESULT" = "BLOCK" ]; then
    echo "✅ 自己テスト成功: ダミー平文パスワードがBLOCK判定されました"
  else
    echo "❌ 自己テスト失敗: ダミー平文パスワードがBLOCKされませんでした(要調査)" >&2
    exit 1
  fi
fi

echo ""
echo "完了。"
Starter キット .githooks/denylist-paths.txt
置く場所: 作業フォルダ ▸ .githooks ▸ denylist-paths.txt
# 禁止パスパターン(Python正規表現・部分一致)。ここに合うパスは追加投入を自動でブロックする。
# 例外投入は SECRET_OK="理由" + DENYPATH_OK=1 の両方が必要(scan_secrets.py 参照)
# 例: 個人のメモ置き場・人物名簿・生データのアーカイブなど、リポジトリに入れてはいけない場所を書く
(^|/)private-notes(/|$)
(^|/)people(/|$)
(^|/)raw-archive(/|$)
(^|/)\.env(\.[^/]+)?$
Starter キット .githooks/allowlist.txt
置く場所: 作業フォルダ ▸ .githooks ▸ allowlist.txt
# 誤検知の恒久除外リスト(1行1件: フィンガープリント 日付 理由)
# フィンガープリントは scan_secrets.py の BLOCK 出力にある12桁の値をそのままコピーする
# 例: a1b2c3d4e5f6 2026-01-01 テストコードのダミー値のため誤検知と確認済み

貼る指示文(Claude Code にそのまま貼る)

.githooks/pre-commit と pre-push を作り、git config core.hooksPath .githooks で有効化してください。追加行に対して
APIキー形式・平文パスワード・禁止パス(private-notes/ 等)を検出してブロック。誤検知はフィンガープリント付き allowlist、
例外投入は理由付き環境変数でバイパスしログに残す。差分に非UTF-8が混ざっても落ちないよう errors="replace" で読む。

できたかの確認

確認ダミーのAPIキー形式を含むファイルをコミットしようとするとブロックされる。
つまずき差分に画像などの文字でないデータが混ざると、読み取りで落ちることがある。テンプレのスキャナは、読めない部分を飛ばして続ける作りにしてある。
Codex の場合git hook は Claude Code とは独立した git の仕組みなので、Codex でもそのまま効く。

第8章 仕事を型にするスキルと日本語入口

作業フォルダ.claudeskillsdaily-summarySKILL.md手順の本体(説明文だけ常駐)referenceformat.md必要なときだけ読む詳細commands日誌.md日本語の入口 → /日誌
図は横にずらして見られます

なぜこの仕掛けが要るか

毎回プロンプトを書き直すと、言い回しで品質がぶれる。手順をファイル(SKILL.md)にして一言で呼べば、誰がいつ呼んでも同じ手順が動く。常に読まれるのは説明文だけなので、増やしても重くならない。
1毎回書く言い回しで結果が変わる2手順書にするSKILL.md に目的・入力・手順・確認3一言で呼ぶ/日誌 のように短く4増やしても軽い常駐は説明文だけ
1毎回書く言い回しで結果が変わる2手順書にするSKILL.md に目的・入力・手順・確認3一言で呼ぶ/日誌 のように短く4増やしても軽い常駐は説明文だけ

3行でいうと

  1. 毎回プロンプトを書き直すと品質がぶれる。手順をファイル(SKILL.md)にして、一言で呼ぶ。
  2. 常に読まれるのは先頭の説明文(description)だけ。本文は呼ばれたときに読む。だから増やしても重くならない。
  3. Starter キットにはスキルを入れていない。見本を1本置いて動かし、あとは自分の仕事に要るものを指示文で作る。

作り方

  1. テンプレの .claude/skills/daily-summary/ と .claude/commands/日誌.md を、作業フォルダの同じ位置に置く(日次サマリーを /日誌 の一言で追記するスキル)
  2. 新しいセッションで /日誌 と打ち、日次サマリーが追記されることを確かめる
  3. 自分だけの2本目は「一番よくやる仕事」を1つ選び、下の指示文で作る。指示文の <作業名> と <id> を書き換えると、その仕事の SKILL.md と日本語の入口ができる。形は tools/skill_lint.py で検査できる

テンプレ(そのまま置けるファイル)

参考サンプル集 .claude/skills/daily-summary/SKILL.md
置く場所: 作業フォルダ ▸ .claude ▸ skills ▸ daily-summary ▸ SKILL.md
---
name: daily-summary
description: 日次サマリーを作成・追記。「日次サマリー作って」「今日のまとめ」「/日誌」で起動。
---

# daily-summary — 日次サマリー

## 目的

意味のある作業が終わるたびに、その日の記録を1ファイルに残す。翌日の自分と、週報・月報の材料になる。

## 出力先

`diary/YYYY-MM-DD.json`(作業フォルダの `diary/`。置き場を変えるなら `.claude/hooks/session-close`(Windows は .ps1・Mac は .sh)の置き場も合わせる)

## 手順

1. 当日ファイル `diary/YYYY-MM-DD.json` があるか確かめる(日付は推測せず、システムの日付で実測する。Mac は `date +%F`、Windows は `Get-Date -Format yyyy-MM-dd`)
2. あれば `accomplishments` に1件追記、なければ `reference/format.md` の形で新規作成する
3. `summary` は既存の文を消さず、末尾に「 / 新しい要点」を足す
4. 会社名・顧客名・個人が特定できる情報は書かない

## 書き方

- `accomplishments`: 何をして、どうなったか(1件1〜2文)
- `tips_discovered`: 「〔場面〕で〔工夫〕したら〔結果〕だった」の形。ファイル名・技術用語は書かない
- 書式の正本は `reference/format.md`(必要な時だけ読む)

## 受け入れ

```sh
python3 -c "import json,datetime; json.load(open('diary/%s.json' % datetime.date.today()))"   # Mac
python -c "import json,datetime; json.load(open('diary/%s.json' % datetime.date.today()))"    # Windows
```

当日ファイルが JSON として読めれば合格。

## 検品の観点

- 当日の日付のファイルに追記されている(別の日付に書いていない)
- 会社名・顧客名・個人が特定できる情報が入っていない
- 既存の項目が消えていない(追記であって上書きでない)
参考サンプル集 .claude/skills/daily-summary/reference/format.md
置く場所: 作業フォルダ ▸ .claude ▸ skills ▸ daily-summary ▸ reference ▸ format.md
# daily-summary の JSON 書式

```json
{
  "date": "YYYY-MM-DD",
  "accomplishments": ["本日の作業(何をして、どうなったか)"],
  "tips_discovered": ["再利用できる仕事の気づき"],
  "summary": "一行サマリー"
}
```

- `date`: 対象日
- `accomplishments`: その日の作業。1件1〜2文
- `tips_discovered`: 「〔場面〕で〔工夫〕したら〔結果〕だった」
- `summary`: 要点を一行。追記する時は既存の文を残して「 / 」でつなぐ

既存 JSON を更新する時は、配列の既存項目を残したまま追加する。
参考サンプル集 .claude/commands/日誌.md
置く場所: 作業フォルダ ▸ .claude ▸ commands ▸ 日誌.md
---
description: 日誌係 — /daily-summary の日本語エイリアス(名簿: context/ai-org.md)
argument-hint: "なし"
---

これは日誌係(/daily-summary)の日本語呼び出しです。
`.claude/skills/daily-summary/SKILL.md` を読み、そこに書かれた手順に従ってそのまま実行してください。

引数: $ARGUMENTS
参考サンプル集 tools/skill_lint.py
置く場所: 作業フォルダ ▸ tools ▸ skill_lint.py
#!/usr/bin/env python3
"""Claude Codeスキルの形式(説明文・本文の量・参照の実在・受け入れコマンド)を検査する。"""

from __future__ import annotations

import re
import sys
from pathlib import Path
from typing import Dict, List, Optional, Tuple


MAX_BODY_BYTES = 6000
SAMPLE_EXEMPTIONS = {"daily-summary"}
HISTORY_PATTERN = re.compile(
    r"(20\d{2}-\d{2}-\d{2}\s+(?:追加|更新|確立|指摘))"
)
REFERENCE_PATTERN = re.compile(
    r"(?<![A-Za-z0-9_./-])((?:automation|tools|reference)/[A-Za-z0-9_./-]+)"
)
COMMAND_PATTERN = re.compile(
    r"^(?:python3?|bash|sh|zsh|node|npm|npx|pytest|make|go|ruby|php|git|curl|uv)(?:\s|$)"
)
TRIGGER_WORDS = (
    "起動",
    "使用",
    "依頼",
    "作成",
    "作って",
    "確認",
    "生成",
    "変換",
    "整理",
    "分析",
    "登録",
    "レビュー",
    "チェック",
)


def parse_frontmatter(text: str) -> Tuple[Dict[str, str], str, List[str]]:
    """先頭の簡易YAML frontmatterと本文を分離する。"""

    lines = text.splitlines(keepends=True)
    errors: List[str] = []
    if not lines or lines[0].strip() != "---":
        return {}, "", ["先頭に frontmatter の開始記号 `---` がありません"]

    end_index: Optional[int] = None
    for index in range(1, len(lines)):
        if lines[index].strip() == "---":
            end_index = index
            break
    if end_index is None:
        return {}, "", ["frontmatter の終了記号 `---` がありません"]

    fields: Dict[str, str] = {}
    front_lines = lines[1:end_index]
    index = 0
    while index < len(front_lines):
        raw_line = front_lines[index].rstrip("\r\n")
        if not raw_line.strip():
            index += 1
            continue
        match = re.match(r"^([A-Za-z0-9_-]+):\s*(.*)$", raw_line)
        if not match:
            errors.append(f"frontmatter の解釈できない行: {raw_line}")
            index += 1
            continue

        key, value = match.groups()
        if value in {"|", ">"}:
            continuation: List[str] = []
            index += 1
            while index < len(front_lines):
                continuation_line = front_lines[index].rstrip("\r\n")
                if continuation_line and not continuation_line[0].isspace():
                    break
                continuation.append(continuation_line.strip())
                index += 1
            separator = "\n" if value == "|" else " "
            fields[key] = separator.join(continuation).strip()
            continue

        value = value.strip()
        if len(value) >= 2 and value[0] == value[-1] and value[0] in {'"', "'"}:
            value = value[1:-1]
        fields[key] = value
        index += 1

    body = "".join(lines[end_index + 1 :])
    return fields, body, errors


def section_body(body: str, heading: str) -> Optional[str]:
    """指定されたH2節の本文を返す。"""

    heading_pattern = re.compile(r"^##\s+" + re.escape(heading) + r"\s*$", re.MULTILINE)
    match = heading_pattern.search(body)
    if not match:
        return None
    next_heading = re.search(r"^##\s+", body[match.end() :], re.MULTILINE)
    end = match.end() + next_heading.start() if next_heading else len(body)
    return body[match.end() : end]


def has_executable_command(section: str) -> bool:
    """節内のコードブロックまたはインラインコードからコマンドを探す。"""

    fenced_blocks = re.findall(r"```[^\n]*\n(.*?)```", section, re.DOTALL)
    candidates = fenced_blocks + re.findall(r"`([^`\n]+)`", section)
    for block in candidates:
        for line in block.splitlines():
            command = line.strip().lstrip("$> ")
            if COMMAND_PATTERN.match(command):
                return True
    return False


def referenced_paths(body: str) -> List[str]:
    """検査対象にしている相対パスを重複なしで返す。"""

    paths: List[str] = []
    for match in REFERENCE_PATTERN.finditer(body):
        path = match.group(1).rstrip(".,;:。、")
        if path not in paths:
            paths.append(path)
    return paths


def lint_skill(skill_dir: Path) -> List[str]:
    errors: List[str] = []
    skill_file = skill_dir / "SKILL.md"
    if not skill_file.is_file():
        return [f"SKILL.md がありません: {skill_file}"]

    try:
        text = skill_file.read_text(encoding="utf-8")
    except UnicodeDecodeError as exc:
        return [f"SKILL.md がUTF-8ではありません: {exc}"]

    fields, body, frontmatter_errors = parse_frontmatter(text)
    errors.extend(frontmatter_errors)

    name = fields.get("name", "").strip()
    description = re.sub(r"\s+", " ", fields.get("description", "")).strip()
    if not name:
        errors.append("frontmatter に name がありません")
    if not description:
        errors.append("frontmatter に description がありません")
    elif len(description) > 60:
        errors.append(f"description が60文字を超えています: {len(description)}文字")
    elif not (
        any(word in description for word in TRIGGER_WORDS)
        or (name and name in description)
        or (name and f"/{name}" in description)
    ):
        errors.append("description にトリガー語がありません")

    body_bytes = len(body.encode("utf-8"))
    if body_bytes > MAX_BODY_BYTES:
        errors.append(f"SKILL.md 本文が6000バイトを超えています: {body_bytes}バイト")
    if HISTORY_PATTERN.search(body):
        errors.append("本文に日付付き変更履歴があります")

    repo_root = Path(__file__).resolve().parent.parent
    for relative_path in referenced_paths(body):
        if relative_path.startswith("reference/"):
            target = skill_dir / relative_path
        else:
            target = repo_root / relative_path
        if not target.exists():
            errors.append(f"参照先が存在しません: {relative_path}")

    skill_id = name or skill_dir.name
    if skill_id not in SAMPLE_EXEMPTIONS and not (skill_dir / "reference" / "sample.md").is_file():
        errors.append("reference/sample.md がありません")

    acceptance = section_body(body, "受け入れ")
    if acceptance is None:
        errors.append("`## 受け入れ` 節がありません")
    elif not has_executable_command(acceptance):
        errors.append("`## 受け入れ` 節に実行可能なコマンドがありません")

    inspection = section_body(body, "検品の観点")
    if inspection is None:
        errors.append("`## 検品の観点` 節がありません")
    else:
        inspection_lines = [line for line in inspection.splitlines() if line.strip()]
        if len(inspection_lines) < 3:
            errors.append("`## 検品の観点` 節が3行未満です")

    return errors


def main(argv: List[str]) -> int:
    if len(argv) != 2:
        print("使い方: python3 tools/skill_lint.py .claude/skills/<id>", file=sys.stderr)
        return 2

    skill_dir = Path(argv[1]).resolve()
    if not skill_dir.is_dir():
        print(f"不合格: スキルディレクトリがありません: {skill_dir}", file=sys.stderr)
        return 1

    errors = lint_skill(skill_dir)
    if errors:
        print(f"不合格: {skill_dir}", file=sys.stderr)
        for error in errors:
            print(f"- {error}", file=sys.stderr)
        return 1

    print(f"合格: {skill_dir}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))

貼る指示文(Claude Code にそのまま貼る)

「<作業名>」を .claude/skills/<id>/SKILL.md として作ってください。frontmatter は name と description(60文字以内・
トリガー語を含む)。本文は目的3行・入力表・番号付き手順・受け入れコマンド・出力先・検品の観点(3行以上)で6KB以下。
書式テンプレ reference/format.md と、理想の完成品1本 reference/sample.md(skill_lint が必須とするファイル名)を reference/ に置き、手順から「必要な時に読む」と参照する。日付付きの変更履歴は書かない。
完了条件は python3 tools/skill_lint.py .claude/skills/<id> の終了コード0。

.claude/commands/議事録.md を作り、description を「議事録係 — /minutes の日本語エイリアス」(20文字程度)、本文は
「.claude/skills/minutes/SKILL.md を読み手順どおり実行。引数: $ARGUMENTS」だけにしてください。

できたかの確認

確認/日誌 の一言で日次サマリーが追記され、新セッションのスキル一覧に説明文が出る。
つまずきスキル本文が長くなると常駐コストが増える。説明文は1〜2文、本文は6KB以下(目安)、詳細は reference/ に逃がす。
Codex の場合Codex にもスキルがある(同じ SKILL.md 形式。置き場は 作業フォルダ ▸ .agents ▸ skills(自分だけなら 自分のホーム ▸ .agents ▸ skills)。/skills で一覧、$名前 で呼ぶ。作るなら $skill-creator)。参考サンプルの SKILL.md はそこへコピーすれば使える。日本語の入口(.claude/commands)は Claude Code だけの仕組み。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

スキルの本数と入口コマンドの本数を、自分の環境で数えてみる(作業フォルダで実行する)。

(Get-ChildItem .claude\skills -Directory).Count; (Get-ChildItem .claude\commands -Filter *.md).Count
ls -d .claude/skills/*/ | wc -l; ls .claude/commands/*.md | wc -l

第9章 別の目検品係とサブエージェント

1作る本体が成果物を作る2渡す検品係に成果物と評価基準だけ渡す3判定まっさらな文脈で 合格・要改善・不合格4直す本体が直して再検品(最初を含め最大3回)
1作る本体が成果物を作る2渡す検品係に成果物と評価基準だけ渡す3判定まっさらな文脈で 合格・要改善・不合格4直す本体が直して再検品(最初を含め最大3回)

なぜこの仕掛けが要るか

作った本人が自分の成果物を検品しても、同じ見落としをする。本体は設計と判断に集中し、実装は Sonnet のサブエージェントや Codex に任せ、検品は文脈を渡さない別の AI にさせる(いまの使い分けは付録E)。
1作る本体(Opus)が設計・判断する2任せる実装や量産は Sonnet のサブエージェントや Codex3疑う検品係は経緯を知らない別の目4直す本体が直して再検品(最大3回)
1作る本体(Opus)が設計・判断する2任せる実装や量産は Sonnet のサブエージェントや Codex3疑う検品係は経緯を知らない別の目4直す本体が直して再検品(最大3回)

3行でいうと

  1. 作った本人が自分の成果物を検品しても、同じ見落としをする。別の目が要る。
  2. サブエージェントは、まっさらな文脈で1つの仕事だけをする別の AI。結果だけ本体に返る。
  3. 検品係は合否と指摘だけ返す。修正はしない。渡すのは成果物と評価基準だけで、作った経緯は渡さない。

作り方

  1. テンプレの .claude/agents/kenpin.md を 作業フォルダ ▸ .claude ▸ agents にコピーする
  2. 「チェック観点」の2番(フッター・敬称・名簿)を、自分の決まりに書き換える
  3. (任意)わざと壊した成果物(数字の出典が無い・用語が揺れている・フッターが違う)を1本作り、検品係が「不合格」や「要改善」を返すか試す。返さなければ、検品係の観点を見直す
  4. 成果物を1つ作ったら、下の指示文で検品係を呼ぶ(Claude Code に貼る)。ChatGPT・Gemini では checkup/kenpin-paste-prompt.md を新しいチャットに貼る
  5. 最初の1回を含めて3回検品しても合格しなければ、成果物ではなく評価基準か指示を疑って人が見る

テンプレ(そのまま置けるファイル)

参考サンプル集 .claude/agents/kenpin.md
置く場所: 作業フォルダ ▸ .claude ▸ agents ▸ kenpin.md
---
name: kenpin
description: 検品係 — レポート・議事録・文面・登録データなど納品物の最終チェック専門。納品前にまっさらな文脈で合否を判定する。修正はしない。
tools: Read, Grep, Glob, Bash
---

# 検品タスク

## タスク
納品物(レポート・議事録・スライド・メール文面・登録データ)を、作った側とは独立した目でチェックし、**合否と指摘だけ**を返す。

## 鉄則
- **修正しない。実装案・書き直し案も出さない**(作成者の文脈に引き戻されるため)
- 褒めない・励まさない。仕事は「通すか、止めるか」の判定だけ
- 判定できない項目は「未検証」と正直に書く(勝手に合格にしない)

## チェック観点(自分の環境のルールに合わせて書き換える)
1. **数値の根拠**: 件数・金額・割合・目標値に出典(ファイル・コマンドの結果)があるか。出典と食い違う数値は high。**出典が見つからない数値は medium の不合格**にし、「未検証」に逃がさない
2. **表記ルール**: フッター・敬称・言語が自分の環境の決まりどおりか(例: 「<会社名> | CONFIDENTIAL」・人名は「さん」付け)。人名は名簿(例: `context/team.md`)と照合し、名簿にない名前は変換ミスを疑って不合格にする
3. **禁止事項**: 秘密(認証ファイル・個人情報)が含まれていないか。社内データを外部に置くことを促していないか
4. **宛先**: 送る先・書き込む先(アカウント・フォルダ)が正しいか
5. **完了条件との照合**: 頼まれた要件をすべて満たすか。頼まれていない追加や整理をしていないか
6. **成果物の実在**: 報告されたファイル・URL・登録が実在するか(パスを Read/Bash で実際に確かめる)
7. **日本語の読みやすさ(文章のとき)**: 次に当たる所がないか。重さは原則 low
   - 出来事の日付と書いた順が逆
   - 並べた事柄の形がそろっていない
   - 述語のない語句を読点だけで3つ以上並べている
   - 独立した2つの事実を読点だけでつないでいる
   - 同じ略語・用語に違う訳語や表記を使っている(例: 同じ指標を「一次解決率」と「初回解決率」)
   - 意味の取りにくい縮め語

## 合格の条件
- high・medium の指摘が0件のときだけ合格(`passes: true`)。low だけなら合格のまま指摘を返す
- 3段の判定 `verdict`: 指摘なし=「合格」/low だけ=「要改善」/high か medium がある=「不合格」

## 返答形式(これ以外を出力しない)
```json
{
  "passes": true または false,
  "verdict": "合格" または "要改善" または "不合格",
  "failures": [
    {"item": "対象箇所", "reason": "何が問題か → 放置するとどうなるか", "severity": "high|medium|low"}
  ],
  "unverified": ["検証できなかった項目とその理由"]
}
```

## 呼ぶ側の決まり(作った側の Claude Code が守る)
- `Agent(subagent_type="kenpin", model="<使うモデル。例: opus>")` で、まっさらな文脈で呼ぶ
- 渡すのは**成果物と評価基準(完了条件・出典の場所)だけ**。作った経緯・苦労・「ここは直した」などの説明は渡さない(採点が甘くなる)
- 同じ成果物の検品は**最大3回**(最初の1回を含む)。3回目も不合格なら直すのをやめ、成果物ではなく基準か指示を疑って人が見る
- この定義を書き換えたら、わざと壊した成果物(数字の出典が無い・用語が揺れている等)を1〜2本作って通し、落とせるかを確かめる
参考サンプル集 checkup/kenpin-paste-prompt.md
置く場所: 作業フォルダ ▸ checkup ▸ kenpin-paste-prompt.md
# 貼るだけで使える検品の指示文(ChatGPT・Gemini・Claude 共通)

作った AI とは**別の新しいチャット**に貼る。同じチャットで「チェックして」と頼むと、自分の成果物に甘くなる。
社外秘の文章を貼るときは、会社で使ってよいサービスか先に確かめ、取引先名・個人名は伏せ字(〇〇)にする。

```
下の成果物を、下の評価基準だけで判定してください。
直さないでください。書き直し案も出さないでください。褒めないでください。

# 評価基準(番号順に判定する)
1. 数値: 出典(下に貼った資料)と一致するか。出典と食い違う数値は「重」、出典が見つからない数値は「中」
2. 表記: (自分の決まりを書く。例: フッターは「〇〇株式会社 | CONFIDENTIAL」のみ・人名は「さん」付け)
3. 完了条件: (頼んだことを書く。例: 今週の件数と前週比が入っている)
4. 読みやすさ(重さは「軽」): 日付と書いた順が逆/並べた形がそろわない/同じ用語に違う呼び方

# 合格の条件
「重」と「中」が0件のときだけ合格。「軽」だけなら「要改善」。
判定: 合格/要改善/不合格 のどれか1つ。

# 出力
- 判定(1語)
- 指摘の表: 場所(原文をそのまま引用)/何が問題か/放置するとどうなるか/重さ(重・中・軽)
- 確かめられなかったこと(あれば)

# 成果物
(ここに貼る)

# 出典
(ここに貼る。無ければ「なし」と書く)
```

## 使い方の決まり
- 渡すのは**成果物と評価基準(と出典)だけ**。作った経緯や「ここは直した」という説明は渡さない(採点が甘くなる)
- 検品は同じ成果物で**最大3回**(最初の1回を含む)。3回目も不合格なら、成果物ではなく評価基準か最初の指示を疑う
- 評価基準は「分かりやすいか」のような抽象語で書かない。「前週比が入っているか」のように、はい・いいえで答えられる形にする

出どころ: 作る役と採点する役を分ける設計(Anthropic 公式の evaluator-optimizer パターンを日本語で解説した公開記事)と、合格の条件を「すべての基準を満たしたときだけ合格」と先に決める書き方。

貼る指示文(Claude Code にそのまま貼る)

いま作った成果物(<ファイル名>)を検品係にかけてください。Agent ツールで subagent_type="kenpin"、model="<使うモデル名。例: opus>" を指定して、まっさらな文脈で呼んでください。渡すのは成果物の場所と評価基準(頼んだ完了条件・数字の出典の場所)だけにし、作った経緯や直した点の説明は渡さないでください。返ってきた判定(合格・要改善・不合格)と指摘をそのまま私に報告し、勝手に直さないでください。

できたかの確認

確認検品係の判定(合格・要改善・不合格)と指摘が返り、指摘に「場所/何が問題か/放置するとどうなるか」が揃う(修正案は出ない)。わざと壊した成果物では「不合格」か「要改善」が返る。
つまずき作った経緯を検品係に渡すと、採点が甘くなる。同じ成果物を何度も検品に回し続けない(最初の1回を含めて3回まで)。検品係の定義を書き換えたら、わざと壊した成果物でもう一度試す。
Codex の場合Codex にもサブエージェントがある(設定は config.toml)。無い場合は、成果物を新しい Codex セッションに渡して「合否と指摘だけ返して。修正はしないで」と頼めば同じ効果になる。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

サブエージェントの本数を、自分の環境で数えてみる(作業フォルダで実行する)。

(Get-ChildItem .claude\agents -Filter *.md).Count
ls .claude/agents/*.md | wc -l

第10章 名簿係の名簿(組織図)

1課似た仕事のまとまり(最初は3〜4つ)2係名人が呼ぶ名前(例: 日誌係)3呼び出し/日誌 と、実体の id4実体SKILL.md か、スクリプトか、エージェント5仕事1文。何を入力に何を出すか
1課似た仕事のまとまり(最初は3〜4つ)2係名人が呼ぶ名前(例: 日誌係)3呼び出し/日誌 と、実体の id4実体SKILL.md か、スクリプトか、エージェント5仕事1文。何を入力に何を出すか

なぜこの仕掛けが要るか

スキルと無人ジョブが増えると「誰が何をするか」が分からなくなる。名簿を1枚持てば、増やす前に「その係は本当に要るか」を考えられる。
1増えるスキル・ジョブ・エージェントが増える2名簿1枚課・係名・呼び出し・実体・仕事3減らす3か月使わない係は退避する
1増えるスキル・ジョブ・エージェントが増える2名簿1枚課・係名・呼び出し・実体・仕事3減らす3か月使わない係は退避する

3行でいうと

  1. スキルと無人ジョブが増えると「誰が何をするか」が分からなくなる。名簿を1枚持つ。
  2. 名簿は5列。課 → 係名 → 呼び出し → 実体 → 仕事。人名は使わず係名だけ。
  3. 入れる係は読者が決める。参考サンプルの名簿は見本で、第8・9章でコピーした係だけを残して始める。
この章の言葉: 係の名簿(付録A)

作り方

  1. テンプレの context/ai-org.md を 作業フォルダ ▸ context に置く
  2. 第8・9章で実際にコピーした係(例: 日誌係・検品係)だけを残し、入れていない係の行は消す。部署名を書き換える
  3. 係を足すときは「仕事を1文で決める → 実体を作る → 日本語の入口 → 名簿に1行」の順
  4. 3か月使わなかった係は退避する(増やすより減らす方が難しい)

テンプレ(そのまま置けるファイル)

参考サンプル集 context/ai-org.md
置く場所: 作業フォルダ ▸ context ▸ ai-org.md
# 係の名簿(サンプル: 3課+夜勤チーム・係4つから始める)

運用: スキル・自動化を新設したら、この名簿に1行足す。人名は使わず係名だけ。呼び出しは日本語コマンドか自然文のどちらでも。

## 組織図

```
🏢 <仕事の名前> の係(担当: <あなた> / 現場統括: Claude Code 本体)
│
├─ 📋 秘書室 …………… 毎日の記録
├─ 📝 会議事務局 ……… 会議の前後
└─ 🛡 品質管理室 ……… 納品前の検品
```

## 名簿

### 📋 秘書室

| 係名 | 呼び出し | 実体 | 仕事 |
|---|---|---|---|
| 日誌係 | **/日誌**(=/daily-summary) | daily-summary | 日次サマリーを1日1ファイルに追記する |

### 📝 会議事務局

| 係名 | 呼び出し | 実体 | 仕事 |
|---|---|---|---|
| 議事録係 | **/議事録**(=/minutes) | minutes(第8章の指示文で作る例) | 文字起こしから議事録を作り、決定事項と宿題を出す |

### 🛡 品質管理室

| 係名 | 呼び出し | 実体 | 仕事 |
|---|---|---|---|
| 検品係 | `Agent(subagent_type="kenpin", model="<使うモデル。例: opus>")` | .claude/agents/kenpin.md | 納品物の合否だけを返す(修正はしない。まっさらな文脈で呼ぶ) |

### 🌙 夜勤チーム(無人で動くもの。時刻と実体を書く)

| 係名 | 出勤時刻 | 実体 | 仕事 |
|---|---|---|---|
| 日誌配達員 | 毎朝 07:30 | automation/windows/run_daily_job.ps1(Mac は automation/mac/run_daily_job.sh) | 前日の日次サマリーを保管フォルダへ写す |

## 増やし方
1. 仕事を1文で決める(入力→出力)。1文にならなければ係を分ける
2. 実体を作る(スキルなら SKILL.md、無人ならスクリプト+plist)
3. 日本語の入口を1つ作る(.claude/commands/<係名>.md)
4. ここに1行足す
5. 3か月使わなかった係は退避する

貼る指示文(Claude Code にそのまま貼る)

context/ai-org.md(係の名簿)に、新しい係を1行追加してください。列は「課|係名|呼び出し|実体|仕事」で(課は既存の見出しのどれかに入れる)、係名は人名を使わず係名だけ、呼び出しは日本語コマンド(例: /議事録)と実体の id、仕事は1文(何を入力に何を出すか)。追加後、名簿の表と .claude/skills/・.claude/commands/ の実体が食い違っていないか(名簿にあって実体が無い/実体があって名簿に無い)を一覧で報告してください。名簿以外のファイルは変更しないでください。

できたかの確認

確認名簿に残した係を /係名 で呼ぶと、その手順が動く。
つまずき係を先に増やすと名簿が飾りになる。仕事が3回繰り返されてから係にする。
Codex の場合名簿は Markdown なので Codex でも同じ。呼び出し列は $名前(Codex のスキル呼び出し)に読み替える。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

名簿の表の行数(見出しの行を引く)を、自分の環境で数えてみる(作業フォルダで実行する)。

(Select-String -Path context\ai-org.md -Pattern '^\|').Count
grep -c '^|' context/ai-org.md

第11章 無人化タスクスケジューラlaunchd

1スクリプトautomation/ に置く(.ps1 と .py)2登録register_task.ps1 -Apply でタスク登録3時刻で起こす毎朝 07:30 にタスクスケジューラが実行4ログを見る失敗は終了コードとログで拾う
1スクリプトautomation/ に置く(.ps1 と .py)2登録register_task.ps1 -Apply でタスク登録3時刻で起こす毎朝 07:30 にタスクスケジューラが実行4ログを見る失敗は終了コードとログで拾う
1スクリプトautomation/ に置く(.sh と .py)2配布deploy.sh で実行場所へコピー3時刻で起こすplist に時刻を書き launchd に登録4ログを見る失敗は終了コードとログで拾う
1スクリプトautomation/ に置く(.sh と .py)2配布deploy.sh で実行場所へコピー3時刻で起こすplist に時刻を書き launchd に登録4ログを見る失敗は終了コードとログで拾う

なぜこの仕掛けが要るか

人が起動しないと動かない仕組みは、忙しい日に止まる。時刻に起こす役は OS に任せる。ただし対話中の Claude Code に夜通し任せると、承認の確認で止まったまま朝を迎える。
1手で毎回忙しい日に止まる2OS の時計スケジューラが時刻に起こす3対話は×夜通し放置すると承認待ちで止まる4無害から通知しない・消さない・上書きしない
1手で毎回忙しい日に止まる2OS の時計スケジューラが時刻に起こす3対話は×夜通し放置すると承認待ちで止まる4無害から通知しない・消さない・上書きしない

3行でいうと

  1. 人が起動しないと動かない仕組みは、忙しい日に止まる。毎朝・夜間の定型は無人にする。
  2. Windows 標準の「タスクスケジューラ」に「いつ・何を」を登録すると、時刻に起こしてくれる。Mac 標準の launchd に「いつ・何を」を書いた plist を渡すと、時刻に起こしてくれる。
  3. 最初の無人ジョブは「失敗しても被害がない」もの。日次サマリーの転送が向く。
この章の言葉: タスクスケジューラ/launchd・deploy(付録A)

作り方

  1. テンプレの automation/daily_job.py と automation/windows/ を 作業フォルダ ▸ automation にコピーする(毎朝 07:30 に前日の日次サマリーを写す無害なジョブ)
  2. PowerShell で powershell -ExecutionPolicy Bypass -File automation\windows\register_task.ps1 を実行して登録内容を見てから、-Apply を付けて登録する
  3. schtasks /Query /TN "my-harness\daily-job" で登録が見える。翌朝、automation\windows\daily_job.log が増えていることを見る
  4. 無人にしてよいのは「通知しない・消さない・上書きしない」ジョブから。通知を伴うジョブは試験運転を先に
  5. 無人ジョブが2本以上になったら、テンプレの automation/stop-conditions.md を 作業フォルダ ▸ automation にコピーし、中の指示文で「止まる条件」(試行の上限・制限時間・枠が切れたら・失敗に誰が気づくか)を点検する
  1. テンプレの automation/daily_job.py と automation/mac/ を 作業フォルダ ▸ automation にコピーする(毎朝 07:30 に前日の日次サマリーを写す無害なジョブ)
  2. ターミナルで bash automation/mac/deploy.sh を実行して何が配布されるか見てから、--apply で実行場所(自分のホーム ▸ Library ▸ Scripts)へコピーし launchd に登録する
  3. launchctl list | grep com.example に載ることを確かめる。翌朝、ログ(自分のホーム ▸ Library ▸ Logs)が増えていることを見る
  4. 無人にしてよいのは「通知しない・消さない・上書きしない」ジョブから。通知を伴うジョブは試験運転を先に。Google Drive 上のファイルは launchd から直接動かせないので、実行場所は手元に置く

テンプレ(そのまま置けるファイル)

参考サンプル集 automation/daily_job.py
置く場所: 作業フォルダ ▸ automation ▸ daily_job.py
#!/usr/bin/env python3
"""daily_job.py — 前日の日次サマリー(diary/YYYY-MM-DD.json)を保管フォルダへ写す。

最初の無人ジョブに向く「失敗しても被害がない」仕事。環境変数で場所を変える:
  DIARY_DIR   日次サマリーの置き場(既定: <作業フォルダ>/diary)
  ARCHIVE_DIR 保管先(既定: ~/Documents/diary-archive)
終了コード: 0=写した/0=前日分が無い(何もしない)/1=失敗
"""
import datetime as dt
import os
import shutil
import sys
from pathlib import Path

HERE = Path(__file__).resolve().parent
DIARY_DIR = Path(os.environ.get("DIARY_DIR", HERE.parent / "diary"))
ARCHIVE_DIR = Path(os.environ.get("ARCHIVE_DIR", Path.home() / "Documents" / "diary-archive"))


def main() -> int:
    day = (dt.date.today() - dt.timedelta(days=1)).isoformat()
    src = DIARY_DIR / f"{day}.json"
    if not src.exists():
        print(f"skip: {src} が無い")
        return 0
    try:
        ARCHIVE_DIR.mkdir(parents=True, exist_ok=True)
        shutil.copy2(src, ARCHIVE_DIR / src.name)
        print(f"copied: {src} -> {ARCHIVE_DIR / src.name}")
        return 0
    except OSError as e:
        print(f"error: {e}", file=sys.stderr)
        return 1


if __name__ == "__main__":
    sys.exit(main())
参考サンプル集 automation/windows/run_daily_job.ps1
置く場所: 作業フォルダ ▸ automation ▸ windows ▸ run_daily_job.ps1
# run_daily_job.ps1 — 毎朝1回の無害な無人ジョブ(Windows タスクスケジューラから起動)
# 前日の日次サマリーを保管フォルダへ写す。失敗は終了コードで返す(0以外=失敗。タスクの「前回の実行結果」に残る)
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$log = Join-Path $here "daily_job.log"
$stamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
& python (Join-Path $here "..\daily_job.py") 2>&1 | Tee-Object -FilePath $log -Append
$rc = $LASTEXITCODE
Add-Content -Path $log -Value "[$stamp] run_daily_job: done rc=$rc"
exit $rc
参考サンプル集 automation/windows/register_task.ps1
置く場所: 作業フォルダ ▸ automation ▸ windows ▸ register_task.ps1
# register_task.ps1 — タスクスケジューラに「毎朝 07:30 に run_daily_job.ps1 を実行」を登録する(Windows)
# 使い方(PowerShell で。管理者権限は不要):
#   powershell -ExecutionPolicy Bypass -File automation\windows\register_task.ps1          # 登録内容を表示だけ
#   powershell -ExecutionPolicy Bypass -File automation\windows\register_task.ps1 -Apply   # 実際に登録
param([switch]$Apply)
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$script = Join-Path $here "run_daily_job.ps1"
$taskName = "my-harness\daily-job"       # <自分の名前に変える>
$action = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$script`""
Write-Output "タスク名: $taskName"
Write-Output "実行内容: $action"
Write-Output "時刻: 毎日 07:30"
if ($Apply) {
    schtasks /Create /F /SC DAILY /ST 07:30 /TN $taskName /TR $action | Out-Null
    Write-Output "登録しました。確認: schtasks /Query /TN `"$taskName`" /V /FO LIST"
} else {
    Write-Output "(-Apply を付けると登録します)"
}
参考サンプル集 automation/mac/run_daily_job.sh
置く場所: 作業フォルダ ▸ automation ▸ mac ▸ run_daily_job.sh
#!/usr/bin/env bash
# run_daily_job.sh — 毎朝1回の無害な無人ジョブ(launchd: com.example.daily-job)
# 前日の日次サマリーを保管フォルダへ写す。失敗は終了コードで返す(0以外=失敗。launchctl list の status に残る)
set +e
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
[ -f "$SCRIPTS_DIR/.env" ] && { set -a; source "$SCRIPTS_DIR/.env"; set +a; }
log(){ echo "[$(date '+%F %T')] run_daily_job: $*"; }

python3 "$SCRIPTS_DIR/daily_job.py"   # deploy.sh が daily_job.py を同じ場所に配布する
rc=$?
log "done rc=$rc"
exit "$rc"
参考サンプル集 automation/mac/deploy.sh
置く場所: 作業フォルダ ▸ automation ▸ mac ▸ deploy.sh
#!/bin/bash
# deploy.sh — 作業フォルダの automation/ を「実行場所」へ配布し、plist を LaunchAgents に置く
#
# なぜ分けるか: クラウド同期フォルダ(Google Drive 等)の中のファイルは launchd から実行できないことがある。
# 実行実体は自分のホームの Library/Scripts/<名前>/ に置き、ここから一方向にコピーする。
#
# 使い方:
#   bash automation/mac/deploy.sh            # 何が変わるか表示だけ(既定・安全)
#   bash automation/mac/deploy.sh --apply    # 実際にコピー+plist 配置+launchd 登録
set -euo pipefail
NAME="${DEPLOY_NAME:-my-harness}"                         # <自分の名前に変える>
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"          # automation/mac
SRC_ROOT="$(cd "$SRC/.." && pwd)"                            # automation(daily_job.py はここ)
DEST="$HOME/Library/Scripts/$NAME"
LOG_DIR="$HOME/Library/Logs/$NAME"
AGENTS="$HOME/Library/LaunchAgents"
MODE="${1:---dry-run}"

echo "=== ${SRC} → ${DEST}(${MODE})==="
if [ "$MODE" = "--apply" ]; then
  mkdir -p "$DEST" "$LOG_DIR"
  rsync -av --update --exclude '.env*' --exclude 'secret_*.json' --exclude 'credentials*.json' --exclude '*.plist' "$SRC/" "$SRC_ROOT/daily_job.py" "$DEST/"
  for p in "$SRC"/*.plist; do
    [ -f "$p" ] || continue
    out="$AGENTS/$(basename "$p")"
    sed -e "s#__SCRIPTS_DIR__#$DEST#g" -e "s#__LOG_DIR__#$LOG_DIR#g" "$p" > "$out"
    plutil -lint "$out" >/dev/null
    launchctl unload "$out" 2>/dev/null || true
    launchctl load -w "$out"
    echo "登録: $(basename "$p")"
  done
  echo "確認: launchctl list | grep com.example"
else
  rsync -avn --update --exclude '.env*' --exclude 'secret_*.json' --exclude 'credentials*.json' --exclude '*.plist' "$SRC/" "$SRC_ROOT/daily_job.py" "$DEST/" | grep -v '/$' || true
  echo "(--apply で実行。plist は __SCRIPTS_DIR__=${DEST}, __LOG_DIR__=${LOG_DIR} に置換して ${AGENTS} に置く)"
fi
参考サンプル集 automation/mac/com.example.daily-job.plist
置く場所: 作業フォルダ ▸ automation ▸ mac ▸ com.example.daily-job.plist(deploy.sh が LaunchAgents に置く)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.example.daily-job</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>__SCRIPTS_DIR__/run_daily_job.sh</string>
    </array>
    <!-- 毎朝 07:30。deploy.sh --apply が __SCRIPTS_DIR__ を実際の場所に置き換えて LaunchAgents に置く -->
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>7</integer>
        <key>Minute</key>
        <integer>30</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>__LOG_DIR__/daily_job.log</string>
    <key>StandardErrorPath</key>
    <string>__LOG_DIR__/daily_job_err.log</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
        <key>LANG</key>
        <string>ja_JP.UTF-8</string>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
参考サンプル集 automation/stop-conditions.md
置く場所: 作業フォルダ ▸ automation ▸ stop-conditions.md
# AIを無人で動かすスクリプトの「止まる条件」点検表

夜間や朝に、人が見ていないところで AI(Claude Code の `claude -p` など)を動かすスクリプトは、止まる条件を決めておかないと、失敗しても気づけなかったり、使用上限(枠)を使い切るまで回ったりする。
無人ジョブが2本以上になったら、この表で1本ずつ点検する。月1回の健診(第12章)でも見直す。

## 表の型(自分の作業フォルダの `automation/` に置いて埋める)

| スクリプト | 起動のされ方 | 完成の条件 | 試行の上限 | 制限時間 | 枠が切れたら | 使うモデル | 失敗したら誰が気づくか |
|---|---|---|---|---|---|---|---|
| (例)daily_job.py | 毎朝 07:30(タスクスケジューラ/launchd) | 保管フォルダに前日分のファイルがある | 1回 | なし | 対象外(AI を使わない) | 使わない | 翌朝ログを見る |

各欄の意味:
- **完成の条件**: 何ができたら終わりか(ファイルがある・検品が合格した など)。「動いた」ではなく「できた」で書く
- **試行の上限**: AI を呼ぶ回数とやり直しの上限。「上限なし」は危ない
- **制限時間**: 1回あたり何秒で打ち切るか。無いと固まったまま朝を迎える
- **枠が切れたら**: 使用上限(枠)のエラーを見分けて「待つ/止める/知らせる」のどれにするか。見分けないと、ただの失敗として記録される
- **失敗したら誰が気づくか**: 通知・ログ・翌朝の点検など。「誰も気づかない」が一番危ない

## 貼るだけの指示文(Claude Code に貼る)

```
作業フォルダの automation/ の中で、AI を画面なしで動かすスクリプト(claude -p や --print を呼ぶもの)を全部探してください。
1本ずつコードを読み、automation/stop-conditions.md の表の型の8つの欄を埋めた表を作ってください。
- コードに書いていないことは「なし」と書く。推測で埋めない
- 各欄に根拠の場所(ファイル名:行)を付ける
- 最後に「試行の上限がない」「制限時間がない」「枠が切れても見分けない」「失敗に誰も気づかない」ものを一覧にする
スクリプトは直さないでください。直すかどうかは表を見て私が決めます。
```

## 直すときの目安
- 試行の上限・制限時間が無いもの → 先に足す(いちばん効く)
- 枠切れを見分けないもの → エラー文に「limit」などが出たら、戻る時刻まで待って最大3回やり直す形にする
- 失敗に誰も気づかないもの → 失敗したときだけ自分あてに1通知らせる

出どころ: Claude Code 公式のループの整理(目標型のループは「成功条件+最大試行回数」を明示する)と、このガイドの作者の環境で24本を点検した結果(2026-09)。

貼る指示文(Claude Code にそのまま貼る)

毎朝1回動く無害な無人ジョブを1本作ってください。automation/daily_job.py(前日の diary/YYYY-MM-DD.json を保管フォルダへコピー、無ければ何もしない、失敗は終了コード1)と、それを呼ぶ automation/windows/run_daily_job.ps1、タスクスケジューラに毎日 07:30 で登録する register_task.ps1(-Apply を付けた時だけ登録)を作ってください。通知は出さないでください。登録は私が手で実行します。
毎朝1回動く無害な無人ジョブを1本作ってください。automation/daily_job.py(前日の diary/YYYY-MM-DD.json を保管フォルダへコピー、無ければ何もしない、失敗は終了コード1)と、それを呼ぶ automation/mac/run_daily_job.sh、launchd の定義 automation/mac/com.example.daily-job.plist(毎日 07:30・ログは自分のホームの Library/Logs)と、実行場所へ配布して登録する deploy.sh(--apply を付けた時だけ実行)を作ってください。通知は出さないでください。登録は私が手で実行します。

できたかの確認

確認タスクスケジューラに載りlaunchctl list に載り、翌朝ログが増えている。
つまずき対話中の Claude Code に夜間ジョブを任せると、承認ダイアログで止まったまま朝を迎える。無人ジョブは必ずタスクスケジューラlaunchdから起動する。
Codex の場合無人化は OS の仕組み(タスクスケジューラlaunchd)なので Codex でも同じ。AI に判断させたい無人ジョブは codex exec "指示" を .ps1.sh から呼ぶ。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

登録されている定時ジョブの数を、自分の環境で数えてみる(作業フォルダで実行する)。

schtasks /Query /FO LIST | Select-String 'TaskName' | Measure-Object
launchctl list | wc -l

第12章 腐らせない健診・数字・この資料の更新

1数えるmeasure.sh で常駐コストを出す2比べる前月の表と並べる3指摘する参照切れ・矛盾・肥大化・危険を番号付きで41件ずつ直す差分を見てから反映
1数えるmeasure.sh で常駐コストを出す2比べる前月の表と並べる3指摘する参照切れ・矛盾・肥大化・危険を番号付きで41件ずつ直す差分を見てから反映

なぜこの仕掛けが要るか

指示書・記憶・スキルは、書いた後に必ず腐る。腐り方は決まっているので、月に1回、数えて前の月と比べれば気づける。
1書く最初は正しい2腐る参照切れ・矛盾・肥大化3数える月1回、常駐コストを前月と比べる4直す1件ずつ差分を見て反映する
1書く最初は正しい2腐る参照切れ・矛盾・肥大化3数える月1回、常駐コストを前月と比べる4直す1件ずつ差分を見て反映する

3行でいうと

  1. 指示書・記憶・スキルは、書いた後に必ず腐る(参照切れ・矛盾・肥大化)。
  2. 月に1回、数えて比べる。常駐コスト(rules の容量・記憶の索引・毎ターン注入)と、参照切れ・矛盾。
  3. この資料の「自分の環境で数えてみる」と同じ数え方で、毎月の数字を前月と比べる。

作り方

  1. テンプレの checkup/ を 作業フォルダ ▸ checkup にコピーする
  2. 月初に Git Bash でターミナルで bash checkup/measure.sh を実行し、instruction-checkup.md の表に今月の値を書く
  3. 4観点(参照切れ・矛盾・肥大化・危険)を見て、番号付きで書き出す。修正はしない
  4. 直すときは番号を選び、1件ずつ差分を見てから反映する。翌月、同じ指摘が出ていないことを確かめる

テンプレ(そのまま置けるファイル)

参考サンプル集 checkup/instruction-checkup.md
置く場所: 作業フォルダ ▸ checkup ▸ instruction-checkup.md
# 指示書の健診(月1回・チェックリスト)

指示書(CLAUDE.md・rules・settings.json・スキルの説明文)は書いた後に腐る。月初に次を数えて、前月と比べる。**直すのは番号を選んでから1件ずつ**。

## 数える(`bash checkup/measure.sh` で一度に出る)

| 項目 | 目標 | 前月 | 今月 |
|---|---|---|---|
| `.claude/rules/*.md`+`CLAUDE.md` の合計バイト | 20KB 以下 | | |
| MEMORY.md のバイト数 | 20KB 以下・1行1メモリ | | |
| 毎ターン注入(inject-core-rules.sh の出力) | 300B 以下 | | |
| スキル説明文(description)の合計文字数 | 増えていないか | | |
| permissions.allow の項目数 | 増えていないか | | |

## 見る(4観点・番号を付けて書き出す)

1. **参照切れ**: 指示書の中の実在しないパス・ファイル名
2. **矛盾**: 同じことが2か所に別の値で書かれている
3. **肥大化**: 1ファイル200行超・コードを読めば分かる説明・古い日付の断定
4. **危険**: APIキー・トークンの直書き、広すぎる allow

## 書く

`improvements/instruction-checkup-YYYY-MM.md` に、上の表と番号付きの指摘を保存する。修正はしない。
参考サンプル集 checkup/measure.sh
置く場所: 作業フォルダ ▸ checkup ▸ measure.sh
#!/bin/bash
# measure.sh — 常駐コストを数える(月1の健診で前月と比べる)。作業フォルダで実行する。
set -u
cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
echo "計測日: $(date '+%Y-%m-%d %H:%M')"
printf 'rules+CLAUDE.md      : %s B\n' "$(cat .claude/rules/*.md CLAUDE.md 2>/dev/null | wc -c | tr -d ' ')"
MEM="$HOME/.claude/projects/$(pwd | sed 's#/#-#g')/memory/MEMORY.md"
[ -f "$MEM" ] && printf 'MEMORY.md            : %s B / %s 行\n' "$(wc -c < "$MEM" | tr -d ' ')" "$(wc -l < "$MEM" | tr -d ' ')" || echo "MEMORY.md            : まだ無い(Claude Code が最初の記憶を書くと作られる)"
if [ -f .claude/hooks/inject-core-rules.ps1 ] && command -v powershell.exe >/dev/null 2>&1; then printf '毎ターン注入          : %s B\n' "$(powershell.exe -NoProfile -ExecutionPolicy Bypass -File .claude/hooks/inject-core-rules.ps1 | wc -c | tr -d ' ')"; elif [ -f .claude/hooks/inject-core-rules.sh ]; then printf '毎ターン注入          : %s B\n' "$(bash .claude/hooks/inject-core-rules.sh | wc -c | tr -d ' ')"; else echo "毎ターン注入          : hook が無い"; fi
printf 'スキル説明文の合計    : %s 字\n' "$( (grep -h '^description:' .claude/skills/*/SKILL.md .claude/commands/*.md 2>/dev/null || true) | sed 's/^description: *//' | tr -d '\n' | wc -m | tr -d ' ')"
PY="$(command -v python3 || command -v python)"
[ -f .claude/settings.json ] && printf 'permissions.allow     : %s 項目\n' "$("$PY" -c "import json;print(len(json.load(open('.claude/settings.json')).get('permissions',{}).get('allow',[])))")"

貼る指示文(Claude Code にそのまま貼る)

月初の点検をしてください。まず bash checkup/measure.sh を実行し、出た値(rules+CLAUDE.md の容量・MEMORY.md の容量と行数・毎ターン注入のバイト数・スキル説明文の合計文字数・permissions.allow の項目数)を checkup/instruction-checkup.md の表の「今月」列に書いてください。次に CLAUDE.md・.claude/rules/・.claude/skills/*/SKILL.md・.claude/settings.json を読み、参照切れ(実在しないパス)・矛盾(同じことが別の値で2か所)・肥大化(200行超・古い日付の断定)・危険(鍵の直書き・広すぎる allow)を番号付きで指摘してください。修正はしないでください。45日以上使っていないスキルがあれば「退避候補」として挙げるだけにし、移動もしないでください。

できたかの確認

確認月初に表が埋まり、2か月目から前月との差が見える。
つまずき健診結果を読んだだけで直さないと翌月同じ指摘が出る。直す時は1件ずつ差分提示→承認→反映。
Codex の場合点検の対象は AGENTS.md・config.toml・skills。measure.sh の rules の行を AGENTS.md に読み替える。

自分の環境で数えてみる(参考・読まなくても次の章へ進める)

毎月の記録表(自分で埋める)
項目数え方今月前月
指示書(rules+CLAUDE.md)の合計容量第2章  
MEMORY.md の行数第3章  
allow・deny・ask の項目数第4章  
MCP サーバーの数第5章  
スキルの本数第8章  
サブエージェントの本数第9章  
定時ジョブの本数第11章  
ゼロから作る人の順番の目安

ゼロから作る人の順番の目安。★の区分は章に対応する(★=第0〜4章、★★=第5〜10章、★★★=第11〜12章)。

★ 最初の1週間(第0〜4章・これだけで動く)
部品理由
指示書(CLAUDE.md+rules 1本)絶対ルール5項目。最初の1本
権限(allow/deny/ask)認証ファイルを読ませない・消す前に聞く
hook 3本日付とルールを毎回1行差し込む。手前で止める。終了時に確認する。数百バイトで効く
日次サマリーその日やったことを1日1ファイル
★★ 最初の1か月(第5〜10章・つないで型にする)
部品理由
MCP 1本(まず Drive・メール・カレンダー)仕事の入口と出口がつながる
git hook(秘匿スキャン)ターミナルからの素通りを止める
スキル 3〜5本(日誌・議事録・週報など)いつもの仕事を一言で呼ぶ
検品係 1本作った本人とは別の目。最初のサブエージェント
係の名簿 1枚係が増えたときの座席表
★★★ 3か月目以降(第11〜12章・無人化と健診)
部品理由
無人ジョブ 1本(失敗しても被害のないもの)日次サマリーの転送など。最初の1本に向く
指示書健診(月1回)参照切れ・矛盾・肥大化を数えて前月と比べる
Codex 連携(任意)実装・反復の別枠。付録Dと付録Eを見る
夜間の編纂ジョブ(任意)記憶の整理など。無人化に慣れてから
◇ 仕事に固有のもの(自分の仕事に合わせて自作するか、不要)
部品理由
仕事専用のスキル・ジョブ・サブエージェント仕事ごとに違うもの。真似せず、自分の仕事で同じ型を作る

付録A 用語集

章の順に並べてある。1語=ひとこと・日常のたとえ・どこにあるか。

章用語ひとこと日常のたとえどこにあるか
第0章Claude Codeフォルダの中で動くAIアシスタント。ファイルを読み書きし、コマンドも実行する机の隣に座る新人。指示書を渡せば同じ仕事を繰り返せるターミナル(claude コマンド)か VS Code 拡張。入れ方は 公式セットアップ
第0章PowerShell/ターミナル文字でコマンドを打つ画面。Windows は PowerShell(スタートで「PowerShell」と検索)、Mac は「ターミナル」受付の窓口。決まった言い方で頼むと動くスタートメニューで「PowerShell」と検索アプリケーション ▸ ユーティリティ ▸ ターミナル
第0章セッション会話の1区切り。閉じると文脈(それまでの会話の中身)は消え、記憶に書いたものだけ残る1日の勤務。翌日に持ち越すには日報が要る—
第0章スラッシュコマンド「/」で始まる呼び出し。スキルや設定の入口内線番号。押せば決まった係につながる.claude/commands/・.claude/skills/
第0章ターン指示を1回出して返答が1回返るまでの往復会話のひと往復—
第0章本体モデル会話を受け付けて判断しているAIモデル(例: Opus)。設定ファイルで決まるその日の担当者。設計判断は担当者本人がする自分のホーム ▸ .claude ▸ settings.json の model
第1章git/リポジトリファイルの変更履歴を残す道具(git)と、それで管理するフォルダ(リポジトリ)。作業フォルダで一度 git init すればよい戻せる台帳付きの書庫作業フォルダ直下の .git/(見えないフォルダ)
第1章コミット変更をひと区切りとして履歴に記録する操作台帳に日付と要約を書いて綴じるgit commit
第1章GitHubgit の履歴を置く共有場所(クラウド)。1人で使う間は不要。使う時は所属する組織のルールに従う共有の書庫https://github.com
第2章ハーネスAIを仕事に合わせて縛る道具立て全体(指示書・記憶・安全装置・スキル・接続・自動化)馬具。馬(モデル)を替えても同じ荷が運べるようにするこの資料の全部
第2章CLAUDE.md起動時に必ず読まれる目次。役割と「どのファイルを読むか」だけ書く机の上の1枚の案内板CLAUDE.md(リポジトリ直下)
第2章rules絶対ルールのファイル群。毎セッション自動で読まれる就業規則。短く、正本は1か所.claude/rules/*.md
第2章文脈そのセッションで AI が今読んでいる中身の全部(指示・ファイル・返答)。多いほど遅く高くなる机の上に広げた書類の山—
第2章常駐コスト毎ターン必ず文脈に入るもの(指示書・記憶の索引・スキルの説明文)の量。小さく保つ毎回持ち歩くカバンの重さ第12章の記録表で毎月数える
第3章MEMORY.mdセッションをまたいで覚えておく事実の索引(1行1件)。事実の本文は1ファイル1事実で同じフォルダに置く引き継ぎノートの目次自分のホーム ▸ .claude ▸ projects ▸ (作業フォルダの場所を「-」区切りにした名前) ▸ memory ▸ MEMORY.md(Claude Code が自動で作る。手で作らない)
第3章context/チーム・顧客・案件・保存先の台帳。人が更新する部署の名簿と棚の配置図context/*.md
第3章日次サマリーその日の実績を1ファイルに残す。翌日と月報の材料日報作業フォルダ ▸ diary ▸ YYYY-MM-DD.json(テンプレの置き場。自分で1か所決める)
第4章settings.jsonClaude Code の設定。権限・hooks・モデルが入る鍵束と入退室ルール作業フォルダ ▸ .claude ▸ settings.json(この作業フォルダ用)/自分のホーム ▸ .claude ▸ settings.json(自分の全体用)
第4章allow / deny / askツール操作の「許可・禁止・毎回確認」の3区分自由に入れる部屋・立入禁止・受付で聞く部屋settings.json の permissions
第4章トークン(認証)外部サービスに入るための鍵ファイル。読ませない・コミットしない金庫の鍵。新人に持たせないsecret_*.json など(作業フォルダの外に置く)
第5章MCP外部システムを「道具」としてAIに渡す共通の口(Model Context Protocol)電源のコンセント規格。合えば何でも挿せる作業フォルダ ▸ .mcp.json(そのフォルダで共有)/自分のホーム ▸ .claude.json(自分だけ)
第5章コネクタMCP でつながった先(Drive・Gmail・カレンダーなど)コンセントに挿した機器第5章(MCP の説明)
第5章プラグインスキル・コマンド・MCP をまとめて配布する包み拡張パック自分のホーム ▸ .claude ▸ plugins
第5章uvPython の道具を、入れる手間なく1コマンドで動かす小さなツール。MCP サーバー(Google Workspace など)の起動に使う道具箱ごと持ってきてくれる係PowerShellターミナルで uv --version が出れば入っている
第6章hook決まった瞬間(開始・指示のたび・ツールの手前・終了)に自動で走る小さなスクリプトドアに付けた鈴。通るたびに鳴る作業フォルダ ▸ .claude ▸ hooks(Windows は .ps1、Mac は .sh/.py)。登録は settings.json。瞬間の名前は4つ: SessionStart(開始)・UserPromptSubmit(指示のたび)・PreToolUse(ツールの手前)・Stop(終了)
第6章終了コードコマンドが終わる時に返す数。0 が成功、それ以外が失敗。無人ジョブの失敗はこれで拾う仕上がりの判子(OK/NG)echo $? で見える
第7章git hook(秘匿スキャン)コミット・プッシュの直前に秘密の混入を機械的に検査して止める出荷前の金属探知機.githooks/pre-commit・pre-push
第8章スキル繰り返し作業の手順書。一言で呼ぶと同じ手順が動く作業マニュアルの1冊.claude/skills/<id>/
第8章SKILL.mdスキルの本体ファイル。目的・入力・手順・確認方法を書くマニュアルの本文.claude/skills/<id>/SKILL.md
第8章description(説明文)スキルの先頭に書く1〜2文。これだけが常に読まれ、本文は呼ばれた時に読むマニュアルの背表紙SKILL.md の先頭の frontmatter(--- で囲んだ名前と説明文の欄)
第8章reference/スキルの詳細資料置き場。必要な時だけ読まれるマニュアルの付録.claude/skills/<id>/reference/
第8章日本語エイリアス英語の id に付けた日本語の呼び名(例: /議事録)内線の名前表示.claude/commands/<日本語名>.md
第8章frontmatterMarkdown の先頭を --- で囲んだ欄。名前・説明文・使う道具を書く書類の表紙欄SKILL.md・エージェント定義・コマンド定義の先頭
第8章標準形式スキル.claude/skills/<id>/SKILL.md+reference/ の形。説明文だけ常駐し、本文は呼ばれた時に読む背表紙だけ棚に出ている本.claude/skills/(旧形式は skills/<id>.md)
第8章受け入れ検査(skill_lint)スキルの形が約束どおりか(説明文の長さ・本文の量・参照の実在)を機械で検査する提出前のチェックリストテンプレの tools/skill_lint.py(作業フォルダ ▸ tools)
第9章サブエージェントまっさらな文脈で1つの仕事だけをする別のAI。結果だけ本体に返す別室で作業する担当者。本体の机は汚れない.claude/agents/*.md
第9章検品係納品物の合否だけ返すサブエージェント。修正はしない。まっさらな文脈で呼び、成果物と評価基準だけを渡して「別の目」にする出荷検査員。作った人とは別の人.claude/agents/kenpin.md
第9章モデル名(haiku/sonnet/opus など)AIモデルの大きさの系列。小さいほど速く安く、大きいほど判断が要る仕事向き。「固定」は定義ファイルに書いた指定、「呼ぶ時に指定」はその都度渡す指定軽自動車・普通車・大型車。荷物で選ぶエージェント定義の model:、または呼び出し時の model=
第9章プランモード手を動かす前に方針だけ出して合意する動き方着工前の設計図の確認本体の EnterPlanMode
第10章係の名簿係名・呼び出し・実体・仕事を1行ずつ並べた組織図部署の座席表作業フォルダ ▸ context ▸ ai-org.md
第11章タスクスケジューラ/launchd決めた時刻にプログラムを動かす OS の仕組み。Windows はタスクスケジューラ(schtasks)、Mac は launchd(plist)目覚まし時計付きの当番表Windows: タスクスケジューラ(schtasks /Query)/Mac: 自分のホーム ▸ Library ▸ LaunchAgents
第11章deployスクリプトを実行場所へ配布すること(Mac の参考サンプル)。Windows は作業フォルダから直接タスク登録するので不要倉庫から現場へ道具を運ぶテンプレの automation ▸ mac ▸ deploy.sh
第12章指示書健診指示書の参照切れ・矛盾・肥大化・危険を月1回数えて指摘する定期健康診断テンプレの checkup/instruction-checkup.md と measure.sh(作業フォルダ ▸ checkup)
第12章スナップショット毎月の実測値を1ファイルに残し、前月と比べる材料にする毎月の体重記録毎月の計測結果を残すフォルダ(自分で決める)
第12章第二の脳(ノート置き場)会議録・日次サマリーなどを整理して置く知識ベース(任意)整理された自分用の百科事典自分のホームの中の好きな場所
—Codex CLIOpenAI の AI コーディング道具。Claude Code と同じ足場が作れる(対応表は付録D)。どちらか1つで足りる外注の実装チーム。仕様書と受け入れ検査で付き合うcodex・設定は 自分のホーム ▸ .codex ▸ config.toml・指示書は AGENTS.md
—引き継ぎ書/受け入れコマンドCodex に渡す仕様書と、できたかを機械で判定する1コマンド。自己申告でなく終了コードで完了を決める発注書と検収の合格基準付録D のテンプレ(CODEX_指示_テンプレ.md)

付録B やってはいけないこと

つまずきやすい失敗と、その防ぎ方。どれも「あとで気づいて直すのが大変」なものばかり。

よくある4つの失敗1書き過ぎるhook や MEMORY.md に方針・経緯を詰めて肥大させる2確かめない設定・数字・AI の説明を、見ずに信じる3広すぎる全部を add する・権限を丸ごと許可する4放置する使わない MCP や古いファイルを残す
よくある4つの失敗1書き過ぎるhook や MEMORY.md に方針・経緯を詰めて肥大させる2確かめない設定・数字・AI の説明を、見ずに信じる3広すぎる全部を add する・権限を丸ごと許可する4放置する使わない MCP や古いファイルを残す

付録C 全体の絵

章を全部終えた後に、全体がどうつながっているかを見る3枚。

Claude Codeを、仕事の専属アシスタントとして使うための足場。指示・記憶・接続・自動化を層に分け、それぞれを最小に保つことで、AIが同じ判断を毎回繰り返せるようにしている。

5層の全体像

毎ターン読まれる 常時バックグラウンド稼働 L1 指示層毎セッション自動ロード・絶対ルール CLAUDE.md(目次)/.claude/rules/数値の扱い・配分・文体・パスの正本 L1′ 記憶層セッションをまたぐ事実 MEMORY.md(1行索引)+1ファイル1事実feedback/project/reference+context/ L2 自動注入(hooks・settings)+ MCP・コネクタ毎ターンの最小注入と安全装置。外部システムへの接続口もここ hooks(SessionStart/UserPromptSubmit/PreToolUse/Stop)/settings.json(allow・deny・ask)/.mcp.json L3 スキル層繰り返し作業の手順 .claude/skills/<id>/SKILL.md+reference/常駐は説明文のみ・本文は呼ばれた時に読む L3′ サブエージェントまっさらな文脈で判定 検品係など(.claude/agents/)設計・判断は本体、実装は Sonnet に任せてもよい L4 役割分担(モデルで分担) 本体(Opus):設計・判断・検品 Sonnet:実装・定型の量産 Codex:実装・反復(枠が別) L5 自動化(無人ジョブ) スクリプト → OS の定時実行(タスクスケジューラ/launchd)→ ログ 実行場所へ配布して登録し、失敗は終了コードとログで拾う
図は横にずらして見られます

1ターンの流れ

入力(ユーザーの指示) UserPromptSubmit hook 現在日時1行+rules指差し1行を注入 システムプロンプト構成 CLAUDE.md+rules+MEMORY.md索引+スキルdescription一覧+MCPツール定義 本体(settings.jsonのmodel)が受付・判断 該当スキルありSKILL.md読込必要な時だけ reference/ 該当スキルなし本体がそのまま対応(MCPツールも直接呼ぶ) 重い設計・実装・検品が必要なら(判断は本体) 設計本体(プランモード)方針を決めてから実行 実装Sonnet・Codex方針が決まったら任せる 検品検品係まっさらな文脈で判定 出力(ユーザーへ返答) Stop hook 当日の日次サマリーJSONが無ければ systemMessage で警告第6章で作る確認(日次サマリーがあるか)
図は横にずらして見られます

運用サイクル

短い間隔・軽い処理長い間隔・重い処理 毎ターン UserPromptSubmit hook日時1行+rules指差し1行数百バイトだけ 毎セッション SessionStart(発展)直近の記録を注入(発展)CLAUDE.md+rulesロードMCP接続・スキル説明文 毎日 日次サマリーYYYY-MM-DD.json1日1ファイル意味のある作業のたびに1件追記する 毎週 週次メンテ(発展)改善チェック+台帳の鮮度+メモリ整理(並列で実行してもよい) 毎月 指示書健診参照切れ・矛盾・肥大化常駐コストを前回値と比較月に1回、数えて比べる
図は横にずらして見られます

運用サイクルの図のうち、「毎セッションの SessionStart hook」と「毎週の週次メンテナンス」は発展で、この資料では作らない。第12章で作るのは月1回の健診。1ターンの図の Stop hook は、第6章で作る「日次サマリーがあるかの確認」だけ。

安全装置の一覧(この資料で作るもの)

何をどこでどう
認証ファイルの読み書きsettings.json の deny+手前で止める hooksecret_*.json・credentials*.json・.env は読ませない。コマンド経由の操作も止める
削除コマンドsettings の askrm 系は毎回確認
定時ジョブの停止・書き換えhooklaunchd/タスクスケジューラの操作は警告して止める
秘密のコミット.githooks/pre-commit(scan_secrets.py)APIキー形式・平文パスワード・禁止フォルダを機械でスキャン。例外は理由付きで記録
数値の捏造rules+検品係件数・数字は実データだけ。検品で出典の実在を確かめる
外部サービスへのアップロードrules仕事のデータを、許可されていない外部サービスに上げない
通知・課金・本番操作rules実行前に毎回確認(外への送信・課金が出る API・本番環境)
うっかり全部をコミット運用ルールgit add <ファイル名> でファイルを指定し、続けて commit する。フォルダ丸ごとの add はしない

付録D Codex で同じことをする

同じ足場を Codex(OpenAI)で作る人のための対応表。どちらか1つのサブスクリプションで足りる。両方を連携させる必要はない。

項目Claude CodeCodex
入れる(第0章)irm https://claude.ai/install.ps1 | iexpowershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"。codex で起動し ChatGPT アカウントでログイン
指示書(第2章)CLAUDE.md+.claude/rules/作業フォルダ直下の AGENTS.md 1枚(下のテンプレ codex/AGENTS.md.sample)
記憶(第3章)自動メモリ(MEMORY.md)+context/日次サマリーMemories(既定オフ・config.toml の features.memories = true)+context/日次サマリー
権限(第4章)settings.json の allow/deny/ask自分のホーム ▸ .codex ▸ config.toml の approval_policy/sandbox_mode
MCP(第5章).mcp.jsonconfig.toml の [mcp_servers.名前]、または codex mcp add
hooks(第6章)settings.json の hookshooks あり(features.hooks = true+hooks.json。同名イベント)。approval/sandbox も併用
秘匿スキャン(第7章)git hook同じ(git の仕組み)
スキル(第8章).claude/skills/<id>/SKILL.md+日本語入口SKILL.md は同形式。置き場は .agents/skills(作業フォルダ)か 自分のホーム ▸ .agents ▸ skills。/skills で一覧、$名前 で呼ぶ。日本語入口は無い
検品係(第9章).claude/agents/ のサブエージェントサブエージェント(config.toml)か、別セッションに渡して判定だけ頼む
無人化(第11章)タスクスケジューラ/launchd から claude -p同じ仕組みから codex exec
発注(参考)—下のテンプレ codex/CODEX_指示_テンプレ.md(触ってよいファイル・受け入れコマンド・禁止)

テンプレ(そのまま置けるファイル)

参考サンプル集 codex/AGENTS.md.sample
置く場所: 作業フォルダ ▸ AGENTS.md(改名して置く)
# AGENTS.md — <仕事の名前> の Codex 設定(Claude Code の CLAUDE.md に相当・目次だけ)

## 役割
<仕事の名前>の専属アシスタント。<主な仕事を1行で>

## 絶対ルール(5つ)
1. 数値は実データだけ。根拠がない数値は「不明」と書く
2. ファイルの上書き・外部への送信は、方針を一言確認してから
3. `secret_*.json`・`credentials*.json`・`.env` は読まない・書かない・コミットしない
4. 「どう思う?」は分析だけ返す。修正・送信は頼まれてから
5. 意味のある作業が終わったら `diary/YYYY-MM-DD.json` に1件追記する

## 保存先
新しいファイルの置き場は `context/README.md` が正本。迷ったら `inbox/` に置く。

## 補足
Codex の hooks(`features.hooks`)と Memories(`features.memories`)は既定では使わない前提で、ルールは全部この AGENTS.md に書き、記憶は `context/` と日次サマリーで持つ。使うなら config.toml で有効にする。
参考サンプル集 codex/CODEX_指示_テンプレ.md
置く場所: 作業フォルダ ▸ handoffs(発注のたびに書き写して使う)
# Codex への指示: <作るもの1行>

作成: <YYYY-MM-DD> / 依頼者: Claude Code 本体 / 形態: `codex exec`(非対話)

## 触ってよいファイル(これ以外は読むだけ。編集・作成禁止)
- <新規作成 or 編集するファイルを1つずつ書く>
- git 操作(add/commit/push)はしない

## 目的
<何のために、何ができればよいかを3行で>

## 仕様
- <入力と出力>
- <守るべき形式・制約>
- <実測済みの罠。想像で足さない>

## 完了条件(受け入れコマンド)
```sh
<1コマンド。終了コード0で合格。例: python3 tools/xxx.py --selftest>
```
- 依頼側(Claude)がこのコマンドを実行して判定する。**自己申告では完了にならない**
- 落ちたら失敗内容をファイルに書いて再発注。上限2回、超えたら人へ

## 禁止
- 外部ネットワーク・パッケージの追加インストール
- 数値・日付・人名・顧客名をサンプルに入れる
- 他ファイルの編集

## 発注コマンド(Claude 側で実行・長時間なら nohup で切り離す)
```sh
nohup codex exec -s workspace-write -C <作業フォルダ> "<このファイルのパス> を全文読んでから、そこに書かれたファイルだけを作成してください。完了条件は受け入れコマンドの終了コード0です。最後に実行結果と作成したファイルを出力してください。" > <ログファイル> 2>&1 &
```

出典: 各章の「Codex の場合」注釈と、Codex 公式ドキュメント(developers.openai.com/codex)

付録E モデルと道具の使い分け(いまの目安)

2026年10月時点の一つの運用例。本体は Opus(5.5)、方針が決まった実装は Sonnet(5.5)のサブエージェント、Codex は利用枠が別なので並行して使う(非セキュリティの実装・反復・大量処理の主力)。モデル名は変わるので、数字よりも「仕事の種類で担当を分ける」考え方を持ち帰る。

1本体(Opus)受付・設計・判断・最終チェック2Sonnet方針が決まった実装・文面・定型の量産3Codex非セキュリティの実装・反復・大量処理の主力。枠が別4検品係まっさらな文脈で合否だけ返す
1本体(Opus)受付・設計・判断・最終チェック2Sonnet方針が決まった実装・文面・定型の量産3Codex非セキュリティの実装・反復・大量処理の主力。枠が別4検品係まっさらな文脈で合否だけ返す
仕事の種類担当呼び方の例
方針・設計・最終チェック本体(Opus)。判断が重い仕事だけ本体が自分で動くプランモードで方針を決めてから実行に移る
普通の実装・バグ修正・資料や文面の作成Sonnet のサブエージェントAgent(model="sonnet")
判断が要らない大量の処理(要約・整文・分類・抽出)Sonnet のサブエージェント(本体の文脈を汚さない)Agent(model="sonnet")
非セキュリティの実装・設計・反復・大量処理Codex Luna(GPT-5.6・考える深さは最大)。Claude とは利用枠が別なので主力にできるcodex exec -m gpt-5.6-luna -c model_reasoning_effort="max"
判断を伴う実装(仕様の曖昧さが残る・既存コードへの影響が広い)Codex Terra(GPT-5.6)codex exec -m <Terra のモデル名>
セキュリティ判断(認証・権限・秘密情報)・原因不明の障害の第二の目Codex Sol(GPT-6.1・high 以上)codex exec -m gpt-6.1-sol -c model_reasoning_effort="high"
最終検品まっさらな文脈のサブエージェント(Opus)Agent(subagent_type="kenpin", model="opus")