8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

こんにちは!株式会社うるるの八巻です。

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 を自分のテーブルに変えればそのまま動きます。

最小構成での始め方は、こんな順序がおすすめです。

  1. /insights/export-usage 相当のエクスポートコマンドを1枚書く(自然言語プロンプトでOK)
  2. メンバー数人分のJSONを集めて /team-analytics 相当の分析コマンドに食わせる
  3. 出てきた「根拠つき改善ルール」をチームで読み合わせ、CLAUDE.md に反映する
  4. 余力があれば、Hookで自動計測(②)を足す

ここまでお読みいただきありがとうございました。
組織を変えるのは、たった一人の熱量から始まります。
同じように組織を変えようと、チームでのAIツール活用に取り組んでいる方の参考になれば幸いです!

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?