关于 crm-data-quality
crm-data-quality 是一项通过 hubspot 命令行工具维护 HubSpot CRM 数据的技能,涵盖属性检查、查找信息不完整的记录、规范字段值、去重和属性审计,并为破坏性操作设置安全步骤。
主要功能
- 01发现 CRM 属性名称和枚举选项
- 02查找缺少字段的记录
- 03用 jq 管道规范字段值
- 04通过安全步骤合并重复记录
- 05审计和管理属性
适用场景
- 01查找缺少邮箱或电话的联系人
- 02统一公司字段的值
- 03查找并合并重复联系人
- 04检查枚举选项和属性分组
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hubspot/ agent-cli-skills --skill crm-data-quality安装后在 Claude Code 中输入/crm-data-quality确认已加载。
详细介绍
先阅读 bulk-operations/SKILL.md——JSONL 管道传输、批量读取、分页以及 dry-run/digest/confirm 门控适用于以下所有命令。
属性发现
不要猜测属性名称。先列出:
hubspot properties list --type contacts --format table
hubspot properties list --type contacts | jq -c 'select(.type=="enumeration") | {name, label}'
--type companies、deals 或任何自定义类型(hubspot objects types)也同样适用。
1. 查找不完整记录
!name = NOT_HAS_PROPERTY(缺失或为空)。单独的 name = HAS_PROPERTY。在一个 --filter 中使用 AND 链接条件;多个 --filter 标志之间使用 OR。
hubspot objects search --type contacts --filter "!email" --properties firstname,lastname,company
hubspot objects search --type contacts --filter "!phone AND !mobilephone" --properties email
hubspot objects search --type contacts --filter "!hubspot_owner_id" --properties email,lifecyclestage
结果超过 100 条时,使用 bulk-operations 中的分页循环。
2. 规范化字段值
搜索 → 使用 jq 重塑 → 管道传入 update。objects update 不可逆,因此要先运行 --dry-run——无论行数多少,都必须遵循 dry-run → digest → confirm 流程,不仅限于超过 100 行的情况(bulk-operations 中有完整说明)。重塑模式见:bulk-operations/resources/json-patterns.md。
# Collapse spellings into one canonical value — 1. preview
hubspot objects search --type contacts --filter "company~acme" \
| jq -c '{id, properties:{company:"Acme Corporation"}}' \
| hubspot objects update --type contacts --dry-run \
| tee /tmp/normalize.preview.jsonl
# 2. lift the digest + confirm (present at every row count)
digest=$(jq -r 'select(.digest != null) | .digest' /tmp/normalize.preview.jsonl)
confirm=$(jq -r 'select(.digest != null) | .target.id' /tmp/normalize.preview.jsonl) # single: record ID; batch of 2+: row count
# 3. execute — re-pipe the SAME inputs plus --digest/--confirm
hubspot objects search --type contacts --filter "company~acme" \
| jq -c '{id, properties:{company:"Acme Corporation"}}' \
| hubspot objects update --type contacts --digest "$digest" --confirm "$confirm"
# Lowercase emails (read, reshape, write) — 1. preview
hubspot objects search --type contacts --filter "email" --properties email \
| jq -c '{id, properties:{email: (.properties.email | ascii_downcase)}}' \
| hubspot objects update --type contacts --dry-run \
| tee /tmp/lower.preview.jsonl
# 2. lift the digest + confirm, then 3. re-pipe the SAME inputs to execute
digest=$(jq -r 'select(.digest != null) | .digest' /tmp/lower.preview.jsonl)
confirm=$(jq -r 'select(.digest != null) | .target.id' /tmp/lower.preview.jsonl)
hubspot objects search --type contacts --filter "email" --properties email \
| jq -c '{id, properties:{email: (.properties.email | ascii_downcase)}}' \
| hubspot objects update --type contacts --digest "$digest" --confirm "$confirm"
3. 使用 hubspot objects merge 去重
次要记录会合并到主要记录中并被删除。**不可逆。**适用 dry-run/digest/confirm 门控。
# Single pair — dry-run first, then execute with the digest + confirm (confirm = the secondary ID for one pair)
hubspot objects merge --type contacts --primary 149 --secondary 425 --dry-run
hubspot objects merge --type contacts --primary 149 --secondary 425 --digest <hash> --confirm 425
批量操作:通过 stdin 传入 JSONL {"primary":"...","secondary":"..."}(省略 --primary/--secondary)。
必须分页。objects search 每次调用最多返回 100 行,而 jq -s 会将单个数据流全部读入内存——对原始 search 运行下面的代码片段时,任何跨越分页边界的重复项都会被悄然遗漏。先使用 bulk-operations/SKILL.md 中的分页循环收集完整数据集(写入 /tmp/contacts.jsonl),然后再从文件中去重:
# /tmp/contacts.jsonl produced by the pagination loop (bulk-operations/SKILL.md)
jq -s -c '
group_by(.properties.email)[]
| select(length > 1)
| sort_by(.id | tonumber)
| .[0].id as $p | .[1:][] | {primary: $p, secondary: .id}
' /tmp/contacts.jsonl \
| hubspot objects merge --type contacts --dry-run | tee /tmp/merge-preview.jsonl
无论数据量大小,都从预览行中提取 digest/confirm——使用 select(.digest != null);对于批次,confirm 是配对数量(.target.id),而 mutation_kind 仅在超过 100 行的阈值时为 BulkData(100 行或以下为 RecordMutation,但无论哪种情况都会提供 digest)。使用 --digest/--confirm 重新传入同一生产端(参见 bulk-operations)。
4. 审计属性
hubspot properties list(以及 get、batch-read)会为每一行输出 {name, label, type, fieldType, groupName, optionsDisplay}。枚举选项值可通过 properties options-list 获取——无需从实时记录或 UI 中读取。
# Count properties per group (HubSpot groups standard fields; custom groups stand out)
hubspot properties list --type contacts | jq -rs 'group_by(.groupName) | map({group: .[0].groupName, count: length}) | .[]'
# All enumeration properties
hubspot properties list --type contacts | jq -c 'select(.type=="enumeration") | {name, label, fieldType}'
# Create a DQ flag property, then set it via the normalize pattern in section 2
hubspot properties create --type contacts --name dq_missing_phone --label "DQ: Missing Phone" --prop-type string --field-type text
枚举选项——列出和管理(properties options-*,v0.11.0)
# List the allowed options on an enumeration property
hubspot properties options-list --type contacts hs_buying_role
# each row: {"value":"EVALUATOR","label":"Evaluator","displayOrder":9,"hidden":false}
# Add / rename / remove an option (options-delete is irreversible — dry-run → digest → confirm, confirm = the option value)
hubspot properties options-create --type contacts hs_buying_role --label "Evaluator" --value EVALUATOR --display-order 9
hubspot properties options-update --type contacts hs_buying_role --value EVALUATOR --label "New Label"
hubspot properties options-delete --type contacts hs_buying_role --value EVALUATOR --dry-run
hubspot properties options-delete --type contacts hs_buying_role --value EVALUATOR --digest <hash> --confirm EVALUATOR
对于选项只读的 HubSpot 定义属性,options-create/update/delete 会在调用 API 前被拒绝。
恢复
合并不可逆。每次合并后,hubspot history --since 1h 会记录审计跟踪。如果方向错误,请从 UI 的回收站恢复次要记录。