Prereq: read bulk-operations/SKILL.md first. JSONL piping, pagination, dry-run/digest/confirm, and hubspot history recovery live there. Reshape patterns live in bulk-operations/resources/json-patterns.md.
hubspot_owner_id is a string field on contacts, companies, deals, and tickets. Owners are CRM users — hubspot owners list returns them; there is no teams object, so team-level views are client-side groupings by hubspot_owner_id.
1. Resolve email → owner ID
Never hardcode IDs — they are portal-specific. Resolve, then cache:
2. Find records for an owner
Same filter across all four object types. Add object-specific --properties for context. Unowned records use the !property form.
100 hits — page with the
--afterloop frombulk-operations. Counting only: pipe towc -l.
3. Bulk reassign — search → update
Reshape each search row into {id, properties:{hubspot_owner_id}} and pipe to objects update. objects update is irreversible, so dry-run first: the dry-run emits a digest + apply_command_hint at every size (confirm = the record ID for one record, the row count for a batch). Then re-run with --digest/--confirm (see bulk-operations/SKILL.md § "Safe destructive workflow").
Single-record assignment — no stdin, no jq. Still irreversible, so dry-run first (confirm = the record ID):
4. Rep-leaves workflow
Loop over the four object types the rep touches:
Review each digest line, then re-run per type with the --digest/--confirm lifted from that type's preview line (required at every size; confirm = the row count for a batch, the record ID for a single). Mis-reassigned? hubspot history --since 1h lists the affected IDs.
5. Team-level views (client-side grouping)
Group records by hubspot_owner_id, join to owners list for human-readable emails:

