Read bulk-operations/SKILL.md first — JSONL piping, batch read, pagination, and dry-run/digest/confirm gating apply to every command below.
Property discovery
Don't guess property names. List them:
Same for --type companies, deals, or any custom type (hubspot objects types).
1. Find incomplete records
!name = NOT_HAS_PROPERTY (missing or empty). Bare name = HAS_PROPERTY. Within one --filter, chain with AND; multiple --filter flags are OR'd.
For >100 results, use the pagination loop from bulk-operations.
2. Normalize field values
Search → reshape with jq → pipe into update. objects update is irreversible, so --dry-run first — the dry-run → digest → confirm flow is required at every row count, not just >100 (bulk-operations covers it end to end). Reshape patterns: bulk-operations/resources/json-patterns.md.
3. Dedupe with hubspot objects merge
Secondary is folded into primary and deleted. Irreversible. Dry-run/digest/confirm gating applies.
Bulk: pipe JSONL {"primary":"...","secondary":"..."} on stdin (omit --primary/--secondary).
Pagination required. objects search caps at 100 rows per call and jq -s slurps a single stream into memory — running the snippet below against a raw search will silently miss every duplicate that crosses a page boundary. Collect the full set first with the pagination loop from bulk-operations/SKILL.md (write to /tmp/contacts.jsonl), then dedupe from the file:
Lift the digest/confirm from the preview line at any size — select(.digest != null); for a batch the confirm is the pair count (.target.id), and mutation_kind is BulkData only above the 100-row threshold (RecordMutation at or below it, but the digest is present either way). Re-pipe the same producer with --digest/--confirm (see bulk-operations).
4. Audit properties
hubspot properties list (and get, batch-read) emits {name, label, type, fieldType, groupName, optionsDisplay} per row. Enum option values are exposed via properties options-list — no need to read them off a live record or the UI.
Enum options — list and manage (properties options-*, v0.11.0)
HubSpot-defined properties with read-only options reject options-create/update/delete before the API is called.
Recovery
Merge is irreversible. After any merge, hubspot history --since 1h captures the audit trail. If wrong direction, restore the secondary from the UI's recycle bin.

