課題:情報の分散と二重管理
「これはどこに置けばいいですか?」
エージェントシステムを育てながら、この問いに繰り返し直面する。顧客マスタは Notion か JSON か。議事録は Drive か repo か。スクリプトの設定値は環境変数か YAML か。一見些細な判断に見えるが、積み重なると「何がどこにあるか不明確」な状態が生まれる。
その結果、二つの脆弱性が露出する。
ひとつは、AI エージェントが誤った場所に書き込む事故だ。スクリプトが Notion から古い顧客名を参照して見積を生成し、人間が気づいて修正する。その修正を反映するため、誰かが config ファイルも更新する。翌週、また別の誰かが Sheets の方を書き換えている——こうした往復がコストになる。
もうひとつは、「どちらが正しいか」を確認する時間だ。設定が複数箇所に分散していると、特に査察や監査のときに「今の正規値はどれか」を追跡するだけで数時間かかる。データの変更履歴も分散するため、いつ誰がなぜ変えたのかを遡るのが困難になる。
八雲では、この問題への答えを設計として固めている。
パターン定義:3 層の役割分類
情報・データ・アクションの置き場所を Notion / リポジトリ / Google Drive の 3 層 に分類し、層ごとの責務を明確に分離する。
各層の役割を一言で言えば、Notion は「人間のアクション」、repo は「システムのロジック」、Drive は「ドキュメント実体」 だ。
| 層 | 役割 | 具体例 |
|---|---|---|
| Notion | 人間のアクション + 視覚管理 | Tasks(判断待ちタスク)/ Projects(ステージ可視化)/ Cases(案件 DB) |
| リポジトリ(repo) | システム・仕様・ロジック | config/*.json(SSOT)/ specs/*.md / scripts/ / .claude/skills/ |
| Google Drive | ドキュメント・データ実体 | 見積書・請求書・契約書・議事録・パイプラインシート |
判断に迷ったときは、次の 3 つの問いで確認できる。
| 問い | Yes → 配置先 |
|---|---|
| 人間が毎日見て判断・承認する? | Notion |
| 機械が読む設定値・仕様・コード? | repo |
| 書類実体・最終形式(Docs/Sheets)? | Drive |
Notion は「判断する人間のインターフェース」として機能する。タスクの承認・プロジェクト状況の確認・案件のレビュー——これらは人間の目と判断を介するものであり、ツール側は「入力デバイス」に徹するべき領域だ。スクリプトが Notion API を叩いて config を読むような設計は、Notion が落ちたときにシステムごと止まる脆弱性を抱える。だから機械が読む設定値は Notion には置かない。
repo は「機械が読むものを全部置く場所」だ。スクリプトの動作を制御する JSON・エージェントのスキル定義・プロジェクト横断のルールを記述した仕様書・CLAUDE.md——これらはすべて repo に置く。理由は二点:(1)Git で変更履歴が追跡可能、(2)Claude Code がプロジェクト起動時に自然に読める。
Drive は「書類の実体を置く場所」だ。見積書・請求書・議事録のような Google Docs / Sheets ファイルは、Drive にしかない形式(Docs の版管理・Sheets の条件付き書式・コメント機能)を活かす必要がある。取引先とやりとりする最終成果物や、人間が署名する書類は Drive に住む。
設計の核:SSOT は 1 層のみ
3 層設計の核心は、SSOT(Single Source of Truth)を 1 層にのみ置くというルールだ。
顧客コードと会社名の対応は config/clients.json だけが持つ。Notion の Clients DB にも顧客が並んでいるが、そこはビューにすぎない。見積書の単価は config/pricing.json にのみ記録し、Drive の見積書はそこを参照して生成される。パイプラインの列定義は config/pipeline-columns.json が SSOT で、Drive のスプレッドシートも GAS もその値を読む。
なぜ二重管理が問題なのか。端的に言えば、「どちらが正しいか」の確認コストが指数関数的に増えるからだ。
具体的なシナリオを描くと:
- 日曜夜、営業が Notion のクライアント DB で顧客 X の名称を「ABC Corp」に更新
- 月曜朝、エージェントが
config/clients.jsonを読んで(まだ「ABC Ltd」)見積を生成 - 営業が見積を見て「名称が違う」と気づいて報告
- 開発者が config ファイルを更新し、見積を再生成
- 同時に Drive のパイプラインシートを見ていた別の人が、古い「ABC Ltd」を見て、「Notion と合わせなくては」と Sheets を変更
- 結果、Sheets と config が競合し始める
このサイクルは、SSOT が複数ある限り続く。
以下は八雲の SSOT マップの一部だ。
| データ | SSOT | 参照する層 |
|---|---|---|
| 顧客コード → 会社名 | config/clients.json | Notion Clients DB(参照プロパティ)/ Drive 書類名 |
| 時給・料金設定 | config/pricing.json | 見積・請求(Drive) / GAS |
| パイプライン列定義 | config/pipeline-columns.json | パイプラインシート(Drive)/ GAS |
| 人間のタスク状態 | Notion Tasks DB | repo script が読み書き(ステータス変更) |
| 書類実体(見積・請求) | Drive(Sheets) | config/templates.json が定義 → Drive が実装 |
「Notion にも似たデータが見える」状態は許容する。ただしそれは「参照」であって「保持」ではない。Notion のプロパティには Drive のリンク URL や config/clients.json の key を持たせ、実データへの参照に徹させる。こうすることで、データ変更は常に SSOT を向き、Notion は「ビュー層」として一貫性を保つ。
適用例:層をまたぐ操作パターン
3 層が分かれているからこそ、層をまたぐ操作には一定のパターンがある。
パターン 1:案件リサーチから提案まで
1. スクレイピングスクリプト(repo)実行
→ 提案文ドラフト生成(Drive に保存)
2. Notion Tasks に [提案レビュー待ち] を投入
→ ドラフト URL を参照プロパティに含める
3. 人間が Notion でレビュー
→ 修正コメント記入 / ステータス「承認済」に変更
4. task-sync スクリプト(repo)が cron で検知
→ Drive ドラフトを最終形に変換
→ 取引先に提出(API / メール / Drive リンク共有)
5. 人間が Notion ステータスを「完了」に手動更新
このフローで重要なのは、ロジック・データ・進捗が層を分けているという点だ。ロジック(スクレイピング・提案生成・提出処理)はすべて repo のスクリプトが担う。生成物の実体(ドラフト・最終版)は Drive に置かれる。人間の判断フロー(レビュー待ち・承認・完了)は Notion で管理される。それぞれが得意な仕事をしている。
パターン 2:書類作成と承認
1. 書類テンプレート定義が SSOT
→ config/templates/ に YAML / JSON で保存
→ バージョン管理・diff 追跡可能
2. スキル実行(repo script)
→ config/templates/invoice.json を読み込む
→ Drive 上の Sheets テンプレートを複製
→ GAS で顧客データを参照フィルタリング
→ 書類に記入
3. Notion Documents DB に [最終確認待ち] 登録
→ Drive リンクを参照プロパティに
4. 承認者が Drive で内容を確認
→ Notion のステータスを [承認] に変更
5. repo script(別 cron)が検知
→ Drive で PDF 化・署名フロー実行
→ 完了ステータスに自動更新
ここで設計的に重要な決断は、repo は Notion を知らない前提で動く という原則だ。スクリプトから見ると Notion は「人間の入力デバイス」にすぎず、API でのクエリに限定される。スクリプト自体は Notion の DB 構造に依存していない。もし Notion が別のツール(Linear、Asana など)に置き換わっても、repo のロジック自体は書き直さずに済む。この疎結合が長期的な保守性を支える。
落とし穴と運用の工夫
効果:探す場所が決まる
最も実感する効果は「探す場所が決まる」ことだ。何かを調べたいとき、それが設定値なら config/ を見る、仕様なら specs/*.md を見る、書類なら Drive を見る、判断状況なら Notion を見る——という行動が自動化される。
AI エージェントへの指示も明確になる。「config/pricing.json を読んで見積を生成する」「Drive のパイプラインシートを読んで Notion Tasks に投入する」という形で、どの層のどこを読み書きするかを明示できる。エージェントが勝手な場所に書き込む事故が減る。
落とし穴 1:層の境界が曖昧な領域
一方で実装の課題が存在する。「これはどの層か」の判断が難しい領域が存在するという問題だ。
たとえばパイプラインシートは Drive の Sheets に置いているが、「設定なのか、データなのか」という揺らぎがある。列定義は config/pipeline-columns.json が SSOT だが、シートの実データ行は Drive が持つ。この境界を最初から明快に設計できていたわけではなく、運用しながら SSOT マップを更新してきた。
初期段階で「全部 Sheets に置こう」と判断していたら、今この瞬間の「列定義を変えたら自動的に全パイプラインに反映される」という設計は実現していないはずだ。
落とし穴 2:Notion の参照規律の維持
もうひとつは、Notion プロパティを「参照だけ」に抑える規律の維持だ。「ここに直接書いたほうが早い」という誘惑は常にある。短期的にはそれで済むが、積み重なると Notion が SSOT になっているデータが増え始める。
例えば、クライアント DB に「更新日」というプロパティを追加して、「最後にこの顧客と連絡した日」を直接 Notion に記入してしまったとしよう。当初は「参照だけ」のはずだった Notion が、実は「更新日の SSOT」になっている。数週間後、Drive の顧客マスタシートを見ると「最後の連絡日は 3 か月前」と書いてある。Notion と Drive で別のデータが「正」として存在している。
この引き締めは、メンバー間での意識的な合意が必要だ。CLAUDE.md に「Notion プロパティは参照または計算フィールドのみ」と明記し、PR レビューで「ここに直接 write していないか」を確認するステップを入れる。
完璧な分類が最初からできるわけではない。「迷ったらここ」という判断基準を持ち、実際に運用しながら SSOT マップを育てていく姿勢が長続きするコツだと実感している。
まとめ
3 層責務分離は、情報の置き場所に「理由」を持たせる設計だ。Notion には人間のアクション、repo にはシステムのロジック、Drive にはドキュメントの実体——この分類を守ることで、AI エージェントが誤った場所に書き込む事故を減らし、「何かあったらここを見る」という共通認識が生まれる。
SSOT を 1 層にのみ置くという原則は、その設計を支える骨格だ。二重管理を禁じることで、「どちらが正しいか」の確認コストがなくなり、変更履歴を単一の場所で追跡できる。
この仕組みがどんな文脈で動いているかは、AI 駆動開発で情報の一貫性を保つでより広く整理している。また変更のたびに仕様書が陳腐化しないよう CLAUDE.md に更新ルールを持たせる設計については、ドキュメント自動更新ルールの設計で詳しく扱っているので、あわせて参照してほしい。