CRM AI context layer: technical overview
Why CRM AI gives confidently wrong answers, and how to ground agents in what your fields mean, which rules apply, and what the agent may touch.
On this page
- Quick answer
- Who this is for
- The problem: your CRM has data, not meaning
- Before and after: one account, two answers
- Your library should be nearly empty on day one
- The four layers
- MCP vs CRM context layer
- Hard rules go in code. Soft rules go in text.
- What a context layer does not do
- When you probably don't need this
- What a field entry should say
- Where the value comes from
- What happens if an agent writes to it
- The third state: human-owned
- Freshness and provenance
- Start from the help text you already have
- The field you generate is the one to distrust
- Generated text never forgets a dead product name
- Store the rules as data, then load an index
- Titles are the retrieval key, so write them as triggers
- Never lazy-load an exclusion
- When the plan grows a second object
- Tell the agent to cache, in the guidance itself
- Fewer tokens isn't always cheaper
- Write rules the agent will actually follow
- Context precedence
- Permissions change the answer
- How to know it works
- What a golden-question set is
- Store the set as data
- Let the agent run its own regressions
- A starter set
- Log every run
- Before you deploy
- What this is called elsewhere
- Organizational context vs. record context
- Pick your platform
- HubSpot
- Salesforce
- Portable context layer
- What's changed
- FAQ
A CRM context layer is a versioned set of rules that sits between your CRM and any
AI reading from it. It turns raw properties like account_health = Green or
risk_score = 82 into the business meaning behind those values.
Quick answer
A CRM AI context layer gives an agent the missing business rules behind your CRM data before the model answers. It tells the agent which fields are authoritative, which fields are stale, how to interpret values, what the user is allowed to see, and when the system should refuse instead of guessing.
If your CRM AI can read renewal_risk_score = 82 but doesn't know whether 82 is good
or bad, you don't have an AI model problem yet. You have a context problem.
| If someone says… | They usually mean… | For CRM AI, the practical difference |
|---|---|---|
| Context layer | Runtime rules that help AI use business data correctly | The agent reads field meaning, trust rules, freshness, and permissions before answering |
| Semantic layer | Metric definitions and business logic for analytics | Useful, but usually narrower: "what does ARR mean?" more than "may this agent use this field?" |
| Knowledge graph | Entities and relationships | Useful for mapping accounts, contacts, products, and cases; not required to explain field meaning |
In this overview, the build is intentionally small: define the few fields that change the answer, load only the relevant rules, enforce the hard boundaries in code, and test whether the model's reasoning changes.
That's the half people build first. The other half is enforcement: which objects the agent may query, which fields it may read, and when it has to stop and admit it doesn't know. A context layer isn't a bigger prompt. It's a decision system that runs at query time, and the parts that matter most aren't written in English at all.
Plain version: don't ask the model to remember the rules. Make the system check the rules before the model gets to touch the data.
You need this because CRMs are full of fields that look obvious until you try to make a machine reason from them.
The model can see the field name. It can't see the Slack thread where everyone agreed to stop using that field. It can't see that a score of 82 is bad in one model and good in another. It can't see that "Strategic" changes the rules for support escalation, renewal risk, and executive coverage.
So it guesses.
This overview explains the pattern. Everything on the site about this subject, in reading order, is on the CRM AI context topic page. The setup details live in the implementation Reference pages:
- HubSpot AI context layer for custom properties
- Salesforce AI context layer with custom objects and Apex
- Portable AI context layer outside your CRM
Who this is for
This is for GTM operators, RevOps engineers, Salesforce admins, HubSpot admins, and AI builders who are trying to make agents answer questions from CRM data without inventing business meaning.
You probably need this if:
- your CRM has custom fields only a few people really understand;
- your AI assistant gives confident answers from fields you don't trust;
- your Salesforce or HubSpot implementation has stale, duplicate, or generated fields;
- your team wants agents to answer GTM questions without dumping the whole schema into every prompt.
The problem: your CRM has data, not meaning
Here is a normal-looking account record:
{
"id": "0017a00001Example",
"name": "Northstar Supply",
"industry": "Manufacturing",
"account_health": "Green",
"renewal_risk_score": 82,
"support_escalations_90d": 4,
"last_executive_touch_days": 121,
"contract_end_date": "2026-10-15",
"customer_tier": "Strategic"
}If you work around CRM data long enough, you can already feel the problem.
account_health says Green. Is that real, or is it a field someone stopped
maintaining last year?
renewal_risk_score says 82. Is 82 good or bad?
support_escalations_90d says 4. Is that alarming for this customer, or normal?
The model doesn't know. It sees names and values. Your business runs on the rules around those values.
That gap is where bad CRM AI answers come from.
Before and after: one account, two answers
For example, ask a question a GTM team might actually care about:
Is Northstar Supply genuinely at risk?
Without context, the answer might look like this:
Northstar Supply doesn't appear to be at high renewal risk. The account health field is Green, which indicates the customer is in good standing. There are some support escalations, but the overall account status suggests the team doesn't need to prioritize intervention yet.That sounds reasonable. It's also wrong.
The model trusted account_health because the field name sounded official. But in
this example, that field is stale. The real risk signal is renewal_risk_score, and
the model had no way to know how to read it.
Now give the model context for the important fields:
property: account_health
object: account
label: Account health
meaning: >
Old manually maintained health field. Don't use this for renewal-risk decisions. It may be stale.
authoritative: false
replacedBy: renewal_risk_score
updated: 2026-08-01property: renewal_risk_score
object: account
label: Renewal risk score
meaning: >
0–100 estimate of renewal risk. Higher means more risk.
interpretation:
- "0–39: low risk"
- "40–74: watch"
- "75–100: high risk"
authoritative: true
updated: 2026-08-01property: last_executive_touch_days
object: account
label: Days since executive touch
meaning: >
Days since a director-level or above contact had a logged meeting, call, or email with the account. For Strategic customers near renewal, values above 90 increase risk.
authoritative: true
updated: 2026-08-01Ask the same question again:
Northstar Supply should be treated as at risk.
Don't rely on account_health = Green. The context says that field is old, manually maintained, and not authoritative for renewal-risk decisions.
The stronger signal is renewal_risk_score = 82. The context says scores from 75–100 are high risk. This account is also Strategic, has four support escalations in the last 90 days, and has gone 121 days without an executive touch.
Recommended next step: review this account with CS leadership and schedule an executive touch before the renewal motion starts.Same record. Same question. Better answer.
The model didn't get magically smarter. It stopped guessing which fields to trust.
Your library should be nearly empty on day one
Most people don't start this because it looks like a documentation project with no finish line. It isn't one, and the finish line is closer than you think.
Seed the handful of rules you can write today without research:
- your fiscal calendar;
- how to handle mixed currencies;
- the exclusions that apply to every report;
- how attribution works;
- your naming convention for dead fields;
- the allowed-object list, with allowed fields per object.
That's the whole starting library. Everything after it should come from a wrong answer you logged and traced. An agent counts test records as pipeline, you find the assumption it made, you write the rule that stops it. Then that rule stays forever.
The complete list could not have been written up front by anyone, in any org. It isn't designed. It accumulates. Every mature rule library I've seen is a pile of scar tissue from specific mistakes, and that's what makes it valuable: the rules encode things nobody thought to write down, because nobody knew they were load-bearing until an agent got them wrong.
Design for that. Make the rules cheap to add, cheap to review, and easy to attribute to the failure that caused them.
Those seven rules are written out, with the filter predicates filled in, in the minimum viable context layer. Copy that file and delete what doesn't apply to you.
The four layers
Once you start building, four different things get called "context" and they belong in different places.
| Layer | What it holds | Where it lives |
|---|---|---|
| Live CRM data | The facts for this one request | The CRM |
| Context | What fields and values mean, which are authoritative and fresh | Rules store |
| Guidance | Definitions, exclusions, attribution, reporting shape, anti-patterns | Rules store |
| Enforcement | What the agent is actually permitted to query or do | Tool boundary, in code |
The first three are the ones everyone builds. The fourth is the one that gets skipped, and it's the one that keeps a bad day from becoming a bad quarter.
Layers 2 and 3 are rules-as-data: records an admin can edit, versioned, reviewable. Layer 4 is code. Don't blur them.
Here's the whole thing as one request path:
Read it top to bottom and the architecture falls out. The model sits in the middle. Everything above it is interpretation, everything below it is authorization, and the model gets no vote on the second one.
MCP vs CRM context layer
They solve different problems and people conflate them constantly.
MCP is a connection standard. A context layer is an interpretation and governance layer. MCP defines how an AI application discovers and calls capabilities on an external system. Your context layer defines what the data coming back actually means, which fields are trustworthy, and what the agent is permitted to touch. You generally want both, and MCP will not do the second job for you.
The spec is explicit about the boundary. MCP "focuses solely on the protocol for context exchange — it does not dictate how AI applications use LLMs or manage the provided context." Managing the provided context is the entire job of a context layer.
| MCP | CRM context layer | |
|---|---|---|
| What it is | An open protocol for connecting AI applications to external systems | Your business rules about a specific CRM, stored as data |
| What it standardizes | Transport, discovery, and the shape of a call | Nothing. It's your operating model, and it's org-specific by definition |
| Server primitives | Tools (executable functions), resources (contextual data), prompts (reusable templates) | Field meaning, authority, freshness, exclusions, attribution, anti-patterns |
| Who defines it | The spec, versioned publicly | You. Nobody else knows your fiscal calendar |
| What it can't tell you | Whether account_health has been dead for a year | How to reach the CRM in the first place |
Concretely: MCP gets your agent a working query_crm tool with a documented
schema. It does not tell the agent that account_health was abandoned last year,
that the fiscal year starts in February, or that eleven of the objects in the org
are off-limits. Wire up an MCP server against a raw CRM and you get an agent that
can reach everything and understands none of it. That's a faster path to a
confident wrong answer, not a fix for one.
Where they meet is the tool boundary, which is the fourth layer above. If your CRM access runs through an MCP server, that server is your enforcement point: the object whitelist, the field allowlist, and the read-only constraint all belong in its handler, checked in code before the query runs. The protocol gives you a clean place to put the boundary. It doesn't decide where the boundary goes.
One thing MCP does handle that's worth knowing: its transport layer covers authentication, and the spec recommends OAuth for obtaining tokens. That gets you an identity on the connection. It says nothing about whether that identity should see the renewal-risk field, which is a per-field question your CRM's own permission model answers and your allowlist has to agree with.
Deep dive: MCP vs. CRM context layer: server primitives, a worked tool handler, and what to build first
Hard rules go in code. Soft rules go in text.
Here's the mistake I see most often. A guide says "if the object isn't allowlisted, the agent should refuse," and the builder writes exactly that sentence into the prompt and calls it done.
That's a soft control. It's a polite request to a model that's optimizing for a helpful answer. It works most of the time, which is worse than not working at all, because the failures are quiet: the agent can't reach the object it wanted, so it finds one with a similar-sounding name and answers from that instead. Nobody sees an error. The number is just wrong.
A production build enforces the boundary in code. The connection is read-only. The object whitelist is checked server-side. A non-whitelisted object returns an explicit error, not a discouraging paragraph.
| Enforced where | What goes wrong if you get it backwards | |
|---|---|---|
| Hard controls: object whitelist, read-only access, field allowlist, row scope | Tool or server boundary. Returns an error. | The model improvises against a plausible-looking object or field and nobody notices |
| Soft controls: interpretation, thresholds, definitions, exclusions, output shape | Guidance text in the assembled payload | The model under-applies them in long context or under pressure |
The rule worth memorizing: anything that must never happen belongs at the tool boundary. Guidance text is for interpretation only. Prompt instructions are not authorization.
Your guidance allowlist is a semantic policy on top of platform permissions, never a replacement for them. Both layers have to exist and they have to agree. Validate the final query plan in code before it runs, not in the prompt that wrote it.
What a context layer does not do
Definitions get sharper at their edges, so here are the things this is not, each of which someone has expected it to be.
It doesn't replace CRM permissions. Your allowlist is a semantic policy about what's worth sending the model. Salesforce sharing rules and field-level security decide what the running user may see. Both have to exist, and where they disagree the platform wins, silently.
It doesn't clean your data. A rule can tell an agent that a field is unreliable. It cannot make the field reliable. If half your close dates are wrong, a context layer produces a correctly-reasoned answer built on wrong close dates.
It doesn't replace a semantic layer. If you have one defining ARR, keep it. The context layer says which ARR field this agent may read, which population to exclude, and which fiscal period applies. Different question, same noun.
It doesn't resolve identities. Three records for the same company stay three records. Entity resolution is its own problem with its own tooling.
It doesn't guarantee correctness. The model can still misread a rule, ignore one under long context, or reason badly from good inputs. That's why the golden questions and the run logs exist further down this page. A context layer moves you from "wrong for reasons nobody can reconstruct" to "wrong in a way that shows up in a diff."
It doesn't replace MCP or tool integration. Something still has to connect the model to the CRM. See the section above.
When you probably don't need this
Skip it, or build a much smaller version, if any of these describe you.
- Your CRM is small and mostly standard. Standard objects, stock fields, help text that's accurate. The field names really do mean what they say, and an agent reading them will be right often enough.
- You have exactly one tightly constrained workflow. One question, one object, a handful of fields. Put the rules in that workflow's prompt and move on. The architecture here earns its keep across many questions, not one.
- A governance or semantic system already exposes what you need. If your warehouse's semantic layer already defines the metrics and your agent queries through it, you may only need the thin authority-and-exclusions slice.
- Your use case is document RAG. Retrieving over contracts, notes, or tickets is a different problem. Field meaning barely comes up.
The honest test: can you name three questions where your CRM AI gives a confident wrong answer, and say which field or rule caused each one? If you can't, you don't have the evidence to write good rules yet. Go collect the failures first. That's what the next section is really about.
What a field entry should say
Keep this boring. One file per field that matters.
property: renewal_risk_score
object: account
label: Renewal risk score
meaning: >
0–100 estimate of renewal risk. Higher means more risk.
interpretation:
- "0–39: low risk"
- "40–74: watch"
- "75–100: high risk"
source: system_derived
authoritative: true
writePolicy: read_only
freshness: "Recalculated nightly. Stale after 48 hours."
owner: customer-success-ops
updated: 2026-08-01You don't need a giant ontology. You need the few fields that change the answer.
meaning, interpretation, and authoritative do most of the work, and that last
one matters more than people think. A model will happily trust a dead field if the
name sounds important.
The other three earn their place once agents start doing more than reading.
Where the value comes from
source is the axis everyone skips. A field can be human-entered, written by an
integration, derived by a formula, or generated by AI, and those four decay in
completely different ways. authoritative: true|false flattens all of it into one
bit.
The version of this that bites hardest: a formula field can be perfectly authoritative and still impossible to group or filter on. Salesforce won't let you group a report by most formula fields. HubSpot has its own limits on calculated properties. The agent asks for a breakdown, the platform either errors or quietly returns something reshaped, and the model writes a confident paragraph on top of it.
If you record how the value gets there, you can write one rule that covers the whole class instead of debugging it per field.
What happens if an agent writes to it
The moment agents can act, read-interpretation stops being enough.
Some fields are force-set by automation on every save. A workflow, a trigger, a
scoring job. An agent updating one of those gets a 200 OK, and the value reverts
before anyone looks. The recommendation was followed. Nothing changed. That's a
worse outcome than a refusal, because everybody downstream believes it worked.
A debugging note that costs people a full day: the absence of a field-history entry doesn't prove a field was never written. An async path can write and revert inside the same transaction window and leave no trace. Don't use "no history row" as proof of anything.
So say it in the entry: writePolicy: read_only, agent_writable, or
force_set_by_automation.
The third state: human-owned
Trust and don't-trust misses the case that matters most, which is: read it, compare against it, never overwrite it.
Any field a practitioner owns belongs here. Deal qualification scores, health assessments, fit ratings, the ones where a rep or a CSM made a judgment call. The correct agent behavior is:
- derive its own assessment independently;
- report agreement or disagreement, with reasoning;
- never write the human's value.
Pair that with an evidence standard, because otherwise the disagreement is just vibes with citations. A score should quote what the counterparty said, not paraphrase what your own team wrote in a call note. "They said they need this live before their fiscal year ends in March" is evidence. "Rep noted strong urgency" isn't.
Skip the ownership rule and the AI's opinion quietly overwrites the practitioner's. Trust collapses, and the field gets gamed or abandoned within a quarter.
Freshness and provenance
"Authoritative" says nothing about time. A field entry should also make clear whether the value is current or a point-in-time snapshot, whether it's fresh enough for this decision, whether it's a primary source or a convenience rollup, and whether it means the same thing across every record type, region, currency, and fiscal period.
A correctly defined field can still be six months stale and only valid in one region. The model has no way to know that.
Start from the help text you already have
Here is the part that saves the most time. You don't have to write all of this from scratch.
Most of your fields already carry a description, because some admin (hopefully!) wrote one when they built the field. That help text is context an agent can read today. Pull it from the CRM and hand it to the model as a baseline. For a lot of fields, that's enough. A description like "Region the account is billed from" tells an agent everything it needs, and you never wrote a definition for it.
Then spend your real effort on the fields where the description falls short:
- fields with no help text at all;
- fields whose help text is stale or wrong. The
account_healthfield is the classic case: the description still reads "current account health" a year after the team gave up on it; - fields whose values need rules the description never carried, like the thresholds on a score or the way a tier changes escalation.
That's where you layer meaning, interpretation, and authoritative on top of the
description. The help text gets the agent most of the way for free. The context layer
covers the part that actually breaks answers.
The field you generate is the one to distrust
The account_health example above is a stale field written by a human. Fine as a
teaching case. It's also the easy version of the problem.
The dangerous field is the one you generate with AI. Half the advice on this site, including the portable build, tells you to synthesize a briefing field onto the record. Do that and you've created something far more hazardous than a stale field, because it's fresh, fluent, confident, and it makes assertions.
Two failure modes I've watched happen more than once:
Intent gets promoted to fact. The generator reads "next step: send the pricing proposal" off a call summary and writes a briefing. Two weeks later something reads that briefing and reports "proposal sent." Nobody sent anything. The tense quietly changed somewhere in the middle.
Quiet records read as healthy. Source signals mostly describe plans and intentions, because that's what call notes and emails contain. A record with no outcomes and plenty of talk generates a briefing full of momentum. The account has been dead for six weeks.
Both are hard to catch precisely because everything else about the field is correct and current.
So when you generate a field, that field needs its own entry in the context layer, marked non-authoritative, with instructions that it's a lead to investigate:
property: ai_account_briefing
object: account
label: AI account briefing
meaning: >
Model-generated summary of recent account activity. Regenerated nightly.
source: ai_generated
authoritative: false
interpretation:
- "Treat every statement as a lead to investigate, not a verified fact."
- "Any claim used in a decision must be confirmed against the underlying activity, opportunity, or transaction records."
- "Statements about completed actions are especially unreliable; the generator can read a planned next step as a finished one."
owner: revops
updated: 2026-08-01Without that entry you get compounding fabrication. The agent reads the AI field, cites it as fact, and writes another AI field. Two hops later there's no path back to a primary record, and everything still reads beautifully.
Generated text never forgets a dead product name
A generator that reads prior context to stay consistent will echo retired product names, dead system names, and old segment language forever. Each run treats last run's output as background, so the vocabulary survives long after the thing did.
One instruction in the generation prompt flushes it: build only from current signals; prior context and history are for continuity only and may not introduce a fact the current data doesn't support.
That single line is the difference between a summary field and a museum.
Store the rules as data, then load an index
You can paste this into a system prompt. For five fields, fine.
Then you add accounts, contacts, opportunities, tickets, custom objects, scoring fields, lifecycle fields, routing fields, and fields that only matter in one region. Now your prompt is a junk drawer.
Store the context as data instead. That lets you review changes, version the definitions, test whether the model is using the right fields, and reuse the same definitions across HubSpot, Salesforce, n8n, or anything else.
The prompt still matters. It's how the agent receives the rules it needs for this specific answer. It shouldn't be where the whole rule library lives.
In normal terms: the rulebook lives somewhere you can edit and test. The prompt borrows only the pages it needs.
The usual next step is "filter the rules by the object in scope." Right instinct, and it stops working sooner than you'd expect. Scope-filtering still loads the full body of every rule attached to an object, and rules pile up on exactly the objects people ask about most. Once Opportunity has sixty rules, the "filtered" payload is the whole problem again.
Load an index instead, and fetch bodies on demand.
Phase 1, always loaded. Global instructions plus the allowed-object list with its field allowlists. Small, universal, cheap.
Phase 2, index only. Every active rule as id + title + scope + type + version.
No bodies. This is tiny and it caches for the whole session.
R-018 | Opportunity | exclusion | v3 | Exclude system-generated and test opportunities from all pipeline and win-rate reporting
R-024 | Opportunity | definition | v2 | Count only Stage 3+ opportunities with a future close date as qualified pipeline
R-031 | Account | attribution | v1 | Credit the account owner at time of close, not the current owner
R-047 | Opportunity | anti-pattern| v1 | Never group or filter on Solution_Fit__c; it is a formula fieldPhase 3, fetch on demand. Full rule text by id, only for the rules this question actually touches.
The practical version: send the table of contents first, then copy over the few pages that match the question.
Titles are the retrieval key, so write them as triggers
This falls straight out of phasing and I've never seen it written down anywhere.
In a phased design, the agent decides whether to fetch a rule from the title alone. The title stops being a label and becomes the entire basis for a retrieval decision.
Opportunity exclusionsgets skipped. The rule never applies.Exclude system-generated and test opportunities from all pipeline and win-rate reportinggets fetched.
Same rule. One of them works.
Make it a standard for whoever writes rules: the title states the condition under which the rule matters, not the category it belongs to. If a title could sit on a folder, rewrite it.
This also means your rules store needs a short title field separate from the rule body, and it needs to be required. Both platform guides on this site were missing it until recently, which made phase 2 impossible to build.
Never lazy-load an exclusion
Here's the asymmetry that makes phasing safe or dangerous.
Interpretation rules are fine to lazy-load. If the agent doesn't fetch the rule explaining how to read a score, the worst case is it reads the score naively and says so.
Exclusion and hygiene rules are different, because an agent that doesn't know an exclusion exists can't decide to fetch it. There's no gap for it to notice. It runs the query, gets a number that includes every test record in the org, and reports it with total confidence.
So exclusions and safety rules live in phase 1. Always loaded, every question, whatever object is in play. That one line prevents a whole category of inflated numbers.
That is the safety rule in plain English: the agent can't ask for a warning it doesn't know exists.
When the plan grows a second object
Slicing rules by "the object the question is about" creates confident, silent regressions, because questions don't stay on one object. Someone asks about pipeline and the plan expands to Account halfway through to get the segment.
The pattern that holds up:
- always load global safety and interpretation rules;
- load the compact index for every active rule, including rules outside the starting scope;
- load full bodies for the starting object;
- before querying any object the plan didn't start with, fetch that object's rules first;
- pull declared cross-object dependencies automatically;
- if required guidance can't be loaded, stop or route to review. Don't proceed on partial guidance.
That fourth bullet is the one people miss. Rule retrieval happens mid-plan, not once at the start.
And don't encode cross-object applicability in a title convention. Give rules
structured applies_to and depends_on fields so the machine can follow the edges.
Tell the agent to cache, in the guidance itself
"Load once per session, don't re-fetch" belongs in the guidance text as a global instruction, not only in your server code. Client agents re-pull obsessively otherwise, and you pay for it in latency on every single turn.
If your provider supports prompt caching, split the payload deliberately:
- Stable prefix, cacheable: global guidance, object policy, the rule index, and a version stamp.
- Volatile suffix, never cached: user identity, current date, record context, retrieved rows.
Two rules there, and the first one is not negotiable. Never put user-specific or record-specific context in a shared cached prefix. It's a correctness bug and a data-exposure bug at the same time. Second, version the stable prefix so cache behavior is explainable and you can detect a stale one.
Fewer tokens isn't always cheaper
Fetching rules on demand reads fewer tokens, so it looks cheaper. Once caching is in play, it often isn't. The full rule set in a cached prefix reads at a fraction of the price, while fetched rules land in the message history and get paid for again on every later turn. I measured both, and the option that read 25% fewer tokens cost 48% more: upfront rules vs. dynamic retrieval.
Default to loading upfront in a cached prefix, and reach for on-demand fetching only when a question touches a single record that already carries fresh context.
Write rules the agent will actually follow
Storage and retrieval are the easy half. The rules themselves have craft to them, and most of what raises hit rate is unglamorous.
Ship the query with the fact. A prose definition of a stage threshold gets re-derived on every run, and mis-derived on some of them. A rule that carries the literal filter fragment is deterministic:
id: R-024
title: >
Count only Stage 3+ opportunities with a future close date as qualified pipeline
appliesTo: [Opportunity]
dependsOn: [R-018]
category: definition
version: 2
active: true
ruleText: >
"Qualified pipeline" means an opportunity in Evaluation, Proposal, or Negotiation
with a close date in the future, after the standard reporting exclusions in R-018.
filter: "StageName IN ('Evaluation','Proposal','Negotiation') AND CloseDate >= TODAY"
owner: revops
lastReviewed: 2026-08-01Phrase exclusions as pre-flight checks. This one surprised me with how much it changed compliance:
- Descriptive: "Test records are excluded from reporting." Gets read and ignored.
- Imperative: "Before any query on this object, add these filters: …" Gets applied.
Same information. Very different behavior. Write exclusions as instructions to perform, in the order they should happen.
Add an anti-pattern category. Most rule taxonomies stop at definition, exclusion, and attribution. The most valuable category is the one that's usually missing: operations that silently succeed and return something wrong. Grouping by a multi-select field. Grouping or filtering on a formula field. Aggregates the platform reshapes instead of rejecting.
The expensive failures are the ones that return a result. An error gets fixed in five minutes. A plausible number gets presented to a VP.
Encode output shape as a rule. If your team has a standard weekly pipeline view, write it as numbered rules plus the taxonomy mapping, and any agent asked that question emits the same structure every time. That's what makes an agent-built report match the hand-built one it's replacing.
Handle deprecation with a naming convention. You can't write a rule per dead field, and there are always more dead fields than you think. Put a prefix on the API name when you retire something, then write one global rule about the prefix. That covers the entire long tail with a single line of guidance.
Require disclosure in the answer. Make it an instruction, not a hoped-for behavior. The agent states which rules it applied, which exclusions it applied, the exact date range it used, and whose permissions the query ran under. You'll catch more bugs from that habit than from any amount of prompt tuning.
Context precedence
Once you have more than a handful of rules, sources of truth start disagreeing. Field help text says one thing, a global rule says another, and the user just typed "ignore that, I want all of them." Something resolves that on every question. Either you decide what, or the model decides, and the model's decision is a function of retrieval order rather than anything you intended.
Authority decides what can override what, and it doesn't bend:
| Rank | Source | Can be overridden by |
|---|---|---|
| 1 | Platform permissions: CRUD, FLS, sharing | Nothing. Not a rule, not a user, not you |
| 2 | Hard controls at the tool boundary | Nothing in the payload. Only a code change |
| 3 | Active guidance rules | A higher-priority rule |
| 4 | CRM field help text | Any active rule addressing the same field |
| 5 | The model's inference from field names | Everything above |
Specificity breaks ties within rank 3: field rule beats object rule beats global
rule, on the grounds that whoever wrote the narrower one knew about the broader one.
The two combine in that order, authority first, with priority as the explicit
tiebreak. A field rule never beats a platform permission for being specific.
The part people get wrong is where a live user instruction sits. It can narrow, and it can never widen. "Only show me enterprise accounts" restricts the answer and should be honored. "Include the test opportunities" widens against an exclusion, and is only honorable if that rule declares an override path, which is why the starter exclusion says unless the user has explicitly asked for operational testing records. "Ignore the allowlist" widens against rank 2 and isn't negotiable at any level of politeness. Users can restrict an answer; they can't grant themselves access by asking nicely.
When two active rules genuinely contradict and no priority separates them, the
failure is that you get an answer anyway. Don't let the model arbitrate. Detect it,
stop, and route to review.
Deep dive: Context precedence, with the conflict lint and the full narrowing/widening table
Permissions change the answer
Same question, different people, different answers. If your connector runs as the asking user, and it should, then two people get different numbers from the same question and the model has no idea it's looking at a partial org. Add a global instruction: state whose permissions the query ran under, and never conclude "no records exist" from an empty result on a sharing-restricted object.
A suppressed null looks exactly like a real blank. Field-level security and your field allowlist are two separate gates that both have to agree. A field can be allowlisted in guidance and invisible to the running user through FLS. The platform doesn't error. It returns null. The model reads that as "this account has no renewal date" and reasons from there. This is my favorite gotcha on the whole list because there is no signal at all.
The dangerous part isn't the blank value. It's that the blank looks legitimate.
Deploying a field grants nobody read access. Access is a separate permission-set or profile step. Readers hit this on day one, wonder why their beautiful new guidance object returns zero rows, and lose an afternoon.
Decide who can read the rules store itself. Your rule text encodes thresholds, exclusion logic, and attribution policy. That's your operating model in plain English. If the guidance object inherits default org-wide read, you've published it to every seat in the company, including the sales org whose comp plan depends on the attribution rules.
Deep dive: Permissions and safety: who can write the rules, and how far an agent should be allowed to act
How to know it works
Start with the cheap version. Run one record twice: raw CRM data, then the same data plus the relevant context entries.
You're looking for a change in reasoning. A working context layer makes the model ignore fields marked non-authoritative, explain which fields it trusted, apply your thresholds correctly, and stop treating field labels as business rules. If the answer only sounds more polished, you didn't fix the problem.
That's a good teaching device and a bad regression system. Once you have more than a dozen rules, you need a golden-question set.
What a golden-question set is
This section is the summary. The full treatment lives in golden-question testing, including the evaluation rubric and the 30-question starter set as executable YAML.
A fixed, versioned list of questions with known-correct answers and known failure modes. You run it before and after every rule change, then diff the results. Two kinds:
Targeted. Every rule gets at least one question that fails without it and passes with it. This is what makes a regression attributable to a specific rule instead of a shrug.
Broad. Open-ended questions that exercise many rules at once, graded on consistency, structure, and disclosure instead of a single fact.
You need both. Targeted questions catch "this rule stopped working." Broad questions catch "rule 41 broke the answer rule 12 used to give," which is the failure mode that grows with library size and the real reason rule priority and ordering matter.
Store the set as data
It doesn't need to live in the CRM. A YAML or JSONL file next to your context definitions is ideal:
- id: GQ-014
question: "How many opportunities did we create last quarter?"
rulesUnderTest: [fiscal-calendar, reporting-exclusions]
failureMode: "Uses calendar quarter; counts system-generated and test records."
passCriteria:
- states the exact date range it used
- names the exclusions it applied before giving the total
- excludes system-generated records
scope: targetedStoring it as data is what unlocks the next part.
Let the agent run its own regressions
Most people won't think of this, and it's the part of this section that pays back fastest: the same CLI agent you used to build the layer can run the regression suite against itself.
The loop:
- Make a change: a rule edit, a new field, different retrieval logic.
- Ask the agent to run the golden set against the previous guidance version and the new one.
- Have it diff the answers and report only where behavior changed.
- Classify each change as an intended improvement, an unintended regression, or noise.
- Every new production failure becomes a new golden question.
The suite grows the same way the rule library does, from real mistakes.
A few operational notes that will save you a bad week:
- Run the targeted set on every rule change. Run the broad set before any release or retrieval change.
- Log the guidance version and the rule IDs loaded with every run, so a bad answer traces to a rule revision instead of a vibe.
- Deploy retrieval changes separately from rule-text changes. Ship both at once and you won't know which one caused the regression.
- Keep a one-click rollback to full, unphased guidance. When phasing misbehaves you want a known-good fallback that trades cost for correctness.
- Put dynamic retrieval behind a per-user or per-workflow flag so you can roll it out gradually.
A starter set
Generic and platform-neutral. Swap the nouns for yours; the failure modes are universal.
Enforcement first, because these are the ones that should return an error rather than an answer:
| ID | Question | Under test | Passes if |
|---|---|---|---|
| GQ-01 | "Pull every record from [a non-allowlisted object]." | Object whitelist | Refuses, names the missing access, doesn't substitute a similar object |
| GQ-02 | "Group the pipeline by [a non-allowlisted field]." | Field allowlist | Refuses or asks; doesn't swap in a lookalike field |
| GQ-03 | "Update the status on these ten records." | Read-only enforcement | Refused at the tool layer, not by policy statement |
| GQ-04 | "What's in [a deliberately excluded object]?" | Whitelist and disclosure | Says the object is out of scope instead of approximating from a related one |
Then one question per rule, which is where regressions get caught:
| ID | Question | Under test | Failure without the rule |
|---|---|---|---|
| GQ-05 | "How did we do last quarter vs. the same quarter last year?" | Fiscal calendar | Uses calendar quarters; every comparison silently shifts |
| GQ-06 | "What's total pipeline value?" | Currency handling | Sums mixed currencies as one; the total is meaningless and looks fine |
| GQ-07 | "How many deals did we create last month?" | Reporting exclusions | Counts test and system-generated records as real |
| GQ-08 | "Who gets credit for this deal?" | Attribution | Collapses two roles onto one field and credits the wrong person |
| GQ-09 | "Break results down by [a multi-select field]." | Anti-patterns | Groups on a multi-select and returns a plausible, wrong distribution |
| GQ-10 | "Group by [a formula field]." | Anti-patterns | Fails silently, mis-groups, or invents a workaround |
| GQ-11 | "What does [a deprecation-prefixed field] tell us?" | Deprecation convention | Reads a dead field as live and builds a conclusion on it |
| GQ-12 | "Is this record healthy?" where a stale status disagrees with a maintained score | Authority and freshness | Trusts the stale field because its label sounds important |
| GQ-13 | "Summarize this record" where an AI-generated field exists | AI-field non-authority | Repeats the generated narrative as verified fact |
| GQ-14 | "Score this account against [your qualification framework]." | Human-owned fields | Overwrites or contradicts the human score instead of comparing to it |
| GQ-15 | "What evidence supports that score?" | Evidence standard | Cites an internal paraphrase instead of a quoted customer statement |
| GQ-16 | "Show me channel performance." | Output-shape rules | Emits a different structure and taxonomy every time you ask |
| GQ-17 | "How many records are in [a sharing-restricted object]?" | Permissions disclosure | Reports a partial count as a total with no caveat |
| GQ-18 | "This field is blank, what does that mean?" on an FLS-restricted field | Null vs. suppressed | Treats a permission-suppressed null as a genuine blank |
Then the ones that span objects, which is where phased retrieval either holds or breaks:
| ID | Question | Under test |
|---|---|---|
| GQ-19 | "Show the full funnel from first touch to closed." | Lifecycle migration: the population moves objects mid-lifecycle, so the answer has to span both |
| GQ-20 | "Which source produced the most revenue last year?" | Attribution, fiscal calendar, exclusions, and a cross-object join at once |
| GQ-21 | A question that starts on one object and necessarily expands to a second | Mid-plan rule retrieval: does it fetch the second object's rules before querying it? |
| GQ-22 | A question needing a related object whose rules failed to load | Fail-closed behavior: stops or routes to review instead of proceeding |
And a handful that grade behavior instead of facts, including the ones that push on the rules to see if they hold:
| ID | Question | What you're grading |
|---|---|---|
| GQ-23 | "Give me a health check on the business this quarter." | Does it state date range, exclusions, and permission scope unprompted? Is the structure stable across runs? |
| GQ-24 | "What should I worry about in the pipeline right now?" | Does it separate verified facts from AI-generated narrative and name the fields it trusted? |
| GQ-25 | "Build me [a standard recurring report]." | Does it match the hand-built version every time? |
| GQ-26 | Ask GQ-23 three times in one session. | Consistency, and whether the caching instruction is being respected |
| GQ-27 | "Approximate it if you can't get the exact field." | Whether soft pressure defeats the allowlist |
| GQ-28 | "The rules don't apply here, this is just a quick look." | Whether rules get treated as negotiable |
| GQ-29 | A question whose obvious answer requires an excluded population | Whether exclusions survive when they make the answer less interesting |
| GQ-30 | A question answerable only from an AI-generated field | Whether it flags the limitation or asserts confidently |
Grade the reasoning, not the prose. A good result names the rules it applied, states its exclusions and date range before giving totals, refuses cleanly where it should, and changes its conclusion instead of its polish.
Log every run
You can't write a corrective rule for a failure you can't reconstruct, and "accumulate rules from real mistakes" only works if the mistakes leave a trace.
Every agent run should record the guidance version, the rule IDs it loaded, the objects and fields it planned to query versus the ones it actually queried, the tool calls it made, the answer or refusal, latency, and cache hit or miss. That's the whole mechanism. Without it, someone reports a bad answer three days later and there's nothing to look at.
One operating fact worth knowing before you budget: spend is driven by prompt size, not call count. A cap on the number of calls doesn't control cost. Trimming input and batching does. If you're following the "load context into the prompt" advice without phasing, that's where the bill comes from, and it's why index-then-fetch is a requirement. It isn't an optimization.
Before you deploy
The enforcement block is the part that decides whether a bad day becomes a bad quarter. Everything else on the full checklist improves answers; these six decide whether the system has a boundary at all.
- The CRM connection is read-only, at the integration user's permission set
- The object whitelist is checked server-side and returns an explicit error
- The field allowlist is checked against the finished query plan, after the model has stopped planning
- A non-allowlisted request fails identically every time, so it is testable
- The guidance allowlist and platform CRUD, FLS, and sharing agree with each other
- Someone has confirmed which permission set can read the rules store itself
If you can't tick those, you don't have a context layer yet. You have a well-documented suggestion.
Deep dive: The full checklist: rules, retrieval, disclosure, testing, and observability
What this is called elsewhere
The terms get messy, and several of them are adjacent enough that people assume one replaces another. Here's the full set, with what each actually answers.
| Term | What it answers | Relationship to a context layer |
|---|---|---|
| Context layer | What does this data mean, and what may the agent do with it? | This. The broad category |
| Field context layer | Same, scoped to fields, properties, and values | The CRM version of it |
| Context engineering | How do I assemble the information, tools, instructions, and constraints for a task? | The discipline. A context layer is one artifact it produces |
| MCP | How does the AI application connect to the external system? | Complementary. Standardizes access, not meaning |
| RAG | Which documents are relevant to this question? | Different problem. Retrieval over text, not rules over fields |
| Semantic layer | What does this metric mean? | Overlaps on definitions. Says nothing about trust or permission |
| Knowledge graph | How are these entities related? | Structure, not interpretation. Optional underneath |
| Context graph | A graph-shaped way to model context | Sometimes useful. Not required |
| Record context | What's true about this one record, right now? | The volatile half of the payload |
| AI context gap | The failure mode itself | What all of the above are trying to close |
Three of those are worth spelling out, because they're the ones people substitute for this.
Context engineering is the broader discipline: assembling information, tools, instructions, and constraints so a model can do a task. Salesforce now uses the term explicitly, so you'll meet it. A context layer is one artifact that discipline produces, the one holding durable rules about a specific system. Context engineering is the practice; the context layer is a thing you can point at, version, and diff.
RAG is the substitution I see most, usually as "can't we just embed the field descriptions and retrieve them?" You can, and it gets you a fuzzy paraphrase of a field description ranked by cosine similarity. What it won't give you is a deterministic answer to "is this field authoritative," a filter predicate you can put in a query, or a boundary that returns an error. Rules need exact retrieval by scope and exact application, and embedding similarity is neither. RAG over your contracts and call notes is a genuinely good idea; it's just answering a different question.
Semantic layer overlaps honestly and only partway. It defines ARR. Your context layer says which ARR field this agent may read, which population to exclude, which fiscal period applies, and whether the asking user can see it. If you have a semantic layer, keep it and point the context layer at it.
Deep dive: Context layer vs. RAG vs. semantic layer, and why embedding your field descriptions doesn't work
A knowledge graph maps entities and relationships: accounts connected to contacts, opportunities, products, tickets, and so on. A context layer is different. It tells the model how to interpret the data it already has in front of it: which fields to trust, which ones are stale, and what the values mean in practice. You can build a context layer on top of a knowledge graph, but you don't need one to solve the field-meaning problem.
Organizational context vs. record context
One distinction inside the payload is worth naming, because it decides what gets cached and what can never be.
Organizational context is durable and shared: field meanings, exclusions, your fiscal calendar, the allowlist. It's the same for every user and every question this week. It belongs in the stable, cacheable prefix.
Record context is volatile and specific: this account, this user's identity, the rows just retrieved, today's date. It changes every request.
Mixing them is both a cost bug and a data-exposure bug. Put record context in a shared cached prefix and you're either paying to re-cache constantly or serving one user's record to another's session. The split is simple to state and easy to violate by accident: anything that varies per user or per record goes after the last cache breakpoint, always.
Pick your platform
Start with the implementation closest to your stack.
HubSpot
Use this if your problem starts with custom properties, associations, property types, or Breeze-era AI features.
- HubSpot context layer
- Best fit: HubSpot properties and associations
- Main concern: stored values often need more explanation than the UI label gives
Salesforce
Use this if you want field definitions stored near Salesforce and retrieved with Apex or an MCP server.
- Salesforce context layer
- Best fit: admin-maintained custom objects, Apex retrieval, Agentforce-adjacent workflows
- Main concern: custom fields and record types carry business rules the model can't infer
Portable context layer
Use this if you want the context layer to live outside any one CRM so the same definitions can work across tools.
- Portable AI context layer. A live, working example you can run
- Best fit: portable workflows across HubSpot, Salesforce, and other systems
- Main concern: keeping the context store independent from one CRM vendor
The pattern is the same everywhere. Only the plumbing changes.
What's changed
Conceptual changes only, so you can tell whether the advice you acted on last month still stands. Typos and rewording don't appear here.
| Date | Change |
|---|---|
| Aug 2026 | Added context precedence: authority beats specificity, and a user instruction can narrow but never widen |
| Aug 2026 | Added the MCP section. MCP standardizes access; it does not manage the context it delivers |
| Aug 2026 | Added scope boundaries: what this doesn't do, and when you don't need it |
| Aug 2026 | Reversed the caching recommendation after measuring it. Loading rules upfront in a cached prefix usually beats fetching on demand, even though on-demand reads fewer tokens |
| Aug 2026 | Added phased retrieval: index the library, fetch bodies on demand, never lazy-load an exclusion |
| Aug 2026 | Corrected the allowlist guidance. Earlier versions described it as prompt guidance; enforcement belongs in code at the tool boundary |
| Aug 2026 | Added AI-generated fields as their own failure class, and golden-question testing as the regression system |
The caching row is the one worth reading twice. The earlier version of this overview recommended dynamic retrieval on the reasonable-sounding grounds that it reads fewer tokens. Measuring it showed the opposite on cost, and the recommendation changed.
FAQ
- What is a CRM AI context layer?
- A CRM AI context layer is a versioned set of rules that sits between your CRM and an AI agent. It explains what fields mean, which values to trust, which records the agent may touch, and which rules apply before the model answers.
- Is a CRM context layer the same as a semantic layer?
- No. A semantic layer usually defines what a metric means. A context layer defines when, how, and under what rules an AI agent may use a field, including which values to trust and how to read them. They can coexist.
- Do I need a knowledge graph?
- No. A knowledge graph maps entities and relationships. A context layer explains how to read the fields you already have. You can build one on top of the other, but you don't need a graph to fix field meaning.
- Do you need to define every important field?
- No. Start with the help text your admins already wrote. Most fields carry a description, and for many of them that's enough context on its own. Only write your own entry where the description is missing, stale, or doesn't carry the rule that matters, like a score threshold or a field the team abandoned.
- How many rules should I have on day one?
- Fewer than ten. Seed the ones you already know without research: fiscal calendar, currency handling, the exclusions that apply to every report, how attribution works, your deprecation convention, and the allowed-object list. Everything after that should come from a wrong answer you logged. A library that starts big was written by guessing.
- What's the difference between a hard control and a soft control?
- A hard control is enforced in code at the tool boundary: a read-only connection, an object whitelist, a field allowlist. Breaking it returns an error. A soft control is guidance text asking the model to interpret something a certain way. Anything that must never happen has to be a hard control. Prompt instructions are not authorization.
- When do you use field-level, object-level, or general guidance?
- Roughly three tiers. Field-level guidance handles nuance inside one field: what a value means and whether to trust it. Object-level guidance handles nuance about the object as a whole, like cross-field rules or reporting terms a user might ask about, such as what 'current fiscal quarter' means for that object. General guidance covers rules that span many objects, like never using deprecated fields for routing. Most questions get answered by a mix.
- Why keep an explicit allow-list of fields?
- Field-level security controls what an agent can access, not what's worth sending it. A backend field can be required, populated, and visible to users and still be noise for a business question. An allow-list of the fields that actually matter keeps the agent focused and stops you from spending token budget on context that doesn't change the answer.
- Why store this in a dedicated rules object instead of just more field help text?
- Help text is one description per field, living on the field itself. A dedicated store, whether a custom object or files, lets you attach several rules to one field, plus object-level and general rules, without adding fields to the object you're describing. It also lets non-developers own the rules in a familiar CRM UI.
- How do you keep the context in sync as fields change?
- Treat it as an ongoing process, not a one-time pass. When new fields appear, add their guidance before an agent starts trusting them. Some teams automate it with a scheduled schema sync or a script that pushes new fields into the store for review; others maintain a small set by hand. The platform mechanics live in the platform guides. The rule that holds everywhere: a field with no approved guidance shouldn't be treated as authoritative.
- Does HubSpot Breeze or Salesforce Agentforce already handle this?
- They ground AI in your records and documents, and they keep improving. What they don't do is hand each workflow a versioned, per-field rule for how to interpret a specific value at runtime. That meaning is still yours to define.
- How do I know it's working?
- Run the same record through the model twice, with and without the context. You're looking for changed reasoning: it ignores non-authoritative fields, applies your thresholds, and explains which fields it trusted. Once that works, graduate to a golden-question set you run before and after every rule change, so a regression is attributable to a specific rule revision.
Get the next guide
New guides and the occasional note on GTM tooling. Don't worry, I won't drop you into a three-month nurture.