Example: a scoped domain tool
Goal: finance reads a deal completely differently from sales. Give them their own view of Opportunity and their own tool — without touching the seller’s. Configuration, plus deploying generated code.
The problem
Sales looks at an Opportunity and wants stage, next step, competitor, close date. Finance wants amount versus expected revenue, payment terms, billing contact, invoice status, and whether the discount was approved.
One entity can’t serve both — widening it to cover both means every payload carries the other team’s fields.
1. Create the finance entity
Go to Entities → Add Entity:
| Field | Value |
|---|---|
| Object | Opportunity |
| Entity name | Finance View |
| API name | finance_view |
| Description | The finance view of Opportunity: revenue recognition, terms, and billing. |
Opportunity already has a default entity, so this is a named view — reachable by name or through a domain, never by accident. See Entities.
2. Curate for finance
Detailed: Name, Amount, ExpectedRevenue, CloseDate, StageName, IsClosed, IsWon, Payment_Terms__c, Discount_Approved__c, Billing_Contact__c, Invoice_Status__c, Account.Name
List: Name, Amount, CloseDate, StageName, Invoice_Status__c
Entity instruction:
Amount is gross before discount; Expected Revenue is net and set manually by the deal desk. When they disagree, Expected Revenue is authoritative for forecasting. A closed-won deal with no invoice status has not been handed to billing yet.
Field instructions:
| Field | Instruction |
|---|---|
Amount | Gross, before discount. |
ExpectedRevenue | Net of discount, set by the deal desk. Authoritative for forecasting. |
Discount_Approved__c | Blank means not submitted, not “no discount”. |
The last one matters most: an agent would otherwise read a blank as a negative.
3. Add a finance metric
Weighted Pipeline — sum of ExpectedRevenue, filtered to IsClosed = false, available for Opportunity. Instruction: “Net of discount. Sales uses gross Amount; these will differ.”
The instruction pre-empts a rep and a controller quoting different numbers and neither knowing why.
4. Create the domain
Go to Domains → New Domain:
| Field | Value |
|---|---|
| Label | Finance |
| Name | finance |
| Description | Revenue, terms, and billing status across the deals and accounts finance owns. |
| Entities | finance_view, account_360, contact_360 |
Account and Contact are the same entities the sales domain uses — finance has no different opinion about what an Account is, so there’s no reason for a second one. The domains page shows account_360 as “Also in: Sales Desk”; sharing entities between domains is normal and visible.
Roster everything finance needs, not just the finance-specific view. A user granted this domain reads only what it rosters — that is why Account and Contact are on it.
4b. Grant it to finance
Click the domain’s Users button and add the finance team — a user, or the public group or role you already use. From that moment their agents read the Finance catalog and the default one drops away, so there is nothing to revoke.
Give whoever maintains the domain Managers as well, plus the ContextWorks Domain Manager permission set. → Domain access
5. Check what it serves
The domain card should show:
| Object | Entity | Also in |
|---|---|---|
| Account | Account 360 | Sales Desk |
| Contact | Contact 360 | Sales Desk |
| Opportunity | Finance View | — |
The same opportunity record, read through this domain, now returns the finance curation.
6. Generate the tools
Go to Deploy → Custom:
| Setting | Value |
|---|---|
| Domain | Finance |
| Level | Pin: Detailed |
| Format | Pin: Markdown |
This generates three classes: FinanceGetCatalogAction, FinanceFindRecordsAction, FinanceGetRecordsAction. Pin level and format because this tool has one job — fewer inputs is less for a planner to get wrong.
7. Deploy and register
Deploy the three classes as you deploy any Apex — they live in your namespace and call only the package’s public API, so upgrades won’t break them.
Register them (3A on the Deploy page for Agentforce, 3B for MCP), named exactly as the classes.
TIP
If finance already has an agent, put the domain’s actions in a topic of their own and add a router transition to it. One topic per domain keeps the planner’s choices clear.
8. Test the difference
Same record, two tools:
Sales tool: “Tell me about the Global Media renewal.” → Stage, next step, close date, competitor, recent activity
Finance tool: “Tell me about the Global Media renewal.” → Amount vs expected revenue, payment terms, discount approval, invoice status
One record, one engine, two curations, no code deciding which is which.
9. Change coverage later
Six weeks later finance starts tracking Invoice__c:
- Create an entity for
Invoice__c. - Add it to the
financedomain.
FinanceGetRecordsAction covers invoices on its next call. Nothing is redeployed, no agent is republished, and the tool’s description is still accurate — it describes purpose, not contents. A tool with a hard-coded entity list would have needed a code change, a deploy, and an agent update.
When not to bother
If finance and sales genuinely want the same fields, don’t build this. A near-copy entity is a maintenance liability — two places to fix every future change. The test is whether the curation differs, not whether the audience does.