こんにちは!株式会社うるるの八巻です。
Claude Code(に限らずAIコーディングツール全般)をチームに導入すると、ほぼ確実にぶつかる壁があります。
「使う人」と「使わない人」の差が、想像以上に大きい。
毎日ヘビーに使い倒して大量のコミットを生んでいるメンバーがいる一方で、インストールはしたものの月に一度も起動していないメンバーがいる。同じチームの中で、この二極化が静かに進みます。
問題は単に「もったいない」だけではありません。
- ノウハウが個人にしか溜まらない — ヘビーユーザーの効果的な使い方が誰にも共有されない
- チーム内に「共通の話題」がない — 「あのSkill便利だよ」という会話すら生まれない
個人の努力に頼っていてもこの格差は埋まりません。そこで私たちのチームでは、格差を「仕組み」で埋めることにしました。本記事では、実際に運用している2つの取り組みを、他チームがそのまま真似できる形で(実際のコマンド定義・Hookスクリプト込みで)紹介します。
社内固有の名称・テーブル名・数値はマスキング/プレースホルダ化しています。コードはそのままの構造で掲載しているので、置換すれば動きます。
解決アプローチ: 定性 × 定量の両輪
やったことは大きく2つ。性質の違う2つのループを回しています。
| ① 月次振り返り運用(人が回すループ) | ② 利用ログのBigQuery蓄積(機械が貯めるループ) |
|---|---|
| 月末にメンバーが手動でエクスポート | セッション終了時に自動送信 |
| チームでレポートをレビュー | 常時、全ツール利用ログを蓄積 |
| 課題と横展開ネタを言語化 | 将来の深掘り分析の土台 |
①は 「個人のデータ」を「チームの会話」に変えるための定性的な仕組み。
②は 手を動かさなくてもデータが貯まり続ける定量的な計測レイヤー。
それぞれ単体でも効果がありますが、組み合わせると「月次の振り返り(定性)× 日次の計測データ(定量)」という強い両輪になります。
取り組み① 月次振り返り運用
全体フロー
[月末]
│
▼
各メンバーが /export-usage を実行
│ (自分のClaude Code利用データをJSON化)
▼
共有ディレクトリ「{月}/{名前}.json」に集約
│
▼
代表者が /team-analytics を実行
│ (メンバー全員分のJSONを横断分析)
▼
・Slack共有用 Markdown
・詳細 HTML レポート
│
▼
チームで読み合わせ → 横展開・改善ルール化
ポイントは、メンバーがやることは スラッシュコマンドを1つ叩くだけ という点です。心理的ハードルを徹底的に下げています。
/export-usage — 個人の利用データを月次でJSON化
Claude Code には /insights というコマンドがあり、セッションの傾向(達成度・フリクション=つまずきパターンなど)を分析した facets データを生成します。/export-usage は、この facets と基本統計(session_meta)を 当月分に絞って JSONに書き出すスラッシュコマンドです。
実際のコマンド定義(.claude/commands/export-usage.md)はこうなっています。これは「Claudeへの指示書」であって、スクリプトではなく自然言語のプロンプトである点がミソです。
# /export-usage - Claude Code利用状況エクスポート
## 概要
Claude Code利用状況データを実行月の期間に絞ってエクスポートする。
**実行時に `/insights` を自動実行**し、最新のfacetsデータを生成してからエクスポートする。
### なぜ `/insights` が必須か?
- **facets**: フリクション分析、達成度、成功要因など高度な分析に必要
- **session_meta**: 基本的な利用統計のみ(セッション数、時間、ツール使用回数など)
チーム改善提案を得るには facets データが不可欠なため、常に最新の `/insights` を実行してからエクスポートする。
## 実行内容
### 🚨 最初に必ず実行すること
**このスキルを開始する前に、ユーザーに以下のメッセージを表示してください:**
```
⚠️ このスキルを実行する前に `/insights` を実行してください
【理由】最新のセッションデータから facets を生成するため。
/insights を実行しましたか? (yes/no)
```
**ユーザーが "yes" と回答した場合のみ、以下の Step 1 以降を実行してください。**
### Step 1: メンバー名の取得
- `git config user.name` から自動取得
- 取得できない場合は環境変数 `USER` を使用
### Step 2: 対象月の設定
- 実行月(現在の年月)を自動設定(例: `2026-04`)
### Step 3: facets データの確認
- `~/.claude/usage-data/facets/` 内のファイル数を確認(0件なら警告)
### Step 4: データ収集
- **facets**: `~/.claude/usage-data/facets/*.json` から全セッション
- **session_meta**: `~/.claude/usage-data/session-meta/*.json` から対象月のみ
### Step 5: プロジェクト名の抽出
- session_meta の `project_path` からプロジェクト名を抽出
- 例: `/Users/alice/workspace/your_repo` → `your_repo`
### Step 6: JSONエクスポート
- 出力先: `~/claude_insights_export_{年月}/{メンバー名}.json`
出力されるJSONのフォーマットはこうです。
{
"member_name": "alice",
"target_month": "2026-04",
"facets": [
// /insights 対象期間分のすべてのセッション
],
"session_meta": [
// 対象月のセッションメタデータ(project_pathをproject_nameに変換済み)
]
}
メンバー名を git config user.name から自動取得しているので、各自はコマンドを叩くだけ。出力されたJSONを共有ディレクトリの {月}/{名前}.json に置けば集約完了です。
/team-analytics — 全員分を横断分析してレポート化
集約された全員分のJSONを読み込み、チーム全体の傾向を分析するコマンドです。これも中身は自然言語のプロンプトで、「何を集計し、どんなレポートを書くか」を細かく指示しています。
実際のコマンド定義(.claude/commands/team-analysis.md 相当)の要点を抜粋します。
# Claude Code チーム利用状況分析
指定ディレクトリにある `{メンバー名}.json` を読み込み、チーム全体の分析レポートを
日本語で作成し、HTML と Slack 用 Markdown の2ファイルを出力してください。
### 2. データの読み込みと集計
各メンバーについて:
- セッション数 / 総利用時間 / 総トークン数
- git_commits / git_pushes / lines_added / lines_removed
- Skill ツール呼出数 / Task(サブエージェント) 利用セッション数
- セッション長分布(≤5分 / 5〜15分 / 15〜30分 / 30〜60分 / 60分〜)
- goal_categories 上位10 / ツール使用数 Top10
- outcome 分布 / user_satisfaction 集計 / friction_counts 集計
- friction_detail テキスト全件
- リポジトリ別セッション数 / リポジトリ別フリクション
### 3. 分析レポートの作成(日本語) — 以下6セクション
1. 全体利用量(メンバー別・チーム合計の表)
2. 利用パターン分析(セッション長分布・ゴール・ツールTop10)
3. 達成度・有用性(outcome / helpfulness / 満足度)
4. フリクション分析(最重要)
- チーム共通フリクションと特定メンバー特有のフリクションを分けて整理
- friction_detail から代表的な失敗事例を抽出
5. メンバー間の比較
6. リポジトリ別 改善提案(最も具体的に記述するセクション)
- 汎用論ではなく、各リポジトリの実際のフリクション事例に基づいた
具体的な CLAUDE.md 追記ルールを提案する
- 各ルールに「根拠となるフリクション事例」「対象メンバー」「期待削減件数」を付ける
- 「横展開推奨パターン」「次月の優先アクション(3件以内)」も含める
### 4. ファイル出力
① チーム分析レポート_Slack用.md(Slack mrkdwn 形式、テーブルは箇条書きに変換)
② チーム分析レポート_詳細.html(インラインCSS・カード形式・フリクションのバーチャート)
このプロンプト設計の肝は、セクション6「リポジトリ別 改善提案」を最も具体的に書かせているところです。「もっと丁寧にレビューしましょう」のような抽象論ではなく、CLAUDE.md にそのままコピペできる粒度のルールを、実際のつまずき事例を根拠つきで出させています。
実際に出てくる成果
このレポートからは、例えばこういう改善ルールが出てきます(社内事例を一般化したもの)。
- 「PRレビュー時は対象ブランチに checkout してから始める(差分を取り違えた事例があったため)」
- 「自動修正系コマンドの全体一括実行は禁止(大量ファイルが変更されてリバートになった事例があったため)」
- 「あるメンバーが多用しているSkillをチーム全員へ横展開する」
抽象論ではなく、根拠つきの改善ルールが出てくる。 これが「個人のデータ」が「チームの会話」に変わる瞬間です。
どれだけ変わったか(相対値)
運用を始めて1ヶ月で、同じチームの数字はこう動きました。
| 項目 | 変化 |
|---|---|
| 総利用時間 | × 3.1 |
| 総トークン | × 3.2 |
| コミット | × 2.1 |
| Push | × 3.6 |
| コード追加行 | × 1.9 |
| 完全達成率 | +7pt |
| 満足度ポジティブ | +5pt |
注目したいのは、「使う量」(時間・トークン)だけでなく「成果の質」(達成率・満足度)も同時に上がっている点です。月次の振り返り × チーム共有が効いている手応えがありました。
取り組み② 利用ログのBigQuery自動蓄積プラグイン
①は人が月末に手を動かす運用でした。②はその裏で、何もしなくてもデータが貯まり続ける自動計測レイヤーです。Claude Code のプラグイン(Hook)として実装し、利用ログを BigQuery に蓄積します。
opt-in 設計(プライバシー配慮)
まず大事な設計判断から。このプラグインは、
プロジェクト直下に .claude/analytics.enabled というマーカーファイルが無いと一切動きません。
計測したいプロジェクトだけ明示的に有効化する opt-in 方式です。個人リポジトリ等で意図せずログが送られることを防ぎます。
4つのHookで「誰が・いつ・どのツールを使ったか」を拾う
| Hook | タイミング | やること |
|---|---|---|
SessionStart |
起動時 | 環境チェック(CLI / 証明書) |
UserPromptSubmit |
プロンプト送信時 | 入力時刻を記録 |
PostToolUse |
ツール実行後 | ツール名・入力をバッファに追記 |
Stop |
セッション終了時 | BigQuery へ一括送信 |
セッション中はローカルの一時ファイル(NDJSON)にバッファリングし、セッション終了時にまとめて送信します。送信に失敗してもローカルにバックアップを残すので、後からリトライできます。
実装は Ruby の標準ライブラリ + bq CLI のみ。外部gem依存ゼロで、これ1ファイルで完結します。実際のHookスクリプト(hooks/analytics.rb)はこちらです(社内テーブル名はプレースホルダ化)。
#!/usr/bin/env ruby
# frozen_string_literal: true
# Claude Code Analytics Hook
# SessionStart / UserPromptSubmit / PostToolUse / Stop の4イベントを処理し、
# ツール利用状況を BigQuery に送信する。
# 依存: Ruby stdlib (json, open3, fileutils) + bq CLI のみ
# Opt-in ガード: プロジェクト直下に .claude/analytics.enabled が無ければ即終了
project_dir = ENV['CLAUDE_PROJECT_DIR'] || ENV['PWD']
exit(0) if project_dir.to_s.empty?
exit(0) unless File.exist?(File.join(project_dir, '.claude', 'analytics.enabled'))
require 'json'
require 'time'
require 'open3'
require 'fileutils'
BQ_TABLE = 'your-project:claude_usage.tool_usage_logs' # ← 自分のテーブルに置換
ERROR_LOG = File.expand_path('~/.claude/analytics_errors.log')
begin
input = JSON.parse($stdin.read)
rescue JSON::ParserError
exit(0)
end
session_id = input['session_id'] || 'unknown'
event = input['hook_event_name']
buffer_file = "/tmp/claude_analytics_#{session_id}.jsonl"
user_ts_file = "/tmp/claude_analytics_user_ts_#{session_id}.txt"
def log_error(msg)
File.open(ERROR_LOG, 'a') { |f| f.puts("[#{Time.now.iso8601}] #{msg}") }
rescue StandardError
nil
end
begin
case event
when 'SessionStart'
issues = []
unless system('command -v bq > /dev/null 2>&1')
issues << 'bq CLI が見つかりません (gcloud SDK 未インストール?)'
end
ca_stdout, _ca_stderr, _ca_status = Open3.capture3('gcloud', 'config', 'get', 'core/custom_ca_certs_file')
ca_path = ca_stdout.strip
if !ca_path.empty? && !File.exist?(ca_path)
issues << "CA バンドルが消えています: #{ca_path} (再起動で /tmp が消えた等)"
end
unless issues.empty?
msg = "⚠️ Claude Code Analytics: セットアップが壊れています\n" +
issues.map { |i| " • #{i}" }.join("\n") +
"\n→ `/setup-analytics` を再実行して修復してください。"
puts JSON.generate('continue' => true, 'systemMessage' => msg)
end
when 'UserPromptSubmit'
now = Time.now.utc.iso8601
File.write(user_ts_file, now)
row = {
session_id: session_id,
timestamp: now,
user_input_timestamp: now,
project_path: ENV.fetch('CLAUDE_PROJECT_DIR', nil) || ENV.fetch('PWD', nil),
tool_name: 'UserPromptSubmit',
tool_input: { prompt: input['prompt'] }.to_json,
user_name: ENV.fetch('USER', nil)
}
File.open(buffer_file, 'a') { |f| f.puts(row.to_json) }
when 'PostToolUse'
user_input_ts = begin
File.read(user_ts_file).strip
rescue StandardError
nil
end
row = {
session_id: session_id,
timestamp: Time.now.utc.iso8601,
user_input_timestamp: user_input_ts,
project_path: ENV.fetch('CLAUDE_PROJECT_DIR', nil) || ENV.fetch('PWD', nil),
tool_name: input['tool_name'],
tool_input: (input['tool_input'] || {}).to_json,
user_name: ENV.fetch('USER', nil)
}
File.open(buffer_file, 'a') { |f| f.puts(row.to_json) }
when 'Stop'
if File.exist?(buffer_file)
ndjson = File.read(buffer_file)
_, stderr, status = Open3.capture3('bq', 'insert', BQ_TABLE, stdin_data: ndjson)
unless status.success?
log_error("bq insert failed: #{stderr.strip}")
backup = File.expand_path("~/.claude/analytics_failed_#{session_id}.jsonl")
FileUtils.cp(buffer_file, backup)
end
begin
File.delete(buffer_file)
rescue StandardError
nil
end
end
begin
File.delete(user_ts_file)
rescue StandardError
nil
end
end
rescue StandardError => e
log_error("#{event}: #{e.message}")
end
exit(0)
このスクリプトを4つのイベントに登録するのが hooks/hooks.json です。
{
"hooks": {
"SessionStart": [
{ "hooks": [ { "type": "command", "command": "ruby \"${CLAUDE_PLUGIN_ROOT}/hooks/analytics.rb\"" } ] }
],
"UserPromptSubmit": [
{ "hooks": [ { "type": "command", "command": "ruby \"${CLAUDE_PLUGIN_ROOT}/hooks/analytics.rb\"" } ] }
],
"PostToolUse": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "ruby \"${CLAUDE_PLUGIN_ROOT}/hooks/analytics.rb\"" } ] }
],
"Stop": [
{ "hooks": [ { "type": "command", "command": "ruby \"${CLAUDE_PLUGIN_ROOT}/hooks/analytics.rb\"" } ] }
]
}
}
送信スキーマ
BigQuery に送られる1行は、こういう形です。
{
"session_id": "abc-123...",
"timestamp": "2026-06-02T09:50:00+09:00",
"user_input_timestamp": "2026-06-02T09:49:55+09:00",
"project_path": "/Users/alice/workspace/your_repo",
"tool_name": "Read | Edit | Bash | ...",
"tool_input": "{ \"file_path\": \"...\" }",
"user_name": "alice"
}
これにより、「誰が・いつ・どのプロジェクトで・何のツールを使ったか」を時系列で追えるようになります。user_input_timestamp を持っているので、「プロンプト送信からツール実行までの時間」のような分析も後から可能です。
セットアップ(/setup-analytics)
プラグインを入れたら、各メンバーは初回だけセットアップコマンドを実行します。中身は以下の3ステップ。bq CLI とGCP認証さえ通れば動きます。
### Step 0: opt-in マーカーの作成
計測したいプロジェクトで以下を実行し、コミットしてチームと共有する:
mkdir -p .claude
touch .claude/analytics.enabled
git add .claude/analytics.enabled
git commit -m "chore: enable Claude Code analytics"
### Step 1: gcloud SDK の確認とインストール
which bq # 無ければ brew install --cask google-cloud-sdk
### Step 2: GCP 認証の確認
bq show your-project:claude_usage.tool_usage_logs
# 失敗したら gcloud auth login → gcloud config set project your-project
これさえ通れば、以降はメンバーが意識することなく、セッション終了時に自動でデータが蓄積されていきます。
今後の展望
A. 蓄積データの活用(これから)
- 利用パターン分析 → ハイパフォーマーの使い方の可視化
- 効果的なスラッシュコマンド / Skill の特定 → 横展開
- リポジトリ別の「つまずきポイント」検出
B. 新メンバーのオンボーディングへの応用
- 実際の使い方をログから観察して個別フィードバック
- 「使い方の型」を早期に渡せる体制に
C. 「月次の定性レビュー × 日次の定量データ」の組み合わせを進化させる
まとめ
- 利用格差は仕組みで埋める。個人の努力に依存させない。
- 定性(月次運用)× 定量(自動計測)の両輪で底上げする。
いきなり全部やる必要はありません。まずは /export-usage 風の月次エクスポート+チームで読み合わせ、だけでも十分効果があります。スラッシュコマンドのプロンプトを1枚書くところから始められます。もう一歩進めたい人は、本記事のHookスクリプトをベースに自動計測レイヤーを足す。BQ_TABLE を自分のテーブルに変えればそのまま動きます。
最小構成での始め方は、こんな順序がおすすめです。
-
/insights→/export-usage相当のエクスポートコマンドを1枚書く(自然言語プロンプトでOK) - メンバー数人分のJSONを集めて
/team-analytics相当の分析コマンドに食わせる - 出てきた「根拠つき改善ルール」をチームで読み合わせ、
CLAUDE.mdに反映する - 余力があれば、Hookで自動計測(②)を足す
ここまでお読みいただきありがとうございました。
組織を変えるのは、たった一人の熱量から始まります。
同じように組織を変えようと、チームでのAIツール活用に取り組んでいる方の参考になれば幸いです!