Skip to main content
skill CX Codex

new-contact-hygiene-workflow — Claude Code skill for HubSpot contact intake

Builds a HubSpot workflow that stages every new contact and pulls company details from the associated company record.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add TomGranot/hubspot-admin-skills --skill new-contact-hygiene-workflow -a claude-code
Open on GitHub

What new-contact-hygiene-workflow does

The skill creates a workflow named "HYGIENE: Default Lifecycle Stage for New Contacts". Enrollment fires when a contact's create date is known; the action sets the lifecycle stage to Lead, and re-enrollment stays on. Three scripts do the work — scripts/before.py, scripts/execute.py, scripts/after.py — each run with uv run. The workflow lands disabled so you can inspect it first.

Creation goes through the v4 Automation API, which HubSpot labels beta, and the scripts call the unversioned /automation/v4/flows path. Two parts of the design stay manual: copy-property actions that read from an associated company, and the branch that notifies a CRM admin when no company ever attaches. Add both in the UI. Should the script's create call start failing, the skill walks through a full manual build as a fallback.

You need HubSpot Marketing Professional or Enterprise, a service key with the automation scope stored as HUBSPOT_ACCESS_TOKEN in .env, and Python 3.10+ with uv. Copying company name and industry only pays off once /enrich-company-name and /enrich-industry have already run over your existing contacts.

What it helps with

  • create the new-contact workflow through the API instead of clicking through the builder
  • give every incoming contact a lifecycle stage before a human sees it
  • fill company name and industry from the associated company
  • catch workflow name collisions before creating anything
  • keep an admin alert for contacts that never get a company

Example prompts for the agent

  • Run uv run scripts/before.py and list the workflows already in the portal
  • Create the new-contact workflow with uv run scripts/execute.py and leave it disabled
  • Add a copy action that pulls the company name from the associated company

How to install new-contact-hygiene-workflow

1Skills CLI (Vercel)

npx skills add TomGranot/hubspot-admin-skills --skill new-contact-hygiene-workflow -a claude-code

2Manually: put the files in place

~/.claude/skills/new-contact-hygiene-workflow/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/new-contact-hygiene-workflow/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about new-contact-hygiene-workflow

How do I install new-contact-hygiene-workflow in Claude Code?

Run npx skills add TomGranot/hubspot-admin-skills --skill new-contact-hygiene-workflow -a claude-code. The skill file is written to ~/.claude/skills/new-contact-hygiene-workflow/SKILL.md.

What does new-contact-hygiene-workflow do?

It builds a HubSpot workflow that enrolls each new contact, sets the lifecycle stage to Lead, and gives you a base to extend with company data. The copy-from-association actions and the admin notification are added in the UI.

What do I need before running it?

A HubSpot Marketing Professional or Enterprise plan, a service key with the automation scope in .env, and Python 3.10+ with uv. Workflow creation relies on the beta v4 Automation API, so review the result in the UI before enabling it.

Source text

SKILL.md · MIT
---
name: new-contact-hygiene-workflow
description: "Build a HubSpot workflow that auto-enriches and stages new contacts upon creation. Sets lifecycle stage via the v4 Automation API, copies company name and industry from the associated company (UI step), and branches on completeness."
license: MIT
metadata:
  author: tomgranot
  version: "1.1"
  category: automation-workflows
---

# New Contact Hygiene Workflow

Build a workflow that automatically enriches every new contact at creation time. This ensures contacts enter the database with a lifecycle stage, company name, and industry before any human touches them.

## What Is and Isn't Scriptable

**API status:** HubSpot documents the Workflows API as **beta** and subject to change. Its current reference is the date-based beta path `/automation/v4/2027-03-beta/flows`; this skill's scripts still call the unversioned `/automation/v4/flows` path, which v4's end of support on March 30, 2027 also covers. Creating workflows disabled and reviewing them in the UI is what makes a beta API acceptable here. If a script's create call starts failing, the manual UI build below is the fallback.

The v4 Automation API creates workflows programmatically, including "is unknown" enrollment conditions via `LIST_BASED` filter criteria. Two pieces of this particular design still belong in the UI:

1. **Copy from associated object** actions (copy company name/industry from the associated company) have no documented v4 action fields. Add them in the UI during review — or build the action once in the UI, `GET /automation/v4/flows/{flowId}`, and extend the script with the exact field shapes your portal returns.
2. **The notification branch** (alert admin when a contact still has no company after the delay) depends on portal-specific recipients.

So the split is: the script creates the default-lifecycle-stage workflow via API; the enrichment copy actions and the notification branch are added in the UI. If you already run `/enrich-company-name` and `/enrich-industry`, their dedicated workflows cover the copy actions and this skill's API-created workflow completes the intake picture.

## Prerequisites

- HubSpot Marketing Professional or Enterprise plan
- A HubSpot service key (`HUBSPOT_ACCESS_TOKEN` in `.env`; an existing legacy private app token also works) with the `automation` scope (for the API path)
- Python 3.10+ with [`uv`](https://github.com/astral-sh/uv)
- Workflow creation permissions in HubSpot
- Company association enrichment completed (run `/enrich-company-name` and `/enrich-industry` first for existing contacts)

## Scripts

Script paths are relative to this skill's directory. Run them from your project directory so `.env`, `data/`, and `reports/` resolve there: prefix each path with wherever this skill is installed (`skills/new-contact-hygiene-workflow/` in a clone of the repo).

| Stage | Script | Run with |
|-------|--------|----------|
| Before | [`scripts/before.py`](./scripts/before.py) | `uv run scripts/before.py` |
| Execute | [`scripts/execute.py`](./scripts/execute.py) | `uv run scripts/execute.py` |
| After | [`scripts/after.py`](./scripts/after.py) | `uv run scripts/after.py` |

`execute.py` creates one workflow — "HYGIENE: Default Lifecycle Stage for New Contacts" (enrollment: create date known AND lifecycle stage unknown; action: set stage to Lead; re-enrollment on) — **disabled, for review before enabling**. Extend it in the UI with the copy actions and notification branch per the design below.

## Building the Workflow: Two Options

**Option A (primary):** run the scripts, then extend the created workflow in the UI with the copy-from-associated-company actions, the delay, and the no-company notification branch (Stage 3, steps 3-6).

**Option B:** build the whole workflow manually in the UI (all of Stage 3).

**Alternatives:** HubSpot Breeze AI provides minimal value for this workflow — it creates event-based (OR) triggers, and cannot create "is unknown" conditions, copy-from-association actions, or re-enrollment rules. The Claude Chrome extension can drive the workflow builder UI directly and handles those cases. Both are secondary options.

## Workflow Design

```
TRIGGER: Contact create date is known
         (fires for every new contact)
           │
           ▼
    ┌─────────────────────────┐
    │ Set lifecycle stage      │
    │ = "Lead" (if empty)      │
    └────────────┬────────────┘
                 │
                 ▼
    ┌─────────────────────────┐
    │ Copy company name from   │
    │ associated company       │
    └────────────┬────────────┘
                 │
                 ▼
    ┌─────────────────────────┐
    │ Copy industry from       │
    │ associated company       │
    └────────────┬────────────┘
                 │
                 ▼
    ┌─────────────────────────┐
    │ Delay: short wait         │
    │ (3-10 min, rec: 5)      │
    └────────────┬────────────┘
                 │
                 ▼
    ┌─────────────────────────┐
    │ IF/THEN BRANCH:          │
    │ Company name is unknown? │
    ├──────────┬──────────────┘
    │ YES      │ NO
    │          │
    ▼          ▼
  Retry      Continue
  copy       (enriched)
  + notify
  admin
```

## Step-by-Step Build Instructions

### Stage 1: Plan

1. Confirm the default stage for new contacts (Lead, unless your funnel differs).
2. Decide who receives the "no company association" notification.

### Stage 2: Before

1. Confirm company enrichment processes have run for existing data.
2. Run `uv run scripts/before.py` to inventory workflows and check name collisions.

### Stage 3: Execute

**Option A:** run `uv run scripts/execute.py`, then open the created workflow in the UI and continue from step 3 below (copy actions, delay, branch). **Option B:** open HubSpot > Automation > Workflows > Create workflow, select "Contact-based", start from scratch, and follow all steps.

1. **Set enrollment trigger:**
   - Property: "Create date" > "is known"
   - This enrolls every new contact automatically.

2. **Add action: Set property value**
   - Property: "Lifecycle stage"
   - Value: "Lead"
   - Condition: Only if lifecycle stage is unknown (use an if/then branch before this step, or rely on HubSpot's "only if empty" option if available in your plan).

3. **Add action: Copy property**
   - Source: Associated company > "Company name"
   - Target: Contact > "Company" property

4. **Add action: Copy property**
   - Source: Associated company > "Industry"
   - Target: Contact > "Industry" property

5. **Add delay: a short delay (3-10 minutes, recommended: 5)**
   - Purpose: Allow time for company associations to sync (especially for form submissions or integrations that create contacts before associating them). Adjust the duration based on how quickly your integrations typically create associations.

6. **Add if/then branch:**
   - Condition: Contact "Company" property is unknown
   - YES branch: Add internal notification to CRM admin — "New contact {firstname} {lastname} ({email}) has no company association after enrichment attempt."
   - NO branch: No further action needed (contact is enriched).

7. **Review settings:**
   - Re-enrollment: OFF (each contact should only go through this once)
   - Unenrollment: None needed
   - Time zone: Not applicable (no time-based actions beyond delay)

8. **Turn on the workflow.**

### Stage 4: After

0. Run `uv run scripts/after.py` (API path) to confirm the workflow exists and report enabled state.
1. Create a test contact manually. Confirm:
   - Lifecycle stage is set to "Lead"
   - Company name copied from associated company
   - Industry copied from associated company
2. Create a test contact with no company association. Confirm:
   - Admin notification fires after the configured delay
3. Check workflow history for any errors in the first 24 hours.

## Rollback

1. Turn off the workflow in HubSpot > Automation > Workflows.
2. Contacts already enriched retain their values — no destructive changes to undo.
3. If lifecycle stages were set incorrectly, use the Search API to find contacts created after the workflow activation date and reset as needed.

## Edge Cases

- **Contacts created via import:** These fire the trigger. If imports include company name/industry, the copy action will overwrite with the associated company's values. Consider excluding imported contacts via a list filter.
- **Contacts without company associations:** The copy action silently fails. The branch handles notification.
- **Multiple associated companies:** HubSpot copies from the primary associated company only.

© tomgranot · MIT · TomGranot/hubspot-admin-skills

Similar skills

All skills for Automation and no-code: n8n, Zapier, Make →

From the same set11

waterfall-enrich-contacts Pulls emails, phone numbers and job titles for HubSpot contacts from an external provider and writes them back with an audit trail. CX Codex +1 ★ 78repo stars suppress-ghost-contacts Finds HubSpot contacts that got marketing email but never opened any of it, then audits them so you can stop mailing the ones that hurt deliverability. CX Codex +1 ★ 78repo stars review-bounced-contacts A weekly manual pass over contacts with 3+ bounces: delete them or try to recover. Keeps suppression from going too far while bad records still leave. CX Codex +1 ★ 78repo stars enrich-company-name Copies the company name from a linked company record into empty contact fields in HubSpot. Useful when empty values break segmentation and personalization tokens. CX Codex +1 ★ 78repo stars create-segment-lists Builds a library of HubSpot segment lists — customers, partners, competitors, employees, ICP tiers, industries. Feeds targeting, suppression and reporting. CX Codex +1 ★ 78repo stars cleanup-workflows Audits HubSpot workflows and flags the ones worth deleting: never enrolled, switched off for 90+ days, or left over from testing. CX Codex +1 ★ 78repo stars cleanup-lead-owners 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. CX Codex +1 ★ 78repo stars cleanup-dashboards Walks you through auditing HubSpot dashboards: spots abandoned screens, duplicates and test copies, then helps merge reports into a few that people actually open. CX Codex +1 ★ 78repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor