41 KiB
Data Library Reference (ADL)
How to provision an Agentforce Data Library (ADL) and wire it into an Agent Script .agent file so the agent can answer questions grounded on uploaded documents, Knowledge articles, or a custom retriever.
This reference is consumed by the Create an Agent and Modify an Existing Agent workflows in SKILL.md. The parent skill decides whether to provision an ADL (by asking the user); this file owns how.
Use sf agent adl CLI Commands
All ADL operations use the sf agent adl CLI. The CLI handles authentication, API version negotiation, polling, and error formatting automatically.
Available commands:
| Command | Purpose |
|---|---|
sf agent adl create |
Create a new library (SFDRIVE, KNOWLEDGE, or RETRIEVER) |
sf agent adl upload |
Upload file(s) to a SFDRIVE library and trigger indexing |
sf agent adl get |
Get full details of a library (status, retrieverId, config) |
sf agent adl status |
Get indexing stage details |
sf agent adl list |
List all libraries in the org |
sf agent adl update |
Update library metadata, content fields, or swap retriever |
sf agent adl delete |
Permanently delete a library |
sf agent adl file add |
Day-2: add files to an existing SFDRIVE library |
sf agent adl file list |
List files in a SFDRIVE library |
sf agent adl file delete |
Remove a file from a SFDRIVE library |
CLI Command Reference
sf agent adl create
Creates a new data library. The --source-type determines which additional flags are required.
FLAGS (required):
-n, --name=<value> Display name (max 80 chars)
-o, --target-org=<value> Target org alias or username
--developer-name=<value> API name (alphanumeric + underscores, starts with letter, max 80 chars)
--source-type=<option> sfdrive | knowledge | retriever
FLAGS (optional / conditional):
--description=<value> Description (max 255 chars)
--index-mode=<option> basic | enhanced (SFDRIVE only; defaults to basic when omitted; controls Intelligent Context — see "Index mode" under Option A)
--retriever-id=<value> Active Custom Retriever ID (required for RETRIEVER)
--primary-index-field1=<value> First primary index field (required for KNOWLEDGE, immutable)
--primary-index-field2=<value> Second primary index field (required for KNOWLEDGE, immutable)
--content-fields=<value> Comma-separated content fields (KNOWLEDGE only; mutable after creation)
--data-category-ids=<value> Comma-separated data category selection IDs (KNOWLEDGE only; mutually exclusive with --data-category-names)
--data-category-names=<value> Comma-separated data category names, qualified form "Group_API_Name.Category" (KNOWLEDGE only; mutually exclusive with --data-category-ids)
--wait=<value> Minutes to wait for indexing (KNOWLEDGE only; SFDRIVE indexes on upload, RETRIEVER is ready immediately)
--json Output as JSON (always use this)
For KNOWLEDGE libraries, --content-fields, --data-category-ids, and --data-category-names can now be set at creation time (previously only sf agent adl update set content fields). --data-category-ids and --data-category-names are mutually exclusive — pass one or the other, not both.
sf agent adl upload
Uploads file(s) to a SFDRIVE library. Handles presigned URL, S3 upload, indexing trigger, and optional polling.
FLAGS (required):
-i, --library-id=<value> Library ID (18-char, prefix 1JD)
-f, --file=<value>... File path(s) — repeat flag for multiple files
-o, --target-org=<value> Target org
FLAGS (optional):
-w, --wait=<value> Minutes to poll for READY (omit = return immediately)
--json Output as JSON
sf agent adl get
Returns full library details including status, retrieverId, and grounding source config.
FLAGS (required):
-i, --library-id=<value> Library ID
-o, --target-org=<value> Target org
FLAGS (optional):
--json Output as JSON
sf agent adl status
Returns indexing stage details: DATA_LAKE_OBJECT → DATA_MODEL_OBJECT → SEARCH_INDEX → INDEXING → RETRIEVER. Each stage also reports an error classification when it fails.
FLAGS (required):
-i, --library-id=<value> Library ID
-o, --target-org=<value> Target org
FLAGS (optional):
--include-artifacts Resolve provisioned Data Cloud asset details (DataStream, DLO, DMO, SearchIndex, Retriever) on each stage. Slower — issues extra queries.
--json Output as JSON
sf agent adl list
Lists all libraries in the org.
FLAGS (required):
-o, --target-org=<value> Target org
FLAGS (optional):
--source-type=<option> Filter: sfdrive | knowledge | retriever
--json Output as JSON
sf agent adl update
Updates mutable properties. Some changes trigger re-indexing.
FLAGS (required):
-i, --library-id=<value> Library ID
-o, --target-org=<value> Target org
FLAGS (optional):
-n, --name=<value> New display name
--description=<value> New description
--content-fields=<value> Comma-separated fields (KNOWLEDGE; triggers re-index)
--[no-]restrict-to-public-articles Public articles only (KNOWLEDGE; triggers re-index)
--retriever-id=<value> Swap retriever (RETRIEVER only; must be active)
--json Output as JSON
sf agent adl delete
Permanently deletes a library and all associated files/indexing data.
FLAGS (required):
-i, --library-id=<value> Library ID
-o, --target-org=<value> Target org
sf agent adl file add
Day-2 operation: add files to an existing SFDRIVE library (must already be READY).
FLAGS (required):
-i, --library-id=<value> Library ID
-f, --path=<value>... File path(s) — repeat for batch
-o, --target-org=<value> Target org
Constraints: ≥1 file, no duplicate names in batch, max 1000 files per library.
sf agent adl file list
Lists files in a SFDRIVE library (name, size, creation date, per-file indexing status). Paginated — returns one page at a time plus a total count, so it lists every file even in libraries with more than 200 files (unlike sf agent adl get, whose inline file list is capped at 200).
FLAGS (required):
-i, --library-id=<value> Library ID
-o, --target-org=<value> Target org
FLAGS (optional):
--page-size=<value> Files per page, 1–200 (default 50)
--offset=<value> Number of files to skip before returning results (pagination)
--status=<option> Filter by indexing status: uploaded | indexing | indexed | index_failed | deleting | delete_failed
--json Output as JSON
When more files remain beyond the current page, the command reports how many of the total it is showing — increase --page-size or page through with --offset to see the rest.
sf agent adl file delete
Removes a file and triggers search index re-hydration. Deletion is asynchronous — the command reports that deletion was initiated; use sf agent adl file list to check when the file clears.
FLAGS (required):
-i, --library-id=<value> Library ID
--file-id=<value> AiGroundingFileRef record ID
-o, --target-org=<value> Target org
Org setup prerequisite
If the org is fresh (just licensed, not yet configured), read Org Setup for ADL FIRST. That reference handles:
- Enabling Einstein GPT Platform + Agentforce (settings deploy)
- Admin user permsets (Data Cloud Architect, Prompt Template Manager, CopilotSalesforceAdmin)
- Lightning Knowledge enablement
- Data Cloud verification + CRM Connector
- Einstein Agent User creation + permissions (AllowViewKnowledge + viewAllRecords)
If Step 0 below fails, the org likely hasn't been set up yet — go to Org Setup for ADL.
What this reference covers
- Step 0 — Verify Data Cloud is provisioned. ADL has a hard dependency on Data Cloud.
- Option A: SFDRIVE (File Library) — Steps 1–7: Create library, upload file, trigger indexing, poll until ready. Step 8: Day-2 add more files.
- Option B: KNOWLEDGE (Knowledge Article Library) — Create library with knowledgeConfig, trigger indexing, poll until ready. Day-2: update config fields.
- Option C: RETRIEVER (Custom Retriever Library) — Create library with active retrieverId, immediately ready.
- Wiring the ADL into Agent Script — the
knowledge:block +AnswerQuestionsWithKnowledgeaction (same for all source types).
Source type decision guide
Ask the user which grounding source they want:
| Source Type | Use When | Provisioning |
|---|---|---|
| SFDRIVE | User has PDF/TXT/HTML docs to upload | Upload → Index → READY (2-10 min) |
| KNOWLEDGE | Org has Salesforce Knowledge articles | Create → Auto-index from KAV → READY (2-10 min) |
| RETRIEVER | User has an existing active Custom Retriever | Create → Immediately READY (no provisioning) |
If the user says "knowledge base" or "FAQ articles" → KNOWLEDGE. If they say "upload files" or "documents" → SFDRIVE. If they say "I have a retriever" or "custom search" → RETRIEVER.
When intent is ambiguous, ASK — do not guess. Common ambiguous cases:
- "knowledge-grounded agent from a PDF" — could be SFDRIVE (upload PDF directly) or KNOWLEDGE (extract content into articles, then ground on those). Ask which approach the user wants.
- "add knowledge to my agent" — generic word "knowledge" doesn't indicate source type. Ask.
- File path + "knowledge" in the same request — the file could be the grounding source (SFDRIVE) or input for creating articles (KNOWLEDGE). Ask.
Outputs the parent skill consumes
After Step 7 succeeds, hand the parent skill these values:
libraryId— the raw library ID returned by the create call.retrieverId— populated once indexing completes.rag_feature_config_id— derived as"ARFPC_" + libraryId. This is the value that goes into the.agentfile'sknowledge:block. It is not the raw libraryId.
Prerequisites
sf (Salesforce CLI) must be on PATH. STOP if missing — do not proceed.
command -v sf >/dev/null 2>&1 || echo "MISSING: sf (Salesforce CLI)"
If sf is missing, do NOT auto-install. Offer:
- Homebrew (recommended on macOS):
brew install --cask sf - npm (Node 20+):
npm install -g @salesforce/cli .pkginstaller: https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm
Minimum version: @salesforce/cli 2.139.6 (includes ADL commands). Check with sf --version.
Confirm the target org is authenticated:
sf org display --target-org <org-alias> --json
If auth is missing: sf org login web --alias <alias> --instance-url https://<your-org>.my.salesforce.com. Do not guess the alias — ask if unspecified.
Set the target-org alias as a shell variable now — every command from Step 0 onward references it:
TARGET_ORG="<org-alias>"
Substitute the user's real alias before continuing.
Step 0 — Verify Data Cloud is provisioned and ADL is reachable
ADL requires both (a) Data Cloud provisioning to be complete and (b) the ADL service routes to be healthy. The two are independent in practice — orgs can have DC provisioned but a broken ADL service. Run both checks; do not collapse them.
0a. DC provisioning check — DataKnowledgeSpace
sf data query --target-org "$TARGET_ORG" --json -q "SELECT COUNT() FROM DataKnowledgeSpace"
- Returns without error (any
totalSize, including 0) → ✅ Data Cloud is provisioned. Continue to 0b. INVALID_TYPEerror → ❌ Data Cloud is NOT provisioned. Skip 0b and STOP with the A/B prompt below.
Why
DataKnowledgeSpaceand notDataStream__dlm:DataKnowledgeSpaceis the exact object the ADL pipeline depends on, and is queryable as soon as DC provisioning completes.DataStream__dlmonly materializes after a user creates a data stream — querying it yieldsINVALID_TYPEeven on fully-provisioned orgs that have never run a stream, so it produces a false-negative on healthy DC orgs.
0b. ADL service health check — sf agent adl list
DC is provisioned. Confirm the ADL service itself is reachable on this org:
sf agent adl list --target-org "$TARGET_ORG" --json
-
status: 0(success) → ✅ ADL service is healthy. The response includesresult.libraries[]— useful for reuse if a matchingdeveloperNameis already provisioned. Continue to Step 1. -
Error with
"This feature is not currently enabled"→ ⚠️ The ADL API checks both org-level and user-level access:- User-level: Logged-in user needs ONE of:
CustomizeApplication(System Admin),EinsteinCopilotBuilder,EinsteinAgentPlatformBuilder, orSelfServiceCopilotBuilder. TheCopilotSalesforceAdminpermset grants these. - Org-level: Org needs
EinsteinKnowledgeConfigorg perm AND the ADL Connect API gate enabled. - Fix: First check if admin user has
CopilotSalesforceAdminpermset (see Org Setup for ADL, Step 0). If assigned and error persists, the org is missing the ADL feature gate — show the A/B prompt below.
- User-level: Logged-in user needs ONE of:
-
Error with
"INTERNAL_ERROR"→ ⚠️ DC is provisioned but the ADL service is unhealthy. Tell the user:⚠️ Data Cloud is provisioned, but the Agentforce Data Library service is returning an internal error on this org. ADL provisioning will fail until the service recovers. Options: A. Skip knowledge grounding for this run — author the agent without an ADL. B. Try a different org where ADL is healthy. C. Open a support case if this org should have ADL working.Default to option A — author without a
knowledge:block — unless the user picks B or C. -
Auth error → Re-authenticate:
sf org login web --alias "$TARGET_ORG"and retry.
A/B prompt — DC not provisioned
⚠️ Data Cloud is not provisioned in this org.
An ADL requires Data Cloud, which provisions asynchronously (~30 min – 2 hr).
Choose one:
A. Trigger Data Cloud provisioning now — I'll deploy CustomerDataPlatformSettings
and have you click "Get Started" on the Setup page. Provisioning runs in the
background. We'll skip ADL on this pass and you can re-run /agentforce-generate
to add grounding once it's live.
B. Skip knowledge grounding — the agent will be authored without an ADL. You can
add it later by re-running this workflow.
-
If A — trigger DC and exit the ADL flow on this pass:
-
Create
force-app/main/default/settings/CustomerDataPlatform.settings-meta.xml:<?xml version="1.0" encoding="UTF-8"?> <CustomerDataPlatformSettings xmlns="http://soap.sforce.com/2006/04/metadata"> <enableCustomerDataPlatform>true</enableCustomerDataPlatform> </CustomerDataPlatformSettings> -
Deploy:
sf project deploy start --json --async --source-dir force-app/main/default/settings/CustomerDataPlatform.settings-meta.xml -
Wait ~60s, re-run the
DataKnowledgeSpacequery from 0a. If it succeeds, re-run 0b. If both pass, continue to Step 1. -
Still
INVALID_TYPEafter ~2 min → opensf org open --target-org "$TARGET_ORG" --path "/lightning/setup/CDPSetupHome/home"and instruct the user:👤 I've opened the Data Cloud setup page. Click the "Get Started" button. Provisioning runs async (~30 min – 2 hr). When it's live, re-run /agentforce-generate to add knowledge grounding. -
Exit the ADL flow. Tell the parent skill to author the agent without a
knowledge:block on this pass.
-
-
If B — skip ADL: Tell the parent skill the user opted out. Author the agent without a
knowledge:block.
Visual cross-check: If you're uncertain about the verdict from 0a/0b, open /lightning/setup/CDPSetupHome/home. If the page reads "Your Data Cloud instance is live and connected", DC is provisioned regardless of what the SOQL says. The page state is the ground truth the user sees in Setup.
Variables
Resolve these once after Step 0 passes (TARGET_ORG was already set in Prerequisites):
FILE_NAME="<absolute-path-to-file>" # e.g. ~/docs/product-manual.pdf
ADL_DevName="<snake_case_unique>" # e.g. MyLib_0424_ab3
ADL_Name="<human readable label>" # e.g. "Product Documentation"
All sf agent adl commands use --target-org "$TARGET_ORG" for authentication — no manual token management needed. If the session expires, re-authenticate with sf org login web --alias "$TARGET_ORG".
Confirm the file to upload exists and is a supported type (PDF, TXT, HTML). Max file size: 100 MB.
Important: Read the file content before proceeding. Use the Read tool on the PDF to understand what it contains. Do NOT ask the user "what's in the file?" — inspect it yourself. The content determines:
- Agent description and instructions
- Test queries for preview validation
- Whether the file is suitable for grounding (empty or corrupt files will fail)
Option A: SFDRIVE — File Library
Use this when the user has PDF, TXT, or HTML documents to upload. The library ingests files, indexes them, and makes content available for grounded retrieval.
Step 1 — Create the SFDRIVE library
sf agent adl create \
--target-org "$TARGET_ORG" \
--name "$ADL_Name" \
--developer-name "$ADL_DevName" \
--source-type sfdrive \
--json
Read the JSON response and capture result.libraryId:
LIBRARY_ID="<paste result.libraryId from the response>"
Choosing --index-mode (Intelligent Context)
SFDRIVE libraries index through the Just-in-Time (JIT) pipeline, which is the default on new libraries. The optional --index-mode flag controls whether Intelligent Context (IC) — LLM-based content processing — is applied during indexing. IC is exposed as a toggle in the Setup UI; --index-mode is the API equivalent.
--index-mode |
UI label | Cost |
|---|---|---|
enhanced |
"Intelligent Context" | Substantially higher per-file processing cost |
basic |
"Text Only" | Standard (lower) |
enhanced turns Intelligent Context on: the file is processed to better handle complex content such as tables, images, and document structure. basic is the toggle-off state, labeled "Text Only" in the UI. When --index-mode is omitted, the library is created with basic (the persisted indexMode is BASIC).
The tradeoff is cost vs. handling of complex content: enhanced (IC) is costly, and the toggle exists so it can be disabled when that processing isn't needed. Weigh whether the corpus has content — tables, images, infographics — that depends on IC's processing against the added cost.
Step 2 — Upload file(s) and wait for READY
The upload command handles the entire flow: readiness check, presigned URL, S3 upload, indexing trigger, and polling.
For a single file:
sf agent adl upload \
-i "$LIBRARY_ID" \
--target-org "$TARGET_ORG" \
--file "$FILE_NAME" \
--wait 10 \
--json
For multiple files (batch):
sf agent adl upload \
-i "$LIBRARY_ID" \
--target-org "$TARGET_ORG" \
--file "$FILE_NAME_1" \
--file "$FILE_NAME_2" \
--wait 10 \
--json
The --wait 10 flag polls until the library reaches READY (up to 10 minutes). When it returns:
{
"status": "READY",
"libraryId": "1JD...",
"retrieverId": "1Cx...",
"ragFeatureConfigId": "ARFPC_1JD..."
}
retrieverIdnon-null → library is ready for grounding.ragFeatureConfigId— this is the value for the.agentfile'sknowledge:block.
If you omit --wait, the command returns immediately with status: IN_PROGRESS. Use sf agent adl status or sf agent adl get to check readiness later.
Checking status manually
sf agent adl status -i "$LIBRARY_ID" --target-org "$TARGET_ORG"
Shows stage progression: DATA_LAKE_OBJECT → DATA_MODEL_OBJECT → SEARCH_INDEX → INDEXING → RETRIEVER
Confirming readiness
sf agent adl get -i "$LIBRARY_ID" --target-org "$TARGET_ORG" --json
Check result.retrieverId — non-null means ready. The top-level status may lag behind; trust retrieverId.
At this point the parent skill receives:
libraryId— from Step 1retrieverId— from Step 2 responserag_feature_config_id— from Step 2 response (or computed as"ARFPC_" + libraryId)
Step 3 — (Optional) Add more files to an existing library
For day-2 incremental additions to an already-provisioned SFDRIVE library:
sf agent adl file add \
-i "$LIBRARY_ID" \
--path "$NEW_FILE_1" \
--path "$NEW_FILE_2" \
--target-org "$TARGET_ORG" \
--json
file add vs upload: upload (Step 2) provisions the full Data Cloud pipeline — it creates the downstream assets (DLO, DMO, SearchIndex, Retriever) on first ingest. file add does not create new downstream assets; it appends files to the existing SearchIndex and triggers re-indexing. Use upload for the initial ingest and file add for day-2 additions to a READY library.
Constraints:
- Library must already be READY (Day-0 provisioning complete).
- At least one file required per invocation.
- No duplicate file names in a batch.
- Total file count in the library must stay ≤ 1000.
- Only works on SFDRIVE libraries.
List files in the library
sf agent adl file list -i "$LIBRARY_ID" --target-org "$TARGET_ORG"
For libraries with many files, page through with --page-size / --offset, or filter to a specific state with --status (e.g. --status index_failed to find only the files that failed):
sf agent adl file list -i "$LIBRARY_ID" --status index_failed --target-org "$TARGET_ORG"
Delete a file
sf agent adl file delete -i "$LIBRARY_ID" --file-id "<fileId>" --target-org "$TARGET_ORG"
Per-file indexing status (JIT)
The JIT pipeline surfaces per-file status, not just the library-level stage progression. sf agent adl file list and sf agent adl get return a status for each file, so you can tell exactly which file is holding a library back. Prefer file list for this: it is paginated and returns every file, whereas get inlines at most 200 files. When a library holds more than 200 files, get reports the true total separately so you know the inline list is partial.
A file reports one of exactly six status values:
| Status | Meaning |
|---|---|
UPLOADED |
File landed in the library; indexing not yet started (in progress). |
INDEXING |
JIT pipeline is processing the file (in progress). |
INDEXED |
File is chunked and searchable — this is the success end state. |
INDEX_FAILED |
Indexing failed for this file — a failure end state. |
DELETING |
File is being removed (in progress). |
DELETE_FAILED |
File removal failed — a failure end state. |
Confirm the file you care about reached INDEXED before relying on grounded answers about that file's content. For a file at INDEX_FAILED, delete it and re-add it to retry.
Wiring the ADL into Agent Script
An indexed ADL does nothing until the .agent file declares the knowledge: block and at least one subagent invokes AnswerQuestionsWithKnowledge. This section gives the exact snippets — copy them verbatim, substituting <libraryId> with the value from Step 1.
1. Top-level knowledge: block
Place between connection: (if present) and language: per the block ordering in Core Language, Section 2:
knowledge:
rag_feature_config_id: "ARFPC_<libraryId>" # e.g. ARFPC_1JDg7000001hilBGAQ
citations_enabled: True # True to render inline citations
citations_url: "" # optional base URL prepended to citations
rag_feature_config_idis not the rawlibraryId. It isARFPC_+libraryId.citations_enabled: Trueturns on inline citation rendering in the agent's response.citations_urlis usually empty. Set it when citations should resolve to a public URL with a known prefix.- Without the top-level
knowledge:block, the@knowledge.*references inside the action's input defaults fail compilation.
2. Subagent that invokes the action
Inside whichever execution block should answer grounded questions, declare the
action invocation in the actions: block under reasoning:. State the
call-before-answer and grounding duties directly:
subagent general_faq:
description: "Answer customer questions by searching knowledge."
reasoning:
instructions: ->
| Ask one concise clarifying question if the request is too vague
to search.
| For every substantive question, call AnswerQuestionsWithKnowledge
before answering.
| Answer only from the returned knowledge summary. If it is empty,
say the knowledge base has no answer and suggest contacting support.
| Include only sources and URLs returned by the action.
actions:
AnswerQuestionsWithKnowledge: @actions.AnswerQuestionsWithKnowledge
with query = ...
with citationsUrl = ...
with ragFeatureConfigId = ...
with citationsEnabled = ...
The four with lines bind the action's inputs. The trailing ... tells the planner to fill them — query from the user's utterance, the other three from the top-level knowledge: block via the action definition's defaults.
Anti-hallucination guard
When retrieval misses (the user asks about something not in the corpus, or the
library is still warming up), the returned knowledge summary is empty. Keep
four duties explicit: call before answering, ground only in returned content,
decline to answer when retrieval is empty, and cite only returned sources.
Do not put authoring-only @outputs paths or formatting micromanagement in
model-facing instructions.
Tune the refuse message to the domain. A compliance agent should say something like "I don't have that in the [Manual Name]. Please contact [the relevant team]." rather than the generic line above.
3. Action definition
Add this actions: block at the same level as reasoning: (still inside subagent general_faq:). Copy verbatim — target and source are platform-fixed values:
actions:
AnswerQuestionsWithKnowledge:
description: "Answers questions about company policies, procedures, troubleshooting, or product information by searching knowledge articles. For example: 'What is your return policy?' or 'How do I fix an issue?'"
inputs:
query: string
description: "Required. A string created by generative AI to be used in the knowledge article search."
label: "Query"
is_required: True
is_user_input: True
citationsUrl: string = @knowledge.citations_url
description: "The URL to use for citations for custom Agents."
label: "Citations Url"
is_required: False
is_user_input: True
ragFeatureConfigId: string = @knowledge.rag_feature_config_id
description: "The RAG Feature ID to use for grounding this copilot action invocation."
label: "RAG Feature Configuration Id"
is_required: False
is_user_input: True
citationsEnabled: boolean = @knowledge.citations_enabled
description: "Whether or not citations are enabled."
label: "Citations Enabled"
is_required: False
is_user_input: True
outputs:
knowledgeSummary: object
description: "A string formatted as rich text that includes a summary of the information retrieved from the knowledge articles and citations to those articles."
label: "Knowledge Summary"
complex_data_type_name: "lightning__richTextType"
filter_from_agent: False
is_displayable: True
citationSources: object
description: "Source links for the chunks in the hydrated prompt that's used by the planner service."
label: "Citation Sources"
complex_data_type_name: "@apexClassType/AiCopilot__GenAiCitationInput"
filter_from_agent: False
is_displayable: False
target: "standardInvocableAction://streamKnowledgeSearch"
label: "Answer Questions with Knowledge"
require_user_confirmation: False
include_in_progress_indicator: True
progress_indicator_message: "Getting answers"
source: "EmployeeCopilot__AnswerQuestionsWithKnowledge"
4. Reuse an existing library
When modifying an existing agent: if the .agent already has a knowledge: block with a populated rag_feature_config_id, skip provisioning and reuse. Confirm the underlying library is still indexed by running sf agent adl get -i <libraryId> and checking retrieverId is present.
A complete minimal template lives at assets/agents/knowledge-grounded.agent.
5. Permission prerequisite — Einstein Agent User access
Wiring the knowledge: block and AnswerQuestionsWithKnowledge action is only half the work. At runtime, the Einstein Agent User needs three layers of access — missing any one causes silent empty results:
5a. Data Cloud permset
The agent user must hold a Data Cloud permset/PSL. Without it, knowledgeSummary returns empty for every query.
The permset name varies by org shape (GenieDataPlatformStarterPsl PSL, GenieUserEnhancedSecurity PS, or DataCloudUser PS). Don't hardcode a name — run the discovery-then-assign procedure documented at Agent User Setup, Step 3b.
5b. Knowledge object + field-level security (KNOWLEDGE source type only)
For KNOWLEDGE libraries, the agent user must also have:
- Object-level Read on
Knowledge__kav - Field-level Read on ALL fields configured in the library (
primaryIndexField1,primaryIndexField2, and allcontentFields)
Without these, the runtime returns: "Looks like you don't have access to one or more fields used by the assigned data library." — but the error is only visible in server logs, not surfaced to the user.
Deploy a permset with the required access:
<?xml version="1.0" encoding="UTF-8"?>
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Knowledge FLS for Agent</label>
<objectPermissions>
<allowRead>true</allowRead>
<object>Knowledge__kav</object>
</objectPermissions>
<fieldPermissions>
<editable>false</editable>
<field>Knowledge__kav.Answer__c</field>
<readable>true</readable>
</fieldPermissions>
<!-- Add all contentFields configured in the library -->
</PermissionSet>
Note: Standard fields like Title and ArticleNumber cannot be set via permset deploy (they're always-readable). Only custom fields (e.g. Answer__c, Summary) need explicit FLS grants.
5c. Language alignment (KNOWLEDGE source type only)
The retriever filters chunks by language at query time. If the article language doesn't match the user's language context, results are silently excluded. Even subtle mismatches like en_US vs en_GB cause empty results (confirmed by W-21956266).
Before declaring a KNOWLEDGE library ready:
# Check article languages in the org
sf data query --target-org "$TARGET_ORG" -q \
"SELECT Language, COUNT(Id) ct FROM Knowledge__kav WHERE PublishStatus='Online' GROUP BY Language"
If the agent user's locale doesn't match the article language:
- Publish articles in the agent user's language variant, OR
- Use a RETRIEVER source type with a custom retriever that disables language filtering
Reference: https://www.salesforce.com/blog/multi-language-guide/
5d. Data Space scope
If the assignment lands but grounded queries still return empty results, also check the Data Space scope on the assigned permset (UI-only, no API) — see Agent User Setup, Step 3b.4.
Common pitfalls
INVALID_SESSION_IDmid-flow → access token expired. Re-authenticate withsf org login web.LightningDomainlogin error → use the*.my.salesforce.comdomain, not*.lightning.force.com.sf agent adl uploadfails with"One or more files have not been uploaded..."→ the org'sbypass-s3-file-existgate hasn't rolled out. Skip ADL on this pass; the user can upload via the Setup UI later.sf agent adl getshows top-levelstatusstuck onIN_PROGRESSwith all sub-stagesSUCCESS→ normal. Top-level lag of 10–30 minutes is common (longer for large files). Do not block on it. UseretrieverId is not nullas the readiness gate..agentvalidation fails withunresolved reference @knowledge.rag_feature_config_id→ the top-levelknowledge:block is missing or misordered. It must precedelanguage:per Core Language Section 2.- Agent published, ADL indexed (
retrieverIdpopulated), but every grounded query returns emptyknowledgeSummaryand the agent refuses → Einstein Agent User lacks Data Cloud access. See "Wiring → Permission prerequisite" above and Agent User Setup, Step 3b. "To create a File data library, enable Agentforce in your org. Required org preferences: EinsteinGPTPlatformEnabled, AgentPlatformEnabled"→ Deploy bothEinsteinGpt.settings-meta.xmlANDAgentPlatform.settings-meta.xml. See Org Setup for ADL Steps 0a and 0b2.
Reference (Option A)
- Grounding source type:
SFDRIVE(File) - All operations use
sf agent adlCLI commands which auto-negotiate API version
Option B: KNOWLEDGE — Knowledge Article Library
Use this when the org has Salesforce Knowledge articles (KAV) and the user wants to ground the agent on article content. No file upload needed — the library indexes directly from Knowledge articles.
Prerequisites (Knowledge-specific)
- "Knowledge User" enabled for the user
- Knowledge articles exist in the org (at least one published article)
- The
isAsyncKnowledgeAdlEnabledgate must be open on the org
Step K1 — Create the Knowledge library
Ask the user which Knowledge fields to index. Required: two primary index fields (immutable after creation). Optional: contentFields for additional searchable content.
Common field choices:
ArticleNumber— unique article identifierTitle— article titleUrlName— URL-friendly nameSummary— article summary- Custom fields like
Answer__c,Detail__c
sf agent adl create \
--target-org "$TARGET_ORG" \
--name "$ADL_Name" \
--developer-name "$ADL_DevName" \
--source-type knowledge \
--primary-index-field1 ArticleNumber \
--primary-index-field2 Title \
--json
Capture result.libraryId from the response. Indexing is auto-triggered on creation.
LIBRARY_ID="<paste result.libraryId>"
You can also set --content-fields and data categories at creation time rather than waiting for a day-2 update:
sf agent adl create \
--target-org "$TARGET_ORG" \
--name "$ADL_Name" \
--developer-name "$ADL_DevName" \
--source-type knowledge \
--primary-index-field1 ArticleNumber \
--primary-index-field2 Title \
--content-fields "Answer__c,Summary__c" \
--data-category-names "Group_API_Name.Category" \
--json
Pass either --data-category-ids or --data-category-names, not both. Add --wait <minutes> to block until KNOWLEDGE indexing completes instead of polling separately.
Step K2 — Poll status until READY
Knowledge libraries provision through stages: DATA_STREAM → DATA_LAKE_OBJECT → DATA_MODEL_OBJECT → SEARCH_INDEX → RETRIEVER
sf agent adl status -i "$LIBRARY_ID" --target-org "$TARGET_ORG"
Check readiness via the detail endpoint:
sf agent adl get -i "$LIBRARY_ID" --target-org "$TARGET_ORG" --json
Once result.retrieverId is non-null, the pipeline is set up: rag_feature_config_id = "ARFPC_" + LIBRARY_ID
IMPORTANT — KNOWLEDGE Day 0 race condition (W-22773383): The library may show READY with retrieverId populated but have 0 chunks. This happens because the Day 0 chunking job runs before the CRM Connector's data commit propagates through the lakehouse (~17s visibility window). The chunking job sees 0 rows, skips processing, and emits READY anyway.
Do NOT declare success based on retrieverId alone for KNOWLEDGE. After retrieverId is populated:
- Wait ~10 minutes (chunking jobs run on ~10 min intervals)
- Send a test grounded query to verify non-empty
knowledgeSummary - If still empty after 10 min, try
sf agent adl update -i "$LIBRARY_ID" --content-fields "<fields>"to force a re-index
Unlike SFDRIVE (which uses JIT indexing and serves immediately), KNOWLEDGE chunking is asynchronous and may lag behind the READY status.
Step K3 (Day-2) — Update Knowledge config
Update which fields are indexed. This triggers full server-side re-indexing.
sf agent adl update \
-i "$LIBRARY_ID" \
--target-org "$TARGET_ORG" \
--content-fields "Answer__c,Summary__c" \
--restrict-to-public-articles
Important constraints:
primaryIndexField1andprimaryIndexField2are immutable after creation- Updates are blocked while provisioning is in progress (server returns
INVALID_REQUEST_STATE) - Knowledge articles re-index automatically when articles are updated in the org
- Metadata-only updates (masterLabel, description) do NOT trigger re-indexing
Knowledge validation errors
| Error | Cause |
|---|---|
MISSING_REQUIRED_FIELD |
primaryIndexField1 or primaryIndexField2 missing |
DUPLICATE_PRIMARY_FIELDS |
Same field for both primary fields |
OVERLAPPING_CONTENT_FIELD |
A contentField matches a primary field |
DUPLICATE_CONTENT_FIELDS |
Same field appears twice in contentFields |
DataCategoryMutuallyExclusive |
Both --data-category-ids and --data-category-names passed — provide only one |
PRIMARY_FIELDS_IMMUTABLE |
Attempt to change primary fields after creation |
ADL_UNSUPPORTED_SOURCE_TYPE |
Knowledge gate not enabled on org |
Option C: RETRIEVER — Custom Retriever Library
Use this when the user has an existing active Custom Retriever and wants to wrap it in an ADL library. No file upload or indexing needed — the library is immediately ready.
Prerequisites (Retriever-specific)
- An active Custom Retriever exists in the org (18-char ID with prefix
1Cxor0pm) - The retriever must be in active state (inactive retrievers are rejected)
Finding an active retriever ID
If the user doesn't know their retriever ID, find one from existing READY libraries:
sf agent adl list --target-org "$TARGET_ORG" --json
Then get the retrieverId from a READY library:
sf agent adl get -i <READY_LIBRARY_ID> --target-org "$TARGET_ORG" --json
Look for result.retrieverId in the response.
Step R1 — Create the Retriever library
sf agent adl create \
--target-org "$TARGET_ORG" \
--name "$ADL_Name" \
--developer-name "$ADL_DevName" \
--source-type retriever \
--retriever-id "<active-retriever-id>" \
--json
Expected: JSON with libraryId, sourceType: "RETRIEVER", groundingSource.retrieverId populated. The library is immediately usable — no indexing or polling needed.
Step R2 — Verify READY status
sf agent adl get -i "$LIBRARY_ID" --target-org "$TARGET_ORG" --json
Expected: status: "READY", retrieverId matches input.
The rag_feature_config_id = "ARFPC_" + LIBRARY_ID — wire this into the agent immediately.
Step R3 (Day-2) — Update metadata or swap retriever
# Update metadata
sf agent adl update -i "$LIBRARY_ID" --target-org "$TARGET_ORG" \
--name "Updated Retriever Library" --description "Updated description"
# Swap to a different retriever
sf agent adl update -i "$LIBRARY_ID" --target-org "$TARGET_ORG" \
--retriever-id "<new-active-retriever-id>"
Retriever validation errors
| Error | Cause |
|---|---|
INVALID_REQUEST_STATE: retriever not active |
retrieverId points to an inactive retriever |
retriever not found |
retrieverId doesn't exist |
retrieverId is required |
sourceType RETRIEVER without retrieverId |
ADL_UNSUPPORTED_SOURCE_TYPE |
File operations (upload, add, indexing) on RETRIEVER library |
Unsupported operations for RETRIEVER
These endpoints return 400: ADL_UNSUPPORTED_SOURCE_TYPE:
POST /file-upload-urlsPOST /filesPOST /indexingGET /upload-readinessDELETE /files/{fileId}