cleanup-lead-owners — Claude Code skill: HubSpot owner cleanup
Strips departed employees out of HubSpot and moves their contacts, companies and deals to someone still on the team. Handy the week a person leaves.
npx skills add TomGranot/hubspot-admin-skills --skill cleanup-lead-owners -a claude-codeWhat cleanup-lead-owners does
The skill walks your CRM through the Owners API. It pulls both active and deactivated owners, lines them up against your roster of current employees, and flags anyone who should not be holding records — former staff, contractors, vendors. For each flagged owner it counts the contacts, companies and deals attached.
Reassignment runs through the batch update API, either to one default owner or by territory and round-robin rules. Companies and deals follow their contacts. When that finishes, the skill points you at /assign-unowned-contacts to sweep up anything left ownerless, then has you search for contacts whose hubspot_owner_id still matches a deactivated owner — the count should land at zero.
Have a HubSpot service key ready in HUBSPOT_ACCESS_TOKEN inside .env, scoped for crm.objects.owners.read plus write access to contacts, companies and deals. You also need Python 3.10+ with uv, a list of current employees, and a rule for where orphaned records go. Deactivating users takes Super Admin rights in HubSpot settings. Without the employee list there is nothing to compare owners against, so the skill cannot tell a leaver from a current hire. Log the original owner assignments first; rollback is a batch update of hubspot_owner_id back to the old value.
What it helps with
- clear departed employees out of HubSpot owner lists
- reassign contacts, companies and deals left behind by former owners
- spot active HubSpot users who no longer work at the company
- count how many records each stale owner still holds
- verify no record is left without an owner after reassignment
Example prompts for the agent
- List every HubSpot owner who is no longer an employee
- Reassign the contacts and deals of departed owners by territory
- Check that no deactivated owner still has contacts attached
How to install cleanup-lead-owners
1Skills CLI (Vercel)
npx skills add TomGranot/hubspot-admin-skills --skill cleanup-lead-owners -a claude-code2Manually: put the files in place
~/.claude/skills/cleanup-lead-owners/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/cleanup-lead-owners/
1Skills CLI (Vercel)
npx skills add TomGranot/hubspot-admin-skills --skill cleanup-lead-owners -a codex2Manually: put the files in place
.agents/skills/cleanup-lead-owners/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add TomGranot/hubspot-admin-skills --skill cleanup-lead-owners -a cursor2Manually: put the files in place
.cursor/skills/cleanup-lead-owners/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install TomGranot/hubspot-admin-skills cleanup-lead-owners2Manually: put the files in place
.github/skills/cleanup-lead-owners/SKILL.md1Skills CLI (Vercel)
npx skills add TomGranot/hubspot-admin-skills --skill cleanup-lead-owners -a gemini-cli2Platform CLI
gemini skills install https://github.com/TomGranot/hubspot-admin-skills --path skills/cleanup-lead-ownersManually: put the files in place
.devin/skills/cleanup-lead-owners/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add TomGranot/hubspot-admin-skills --skill cleanup-lead-owners -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about cleanup-lead-owners
How do I install cleanup-lead-owners in Claude Code?
Run npx skills add TomGranot/hubspot-admin-skills --skill cleanup-lead-owners -a claude-code. The skill lands in ~/.claude/skills/cleanup-lead-owners/SKILL.md.
What does cleanup-lead-owners do?
It finds HubSpot owners who are no longer employees, reassigns their contacts, companies and deals, and tells you which users to deactivate.
What do I need before running cleanup-lead-owners?
A HubSpot service key in HUBSPOT_ACCESS_TOKEN with crm.objects.owners.read and write scopes for contacts, companies and deals, Python 3.10+ with uv, a current employee list, and a reassignment rule. Deactivating users requires Super Admin rights.
Source text
SKILL.md · MIT
---
name: cleanup-lead-owners
description: "Remove non-employee users from HubSpot and reassign their orphaned contacts, companies, and deals. Pairs with the assign-unowned-contacts skill for comprehensive ownership cleanup."
license: MIT
metadata:
author: tomgranot
version: "1.1"
category: ongoing-maintenance
---
# Cleanup Lead Owners
Remove departed employees from HubSpot and reassign their CRM records. Orphaned records with no active owner fall through the cracks.
## Prerequisites
- A HubSpot service key (`HUBSPOT_ACCESS_TOKEN` in `.env`; an existing legacy private app token also works) with `crm.objects.owners.read` and contact/company/deal write scopes
- Python 3.10+ with [`uv`](https://github.com/astral-sh/uv)
- A list of current employees (to compare against HubSpot users)
- A default owner or round-robin assignment rule for orphaned records
## Step-by-Step Instructions
### Stage 1: Plan
Confirm with the user before starting:
1. Who receives reassigned records — a single default owner, or territory/round-robin rules?
2. Which flagged users should be deactivated vs merely stripped of records?
### Stage 2: Before
Identify non-employee owners via the Owners API:
```python
import os, requests
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.environ["HUBSPOT_ACCESS_TOKEN"]
BASE = "https://api.hubapi.com"
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
active = requests.get(f"{BASE}/crm/v3/owners", headers=HEADERS,
params={"limit": 100, "archived": "false"}).json()["results"]
deactivated = requests.get(f"{BASE}/crm/v3/owners", headers=HEADERS,
params={"limit": 100, "archived": "true"}).json()["results"]
```
Cross-reference with your current employee list. Flag:
- Deactivated HubSpot users who still own records
- Active HubSpot users who are no longer employees
- Contractors or vendors who should not own records
For each flagged owner, count how many contacts, companies, and deals they own.
### Stage 3: Execute
1. **Reassign records** owned by non-employees:
- Use the batch update API to reassign contacts to the appropriate active owner
- Apply round-robin or territory-based rules if no specific owner is obvious
- Reassign companies and deals associated with the same contacts
2. **Deactivate users** who are no longer employees (requires Super Admin in HubSpot Settings > Users & Teams).
3. **Run `/assign-unowned-contacts`** after reassignment to catch any records that ended up without an owner.
### Stage 4: After
1. Search for contacts where `hubspot_owner_id` matches any deactivated owner ID — count should be zero.
2. Confirm all reassigned contacts have an active owner.
3. Check that no workflows broke due to owner changes (some workflows may filter by specific owners).
## Rollback
- Owner reassignments can be reversed by batch-updating the `hubspot_owner_id` back to the original value.
- Keep a log of original owner assignments before making changes.
- Deactivated users can be reactivated in HubSpot Settings if needed.
## Tips
- Run this whenever an employee leaves the company — do not wait for quarterly cleanup.
- Set up an offboarding checklist that includes HubSpot record reassignment.
- Pairs with `/assign-unowned-contacts` for comprehensive ownership hygiene.
© tomgranot · MIT · TomGranot/hubspot-admin-skills