その分析、Cursorにやらせてみませんか?
はじめに
最近、Slack に「前日のデータサマリ」を貼るのが地味に面倒になってきました。
クエリ実行 → CSV 出力 → グラフ化 → Slack 投稿。
誰でもできるけど、誰もやりたくない定例作業ですよね。
そこで今回は、Cursor × Snowflake × Slack を使い、自動で分析レポートをSlackへ投稿する仕組みを作ってみました。

cursorの自動レポートによるアウトプット
1. 全体構成
流れ
- SnowsqlとCursor CLIをセットアップし、CursorからSnowflakeを分析するための準備を行う。
- SQL クエリを作成し、Snowflake からデータを取得
- YAML でレポート定義を作成し、AIにMarkdownレポートを生成させる
- GitHub Actions で定期実行し、Slack Webhook に投稿

補足:SnowSQL について
SnowSQL は現在も利用可能な CLI ですが、Snowflake 公式では新しい Snowflake CLI の利用が推奨されています。
古いバージョンの SnowSQL はサポート対象外になる場合があり、今後の機能追加も Snowflake CLI が中心となるため、長期的な運用では移行を検討することをおすすめします。
なお、CursorによるSnowflakeの分析方法については、Snowflake社の菅野様のSnowflake mcpサーバーを用いた方法もあるため、是非ともご参考くださいませ。
2. ディレクトリ構成
slack-reports/
├── .github/ # 定期実行
│ └── slack_reports.yaml # Snowflakeクエリ実行クライアント
│
├── core/ # メインロジック
│ ├── analysis_runner.py # 分析実行のエントリーポイント(YAML→SQL→Slack)
│ ├── cursor_client.py # Cursor APIラッパー(AI補完・自動生成管理)
│ ├── slack_client.py # Slack Webhook送信モジュール
│ └── snowflake_client.py # Snowflakeクエリ実行クライアント
│
├── queries/ # クエリとレポート定義ファイル
│ ├── reports.sql # 定常分析に使うSQLクエリ
│ └── reports.yaml # SQL実行や出力設定のYAML定義
│
├── tmp/ # 一時ファイルや生成レポートの格納先
│ └── reports.md # Slack送信用に整形したMarkdownレポート
│
└── .env # webhook URL / Snowflakeのアカウントを環境変数化
3. Cursor CLIのセットアップとスクリプト解説
今回のレポート生成では、Cursor CLI(cursor-agent)をPythonから呼び出し、
YAML仕様とCSVデータを渡してAIにMarkdownレポートを出力させています。
Cursor CLIの準備
公式からインストールします:
brew install cursor-ai/tap/cursor-agent # macOS
# または
npm install -g cursor-agent # Windows / Linux
# ログインして認証
cursor-agent login
スクリプト側の実装(python)
import subprocess, tempfile
import shutil, textwrap
import os
class CursorClient:
"""Cursor CLIラッパー(プロンプト構築機能を統合)"""
SENTINEL = "__DATA_UNAVAILABLE__"
def __init__(self, bin_path=None):
self.bin_path = bin_path or shutil.which("cursor-agent")
if not self.bin_path:
raise RuntimeError("cursor-agent 実行ファイルが見つかりません。")
def build_prompt(self, yaml_text: str, csv_text: str, sql_name: str) -> str:
"""Cursorに渡すプロンプトを構築"""
return textwrap.dedent(f"""
You are an analytics agent running in Cursor CLI.
INPUT DATA:
Below is the CSV output of the SQL "{sql_name}".
If it is empty or unparseable, output exactly:
{self.SENTINEL}
CSV:
```csv
{csv_text.strip()}
```
YAML SPEC:
```yaml
{yaml_text.strip()}
```
OUTPUT POLICY:
- Output ONLY the final Markdown report.
- No reasoning, logs, or fabricated values.
""").strip()
def run(self, prompt: str) -> str:
with tempfile.NamedTemporaryFile(prefix="cursor_stderr_", delete=False) as errf:
err_path = errf.name
proc = subprocess.run(
[self.bin_path, "--print", "--output-format", "text"],
input=prompt.encode("utf-8"),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
if proc.returncode != 0:
raise RuntimeError(
f"Cursor実行エラー(exit={proc.returncode})\n"
f"{proc.stderr.decode('utf-8', 'ignore')[:300]}"
)
out = proc.stdout.decode("utf-8", "ignore").strip()
# 出力が空の場合はフェイルセーフのセンチネルを返す
return out if out else self.SENTINEL
🧩 CursorClient の役割
- build_prompt:CSV と YAML を受け取り、Cursor CLI が理解できる統合プロンプトを組み立てる
- run:生成したプロンプトを cursor-agent に渡して実行し、結果の Markdown 出力だけを返す
- フェイルセーフ:出力が空または異常終了時には DATA_UNAVAILABLE を返す
テキスト指示 → AI → Markdown という流れが抽象化されているため、
分析者は SQL と YAML を書くだけで済みます。
4. 分析フォーマット(reports.yaml)
YAML では、「何をどの形式で出すか」「どんなインサイトを出すか」を完全に分離して管理しています。これにより、SQLを変更せずに レイアウトだけ差し替える などの運用が可能になります。
title: '定期便 週次レポート(Slack自動投稿)'
slack_channel: '#project-定期便'
formatting:
number:
int: 'comma'
float: 'comma_1'
percent:
default: '1pct'
emoji:
up: '📈'
down: '📉'
flat: '→'
structure:
- id: header
type: text
template: |
💌 *定期便 週次レポート*({{ 対象月 }} 時点)
経過日数:{{ 経過日数 }} / {{ 月総日数 }}
- id: summary
type: text
template: |
*📦 全体サマリ*
CV:{{ 当月配CV | intcomma }}件(前月同日比 {{ 前月比進捗率(%) }}%)
ARPU:¥{{ 当月ARPU | floatcomma }}
構成比:{{ 当月構成比(%) }}%
着地予測(前月比):{{ 着地予測_配送数_前月比 | intcomma }}件 / ¥{{ 着地予測_ARPU_前月比 | floatcomma }}
着地予測(日割):{{ 着地予測_配送数_日割 | intcomma }}件 / ¥{{ 着地予測_ARPU_日割 | floatcomma }}
- id: segments
type: table
header:
[
'セグメント',
'当月配送数',
'構成比(%)',
'前月比進捗率(%)',
'ARPU',
'着地(日割)',
]
rows_from_sql: true
sql_mapping:
セグメント: セグメント
当月配送数: 当月配送数
当月構成比(%): 当月構成比(%)
前月比進捗率(%): 前月比進捗率(%)
当月ARPU: 当月ARPU
着地予測_配送数_日割: 着地予測_配送数_日割
- id: insights
type: bullet_points
title: '🧠 インサイト'
items:
- '全体配送数は前月同日比 {{ 前月比進捗率(%) }}%。ARPUは ¥{{ 当月ARPU | floatcomma }}。'
- '日割着地見込み:{{ 着地予測_配送数_日割 | intcomma }}件(¥{{ 着地予測_ARPU_日割 | floatcomma }})。'
- 'セグメント別では1点構成比低下、2点構成比上昇傾向📈。'
- id: footer
type: text
template: |
_出力元: Snowflake (box_subscription_reports.sql)_
_自動投稿: Slack Webhook via auto_report_bot_
ポイント:フォーマットは分析内容に応じて自由に作れる
この YAML 形式はあくまで一例で、必要な出力や分析要件に応じて、自由に拡張/削減して構いません。
- KPI が多いプロジェクト → テーブルを増やす
- Weekly レポート → グラフ画像を生成して添付
- アラート用途 → 「しきい値を下回ったら赤字で表示」
など、レポート構造を YAML で宣言的に管理することで、業務要件に合わせてレポートを高速に組み替えられるのが最大の利点です。
5. 実際の活用事例
シロクでは、各事業部の KPI の進捗をレポーティングし、伸び代やアラートを Slack から即座に検知できる仕組みとして運用しています。
日々の売上指標、顧客セグメントごとの変化など、決裁や意思決定に直結する指標を毎日自動で共有できるため、現場側の状況把握が早まり、必要なアクションを即時に取れるようになりました。

6. まとめ・展望
CursorとSnowflakeを組み合わせることで、SQL → 分析 → Slack通知 までの流れを自動化できました。AIが実装を代行し、人が設計を磨くそんなワークスタイルが自然に実現できたプロジェクトでした。
「N organic」、「FAS」等の化粧品ブランドを展開している株式会社シロクのエンジニアブログです。 ECサイトを中心とした自社サービスの開発・運用を行っています。 sirok.jp/norganic
Discussion