engineering-retro について
engineering-retro は、期間とパス範囲を指定して Git 履歴を分析する読み取り専用スキルです。指標、作業パターン、変更頻度の高いファイル、コントリビューターの概要、任意の GitHub PR 分析を通じて、開発チームの活動の振り返りを支援します。
主な機能
- 01指定期間内のコミットを分析
- 02リポジトリのサブディレクトリに範囲を限定
- 03変更とコントリビューターの指標を算出
- 04時間分布と作業セッションを集計
- 05コミットを分類しファイルのホットスポットを特定
- 06任意で GitHub のプルリクエストを分析
活用シーン
- 01過去1週間の開発活動を振り返る
- 02特定サービスのディレクトリ内の活動を分析
- 03頻繁に変更されたファイルを特定
- 04コントリビューターとコミット分類を要約
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mathews-tom/ armory --skill engineering-retroインストール後、Claude Code で/engineering-retroを入力して読み込まれたか確認します。
同梱ファイルevals/cases.yaml
詳細
エンジニアリングの振り返り
設定可能な期間について、Git に基づく構造化されたエンジニアリングの振り返りを生成します。これは読み取り専用の分析です。任意の JSON スナップショットを除き、ファイルは変更されません。
引数
/engineering-retro [TIME_WINDOW] [PATH_SCOPE]
- TIME_WINDOW(任意):
24h、7d(デフォルト)、14d、30d - PATH_SCOPE(任意):分析対象をサブディレクトリに限定します(モノレポに対応)。例:
services/api
例:
/engineering-retro— 直近 7 日間、リポジトリ全体/engineering-retro 30d— 直近 30 日間、リポジトリ全体/engineering-retro 14d services/api— 直近 14 日間、services/api/に限定
実行手順
ステップ 1:環境の検出
分析を始める前に、実行環境を検出します。
# Default branch
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@')
if [ -z "$DEFAULT_BRANCH" ]; then
DEFAULT_BRANCH=$(git remote show origin 2>/dev/null | grep 'HEAD branch' | awk '{print $NF}')
fi
# System timezone
TZ_NAME=$(date +%Z)
# Time window — convert argument to --since format
# 24h → "24 hours ago", 7d → "7 days ago", 14d → "14 days ago", 30d → "30 days ago"
DEFAULT_BRANCH の検出に失敗した場合は、推測せずにエラーで中止します。
ステップ 2:Git の生データを収集
検出したデフォルトブランチで、期間内のコミットを収集します。
# All commits in window (with optional path scope)
git log origin/$DEFAULT_BRANCH --since="$SINCE" --format="%H|%aI|%aN|%s" -- $PATH_SCOPE
# Diff stats for the window
git log origin/$DEFAULT_BRANCH --since="$SINCE" --numstat --format="%H" -- $PATH_SCOPE
記録する項目:コミットハッシュ、作成者の日付(ISO 形式)、作成者名、件名、変更されたファイル、追加行数、削除行数。
ステップ 3:集計指標を算出
生データから、次の項目を算出します。
- コミット総数(期間内)
- ユニークな貢献者数(作成者名の重複を除いた数)
- 変更ファイル数(全コミットにわたる一意のファイルパス数)
- 追加行数(追加行数の合計)
- 削除行数(削除行数の合計)
- 差分の純増減(追加 - 削除)
- 平均コミットサイズ(変更行数の合計 / コミット総数)
ステップ 4:時間分布
コミットのタイムスタンプをシステムのタイムゾーン $TZ_NAME に変換して分析します。
- 曜日別コミット数:月曜〜日曜のヒストグラム
- 時間帯別コミット数:0〜23 時のヒストグラム
- ピーク曜日:コミット数が最も多い曜日
- ピーク時間帯:活動が最も多い時間帯
コンパクトなテキスト形式のヒストグラムで表示します。
ステップ 5:セッション分析
2 時間を超える間隔をセッションの区切りとして、コミットを作業セッションにまとめます。
- コミットを作成者とタイムスタンプで並べ替えます。
- 作成者ごとに時系列順で処理し、連続するコミット間の間隔が 2 時間を超えた場合は新しいセッションを開始します。
- セッションごとに、所要時間(最初のコミットから最後のコミットまで)とコミット数を算出します。
- 集計項目:セッション総数、平均セッション時間、最長セッション、セッションあたりの平均コミット数。
コミットが 1 件だけのセッションは、所要時間をデフォルトの 0(ある時点のみ)とします。
ステップ 6:コミットタイプの分類
件名の Conventional Commits プレフィックスを使って、各コミットを分類します。
| プレフィックスのパターン | カテゴリ |
|---|---|
feat:, feat( | feature |
fix:, fix(, bugfix | fix |
refactor:, refactor( | refactor |
chore:, chore(, build:, ci: | chore |
docs:, doc: | docs |
test:, tests: | test |
perf: | perf |
style: | style |
Conventional Commits のプレフィックスがないコミットには、差分のヒューリスティクスを適用します。
- 新規追加ファイルが主な変更の場合 → feature
- 削除が主な変更の場合 → refactor
- テストファイルのみの場合 → test
- 設定ファイル/CI ファイルのみの場合 → chore
- ドキュメントファイルのみの場合 → docs
- 上記以外の場合 → uncategorized
カテゴリごとに件数と割合を報告します。
ステップ 7:ホットスポット分析
コミットで変更された回数が多いファイルの上位 10 件を特定します。
git log origin/$DEFAULT_BRANCH --since="$SINCE" --name-only --format="" -- $PATH_SCOPE | sort | uniq -c | sort -rn | head -20
全コミットの 50% を超える割合で変更されたファイルに、ホットスポットのフラグを付けます。ホットスポットは次のことを示します。
- 開発が活発な領域(機能開発中であれば想定どおり)
- 密結合の問題の可能性(無関係なコミットが同じファイルに繰り返し変更を加えている場合)
- 分割が必要な可能性(ファイルが大きい場合)
Step 8: PR 分析
リモートが GitHub の場合(git remote get-url origin で github.com を確認します):
# Merged PRs in window
gh pr list --state merged --base $DEFAULT_BRANCH --search "merged:>=$SINCE_DATE" --json number,title,author,mergedAt,additions,deletions,changedFiles,reviews
以下を算出します。
- マージ済み PR の合計数
- サイズ分布:S(50 行未満)、M(50~200 行)、L(200~500 行)、XL(500 行超)
- レビュー所要時間:PR 作成から最初のレビューまでの時間(中央値、p90)
- マージ所要時間:PR 作成からマージまでの時間(中央値、p90)
GitHub のリモートではない場合、または gh が利用できない場合は、このステップをスキップし、出力にその旨を記載します。
Step 9: 集中度スコア
集中したコミット(変更対象ファイルが 3 個以下)の総コミット数に対する割合を算出します。
focus_score = commits_touching_le_3_files / total_commits
解釈:
- >0.8:高い集中度。小規模で段階的な変更が中心
- 0.5-0.8:中程度の集中度。対象を絞った変更と広範な変更が混在
- <0.5:広範な変更が中心。大規模なリファクタリング、またはコミット規律の低さを示している可能性があります
Step 10: 作者別の内訳
各コントリビューターについて、以下を報告します。
- コミット数
- 追加/削除した行数
- 最も変更されたファイル上位 3 件
- 主なコミットの種類(Step 6 より)
- セッション数と平均セッション時間(Step 5 より)
これをコントリビューターのハイライトとして提示します。これは成果を称えるものであり、順位付けやパフォーマンス指標ではありません。作者名のアルファベット順に並べます。
Step 11: 週ごとの比較
.engineering-retros/ に以前のスナップショットがあるか確認します。
- 最新の
*.jsonファイルを探します - ファイルがあり、隣接する前の期間を対象としている場合は、差分を算出します。
- コミット数の差分(%)
- 変更行数の差分(%)
- コントリビューター数の差分
- 集中度スコアの差分
- カテゴリー分布の変化
以前のスナップショットがない場合は、今回が初回の振り返りである旨を記載し、比較をスキップします。
Step 12: スナップショットを保存
今後の比較に使う JSON スナップショットを保存します。
.engineering-retros/<YYYY-MM-DD>.json
スキーマ:
{
"date": "YYYY-MM-DD",
"window": "7d",
"path_scope": null,
"branch": "main",
"timezone": "PST",
"metrics": {
"commits": 0,
"contributors": 0,
"files_changed": 0,
"lines_added": 0,
"lines_removed": 0,
"net_delta": 0,
"focus_score": 0.0
},
"categories": {},
"hotspots": [],
"sessions": {
"total": 0,
"avg_length_minutes": 0
},
"authors": {},
"pr_stats": null
}
.engineering-retros/ ディレクトリが存在しない場合は作成します。.engineering-retros/ が .gitignore に含まれていることを確認し、なければ追加します。許可されているファイル変更はこれのみです。
Step 13: 概要を作成
以下の構成で最終出力を作成します。
エンジニアリングの振り返り — [DATE_RANGE]([TIMEZONE]) ブランチ: [DEFAULT_BRANCH] | 対象範囲: [PATH_SCOPE または "リポジトリー全体"]
指標
- コミット数:N | コントリビューター数:N | 変更ファイル数:N
- 行数:+N / -N(差し引き:+/-N)
- 平均コミットサイズ:N 行 | 集中度スコア:N.NN
時間パターン
- ピーク日:[DAY] | ピーク時間帯:[RANGE]
- [簡潔なヒストグラム]
- セッション数:合計 N | 平均時間:Nm | 最長:Nm
作業の内訳
- [カテゴリー]:N コミット(NN%)
- ...
変更の集中箇所
path/to/file— N コミット [HOTSPOT(50% 超の場合)]- ...
コントリビューターのハイライト
- [作者]:N コミット、+N/-N 行、主な変更対象は [上位ファイル]、主なカテゴリーは [カテゴリー]
- ...
PR の概要(利用可能な場合)
- マージ済み:N | サイズ分布:S/M/L/XL | レビュー所要時間の中央値:Xh
週ごとの比較(利用可能な場合)
- コミット数:+/-N% | 行数:+/-N% | 集中度:+/-N.NN
所見
- [パターン、成果、注目すべき領域を示す箇条書き 2~4 件]
- データのみに基づきます。意図を推測したり、個人の品質を評価したりしないでください。
制約
- 読み取り専用:コードの変更、ブランチの変更、状態を変更する Git 操作は禁止です
- タイムゾーンをハードコードしない:常に
date +%Zで検出します - ブランチをハードコードしない:常に
git symbolic-refまたはgit remote showで動的に検出します - 個人のパフォーマンスを評価しない:作者別の内訳は評価ではなく、成果を称えるためのものです
- パス範囲を遵守する:範囲が指定されている場合、すべての Git コマンドに
-- $PATH_SCOPEを含める必要があります - スナップショットの保存先:
.engineering-retros/のみとし、.context/retros/は使用しません