つい2週間前、GitリポジトリとClaude Code Skillで営業管理を自動化した記事を書きました。SFA不要、月額0円、14サブコマンドで完結する仕組みで、あのときは「これで十分だ」と思っていました。
十分だったんです。自分で /sales log と打てる間は。
「自動化」で満足できなくなった瞬間
Skillによる自動化が軌道に乗ると、欲が出てきます。
「電話メモをSlackに投げたら、勝手にパイプライン更新してくれないかな」——つまり、こっちからコマンドを叩かなくても、AIが自律的に動いてほしい。
少人数チームの営業管理の記事の通り、フォロー漏れゼロ、事務作業83%削減は達成できていました。でも「自動化」と「自律化」には思った以上の距離がある。
- 自動化: 人間が指示 → AIが実行
- 自律化: AIが状況を察知 → 人間に確認 → AIが実行
この距離を埋めようとしたとき、Git管理の限界にぶつかりました。
Gitベース営業管理の「3つの壁」
壁1: データ更新のたびにビルドが走る
YAMLファイルを変更 → auto-deploy.shがcommit → push → build → 反映。この流れ、1回あたり1〜2分かかります。
1日に5回更新すると5回ビルドが走り、無料枠を圧迫します。「さっき更新した内容がまだ反映されてない」 というタイムラグも地味にストレスでした。
壁2: テストデータがgit履歴を汚染する
Slack連携のテストで「テスト企業A」のようなデータをcommitすると、git履歴に永遠に残ります。本番とテストが同じリポジトリにある時点で事故の匂いがする(案の定、一度テストデータを本番pushしました)。
壁3: 書き込みとデプロイが密結合
自律エージェントが勝手にデータを書き換えてcommit・pushするとそのたびにデプロイが走ります。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、お疲れさまでした。
移行のポイントは「データ層とデプロイ層の分離」。この単純な変化が、自律エージェント化の前提条件でした。
Neon Postgres + Prisma: なぜこの組み合わせか
「DBにするなら何でもいいんじゃ?」という声もありそうですが、選び方があります。
| 要件 | Neonの答え |
|---|---|
| 無料枠で運用したい | 512MBストレージ、月間190時間のコンピュート(2人分には十分) |
| サーバーレスで接続したい | HTTP接続対応。Vercel Functionsと相性が良い |
| ブランチングでテストしたい | DBブランチで本番データをコピーしテスト可能(git履歴汚染の根本解決) |
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を担当。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を起動します。
サブスク内で動く「自律営業事務」
daemonがclaude -pで呼び出す処理はClaude Codeのサブスクリプション内で動いています。API従量課金ではなく月額固定なので、何回投稿しても追加コストは0。「自律的に動く営業事務を1人雇っている」ようなもので、SFAのライセンス費用(1ユーザー月数千〜数万円)と比べたら誤差の範囲。24時間対応で文句ひとつ言いません。
意図分類: Slackの自然文を営業コマンドに変換
「A社と電話した。提案書来週送る」とSlackに投げると、sales-slack skillが意図分類します。
| 意図 | 判定基準 | 例 |
|---|---|---|
| log | 過去形の動詞 + 企業名 | 「〜と電話した」「〜に見積送った」 |
| info | 企業名 + 疑問詞 | 「A社のステータス」 |
| remind | 「期限」「今日」「今週」 | 「今日の期限は?」 |
| list | 「一覧」「リスト」 | 「提案中の案件リスト」 |
分類されたintentはsalesスキルの対応サブコマンドにルーティングされ、DBを更新し結果が返信されます。つまり、営業担当がやることは「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と打っていた工程が、通知に反応するだけになりました。
セキュリティ: 自律だからこそガードレールは厚く
自律エージェントは便利ですが、「勝手に動く」は「勝手に暴走する」リスクもあります。他の営業メンバーも使うとなると、設計の甘さが事故に直結します。
たとえば「さっき電話して受注になりました」という投稿で意図しない処理が走ったら最悪です。
| 対策 | 内容 |
|---|---|
| Skillの厳格な制限 | daemonが呼べるSkillはsalesのみ |
| Bashツール無許可 | daemonのclaude実行にBashを許可せずRCEを根本排除 |
| コマンドホワイトリスト | 認識済み/salesサブコマンドのみ許可、シェル文字を拒否 |
| ユーザーホワイトリスト | 許可されたSlackユーザーIDのみ処理、それ以外は無視 |
| 構造的プロンプトインジェクション対策 | ユーザーテキストをpromptに直接埋め込まず、一時ファイル経由で分離 |
| Failsafe | 意図不明なら「対応できません」と返して停止 |
| 二段階ゲート | followupのメール送信は必ず人間がSlackボタンで承認 |
ポイントは、プロンプトインジェクションでSkillを切り替えたり任意コマンドを実行させたりすることが構造的に不可能という点です。そもそも悪意のある操作が実行パスに存在しない設計です。
「自律」と「野放し」は違う。 実行の最終承認は人間が握る、という原則を全フローに適用しています。
なぜ自律エージェントフレームワークを使わなかったのか
Open Clawのような自律エージェントフレームワークも検討しました。
でも、営業データを扱うシステムでセキュリティモデルを外部フレームワークに委ねるのは怖かった。セキュリティポリシーをこちら側で完全にグリップしておきたかったからです。
自分でホワイトリストとガードレールを書く方が「何が起きても説明できる」状態を維持しやすい。「フレームワーク側の更新で挙動が変わり情報が漏れた」は絶対に避けたいシナリオです。
結果的に、Claude Code の skill + daemon が「自律性」と「制御可能性」のバランスとして一番しっくりきました。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が反応する前提への転換には、データアクセスの即時性が不可欠でした。
移行コストと現実的な注意点
美しい進化の話だけだと嘘くさいので、正直に。
移行にかかった時間: 約2週間(YAMLからDBへのデータインポートスクリプト作成 + Prismaスキーマ設計 + dashboard改修 + daemon開発)
予想外にハマったポイント:
- daemon の keychain アクセス: LaunchAgentやcronからの起動ではKeychainにアクセスできない。Terminal.app配下でzellijを起動する必要がある(半日溶かした)
- TypeScript移行の連鎖: daemon をJS→TSに移行したら型の不整合が芋づる式に出て、結局scripts層まで全部TS化
- Prisma enumの罠: Pipeline.statusをenum化したら既存データと不整合で初回マイグレーションが通らなかった
今の課題:
- daemonは1台のMacでzellijセッションとして動いており、落ちたら停止する(冗長性ゼロ)
- Slackのボタン操作がタイムアウトすると、gate2のメール送信が宙に浮く
まとめ
Git + YAMLで始めた営業管理が、Neon Postgres + Prisma + Slack daemonの構成に進化しました。「自動化」から「自律化」への一歩。
変わったのはアーキテクチャだけじゃなく、営業担当の振る舞い。以前はターミナルで/sales logと打っていましたが、今はSlackに「さっき電話した」と投げ、面談後はボタンを2回押すだけです。
サブスクリプション内で動くからランニングコストは月額固定のまま。議事録やお礼メールの下書きまで作ってくれます。2人チームにはちょうどいい塩梅です。
道具が変わると行動が変わる。たぶん3ヶ月後には「電話を切ったら自動で記録してくれ」と言い出すんだろうと薄々わかっています。
(daemonが動いてるMacのスリープ設定を「しない」にしてあるので、電気代の請求書はまだ見ないことにしています。)



