cto-heartbeat について
CTOやチームリード向けのリポジトリ運用スキルです。進行中の作業のブロック解除を優先し、未ラベルのIssueを分類して、実行ごとに1件のタスクを割り当てます。状況レポートを作成し、Questに投稿します。
主な機能
- 01オープンPRと進行中Issueの確認
- 02停滞・古い作業の検出
- 03未分類Issueとエピックへのラベル付け
- 04優先度に基づくタスク1件の割り当て
- 05状況レポートの作成と投稿
活用シーン
- 01新規タスク追加前の進行状況確認
- 02リポジトリ内の未ラベルIssueの優先度付け
- 03チームが着手するバックログIssueの割り当て
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ fellowship-dev/ dogfooded-skills --skill cto-heartbeatインストール後、Claude Code で/cto-heartbeatを入力して読み込まれたか確認します。
詳細
cto-heartbeat
リポジトリ向けのフロー最適化運用ループです。まず WIP のブロックを解除し、ラベルのない issue をトリアージして、1 回の実行につきタスクを必ず 1 つだけ割り当てます。
このスキルは、cto ロールスキルで定義された運用原則を実装します。
呼び出し
/cto-heartbeat org/repo [goal-context]
例:
/cto-heartbeat fellowship-dev/booster-pack
/cto-heartbeat fellowship-dev/booster-pack "focus: Vercel deployment pipeline"
トークン
export GH_TOKEN=$(grep "GH_PAT_FELLOWSHIP" $HOME/projects/fellowship-dev/claude-buddy/.env | cut -d= -f2)
# Or for specific teams, use the team's token_var from crew.yml
ステップ 0:ラベルの初期設定(冪等)
対象のリポジトリに存在しない場合は、ラベルを作成します。毎回実行してください。gh label create は冪等であり、ラベルがすでに存在する場合はエラーを表示せずに終了します。
export REPO=$1
export GOAL_CONTEXT="${@:2}"
export GH_TOKEN=$(grep "GH_PAT_FELLOWSHIP" $HOME/projects/fellowship-dev/claude-buddy/.env | cut -d= -f2)
# Priority labels
gh label create "P0" --repo $REPO --color "b60205" --description "Production broken, revenue impact, security — fix now" 2>/dev/null || true
gh label create "P1" --repo $REPO --color "d93f0b" --description "Important but not urgent — fix this week" 2>/dev/null || true
gh label create "P2" --repo $REPO --color "fbca04" --description "Nice to have — fix when convenient" 2>/dev/null || true
# Status labels
gh label create "dispatched" --repo $REPO --color "5319e7" --description "Work sent to a crew member" 2>/dev/null || true
gh label create "blocked" --repo $REPO --color "c5def5" --description "Waiting on external input or another issue" 2>/dev/null || true
ステップ 1:WIP の確認(新しい作業よりブロック解除を優先)
他の作業を始める前に、進行中の作業の現在の状態を確認します。原則は、新しい作業を始めるのをやめ、完了に取り組むことです。
# Open PRs across the repo
gh pr list --repo $REPO --state open --json number,title,labels,createdAt,url
# Issues with dispatched label (work in progress)
gh issue list --repo $REPO --label "dispatched" --state open --json number,title,labels,assignees,url
# Issues with blocked label
gh issue list --repo $REPO --label "blocked" --state open --json number,title,labels,url
# Check if any dispatched issues have associated merged PRs (work completed but label not cleaned up)
# For each dispatched issue, check if there is a recently merged PR that references it
対応:
- 割り当て済みの issue にマージ済み PR がある場合 → issue をクローズするか、
dispatchedラベルを削除し、完了を確認します - 割り当て済みの issue に未解決の PR があり、2 日以上停滞している場合 → ブロッカーとして報告し、調査します
- 割り当て済みの issue に PR がなく、割り当てから 3 日以上経過している場合 → 古い割り当てとして報告します
- ブロックされている issue → ブロッカーが解消されたか確認します。解消されている場合は、
blockedラベルを削除して優先順位を付け直します - レビューのパイプラインが進まず停滞している PR → 報告します
出力:WIP 項目とそのステータスの一覧。実施した対応(ラベルの削除、issue のクローズなど)。
ステップ 2:進行中のエピックに集中
現在進行中のエピックを特定します。「進行中のエピック」とは、dispatched ラベルが付いたオープンな issue が少なくとも 1 つあるエピックです。
# Find which epic labels have dispatched issues
gh issue list --repo $REPO --label "dispatched" --state open --json labels --jq ".[].labels[].name" | sort -u
メタデータラベル(P0、P1、P2、dispatched、blocked、bug、enhancement、documentation など)を除外します。残ったラベルがエピックラベルです。
ルール:
- 割り当て済みの作業があるエピックが 1 つだけの場合 → それが進行中のエピックです。以降のすべてのステップでは、そのエピックに集中します。
- 割り当て済みの作業があるエピックが複数ある場合 → 割り当て済み issue が最も多いエピックを進行中とします。分散していることを懸念事項として報告します。
- 割り当て済みの作業があるエピックがない場合(WIP=0)→ 進行中のエピックはありません。ステップ 4 では、すべてのエピックを対象に最優先のものを選びます。
出力:進行中のエピック名(または「none — WIP is clear」)。
ステップ 3:新しい issue のトリアージ(最大 5 件)
優先度ラベルのない issue を見つけ、トリアージします。
# All open issues
gh issue list --repo $REPO --state open --json number,title,labels,body,createdAt --limit 50
# Filter: issues without P0, P1, or P2 labels (done in code/logic, not pure CLI)
ラベルのない issue ごとに(最大 5 件):
- issue のタイトルと本文を読みます
- 優先度ラベル(P0、P1、P2)を付けます
- 既存のエピックに該当する場合はそのエピックラベルを付け、新しい作業の流れを表す issue の場合は新しいエピックラベルを作成します
- ラベルを適用します:
gh issue edit $ISSUE_NUM --repo $REPO --add-label "P1,epic-name"
スキップ:すでに優先度ラベル(P0/P1/P2)が付いている issue。heartbeat では再トリアージしません。
出力:トリアージした issue と、割り当てた優先度およびエピックを示す表。
ステップ 4:タスクを 1 つ割り当てる
割り当てる issue を必ず 1 つ選びます。割り当てとは、クルーリードが担当者を割り当てられるように dispatched ラベルを追加することです。
優先順位:
- 進行中のエピック内で最優先のもの:そのエピック内で P0 > P1 > P2
- 進行中のエピックがない場合:すべてのエピックから最優先の issue
- 割り当てるものがない場合:「バックログなし」または「すべて割り当て済み」と報告します
# Find undispatched issues in the active epic, sorted by priority
gh issue list --repo $REPO --label "$ACTIVE_EPIC" --state open --json number,title,labels --limit 20
# Filter out issues that already have "dispatched" label
# Pick the highest priority one
# Add dispatched label
gh issue edit $ISSUE_NUM --repo $REPO --add-label "dispatched"
ビルドトレインの提案
同じリポジトリに未割り当ての issue が 2 件以上ある場合(dispatched と blocked を除外した後)、単一の issue の代わりに /build-train org/repo --issues N,M,... の割り当てを検討します。これにより、作業を 1 つのビルドブランチにまとめ、PR ごとではなく 1 回だけレビューパイプラインを実行します。判断は状況に応じて行ってください。issue が互いに独立していて、並行して作業できる場合はビルドトレインが適しています。密接に関連していて、順番に実装する必要がある issue には使用しないでください。
ルール:
- WIP > 3 の場合は割り当てないでください。進行中の作業が多すぎます。ブロック解除に集中してください。
- heartbeat 1 回につき割り当ては 1 件です(1 件の割り当てとして扱われるビルドトレインを使う場合を除き、まとめて割り当てないでください)。
出力:issue 番号、タイトル、優先度、エピック。何も割り当てなかった場合はその理由。ビルドトレインを提案する場合は、まとめる issue の一覧。
ステップ 5:報告
REPORT_DIR="$(git rev-parse --show-toplevel)/reports"
REPORT_PATH="$REPORT_DIR/$(date +%Y-%m-%d)-cto-heartbeat-$(echo $REPO | tr "/" "-").md"
報告の構成:
# CTO Heartbeat: [repo name]
**Date:** YYYY-MM-DD HH:MM
**Repo:** $REPO
**Active epic:** [epic name or "none"]
**Goal context:** $GOAL_CONTEXT (or "N/A")
## WIP Status
| Issue | Title | Status | Epic | Priority |
|-------|-------|--------|------|----------|
| #N | ... | dispatched / blocked / stale | epic-name | P1 |
## Actions Taken
- Closed #N (resolved by PR #M)
- Removed dispatched from #N (stale >3 days)
- Unblocked #N (blocker resolved)
## Triage
| Issue | Title | Priority | Epic |
|-------|-------|----------|------|
| #N | ... | P1 | epic-name |
## Dispatched
- **#N — [title]** (P1, epic: [name]) — dispatched for crew execution
## Blockers
- [blocker description — what is stuck and why]
## Recommendations
1. [highest priority action]
2. [second priority]
Quest に報告を投稿します:
QUEST_TOKEN=$(grep "^QUEST_TOKEN=" $HOME/projects/fellowship-dev/claude-buddy/.env | cut -d= -f2)
curl -s -X POST "http://127.0.0.1:4242/api/event" \
-H "Authorization: Bearer $QUEST_TOKEN" \
-H "Content-Type: application/json" \
-d "$(python3 -c "
import json
content = open('$REPORT_PATH').read()
print(json.dumps({
'source': 'commander',
'type': 'commander.report',
'title': 'CTO Heartbeat: $REPO',
'meta': {'content': content, 'report_type': 'cto-heartbeat'}
}))
")" 2>/dev/null || true
判定リファレンス
| 判定 | 絵文字 | ラベル | マージ? |
|---|---|---|---|
| LGTM | ✅ | approved | いいえ(ハートビートはPRではなくイシューを割り当てます) |
| REWORK | 🔄 | needs-work | いいえ |
| BLOCKED | ⏸️ | needs-work | いいえ |
| NEW_ISSUE | 📋 | — | 別のイシューを作成 |
| STALE | ⏰ | needs-work | いいえ |
注意事項
- ハートビートはフロー最適化ツールであり、スキャナーではありません。 まずWIPのブロックを解除し(着手を減らし、完了を増やす)、ラベルのないイシューをP0/P1/P2とエピックのラベルでトリアージし、1回の実行につきタスクを必ず1つだけ割り当てます。一度に1つずつ割り当てることで、チームの集中を保ち、WIPの膨張を防ぎます。
- ハートビートはバックログの整理を担当します。 マージ済みPRによって解決されたイシューをクローズし、重複を報告して、バックログを整理された状態に保ちます。新しい作業の割り当て判断はリードが担当します。
- WIPが3を超えている場合は、絶対に割り当てないでください — 進行中の作業が多すぎます。その場合のハートビートの役割は、作業を追加することではなく、ブロックを解除することです。
- PRレビュー機能については、
/cto-reviewを参照してください。CTOの役割に関する原則については、ctoロールスキルを参照してください。