The whole design, in writing
Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.
The big idea
An agent that writes into a shared, trusted system
Unlike a personal email inbox, a CRM is a SHARED system of record — every rep, sales manager, and automated report depends on it being accurate. An agent here isn't just risking one user's data; a bad write corrupts something many people and processes trust. And for anything relationship-sensitive (an actual sales conversation), the agent needs to stay a suggester, not an autonomous actor.
We'll build around those two constraints: multi-source enrichment with real provenance tracking, lead scoring, rigorous write-back validation before anything touches the shared CRM, and a suggest-don't-act default for outreach.
What the new pieces do
- Sales Repclient
- Wants research and busywork automated, but stays the primary actor for anything relationship-sensitive — the agent suggests, the rep decides.
Step 1 · The baseline
Manual research, lead by lead
Simplest version: a rep manually researches each lead — company background, contact role, recent news — one at a time. What's the real cost?
Reps manually research every lead individually. What's the actual cost of this approach?
Manual research quality can be good, but it doesn't scale — a rep spending most of their time researching rather than actually engaging prospects is a real, significant opportunity cost, especially across a large lead volume.
Every minute spent manually looking up company details or a contact's role is a minute not spent on the conversations and relationship-building that actually drive sales — automating the research (not the relationship) targets exactly this misallocation of a scarce resource: rep time.
The time cost of manual research scales with lead volume per rep, which is a real constraint even for smaller teams — it's not exclusively a large-team problem.
Manual research consumes a large share of a rep's limited time on data-gathering rather than the actual selling and relationship work that drives revenue. Automating research — not the relationship itself — targets this specific misallocation.
Why this piece earns its place
Worth naming what manual research costs beyond the hours. The result lives in a rep's head and in their own notes, in whatever shape they chose, so two reps working comparable accounts record different things. There is no common set of fields across leads, and the steps that have to compare leads are the ones that die without it: scoring needs the same signals present on every lead to rank them against each other at all, and a freshness check needs a date to compare against. The drafting steps still function on hand research — they just function unevenly, richly for the account somebody dug into and thinly for the one nobody got to, with no way to tell which you are looking at. And the gap stays invisible until someone asks why the pipeline report disagrees with itself. The second cost lands on reassignment. A rep leaves or a territory is redrawn, and the research walks out with them — the new owner restarts from nothing on an account that has been worked for months. Where you would skip this: a team running a handful of named enterprise accounts, where the research is the relationship work and one account justifies weeks of a human reading everything. Automation pays off against volume, not against depth.
What the new pieces do
- CRMgateway
- The shared database every rep, manager, and downstream report depends on — a bad write here doesn't just affect one person, it corrupts a shared asset.
Step 2 · Multi-source enrichment with provenance
Sources disagree and go stale
Automate lead enrichment by pulling company and contact data from multiple external sources. Different sources can disagree with each other, and any of them can go stale. Should the system just trust whichever source it checks first?
Multiple external data sources are used for enrichment, and they can disagree or go stale. How should this be handled?
Blindly trusting the first-responding source ignores that sources vary in reliability and freshness — a fast but stale or unreliable source could confidently supply wrong information with no way to know it might be outdated.
Explicit provenance tracking means every downstream use of enrichment data can account for how reliable and how CURRENT it actually is — a fact from a frequently-updated, generally-reliable source is treated differently than a stale or less-reliable one, rather than flattening all enrichment data into equally-trusted facts.
A single source misses coverage a multi-source approach provides, and doesn't solve the freshness problem either — a single source can still go stale over time, so the underlying issue isn't actually avoided.
Track Source Provenance explicitly — which source supplied each fact, and how recently it was verified — rather than treating every enriched data point as equally trustworthy. This gives downstream consumers the information needed to weigh reliability and catch staleness before acting on outdated data.
Why this piece earns its place
The decision that gets expensive later is granularity. A single last_verified timestamp on the lead record is the obvious first cut and it is close to useless: the record was assembled from several sources at different moments, so one date either condemns the whole record because one field aged out, or blesses it because one field was touched yesterday. Provenance belongs on the field — title, headcount, funding stage each carrying their own origin and date. Retrofitting that means backfilling every record already written, because you cannot reconstruct which source supplied which value after the fact. Field-level provenance also buys something you will need on a Tuesday with no warning: when a data vendor is dropped or a contract lapses, you can find exactly the facts that came from it and re-verify only those. Without it, losing a source means re-enriching the entire database or quietly keeping values nobody can stand behind any more.
What the new pieces do
- Lead Enrichmentservice
- Pulls company and contact data from multiple external sources — which don't always agree, and go stale at different rates.
- Source Provenancedata
- Tracks where every piece of enrichment data came from and how recently it was verified — the basis for trusting (or flagging) any given fact.
Step 3 · Score and prioritize leads
Focus effort where it's actually likely to pay off
A rep has far more leads than time to pursue each equally. Should all leads get equal attention?
A rep has many more leads than time allows pursuing equally. Should attention be spread evenly?
Equal effort across leads with wildly different actual conversion likelihood means real time gets spent on low-probability leads at the expense of the ones most likely to actually close — "fair" in this sense doesn't serve the actual goal.
Lead scoring directs a rep's genuinely scarce time toward leads statistically most likely to actually convert, using the enrichment data already being gathered — a materially better use of limited effort than spreading it evenly regardless of likelihood.
Recency alone says nothing about actual conversion likelihood — a lead that arrived yesterday but shows weak fit signals shouldn't automatically outrank a stronger, slightly older lead.
Add a Lead Scoring model that ranks leads by predicted conversion likelihood, using enriched signals, and surfaces that priority to the rep — directing scarce time toward the leads statistically most worth pursuing.
Why this piece earns its place
A score is derived state, and derived state is where quiet wrongness lives. It was computed from a particular set of enriched facts; enrichment then updates and the score sits there unchanged, ranking a lead on a headcount or a funding stage that has since been overwritten. So re-scoring should hang off the write that changed the inputs rather than off a pass over the whole database on a timer. That is affordable here in a way it deliberately is not for the freshness checks in Step 8, and the asymmetry is worth naming rather than leaving as an inconsistency: re-scoring is local compute over data you already hold, while re-verifying a fact is an outbound call to a source that bills for it. Free derived work can be eager; work that costs money per record waits until somebody needs that record. Two knobs also belong in different places. What the model emits is a likelihood. Where the cut line falls — how far down the list a rep gets in a week — is a capacity decision, not a modelling one, so it lives in team configuration and moves without retraining anything. And ship the reasons beside the number: a bare score invites the rep to argue with it in general, where two named signals let them disagree specifically — the only kind of disagreement you can learn from.
What the new pieces do
- Lead Scoringservice
- Ranks leads by predicted conversion likelihood, so limited rep time and effort goes toward the leads most worth pursuing.
Step 4 · Protect the shared system of record
A bad write corrupts something everyone trusts
Enriched and scored data needs to be written back into the CRM. Should writes happen automatically and immediately, with no validation?
Enrichment writes need to land in the shared CRM. Should they write immediately with no validation?
An unvalidated write can create duplicate records, overwrite a more-reliable existing value with a less-reliable one, or introduce inconsistent data — and because the CRM is SHARED, that corruption affects every rep, manager, and report relying on it, not just one user.
Because the CRM is a shared system of record many people and automated processes depend on, a bad write is far more consequential than a bad write to one person's private data — validating before commit, and blocking writes entirely if the validator itself is down, protects the shared asset from corruption.
The reasoning for validating writes (protecting shared data integrity) applies to any automated write path, not uniquely to this specific agent — though this design specifically focuses on the agent's own write path, the underlying principle isn't agent-specific.
Add a Write Validator that checks every enrichment write for duplicates and consistency before it commits to the CRM — and fails closed: while the validator is unavailable, writes queue rather than risking corruption of a system of record that many people and downstream processes trust.
Why this piece earns its place
Failing closed is the easy half. The hard half is draining the queue. A held write was computed against the record as it looked an hour ago, and in that hour a rep may have edited the same field by hand. Replaying it blindly overwrites a human correction with a machine guess, which is the fastest way there is to lose a sales team's trust in the whole system. So queued writes should be conditional — carrying the record version they read, failing if it moved — and a human edit should win the tie rather than being silently reapplied over. The other place the effort goes is duplicate detection, where the two error directions are not symmetric. Two records for one company is annoying and reversible. Merging two genuinely different companies with similar names destroys history nobody can pull apart afterwards, because the writes that built it are gone. Bias the matcher against merging and route ambiguous pairs to human review: an unmerged duplicate is a task, a bad merge is an incident.
What the new pieces do
- Write Validatorservice
- Checks every write for duplicates and consistency before it lands in the shared CRM — protecting a system many others trust from corruption.
Step 5 · Suggest, don't act
The agent proposes; the rep decides
The system has enriched, scored, and can draft outreach for a lead. Should it autonomously send that outreach, or something else?
A drafted outreach message is ready for a promising lead. Should the agent send it autonomously?
Sales outreach is inherently relationship-sensitive — tone, timing, and specific phrasing matter to a real human relationship in ways that are hard to fully validate automatically, and a wrong or poorly-timed autonomous message can damage a real prospect relationship in a way that's hard to undo.
Defaulting to suggestion rather than autonomous action respects that sales outreach carries relationship stakes an automated check can't fully capture — the rep's judgment stays in the loop for the actual send, while the agent still saves them the drafting and research effort.
Even a high-scored lead is a real relationship with real stakes if the outreach is wrong or mistimed — a high score reflects conversion LIKELIHOOD, not confidence that a specific automated message is appropriate to send unreviewed.
Default the Outreach Drafter to suggestion, not autonomous action: it proposes a next-best-action (a drafted email, a recommended call) but the rep remains the one who reviews and actually sends or acts. This keeps a human as the primary actor for anything relationship-sensitive, while still eliminating the drafting and research burden.
Why this piece earns its place
Two things about suggestions only show up once people use them. First, the edit is the signal. When a rep rewrites a draft before sending, the difference between what was proposed and what actually went out is the most useful data this system produces — it says precisely where the drafter is wrong, for free, from someone who knows. That signal only exists if both versions are kept: store the outcome alone — sent or discarded — and the most informative thing the rep produced is thrown away at the moment they hit send, leaving the drafter to be improved by guesswork. Second, the message goes out under the rep's name, so the rep carries whatever it claims. That means the review surface has to show the facts behind the draft and where they came from, not just the prose — nobody can sanity-check a line about a funding round without being told which source said so and when. And suggestions need an expiry. An unreviewed pile is a second inbox, and a week-old draft rests on a week-old picture of the account, which is the staleness problem arriving through a different door.
What the new pieces do
- Outreach Drafterservice
- Drafts personalized outreach using real enrichment data — proposed to the rep, who remains the one who actually sends it.
Step 6 · Personalize at scale without genericness
Real data, not mail-merge
Drafting outreach for many leads at once risks reading as obviously mass-produced, generic content — the opposite of what makes outreach effective.
Draft outreach using actually-relevant enrichment data — recent company news, a specific role-based pain point, a concrete detail from provenance-tracked research — rather than templated mail-merge with only a name swapped in. The scale comes from automating the RESEARCH and drafting effort, not from producing identical content with superficial substitution.
Why this piece earns its place
The interesting case is the lead with nothing specific about it — thin enrichment, a company nobody has written about. A drafter that must always produce something personalized will reach for the weakest detail available, and a stretched specific reads worse than a plain sentence: it is visibly a machine that tried. So the drafter needs permission to write something short and unremarkable, or to hand back a blank, and every concrete claim it does make should trace to a provenance-tracked fact rather than to the model's own sense of what a company like this is probably doing. The consequence nobody plans for is the second one. A rep's drafting time was an accidental rate limit, and removing it removes the natural ceiling on outbound volume along with it. Sending capacity now has to be a number somebody deliberately chose, per rep and per domain, because the cost of getting that wrong is not one bad email — it is a sending reputation that is slow to rebuild and shared by everyone on the team.
Step 7 · Automatic activity logging
Pipeline visibility without manual data entry
Sales pipeline reporting depends on accurate records of every call, email, and meeting. Should reps be responsible for manually logging every interaction?
Automatically capture and log every interaction — calls, emails, meetings — into the Activity Log, feeding back into the CRM without requiring reps to manually re-enter what already happened. This keeps pipeline reporting accurate and current without adding administrative burden that competes with the actual selling time this whole design exists to protect.
Why this piece earns its place
The hard part of auto-capture is that one real-world interaction arrives more than once — a meeting from the calendar and again from the thread that scheduled it, a call from the dialer and again from the follow-up mail. So the log needs an idempotency key derived from the event itself, participants plus a time window, rather than a row id minted whenever a connector happens to notice. Get it wrong and nothing errors: the log simply counts one conversation twice, and a pipeline report claiming a rep had twice the conversations they had is the least useful kind of wrong, because it is confidently precise. This is also the one store here that should be append-only. Activity is evidence about what happened, so a mistake is corrected with a new entry, never by editing the old one — the moment history becomes editable, a forecast built on it stops being defensible to the first person who asks how it was derived. And draw a line at content. That a call happened, with whom, for how long, is CRM data; what was said in it is a recording, and capturing that carries consent rules that vary by jurisdiction — a setting somebody signs off on per region, never an agent default.
What the new pieces do
- Activity Logdata
- Every call, email, and meeting logged automatically, keeping pipeline reporting accurate without manual rep data entry.
Step 8 · The sharp edges
Stale facts and a scoring model that drifts
Two real risks: enrichment data that was accurate when gathered but is now outdated (a contact changed roles months ago), and a lead-scoring model whose predictions quietly degrade as market conditions shift.
Apply freshness thresholds using the Source Provenance data — enrichment past a certain age gets flagged for re-verification before it's used in outreach, catching exactly the kind of stale-fact embarrassment (congratulating someone on a role they've left) that undermines trust in the whole system. For scoring, apply the same drift-monitoring principle used for any production ML model: track the scoring model's real-world accuracy over time and re-validate or retrain as market conditions shift, rather than assuming a model validated once stays accurate indefinitely.
Why this piece earns its place
A freshness threshold can only flag — the replacement fact is a source call nobody has made yet — so what the solution leaves open is what happens in that gap, and both obvious answers are bad. Hold the draft until re-verification lands and the rep queues behind an API to reach a lead already talking to a competitor. Drop the aging field silently and the draft gets thinner with nobody told why. Show the age on the fact and let the rep judge whether it matters for the sentence they are writing. Two details make the threshold workable: age belongs per field, since a founding year does not rot while a job title does; and a re-verification returning unchanged is itself a write, because confirming a fact resets its clock. Skip that write and the field fails every cycle while you buy the same answer again. On drift, the awkward part is that the label arrives late: whether a lead converted is known long after the score was assigned, so an accuracy number always reports on a model version you have already replaced. Watch the inputs, available the same day — the distribution of enriched features going in, and the rate at which top-ranked leads are actually being worked. If reps quietly stop trusting the ranking, that shows up in their behaviour well before it shows up in conversion data.
You did it
You just designed a sales CRM agent.
Everything you assembled, in order
- Manual lead research consumes rep time that's better spent on actual selling — automate the research, not the relationship.
- Multi-source enrichment needs explicit provenance tracking (source and freshness) since sources disagree and go stale at different rates.
- Lead scoring predicts future conversion likelihood, directing scarce rep time — a genuinely different, more predictive problem than simple urgency triage.
- Writes to the shared CRM are validated and fail closed, because a bad write corrupts a system of record many people and processes trust, not just one user.
- The agent defaults to suggesting next actions, not autonomously executing them, keeping a human as the primary actor for relationship-sensitive outreach.
- Personalization at scale comes from using real, relevant enrichment data, not mail-merge templating.
- Automatic activity logging preserves pipeline reporting accuracy without reintroducing the manual burden the design set out to remove.
- Freshness thresholds and ongoing scoring-model drift monitoring catch stale data and degrading predictions before they cause real harm.