team-ownership について
team-ownershipは、HubSpot CRMの担当者管理を支援するスキルです。コンタクト、会社、取引、チケットの検索と再割り当てに加え、一括変更の安全確認や担当者別の集計方法を扱います。
主な機能
- 01メールから担当者IDを特定
- 024種類のオブジェクトを担当者で検索
- 03レコードの安全な一括再割り当て
- 04担当者別のチームビューを集計
活用シーン
- 01担当者の退職時にCRMレコードを引き継ぐ
- 02担当者ごとの取引件数を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ hubspot/ agent-cli-skills --skill team-ownershipインストール後、Claude Code で/team-ownershipを入力して読み込まれたか確認します。
詳細
前提: まず bulk-operations/SKILL.md を読んでください。JSONL のパイプ処理、ページネーション、dry-run/digest/confirm、そして hubspot history による復元についてはそちらに記載されています。整形パターンは bulk-operations/resources/json-patterns.md にあります。
hubspot_owner_id は contacts、companies、deals、tickets の文字列フィールドです。オーナーは CRM ユーザーであり、hubspot owners list で取得できます。teams オブジェクトは存在しないため、チームレベルのビューは hubspot_owner_id によるクライアント側のグループ化になります。
1. メールアドレス → オーナー ID の解決
ID をハードコードしないでください — これらはポータル固有です。解決してからキャッシュします:
FROM_ID=$(hubspot owners list | jq -r 'select(.email=="[email protected]") | .id')
TO_ID=$(hubspot owners list | jq -r 'select(.email=="[email protected]") | .id')
2. オーナーのレコードを検索する
4 つのオブジェクトタイプすべてで同じフィルターを使用します。コンテキストのためにオブジェクト固有の --properties を追加してください。オーナー未設定のレコードは !property の形式を使用します。
hubspot objects search --type contacts --filter "hubspot_owner_id=$FROM_ID" --properties email,firstname,lifecyclestage
hubspot objects search --type companies --filter "hubspot_owner_id=$FROM_ID" --properties name,domain
hubspot objects search --type deals --filter "hubspot_owner_id=$FROM_ID" --properties dealname,dealstage,amount
hubspot objects search --type tickets --filter "hubspot_owner_id=$FROM_ID" --properties subject,hs_pipeline_stage
# Records with no owner at all
hubspot objects search --type deals --filter "!hubspot_owner_id" --properties dealname,amount
100 件を超える場合 — bulk-operations の --after ループでページングします。カウントのみの場合: wc -l にパイプします。
3. 一括再割り当て — 検索 → 更新
各検索行を {id, properties:{hubspot_owner_id}} に整形し、objects update にパイプします。objects update は不可逆であるため、まず dry-run を実行してください: dry-run はどのサイズでも digest と apply_command_hint を出力します (confirm = 1 件のレコードの場合はレコード ID、バッチの場合は行数)。その後、--digest/--confirm を付けて再実行します (bulk-operations/SKILL.md の「安全な破壊的ワークフロー」を参照)。
# Dry-run
hubspot objects search --type contacts --filter "hubspot_owner_id=$FROM_ID" \
| jq -c --arg to "$TO_ID" '{id, properties:{hubspot_owner_id:$to}}' \
| hubspot objects update --type contacts --dry-run \
| tee /tmp/reassign.preview.jsonl
# Execute — lift the digest + confirm from the preview line (required at every size)
digest=$(jq -r 'select(.digest != null) | .digest' /tmp/reassign.preview.jsonl)
confirm=$(jq -r 'select(.digest != null) | .target.id' /tmp/reassign.preview.jsonl) # single: record ID; batch: row count
hubspot objects search --type contacts --filter "hubspot_owner_id=$FROM_ID" \
| jq -c --arg to "$TO_ID" '{id, properties:{hubspot_owner_id:$to}}' \
| hubspot objects update --type contacts --digest "$digest" --confirm "$confirm"
単一レコードの割り当て — stdin も jq も不要です。これも不可逆であるため、まず dry-run を実行してください (confirm = レコード ID):
hubspot objects update --type contacts 12345 --property hubspot_owner_id=$TO_ID --dry-run
hubspot objects update --type contacts 12345 --property hubspot_owner_id=$TO_ID --digest <hash> --confirm 12345
4. 担当者退職時のワークフロー
担当者が関与する 4 つのオブジェクトタイプをループします:
FROM_ID=$(hubspot owners list | jq -r 'select(.email=="[email protected]") | .id')
TO_ID=$(hubspot owners list | jq -r 'select(.email=="[email protected]") | .id')
for type in contacts companies deals tickets; do
echo "── $type ──"
hubspot objects search --type "$type" --filter "hubspot_owner_id=$FROM_ID" \
| jq -c --arg to "$TO_ID" '{id, properties:{hubspot_owner_id:$to}}' \
| hubspot objects update --type "$type" --dry-run
done
各 digest 行を確認し、そのタイプのプレビュー行から取り出した --digest/--confirm を付けてタイプごとに再実行します (どのサイズでも必須です。confirm = バッチの場合は行数、単一の場合はレコード ID)。誤って再割り当てした場合: hubspot history --since 1h で影響を受けた ID を一覧表示できます。
5. チームレベルのビュー (クライアント側のグループ化)
レコードを hubspot_owner_id でグループ化し、owners list に結合して人間が読めるメールアドレスを取得します:
hubspot objects search --type deals --filter "dealstage!=closedwon AND dealstage!=closedlost" \
--properties hubspot_owner_id --format json \
| jq '.data | group_by(.properties.hubspot_owner_id)
| map({owner_id: .[0].properties.hubspot_owner_id, count: length})' \
> /tmp/by-owner.json
hubspot owners list \
| jq --slurpfile by /tmp/by-owner.json -r \
'. as $o | $by[0][] | select(.owner_id==$o.id) | "\($o.email)\t\(.count)"'