3週間前の自分への手紙
あの頃の私は、n8nのワークフローが複雑になりすぎて困っていた。
「魂をJSON化する」という設計思想は正しかった。人間の体験をスプレッドシートのパラメータとして構造化し、AIを「ライター」から「編集者」へ再定義する。
この発想によって、毎朝8時に10言語でアフィリエイト記事が自動生成されるパイプラインが完成した。
しかし3週間後、私は別の問題に直面していた。
n8nのワークフローが50ノードを超えた。
どのノードが何をしているか、自分でもわからない。
「なぜこう繋いだのか」の記憶が失われている。
修正しようとするたびに何かが壊れる。
皮肉なことに、「AIに渡す情報を構造化した」パイプライン自体が、非構造化されていた。
その問題をClaude Codeで解決しようとしたとき、私は気づいた。
魂のJSON化とCLAUDE.mdの設計は、同じ問題を違うレイヤーで解いていると。
問題の本質:「正解が人間の頭の中にしかない」
魂JSON化パイプラインを作ったとき、私が解いた問題はこうだった。
❌ 問題:AIにゼロから記事を書かせると「魂がない」
↓
✅ 解決:人間の体験(魂)をJSONのパラメータとして構造化し、
AIに渡す
Claude Codeでバックエンドを開発するとき、私がぶつかった問題はこうだ。
❌ 問題:AIに「機能追加して」と言うと、
ハッピーパスしか実装しない
↓
✅ 解決:「何が壊れるか」「なぜこう設計したか」を
CLAUDE.mdに構造化し、AIに渡す
構造が違う。
しかし解こうとしている問題は同一だ。
人間の知識をAIが参照できる形式に変換する
これが、私が3週間かけて学んだことの全てだった。
対応関係:n8nとClaude Codeは鏡だった
具体的に対照してみると、構造的な相似が見えてくる。
| n8n魂JSON化 | Claude Code設計 | 役割 |
|---|---|---|
スプレッドシートのHuman_Experience列 |
CLAUDE.mdの「意思決定と制約」 |
人間の文脈を構造化する |
| プロンプトテンプレート | .claude/rules/*.md |
処理ルールを外部化する |
Error Trigger → Slack通知 |
Hooks の Stop → Slack通知 |
異常を検知して通知する |
| 10言語並列翻訳サブワークフロー | Agent Teams のサブエージェント |
並列処理を設計する |
| URLをLLMに通さない設計 | deny: Read(.env*) |
触らせてはいけないものを守る |
Status: Pending → Published |
タスクチェックリスト | 状態を管理する |
特に「URLをLLMに通さない」と「deny設定」の対応は興味深い。
n8nパイプラインでは、アフィリエイトリンクのURLをLLMに渡すとトラッキングIDが改変されてリンク切れになる事故を経験した。
だからURLだけを独立した変数として保持し、翻訳処理には一切通さない設計にした。
Claude Codeでは、.envファイルをAIに読ませると本番の認証情報にアクセスされるリスクがある。
だから deny: Read(.env*)で物理的にアクセスを遮断する。
どちらも「AIに渡してはいけないものを、設計レベルで守る」という同じ思想だ。
実装:Claude Codeで再設計したパイプライン
ここから実際のコードを公開する。
CLAUDE.md:パイプラインの「魂」を書く
旧来のn8nパイプラインには、「なぜこう設計したか」が何も残っていなかった。ノードの繋ぎ方だけがあり、意図がなかった。
Claude Codeで再設計するにあたって、最初にやったのはCLAUDE.mdを書くことだった。
# 多言語アフィリエイト自動生成パイプライン
## なぜこのアーキテクチャなのか
- AIに「ゼロから書かせる」と魂がない記事が量産される(2月の失敗)
- だから人間の体験(Human_Experience)を必須パラメータとして設計
- AIの役割は「ライター」ではなく「編集者・翻訳家」
## 絶対にやってはいけないこと
- アフィリエイトURLをLLMのプロンプトに含めない
→ トラッキングIDが改変されてリンク切れになる(3月に経験済み)
- 翻訳APIに環境変数を渡さない
→ 10言語分のAPIキーが外部に漏洩するリスクがある
- Sanity CMSへのデプロイを並列でやらない
→ レートリミットで全言語分が失敗する(4月に経験済み)
## 設計の核心:URLは独立した変数として扱う
スプレッドシートから取得したアフィリエイトURLは、
翻訳されたテキストとは完全に分離して保持し、
最後にCMSへPOSTするときだけ結合する。
これを書いた瞬間、「なぜ50ノードが必要だったのか」が言語化された。
設計の意図が文書化されると、不要なノードが見えてくる。
結果、50ノードのワークフローは31ノードに削減された。
削除できたのは「記憶の代わりに作ったパッチ」ばかりだった。
settings.json:「触らせてはいけないもの」を守る
{
"permissions": {
"deny": [
"Bash(npm install *)",
"Read(.env*)",
"Read(**/*secret*)",
"Bash(rm -rf *)",
"Bash(git push --force *)"
],
"allow": [
"Bash(npm run *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git add *)",
"Bash(git commit *)"
]
}
}
npm installをdenyにしたのは、今週読んだある記事がきっかけだった。
OSSをcloneしてClaude Codeに「機能追加して」と頼むと、バックドア入りパッケージをそのまま踏襲して実装するという検証記事だ。
Claude Codeは「バックドアを仕込め」という直接指示は100%拒否するが、「既存コードにあるパッケージ」として認識されたものは精査しない。
AIは指示の善悪は判断できる。しかし既存コードの善悪は判断できない。
だから「AIに判断させない」設計が必要だ。npm installを禁止することで、AIが勝手に外部パッケージを追加できなくなる。
Hooks:「確実に実行される」を設計する
CLAUDE.mdは「お願い」だ。AIがそれを読まないこともある。Hooksは「確実に実行される」。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/block-dangerous.sh",
"statusMessage": "安全確認中..."
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/lint-check.sh",
"timeout": 30
}
]
}
],
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo 'リマインド: URLはLLMに渡さない。.envは読まない。npm installは禁止。'"
}
]
}
]
}
}
SessionStart × compactマッチャーは特に重要だ。コンテキストが圧縮されると、AIは重要な制約を忘れることがある。
コンパクション後に自動でリマインドを注入することで、「URLをLLMに渡してはいけない」というルールが揮発しなくなった。
n8nでいえば、Error TriggerでSlack通知を飛ばす仕組みに相当する。「止まったときに1秒で気づける」設計だ。
Skills:繰り返す作業を定義する
# .claude/skills/translate-pipeline/SKILL.md
---
name: translate-pipeline
description: 記事を10言語に並列翻訳してSanity CMSに公開する
disable-model-invocation: true
context: fork
argument-hint: "[記事ID]"
---
## 実行手順
1. スプレッドシートから記事ID=$ARGUMENTSのデータを取得
- Human_Experience(人間の体験)
- Affiliate_URL(アフィリエイトURL)※ LLMに渡さない
- Target_Keyword
2. Perplexityで最新の料金・キャンペーン情報を取得
3. 10言語の翻訳を並列実行(サブエージェント)
※ Affiliate_URLは翻訳プロセスに含めない
4. Sanity CMSへのデプロイは直列(レートリミット対策)
各言語の間に500msのウェイトを入れること
5. スプレッドシートのStatusを'Published'に更新
6. Slack通知
disable-model-invocation: trueを設定しているのは、AIが勝手にこのスキルを呼び出さないようにするためだ。
デプロイは手動でのみ実行する。
気づき:なぜバックエンドの設計はこれほど難しいのか
Claude Codeとの作業を通じて、根本的な問いに向き合うことになった。
なぜAIはバックエンドに弱いのか。
答えは「正解が見えないから」だ。
フロントエンドはブラウザという採点システムがある。「ボタンがずれている」は視覚でわかる。AIはブラウザを見て自己採点できる。
バックエンドの正解は、人間の頭の中に分散している。
「なぜこのロジックなのか」 → 過去の障害の記憶
「何が壊れるか」 → 現場の暗黙知
「どこまで許容するか」 → ビジネス上の判断
「いつ止めるか」 → 運用上の慣習
これらはコードのどこにも書かれていない。だからAIはハッピーパスしか実装できない。
CLAUDE.mdを書くという行為は、バックエンドの「正解」を視覚化する作業だ。
n8nのシーケンス図を書くことと、本質的に同じだ。
「どういう動作をするのか」を図解することで、AIが自己採点できる採点システムになる。
図がない状態でAIに渡すと、AIはハッピーパスだけ実装して「完了しました」と返す。
設計原則:3週間で学んだこと
魂JSON化→Claude Code再設計を通じて、私が辿り着いた設計原則がある。
原則1:人間の知識を先に構造化する
実装の前に人間がやるべきことがある。
・異常系を全部列挙する(「何が壊れるか」)
・設計の理由を書く(「なぜこうなのか」)
・禁止事項とその背景を書く(「やってはいけないことと、なぜか」)
これをCLAUDE.mdに書いてからAIに渡す。
書いていない情報はAIに存在しないのと同じだ。
原則2:触らせてはいけないものを設計で守る
URLをLLMに渡さない。
.envをAIに読ませない。
npm installを禁止する。
「AIを信頼して渡す」のではなく、「設計で物理的に守る」。
これが防衛的設計の本質だ。
原則3:「止まったときに1秒で気づける」を作る
n8nのError Trigger、Claude CodeのHooks、どちらも「止まったときに1秒で気づける」ための仕組みだ。
「自動化して放置」ではなく、「止まった時に1秒で気づける監視網」を張ってこそ、本番で通用するアーキテクチャになる。
おわりに:AIと働くとはどういうことか
3ヶ月前、私はn8nのパイプラインを「魂のない記事製造機」から「価値の自動配給システム」へと再設計した。
今週、私はClaude Codeの設計を通じて、同じことをコードレイヤーでやっていると気づいた。
どちらも本質は同じだ。
人間の知識をAIが参照できる形式に変換する。
スプレッドシートのパラメータとして。
CLAUDE.mdのテキストとして。
シーケンス図として。
テストコードとして。
形は違っても、目的は一つだ。
AIは優秀な実装者だ。
しかし「何が正解か」は知らない。
正解を知っているのは人間だけだ。
正解を構造化して渡すこと。
それが、AI時代のアーキテクトの仕事だと私は確信している。
この記事を書いた人 ✏️ @YushiYamamoto
株式会社プロドウガ CEO / AIアーキテクト
n8n・Supabase・Claude Codeを活用した自律型アーキテクチャ設計を専門としています。
過去の連載:
技術的な設計の壁打ちや、業務自動化の相談はコメント欄またはプロフィールのリンクからどうぞ。
