# How we keep our CRM clean

Each night an agent merges duplicate HubSpot contacts, fills in blank fields from enrichment data, flags deals that went cold and posts a tidy-up report. Big bulk edits wait for a person.

Canonical page: https://themachine.myapps.ai/use-cases/crm-hygiene

Leave a CRM alone and it gets messy all by itself. Web forms and imports create the
same person twice. New records arrive with half the fields blank. Deals sit in the
pipeline for weeks after everyone has stopped talking. Soon the pipeline report
describes a business you don't quite recognise, and the sales team quietly stops
believing it.

Our fix is an agent on Machine that tidies HubSpot every night. It merges duplicate
contacts, fills in blank fields from enrichment data, flags deals that have gone
cold, and posts a short report on the state of the data. Any bulk edit above a set
size waits until a person approves it.

- **Team:** Machine
- **CRM:** HubSpot
- **Connected systems:** HubSpot · Enrichment data · Slack
- **Mode:** Runs every night · a person approves big changes

## The problem

Keeping the CRM tidy never makes it onto anyone's calendar. When one company is
split across two contact records, its history is split too, and the account owner
only sees half of it. Blank job titles, industries and company sizes make every
segment a guess. Deals that have not budged in weeks still inflate the forecast.

The common remedies wear off. A big one-off clean-up lasts until the next import
messes it up again. A paid de-duplication add-on catches the doubles but does
nothing for blank fields or cold deals. Asking reps to tidy their own records means
asking them to choose admin over selling, and selling wins every time. The upkeep
has to happen by itself, every night, with nobody standing over it.

## What we built

Every night a cron trigger points an agent at HubSpot. Each run gets a sealed-off
session of its own and narrow access to HubSpot and our enrichment provider. The
agent finds duplicate contacts and merges them, fills in what is missing from
enrichment, marks deals that have stalled, and posts a report of everything it
touched. A bulk edit that crosses a set size pauses for a person before anything
is saved.

## How it works

### Schedule a nightly run

A **cron trigger** starts the project once each night. Every start creates a
brand-new **session**: a fresh cloud computer (sandbox) used only for that run,
holding just the CRM and enrichment access a clean-up needs. When the job is done,
the computer is thrown away.

### Write down the house rules

How we model our data is stored in **skills** and **memory**, the playbook loaded
at the start of every run. It covers which fields must be filled, how we tell that
two contacts are really one person, when a deal counts as cold, and how merges
should be done. Whenever an odd case turns up, we add it to the rules.

### Plug in HubSpot and enrichment

**Connectors** are scoped connections to your tools, and the keys stay on our
servers, out of the model's reach. Through them the agent can:

- **Work in HubSpot:** read contacts and deals, merge the doubles and fix fields.
- **Ask the enrichment provider:** fill in blank job titles, company sizes and
industries using outside data.
- **Post in Slack:** a brief report of each run in the RevOps channel.

### Put a limit on big changes

Merging duplicates and filling single blanks happen without supervision. A
**bulk field update above a set size** is different: it halts at a **human
approval gate** before saving, so any change that sweeps across hundreds of
records gets a look first. Credentials are stored encrypted in the **Secrets
Manager** and only handed to the agents you grant them to, at the moment a run
starts.

### Read the morning report

Each run merges duplicates, enriches the blanks, flags the deals that went quiet,
and then reports back: how many contacts it merged, which fields it filled, which
deals it flagged. If a bulk edit is waiting for approval, the report spells out
what it is and why it is waiting.

> **The pattern**
> Start the clean-up with a **cron trigger**. Give the agent scoped
> **connectors** into HubSpot and your enrichment source. Write your data rules
> down as **skills** and **memory**, and put a person in front of any big bulk
> change. From then on, the nightly run tidies up and reports back by itself.

## Guardrails

An agent that can write to your CRM has to protect the data, not just tidy it. On
Machine that means:

- **Isolation.** Every run lives in a sandbox of its own, and the HubSpot and
  enrichment edits it is explicitly allowed to make are the only things that leave
  it.
- **Scoped secrets.** The HubSpot and enrichment credentials are stored encrypted
  in the Secrets Manager and only handed to the agents you grant them to, injected
  into the sandbox when the run starts.
- **Human approval gates.** A bulk field update above the set size cannot save
  until a person approves it.
- **Everything is code.** The duplicate rules, the must-have fields and the meaning
  of "cold deal" are files in the repo. They have a version history and change
  through a reviewed **change request**, not a toggle in a dashboard.

## The outcome

- **Nightly:** The tidy-up happens without anyone booking it in
- **3 passes:** Duplicates, blank fields and cold deals, all in one run
- **Threshold-gated:** Big bulk edits get a human look before saving

Our pipeline reports now look a lot more like real life, because the records
underneath get looked after every night, not in the odd spring clean. When a change
is big enough to matter, a person sees it before it happens. And the RevOps channel
keeps a running diary of what changed and when.
