株式会社TOEでは、社内の定型業務を「AIエージェント基盤」と呼ぶ仕組みに載せて自動で回しています。その中で毎日動くのが、平日の朝に経営状況を1枚にまとめる「日次ブリーフィング」です。

この記事は、その仕組みを紹介するために書いたものではありません。実際に動いているサーバー上で crontab -l を叩き、スクリプトを開き、出力ファイルと実行ログを読んだうえで、確認できたことだけを書いています。うまく動いていない部分もそのまま書きます。

先に結論を1つ。この「AI秘書」の朝の仕事に、AIモデルの呼び出しは1回も入っていません。 その理由も後半で説明します。

まず、時刻の訂正から

社内では「AI秘書の朝ブリーフィングは7時47分」と言い習わされていました。記事を書くにあたって実物を確認したところ、これは事実ではありませんでした。

現在稼働中のcron(決まった時刻にコマンドを自動実行するUNIXの標準機能)の該当行はこうなっています。

0 8 * * 1-5 ... runner.py run daily   # 日次ブリーフィング

0 8 * * 1-5 は「月曜から金曜の8時00分」です。7時47分という設定はどこにもありませんでした。ジョブ登録簿にあたる jobs.yaml でも schedule: "0 8 * * 1-5" と定義されています。

こういう「社内で言われている仕様」と「実際の設定」のズレは、自動化を進めるほど溜まります。記事にする前に実物を見たから見つかった、というだけの話です。

朝の3本立て

平日の朝に動くジョブは、ブリーフィング1本ではありません。時刻順に3本あります。

時刻 ジョブ 内容
7:00 bank 銀行残高同期
7:30 sync_estimate 見積システム同期
8:00 daily 日次ブリーフィング生成

順番に意味があります。先に残高と見積データを取り込んで社内DBを最新にしてから、8時にそれを読んでブリーフィングを組み立てる、という流れです。ブリーフィング側は自分でデータを取りに行かず、前の2本が更新した結果を読むだけです。この「取り込み」と「まとめ」を別ジョブに分ける設計は真似しやすいと思います。1本の巨大なスクリプトにすると、どこで失敗したのか分からなくなります。

ブリーフィングの中身

生成スクリプトは job_daily.py、110行です。読み込むのは社内の経営データベース(といっても実体はYAMLというテキスト形式のファイル4本です)。

  • 顧客台帳.yaml
  • 承認キュー.yaml
  • 数字.yaml
  • パイプライン.yaml

これらから4つのブロックを組み立てて、Markdownファイル1枚として書き出します。

  1. 承認待ち — 社長の決裁を待っている案件。全件ではなく先頭8件を表示し、残りは「…他N件」に畳む
  2. 今日連絡すべき重要顧客 — 顧客台帳のうち、健全度が「危険」かつランクがS・Aのものだけ
  3. 7日以内の期日 — 顧客とパイプライン(商談)の両方から、次アクションの期日が7日以内のものを日付順で
  4. 数字アラート — 数字データにアラートが立っていれば表示、なければブロックごと出さない

出力先は社内DBフォルダと、Google Driveの共有フォルダの2箇所です。Driveにもコピーするのは、iPhoneから外出先で開けるようにするためです。Driveへのコピーだけが失敗しても、警告を出して処理は続行します。本体が書けているのに、コピー失敗で全体をエラー扱いにする意味がないからです。

実際に生成された2026年7月15日分は、こういう見た目でした。顧客名は実在の取引先なので伏せています。

# ☀️ 今日のブリーフィング 2026-07-15(Wed)

## ✋ 承認待ち 29件
- [appr-2026-0003] (S・危険)へご無沙汰メール送信
- [appr-2026-0004] (A・危険)へご無沙汰メール送信
(中略)
- …他21件

## 🚨 今日連絡すべき重要顧客 5件

## ⏰ 7日以内の期日 6件
- 2026-07-19 パイロット価格で提案アポ打診
(後略)

この日の数字は、承認待ち29件・危険なS/A顧客5件・7日以内の期日6件でした。

ちなみに記事執筆時点(7月19日)のデータベースの中身は、顧客23社(S:2 / A:3 / B:5 / C:13)、健全度は危険14社・注意9社、承認キュー37件、商談17件、数字アラート0件です。承認待ちは7月15日の29件から37件に増えています。つまり、朝の1枚は出ているけれど、そこに載った承認は消化しきれていない。仕組みが動いていることと、経営が回っていることは別物だという良い例です。

AIモデルは呼んでいません

ここが一番誤解されやすいところだと思うので、はっきり書きます。

「AI秘書」と呼んでいますが、この朝8時のジョブはClaudeやChatGPTなどの大規模言語モデルを一切呼び出していません。スクリプトを検索しても、モデルのAPIを叩いている箇所はありません。やっているのは、YAMLを読んで、条件で絞り込んで、並べ替えて、Markdownとして書き出すことだけです。

なぜそうしているか。毎朝同じ形式で出てくることに価値がある処理だからです。「危険かつS/Aランクの顧客を抽出する」は条件式で書けます。ここに言語モデルを挟むと、日によって抽出基準が揺れる、出力形式が変わる、失敗したときに原因が追えない、そしてトークン課金がかかる、と悪いことしか起きません。

結果としてこのジョブのランニングコストはゼロです。社内のMac上でOS標準のPythonが動いているだけで、外部サービスの契約もAPIの従量課金もありません。

判断が要るところと要らないところを分ける、というのが実務上たぶん一番大事な設計判断でした。「AIで自動化する」と言うと全部をモデルに投げたくなりますが、定型の集計をモデルにやらせるのは、遅くて高くて不安定な選択です。

3日間、止まっていました

ここからが正直に書くべき部分です。

ブリーフィングの出力ファイルの最終更新は 2026年7月15日 8時01分 でした。この記事を書いているのは7月19日です。16日(木)と17日(金)は平日なので、本来なら動いているはずでした。動いていません。

原因は判明していて、修正済みです。cronの設定が、Xcode(Appleの開発ツール)に同梱されていたPythonのパスを指していました。Xcodeを更新した際にそのPythonが消え、cronから起動されるジョブが全滅しました。ブリーフィングだけでなく、登録してある全ジョブが同時に止まっています。

7月18日に、OS標準で消えることのない /usr/bin/python3 を指すよう設定を書き換えて復旧させました。ジョブ登録簿のコメントにも、なぜこのパスを正とするのかを残してあります。

この事故から学べることは2つあります。

1つ目。cronで動く自動化は、止まっても誰も気づきません。 エラーは画面に出ません。ログファイルの末尾に静かに積まれるだけです。今回も「3日ぶんの朝ブリーフィングが来ていないな」と気づいたのは人間でした。自動化を増やすなら、「動いた通知」より「動くはずの時刻に動かなかった通知」の仕組みを先に作るべきでした。

2つ目。開発ツール同梱のランタイムに依存しない。 Xcodeやパッケージマネージャが入れたPython・Node.jsのパスは、更新やアンインストールで消えます。自動化スクリプトが指すのは、OS標準の場所か、自分で管理しているバージョンにすべきです。

監査ログが役に立たなかった話

もう1つ、うまく設計できていなかった部分があります。

各ジョブは実行するたびに 監査ログ.yaml へ「誰が・いつ・何をしたか」を書き込むようになっています。ところがこのログは直近200件しか保持しない仕様です。

そして同じ基盤には、5分おきに動くジョブ(LINE受信処理)と10分おきに動くジョブ(メール意思決定)が混じっています。1日で数百件です。結果、1日1回の日次ブリーフィングの記録は、高頻度ジョブのログにあっという間に押し流されて消えます。実際、今回この記事のために監査ログを検索しましたが、ブリーフィングの実行記録は1件も残っていませんでした。

「ログは取ってあるから大丈夫」と思っていたのに、いざ調べたら肝心の記録がない。件数で足切りするログは、実行頻度がバラバラなジョブが混在すると機能しません。日付で切るか、ジョブ種別ごとにファイルを分けるべきでした。

実際の実行時間

7月18日に、全ジョブを共通の実行管理スクリプト経由で動かす形に載せ替えました。これによって開始・終了・所要時間・成否が1行ずつJSON形式で記録されるようになっています。

記事執筆時点で595行、期間は7月18日12時20分から7月19日9時00分ぶんです。集計するとこうなります。

ジョブ 実行回数 所要時間(中央値) 最大 失敗
LINE受信処理 195回 0.9秒 13.4秒 0
メール意思決定 97回 24.2秒 51.4秒 0
セルフテスト 5回 0.5秒 0.5秒 0
税務カレンダー更新 1回 0.2秒 0.2秒 0

この表に日次ブリーフィングは入っていません。 載せ替えたのが7月18日(土)で、7月19日は日曜。平日にしか動かないジョブなので、新しい記録の仕組みではまだ一度も動いていないためです。次の平日の朝8時が初回になります。

「毎朝の所要時間は平均◯秒です」と書ければ記事としては格好がついたのですが、まだそのデータはありません。参考までに、同種の処理(税務カレンダー更新)は0.2秒で終わっています。

27本のジョブと、その偏り

朝のブリーフィングは、登録されている27本のジョブのうちの1本です。社内の部署に見立てて分類してあります。

担当 ジョブ数
経理 13
秘書 6
営業 3
社長 2
マーケ 1
補助金 1
基盤 1

経理が13本と突出しています。銀行残高同期、資金繰り予測、月次PL集計、支払管理、請求書発行ドラフト、入金確認ドラフト、収益性分析、税務カレンダー更新など。ここに偏るのは理由があって、経理業務は「入力が決まっていて、出力の形式も決まっていて、毎月同じ日に必ず発生する」 からです。自動化の投資対効果が一番はっきり出る領域でした。

逆にマーケが1本しかないのは、自動化をサボっているというより、その領域の仕事が定型化しきれていないからです。中小企業で自動化を始めるなら、まず経理と、決裁・承認まわりから手をつけるのが素直だと思います。

決裁はスマホの返信で

秘書系のジョブでもう1本紹介したいのが、10分おきに動く「メール意思決定」です。

朝のブリーフィングは「承認待ちが29件あります」と教えてくれますが、それだけでは滞留は解消しません。そこで、社長のメールアドレス宛に本人が送ったメールをIMAP(メールを受信する標準プロトコル)で監視して、本文の書式でコマンドとして処理する仕組みを付けました。

承認 appr-2026-0003 ひとことメモ
却下 appr-2026-0003 理由
承認待ち

iPhoneからメールを1通返すだけで決裁が通ります。ここで大事なのは歯止めで、このジョブが顧客へ直接メールを送ることはありません。 承認された結果は既存の承認フローに乗るだけです。自動化の範囲を「社内の状態を変えるところまで」に留めて、対外送信は別の関門を通す。ここを混ぜると事故ります。

実行ログでは、このジョブは1回あたり24通のメールを走査して、実行したコマンドは0通、という記録が並んでいました。つまり、仕組みは正常に動いているけれど、使われていません。承認キューが37件に増えているのと符合します。作った仕組みが使われないのは、機能不足ではなく習慣の問題なので、ここは技術ではどうにもならない部分です。

できていないこと

最後に、現時点でできていないことを列挙します。

Gmailの受信トレイとカレンダー予定が入っていません。 朝のブリーフィングに「今日の予定」「未読の重要メール」が載っていれば当然もっと便利ですが、載っていません。スクリプトの冒頭のコメントにも「MCP経由が必要なため次段で追加予定」と書いてあり、その次段はまだ来ていません。現状のブリーフィングは、あくまで社内の経営DBの中身を映しているだけです。

失敗の通知がありません。 前述の3日間停止がまさにそれです。復旧はしましたが、「動くはずの時刻に動かなかったこと」を検知する仕組みは、この記事を書いている時点でまだ入っていません。

ブリーフィングの中身の善し悪しを評価する手段がありません。 毎朝出ている、という事実は確認できますが、それが読まれて行動に繋がったかは追えていません。承認待ちが29件から37件に増えていることを見ると、少なくとも一部は繋がっていません。

うちでも同じことができるか

必要だったものを並べると、こうなります。

  • 常時起動しているPC 1台(社内のMacです。専用サーバーではありません)
  • OS標準のPython
  • 経営データを置くテキストファイル数本(データベース製品は使っていません)
  • cronの設定

追加のライセンス費用も、APIの従量課金も、クラウドの利用料もかかっていません。朝のブリーフィングに限れば、ランニングコストはゼロです。

その代わり、必要だったのは「毎朝見たい情報は何か」を言葉で決め切ることでした。「危険かつS/Aランクの顧客」「期日が7日以内」「先頭8件だけ表示して残りは畳む」。この条件をはっきりさせる作業が実質の設計で、コードはその後に付いてきます。逆に言えば、この条件が決められない業務は、AIを使おうが使うまいが自動化できません。

そして今回いちばんはっきりしたのは、自動化は作って終わりではなく、止まるということです。3日間止まっていても誰も気づかず、監査ログを見に行ったら肝心の記録が残っていませんでした。これから同じことを始める方は、ジョブを1本増やすたびに「これが止まったらどうやって気づくか」を一緒に決めておくことをおすすめします。私たちはそこを後回しにして、実際に3日ぶん取りこぼしました。