つい2週間前、GitリポジトリとClaude Code Skillで営業管理を自動化した記事を書きました。SFA不要、月額0円、14サブコマンドで営業活動が完結する仕組み。あのときは「これで十分だ」と本気で思っていました。
十分だったんです。自分から /sales log と打てる間は。
「自動化」で満足できなくなった瞬間
Skillによる自動化が軌道に乗ると、欲が出てきます。
「電話メモをSlackに投げたら、勝手にパイプライン更新してくれないかな」「面談終わったらSlackに通知が来て、ボタン押すだけでお礼メール送信されないかな」——つまり、こっちからコマンドを叩かなくても、AIが自律的に動いてほしい。
少人数チームの営業管理の記事で書いた通り、フォロー漏れゼロ、事務作業83%削減は達成できていました。でも「自動化」と「自律化」のあいだには、思った以上の距離がある。
- 自動化: 人間が指示 → AIが実行
- 自律化: AIが状況を察知 → 人間に確認 → AIが実行
この距離を埋めようとしたとき、Git管理の限界にぶつかりました。
Gitベース営業管理の「3つの壁」
壁1: データ更新のたびにビルドが走る
YAMLファイルを変更 → auto-deploy.shがcommit → push → Vercelがbuild → ダッシュボードに反映。この流れ、1回あたり1〜2分かかります。
1日に5回パイプラインを更新すると、5回ビルドが走る。Vercelの無料枠を圧迫するし、何よりダッシュボードを開いたとき「さっき更新した内容がまだ反映されてない」 というタイムラグが微妙にストレス。
壁2: テストデータがgit履歴を汚染する
Slack連携のテストで「テスト企業A」「テスト電話メモ」みたいなデータをcommitすると、それがgit履歴に永遠に残ります。git rebaseで消すこともできるけど、本番データとテストデータが同じリポジトリにある時点で事故の匂いがする(案の定、一度テストデータを本番pushしました)。
壁3: 書き込みとデプロイが密結合
自律エージェントが勝手にデータを書き換えてcommit・pushするとなると、そのたびにVercelのデプロイが走る。Slack経由で1日20回活動ログを書いたら、20回デプロイ。さすがに無駄すぎる。
要するに、Gitベースのアーキテクチャは「人間が1日数回、意図的にコマンドを叩く」前提で設計されていた。自律エージェントが高頻度でデータを読み書きする世界とは相性が悪かったんです。
Before → After: アーキテクチャの変遷
| レイヤー | Before(Git時代) | After(DB時代) |
|---|---|---|
| データストア | YAML/Markdown in Git | Neon Postgres + Prisma |
| データ操作 | Claude Code → ファイル編集 → commit | Claude Code → scripts/db.sh → Prisma Client |
| ダッシュボード | 静的生成(ビルド時にファイル読み込み) | SSR(リクエスト時にDB直読み、5分ISRキャッシュ) |
| デプロイ | auto-deploy.sh → Vercel Git Integration | auto-deploy.sh 廃止。DBに書けば即反映 |
| Slack連携 | なし | Socket Mode daemon が常駐して自律処理 |
auto-deploy.sh、お疲れさまでした。
移行のポイントは「データ層とデプロイ層の分離」。DBに書き込んだ瞬間にダッシュボードから読める。ビルドもcommitも不要。この単純な変化が、自律エージェント化の前提条件でした。
Neon Postgres + Prisma: なぜこの組み合わせか
「DBにするなら何でもいいんじゃ?」という声が聞こえてきそうですが、少人数チームには少人数チームの選び方があります。
| 要件 | Neonの答え |
|---|---|
| 無料枠で運用したい | 512MBストレージ、月間190時間のコンピュート(2人の営業データには十分すぎる) |
| サーバーレスで接続したい | HTTP接続対応。Vercel Functionsとの相性が良い |
| ブランチングでテストしたい | DBブランチ機能で本番データをコピーしてテスト可能(git履歴汚染問題の根本解決) |
Prismaはスキーマ定義がそのまま型になるのが決め手でした。以前のschema.ymlの役割をPrismaスキーマが引き継ぐ形です。
model Company {
id Int @id @default(autoincrement())
slug String @unique
name String
phone String?
address String?
url String?
employeeCount Int?
pipeline Pipeline?
activities Activity[]
contacts Contact[]
minutes Minute[]
briefs Brief[]
subsidies Subsidy[]
}
model Pipeline {
id Int @id @default(autoincrement())
company Company @relation(fields: [companyId], references: [id])
companyId Int @unique
status PipelineStatus
nextAction String?
nextActionDeadline DateTime?
lastContact DateTime?
appointmentCount Int @default(0)
source String?
}
scripts/db.shがPrisma Clientのラッパーとして全CRUDを担当。Skillからはこのシェルスクリプト経由でDBを操作します。JSON入力・JSON出力で統一されているので、AIとの相性も良い(YAMLパースの不安定さから解放された)。
自律エージェント: sales-slack daemon
ここからが本題。「Slackに投げたら勝手に動く」を実現するアーキテクチャです。
全体構成
Slack #sales チャンネル
↓ Socket Mode
daemon (Node.js 常駐プロセス)
↓ claude -p
sales-slack skill (意図分類 → ルーティング)
↓
sales skill (DB操作 → 結果返却)
↓
daemon → Slack スレッドに返信
daemonはSocket Modeで#salesチャンネルを監視する常駐プロセス。メッセージを受信すると、claude -pでClaude Codeを起動し、sales-slack skillに処理を委譲します。
サブスク内で動く「自律営業事務」
ここで気づいた方もいるかもしれませんが、daemonがclaude -pで呼び出す処理はClaude Codeのサブスクリプションプラン内で動いています。API従量課金ではなく月額固定。つまり、何回Slackに投稿しても、何件followupを処理しても、追加コストは0。
月額固定で「自律的に動く営業事務を1人雇っている」ようなものです。SFAのライセンス費用(1ユーザーあたり月数千〜数万円)と比べたら、もはや誤差の範囲。しかもこの営業事務は24時間対応で、打ち合わせメモの整理もお礼メールの下書きも文句ひとつ言わない(daemonが動いてるMacが寝なければ、ですが)。
意図分類: Slackの自然文を営業コマンドに変換
「A社と電話した。提案書来週送る」とSlackに投げると、sales-slack skillがこれを意図分類します。
| 意図 | 判定基準 | 例 |
|---|---|---|
| log | 過去形の動詞 + 企業名 | 「〜と電話した」「〜に見積送った」 |
| info | 企業名 + 疑問詞 | 「A社のステータス」 |
| remind | 「期限」「今日」「今週」 | 「今日の期限は?」 |
| list | 「一覧」「リスト」 | 「提案中の案件リスト」 |
分類されたintentはsalesスキルの対応するサブコマンドにルーティングされ、DBを更新し、結果がSlackのスレッドに返信される。
つまり、営業担当がやることは「Slackに日本語で投稿する」だけ。コマンド体系を覚える必要すらない。
meeting-followup の自動化: Gemini Notesをトリガーに
Google Meetで面談すると、Geminiが自動で会議メモ(Gemini Notes)を生成してメールで送ってきます。daemonはこのメールを60秒ポーリングで検知。
- gemini-notes メール着信 → daemonが検知
- Slackに「followupやる?」とボタン付きメッセージを投稿(gate1)
- [やる]を押す →
/sales followupが自動実行 - 議事録生成・活動ログ記録・お礼メールの下書き作成
- Slackに「draftできたよ」+プレビュー+[送信][編集][破棄]ボタン(gate2)
- [送信]を押す → Gmail APIでメール送信
面談終了からお礼メール送信まで、Slackのボタンを2回押すだけ。以前は/sales followup todayとターミナルで打っていた工程が、Slackの通知に反応するだけになりました(ターミナルを開く必要すらない)。
セキュリティ: 自律だからこそガードレールは厚く
自律エージェントは便利だけど、「勝手に動く」ということは「勝手に暴走する」リスクもある。自分だけが使う分にはまだいいけど、他の営業メンバーもSlackから使うとなると、設計の甘さが事故に直結する。
たとえば営業メンバーが「さっき電話した結果、受注になりました」と報告するだけの投稿で、意図しない処理が走ったら最悪です。ここはかなり慎重に設計しました。
| 対策 | 内容 |
|---|---|
| Skillの厳格な制限 | daemonが呼び出せるSkillはsalesのみ。他のSkillへの切り替えは構造的に不可能 |
| Bashツール無許可 | daemonからのclaude実行にBashを許可しない。RCEリスクを根本排除 |
| コマンドホワイトリスト | 認識済み/salesサブコマンドのみ許可。シェルインジェクション文字を拒否 |
| ユーザーホワイトリスト | 許可されたSlackユーザーIDのみ処理。それ以外はサイレント無視 |
| 構造的プロンプトインジェクション対策 | ユーザーテキストをpromptに直接埋め込まない。一時ファイルに書き出し、promptとユーザー入力を構造的に分離 |
| Failsafe | 意図が不明なメッセージには「対応できません」と返して停止。曖昧な入力でDBを更新しない |
| 二段階ゲート | followupのメール送信は必ず人間がSlackボタンで承認 |
ポイントは、プロンプトインジェクションでSkillを切り替えさせたり、任意コマンドを実行させたりすることが構造的に不可能という点。ユーザーが何を投稿しても、daemonが実行できる操作はsalesスキルの範囲内に物理的に閉じている。「AIが賢く判断して悪意を検知する」のではなく、そもそも悪意のある操作が実行パスに存在しない設計です。
「自律」と「野放し」は違う。 判断はAIに任せるが、実行の最終承認は人間が握る。この原則を全フローに適用しています。
なぜ自律エージェントフレームワークを使わなかったのか
Open Clawのような自律エージェントフレームワークも検討しました。世の中には「AIエージェントを簡単に構築できます」系のツールが増えているし、使えば開発工数は減っただろうなと思います。
でも、営業データを扱うシステムでセキュリティモデルを外部フレームワークに委ねるのは、ちょっと怖かった。
理由はシンプルで、セキュリティポリシーをこちら側で完全にグリップしておきたかったから。フレームワークが提供するサンドボックスやガードレールがどう実装されているかを隅々まで把握して初めて「安全です」と言える。でも外部依存が増えるほど、その検証コストが膨れ上がる。
自分でホワイトリスト設計して、自分でガードレールを書く方が、結果的に「何が起きても説明できる」状態を維持しやすい。営業データには顧客の連絡先や商談内容が入っているわけで、「フレームワーク側のアップデートで挙動が変わって情報が漏れた」は絶対に避けたいシナリオです。
結果的に、Claude Code の skill + daemon という構成が「自律性」と「制御可能性」のバランスとして一番しっくりきました。Skillはホワイトリストで厳格に制限できるし、daemonのコードは自分たちで書いているから挙動を100%把握できる。フレームワークの魔法に頼らない分、設計意図が透明なんです(その代わり、自分で全部書く労力はかかりますが)。
3つの構成を経て見えたこと
| フェーズ | 構成 | 学んだこと |
|---|---|---|
| Phase 1 | Git + YAML + Claude Code Skill | テキストベースの営業管理は意外と実用的。SFAは5人以下には過剰 |
| Phase 2 | Git + YAML + auto-deploy + Dashboard | 可視化で安心感が生まれた。でもGitは高頻度書き込みに向かない |
| Phase 3 | Neon Postgres + Prisma + daemon + Slack | データ層とUI層の分離が自律化の前提条件。書き込み頻度の制約がなくなった |
Phase 1→2は「見える化」の改善。Phase 2→3は「誰が主導権を持つか」の転換。人間がコマンドを叩く前提から、AIが状況に反応して動く前提へ。この転換には、データアクセスの即時性(DBの強み)が不可欠でした。
移行コストと現実的な注意点
美しい進化の話だけだと嘘くさいので、正直に。
移行にかかった時間: 約2週間(YAMLからDBへのデータインポートスクリプト作成 + Prismaスキーマ設計 + dashboard改修 + daemon開発)
予想外にハマったポイント:
- daemon の keychain アクセス: LaunchAgentやcronからの起動ではmacOSのKeychainにアクセスできない。Terminal.app配下でzellijを起動する必要がある(半日溶かした)
- TypeScript移行の連鎖: daemon をJS→TSに移行したら、型の不整合が芋づる式に出てきて、結局scripts層まで全部TSに書き換えることに(良い判断だったけど想定外の工数)
- Prisma enumの罠: Pipeline.statusをenum化したら、既存データとの不整合で初回マイグレーションが一発で通らなかった
今の課題:
- daemonは1台のMac上でzellijセッションとして動いている。そのMacが落ちたら営業アシスタントも停止する(冗長性ゼロ)
- Slackのボタン操作がタイムアウトすると、gate2のメール送信が宙に浮く
まとめ
Git + YAMLで始めた営業管理が、Neon Postgres + Prisma + Slack daemonの構成に進化しました。「自動化」から「自律化」への一歩です。
変わったのはアーキテクチャだけじゃなく、営業担当の振る舞い。以前はターミナルを開いて/sales logと打っていた。今はSlackに「さっき電話した」と投げるだけ。面談後はSlackの通知に反応してボタンを2回押すだけ。
しかもこの営業管理AI自動化の仕組み、サブスクリプション内で動くからランニングコストは月額固定のまま。SFAを契約するより安いのに、自律的に議事録をまとめてお礼メールの下書きまで作ってくれる。2人チームにはちょうどいい塩梅です。
道具が変わると、行動が変わる。行動が変わると、空いた時間で次の改善を考えるようになる。そしてまた欲が出てくる。たぶん3ヶ月後には「Slackに投げるのすら面倒。電話を切ったら自動で記録してくれ」とか言い出すんだろうな、と薄々わかっています。
(daemonが動いてるMacのスリープ設定を「しない」にしてあるんですが、電気代の請求書はまだ見ないことにしています。)



