The CRM context layer rule schema

· 9 min read· Salesforce · HubSpot

A canonical schema for CRM AI context entries: the governance envelope, field entries, rule entries, the thirteen rule categories, and a JSON Schema file you can validate against.

This is the canonical schema for a CRM AI context layer entry. The main guide develops it through examples; this page is the specification, so supporting pages and downstream tooling have one shape to agree on.

Two files, both stable URLs you can fetch or hand to a coding agent:

An entry is either a field entry, which explains what a CRM field means and how far to trust it, or a rule entry, which carries an instruction the agent has to apply. Both share the same governance envelope, because both need to be reviewed, versioned, retired, and traced back to whatever went wrong to cause them.

The governance envelope

Every entry carries these regardless of kind. Five are required.

FieldRequiredWhat it does
idyesStable handle. Never reused, never renumbered. Referenced by dependsOn, run logs, and golden questions
kindyesfield or rule
titleyesThe retrieval key. See below — this one does more work than it looks like
appliesToyesObjects governed, as an array of API names. ["*"] for universal entries
statusyesdraft · approved · active · deprecated. Only active reaches a production agent
categorynoOne of thirteen, listed further down
dependsOnnoEntry ids to load alongside this one
alwaysLoadnoShip with every question regardless of scope
versionnoIncrement on any change to meaning. Makes a regression attributable to a revision
prioritynoConflict resolution. Higher wins
effectiveFrom / expiresOnnoFor entries only correct inside a window
reviewAfternoFreshness SLA for the entry itself, not the field it describes
replacedBynoSuccessor entry id, set alongside status: deprecated
ownernoTeam or person accountable
evidencenoWhy this is true: a Finance definition, an automation, a policy doc
originFailurenoThe logged wrong answer that caused the entry to exist
testIdsnoGolden questions that fail without it and pass with it
lastReviewed / updatednoDates. Quote them in YAML so parsers return strings

Write the title as a trigger

The schema puts a 12-character minimum on title, which is a crude proxy for a real rule: state the condition under which the entry matters, not the category it belongs to.

In a phased retrieval design the agent decides whether to fetch a body from the title alone. That makes the title the entire basis of a retrieval decision, and category labels lose that decision every time.

  • Opportunity exclusions is a folder name. It gets skipped and the rule never applies.
  • Exclude system-generated and test opportunities from all pipeline and win-rate reporting gets fetched.

If a title could sit on a folder, rewrite it.

Three fields most people skip

dependsOn is what stops cross-object rules from getting stranded. A definition that assumes an exclusion has already been applied should declare it, rather than hoping both happen to be retrieved.

alwaysLoad encodes an asymmetry that matters more than it looks like. Interpretation rules are safe to fetch on demand; the worst case is the agent reads a value naively and says so. Exclusions are not, because an agent that doesn't know an exclusion exists cannot decide to fetch it. It runs the query, gets a number full of test records, and reports it confidently. Set alwaysLoad: true on every exclusion, anti_pattern, and security entry.

originFailure is the one that makes the library reviewable a year later. Most entries past the first handful exist because something got answered wrong once, and recording which failure turns the library from a pile of assertions into a record of what you learned.

Field entries

Additional properties when kind: field. property and meaning are required.

FieldWhat it does
propertyField or property API name
objectThe object it lives on
labelHuman-facing label, when it differs from the API name
meaningWhat the field means in plain language, including who or what writes it
interpretationHow to read the values: thresholds, bands, what each option signifies
valueMapStored value to meaning, for dropdowns where the API value differs from the UI label
sourceHow the value gets there
authoritativeWhether to trust it: true, false, or human_owned
writePolicyWhat happens if an agent writes to it
freshnessHow current, and how stale is too stale for a decision
primarySourcefalse for rollups and summaries
scopeCaveatsWhere the meaning doesn't hold: record types, regions, currencies, periods

source is the axis a single trust flag collapses:

ValueWhy it's distinct
human_enteredDecays through neglect. Someone stops maintaining it and nothing announces that
system_derivedReliable while the job runs. Fails silently when it stops
integration_writtenCarries the integration's timestamp and user, which destroys "recently modified" as a freshness signal
formulaCan be perfectly authoritative and still impossible to group or filter on
ai_generatedFresh, fluent, confident, and asserting things. Should almost always pair with authoritative: false

authoritative: human_owned is the third state binary trust misses. A rep's qualification score or a CSM's health assessment should be read, compared against, and reported as agreement or disagreement with reasoning. Never overwritten. Skip this state and the AI's opinion quietly replaces the practitioner's, trust collapses, and the field gets gamed or abandoned inside a quarter.

writePolicy: force_set_by_automation is the dangerous value. A field a workflow force-sets on every save will accept an agent's update, return 200, and revert. The recommendation looks applied and isn't, which is worse than a refusal because everyone downstream believes it worked.

a field entry
id: F-014
kind: field
title: >
  Read renewal_risk_score as the authoritative renewal signal where 75 and above
  is high risk
appliesTo: [Account]
category: interpretation
status: active
version: 2
property: renewal_risk_score
object: Account
meaning: >
  0-100 estimate of renewal risk, recalculated nightly by the scoring job.
  Higher means more risk. Reps do not enter this manually.
interpretation:
  - "0-39: low risk"
  - "40-74: watch"
  - "75-100: high risk"
source: system_derived
authoritative: true
writePolicy: read_only
freshness: "Recalculated nightly. Treat as stale after 48 hours."
primarySource: true
owner: customer-success-ops
originFailure: "Agent read account_health = Green and called a 82-risk account healthy"
testIds: [GQ-12]
updated: "2026-08-20"

Rule entries

Additional properties when kind: rule. ruleText is required.

FieldWhat it does
ruleTextThe instruction the agent receives
filterFragmentThe literal query predicate, where the rule has one
fieldAllowlistFor allowed-object entries: the fields an agent may read
outputShapeFor output_shape entries: the numbered structure a recurring answer must follow

Two things about ruleText change compliance more than anything else in this schema.

Phrase exclusions as pre-flight checks. "Test records are excluded from reporting" is a description, and descriptions get read and ignored. "Before any query on this object, add these filters: …" is an instruction to perform. Same information, materially different behavior.

Ship the predicate. A prose definition of a stage threshold gets re-derived on every run and mis-derived on some of them. filterFragment is deterministic, and it also gives you something to diff when the definition changes.

The thirteen categories

Naming the categories makes the library sortable, reviewable, and easy to reference from other pages.

CategoryWhat it governsAlways load?
definitionWhat a business term means: qualified pipeline, New ARRno
interpretationHow to read a value: thresholds, bands, stored optionsno
authorityWhich field wins, which is dead, which is human-ownedno
freshnessHow current a value is and when it stops being usableno
exclusionRecords that must be filtered out before countingyes
attributionWho or what gets credit, and from which fieldno
temporalFiscal calendars, period boundaries, date-range handlingyes
currencyMulti-currency handling and conversionyes
write_policyWhat an agent may write, and what silently revertsno
output_shapeThe structure a recurring answer must takeno
anti_patternOperations that succeed and return something wrongyes
cross_object_dependencyRules that only hold when a join is done a specific wayno
securityObject and field allowlists, disclosure requirementsyes

The five marked always-load share a property: the agent cannot detect that they're missing. A skipped interpretation rule produces a hedge. A skipped exclusion produces a confident wrong number.

anti_pattern is the category most taxonomies leave out and the one worth adding first. The expensive failures are the ones that return a result. Grouping on a multi-select, aggregating a formula field, a rollup the platform reshapes rather than rejecting. An error gets fixed in five minutes. A plausible number gets presented to a VP.

Resolution states

Separate from the schema, an assembled payload should be able to say what it doesn't know. Four states beyond the happy path, and each has a different correct behavior:

StateMeaningWhat the agent should do
knownApproved guidance exists and loadedAnswer, naming the rules applied
known_staleGuidance exists but is past reviewAfterAnswer, and flag that the rule is overdue for review
unknownNo approved guidance for a field the question needsRefuse or route to review. Don't infer meaning from the field name
conflictingTwo active entries contradict and priority doesn't separate themStop. Don't let the model arbitrate silently
permission_limitedThe query ran against a partial view of the orgAnswer, and state whose permissions it ran under

conflicting is worth building a validator for. Two rules that disagree will produce an answer either way, and which one wins becomes a function of retrieval order rather than a decision anyone made.

Validating

The schema is strict on purpose: unknown properties are rejected, appliesTo must be an array, and a field entry can't carry rule-only properties.

validate a rule library
pip install jsonschema pyyaml
 
python - <<'EOF'
import json, yaml
from jsonschema import Draft202012Validator
 
schema = json.load(open("context-layer-entry.schema.json"))
entries = yaml.safe_load(open("rules.yaml"))
 
v = Draft202012Validator(schema)
for entry in entries:
    for err in v.iter_errors(entry):
        path = "/".join(map(str, err.path)) or "(root)"
        print(f"{entry.get('id', '?')}  {path}: {err.message}")
EOF

Worth wiring into CI next to the golden-question run. A malformed rule and a wrong rule fail the same way in production: quietly.

Where to start

Don't build to this schema on day one. Start with the minimum viable context layer, which is seven entries using about eight of these fields, and add the rest as you hit the problem each one solves.

FAQ

Do I need every field in this schema?
No. Five fields are required: id, kind, title, appliesTo, and status. Everything else earns its place when you hit the problem it solves. A first library of seven rules will use maybe eight fields total; version, priority, and expiresOn start mattering once rules begin contradicting each other.
Why does the title have a minimum length?
Because in a phased retrieval design the agent decides whether to fetch a rule's body from its title alone, and short titles are almost always category labels. 'Opportunity exclusions' is a folder name and gets skipped. The schema enforces 12 characters as a crude proxy for 'this states a condition, not a category.'
What is the difference between source and evidence?
`source` is on field entries and says how the value gets into the field: human-entered, system-derived, integration-written, formula, or AI-generated. `evidence` is on any entry and says why the entry itself is true — a Finance definition, an automation that force-sets the field, a policy document. One is about the data, the other is about the rule.
Can an entry apply to more than one object?
Yes, and appliesTo is always an array for exactly that reason. A single scope field forces you to either duplicate the rule per object or bury the cross-object part in prose, and prose is invisible to the retrieval layer. Use ["*"] for entries that apply to every question.

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.