#The challenge
Self-serve signup collected an email address and a password and nothing else, so most contacts had no company and no reliable location. Meanwhile the CRM held five different signals for where someone was — self-reported form field, payment location, company location, IP address, and a phone country code — and the territory workflows keyed off whichever one happened to be populated. Reps were being handed accounts that belonged to another region's rep, and sales teams notice that. Separately, every employee had connected their own AI assistant to the CRM individually, so nobody could control write permissions and records were being created and edited by tooling nobody had configured centrally.
#The approach
Build a routing-country waterfall and stamp where the answer came from
Two new contact properties: a routing country, and a source stamp recording which field the value came from. The waterfall runs associated company headquarters first, then the enrichment provider's country, then the contact's self-reported country, then the data-provider country, and IP country last. IP is deliberately last because between corporate VPNs and OS-level private relay, the exit node is frequently in the wrong country. Alongside it, a standardised country-name master list so the same country resolves the same way in every workflow, and headroom in the design for a state or region layer later.
Pick headquarters over the individual's location, on purpose
The business rule was set by sales leadership, not by the data: route on where the company is headquartered, because that is where the executives and the signers usually sit, and let reps hand off between regions afterwards if the contact is elsewhere. That is a defensible rule precisely because it is a rule — the previous behaviour, where the answer changed depending on which field happened to be populated, was not.
Handle the no-company case rather than treating it as an exception
The first build only populated routing country when a contact had an associated company, which in a product-led base is a minority of records. It was rewritten to fall back through whatever country signals do exist and backfilled across roughly 150,000 contacts. Two later fixes came out of live traffic: auto-created company records with no company name were failing the branch that checked for a company, so that check was keyed off a field every company has instead; and an IP-country enrolment path was added for console signups with no company match and no form country.
Trace every consumer before changing the territory field
Roughly ten downstream workflows read the territory field. Before repointing it at the new routing country, all of them were pulled as JSON and mapped, the existing country-to-territory branch lists were compared against the waterfall's output to surface spelling and syntax mismatches between the two, and re-enrolment was tightened to fire when the routing field changes rather than whenever any country field becomes known. Territory lives on the company object while routing country lives on the contact, so the contact-to-company gap had to be resolved explicitly rather than assumed.
Run the AI on a direct model API inside CRM custom code, not on platform AI credits
The CRM's own AI credits were rejected as too expensive per unit and too limited for where the customer wanted to go. Instead the model API key is wired into custom-code actions inside CRM workflows, so the agents run natively in the platform's automation engine with no per-credit metering, and the model can be swapped without rebuilding the workflow. Everything the agents do — drafting, classification, formatting — happens in that custom-code action.
Ship the boring agent first: the meeting briefing note
The failure mode was mundane and expensive. An outsourced development team would work one contact, that contact would forward the booking link, and someone else would book the meeting — so the account executive walked into a call with a person who had no notes and no email history. It happened in roughly two or three of every ten booked meetings. The fix is a workflow that fires on meeting booked, calls the model over the logged email thread and account context, and writes a formatted note onto every contact on the meeting and on the company — who was actually worked, what they want, where the deal stands, a risk, and a source line saying how many emails it read. Scope moved from same-email-domain to every contact on the meeting or company specifically because personal email domains break domain matching in a product-led base. The enablement catch is real: reps only see it if notes are enabled in their activity filter.
Build the outbound agent as two workflows with three explicit branches
A first-touch workflow enrols on a qualifying lead score plus a routing country in the target region, excluding contacts already at opportunity, sales-qualified or customer lifecycle stages, and branches three ways: send, route for human review, or produce no draft at all. A second workflow handles inbound replies. The agent scores its own confidence and escalates when it is low, and escalation raises both a CRM task and a channel notification, so a missed message in one system does not mean a missed handoff. It writes and reviews before it sends: every draft passes a human in the pilot phase, with one named owner and a named backup rather than a shared queue.
Narrow the blast radius to get out of shadow mode
The reply-handling workflow originally triggered on any reply to any seller's email. The sales team was not ready for AI-drafted responses on their own threads, so enrolment was scoped down to replies to the agent's own sends only, with the broader logic preserved as a disabled branch for later re-enablement rather than deleted. That narrowing is what made it safe to leave shadow mode at all — it is easier to widen a working agent than to recover trust after it answers on someone else's thread.
Red-team it before it talks to a human
Two explicit targets before live sending: try to make it produce obscene or inappropriate output, and probe how it answers 'are you a real person?'. The target answer for the second is honest — AI-assisted, never claiming to be human, but not opening cold with a blunt declaration either. The method is a red-team prompt set covering jailbreaks and prompt injection alongside identity probes, one prompt per thread from a controlled test inbox, every reply captured verbatim into a tracker scored by category and severity, guardrail changes, then a re-run. A separate battery covers the six inbound messages that actually arrive: data-source questions, deletion and unsubscribe requests, support issues, programme complaints, credit requests and job enquiries — with the privacy requests treated as hard failures if not honoured.
Measure the AI against the humans doing the same job
The stated evaluation is a before-and-after comparison of reply rates over equivalent windows against the existing outsourced team's performance on the same motion, rather than an absolute target. The agent is framed as augmentation for regions where a human team does not exist and would not be hired, not as a replacement for the regions where one does.
Investigate the AI-write-access problem before building a control for it
The instinct was to cut everyone off and re-provision with tiered permissions. Instead we measured it: a few hundred records created by assistant tooling over a full year, about a quarter of them missing an email address, against a base creating records at a far higher rate. At that volume the customer's own call was to leave it and revisit, backed by a governance dashboard and a rep enablement session rather than a lockdown. The tiered control was scoped as a feasibility spike — a thin proxy between the assistant and the CRM that whitelists allowed tools, objects and fields, blocks field overrides and bulk creation, and gates by permission tier using a scoped token — and deliberately ranked below the agent work.
Turn off the notifications before you bulk-update
A previous bulk activation had fired hundreds of channel alerts and rattled the team. That produced a standing audit: scan every workflow for notification actions, quantify how many send and where they land, and build a bulk redirect and rollback path so a large change can be made without lighting up the company. The first scan covered roughly 340 workflows and found about 40 with notification actions and about 110 send steps, with a single channel receiving most of them.
#Outcomes
The routing waterfall is live and backfilled
Routing country and its source stamp populate across the contact base, backfilled to roughly 150,000 records including contacts with no associated company. The customer switched the new contact-based territory workflow on themselves and turned the old company-based one off the same day.
The meeting briefing note is live
Notes are being generated on booked meetings and written to every contact on the meeting and account, with a walkthrough recorded for reps. This fixed a gap hitting roughly two to three of every ten booked meetings.
The outbound agent is built and running in shadow mode, not live-sending
Both workflows exist in the CRM with enrolment criteria, exclusions and the three-way decision branches in place. At the latest evidence the reply handler was being narrowed and the adversarial stress test had not yet been executed. There are no reply-rate, meeting-booked or volume results, and there should not be any claimed.
The AI write-gating control was scoped and deliberately deprioritised
Measurement showed the problem was smaller than it felt. The proxy design exists as a feasibility spike with a defined architecture and effort estimate; it has not been built, and the customer chose enablement and monitoring first.