| name | sf-ai-agentscript |
| description | Agent Script DSL development skill for Salesforce Agentforce. Enables writing deterministic agents in a single .agent file with FSM architecture, instruction resolution, and hybrid reasoning. Covers syntax, debugging, testing, and CLI deployment.
|
| license | MIT |
| compatibility | Requires Agentforce license, API v65.0+, Einstein Agent User |
| metadata | {"version":"2.3.0","author":"Jag Valaiyapathy","scoring":"100 points across 6 categories","validated":"0-shot generation tested (Pet_Adoption_Advisor, TechCorp_IT_Agent, Quiz_Master, Expense_Calculator, Order_Processor)","last_validated":"2026-02-17","validation_status":"PASS","validation_agents":24,"validate_by":"2026-03-19","validation_org":"AgentforceTesting"} |
SF-AI-AgentScript Skill
"Prompt engineering is like writing laws in poetry - beautiful, but not enforceable."
Agent Script transforms agent development from prompt-based suggestions to code-enforced guarantees. This skill guides you through writing, debugging, testing, and deploying Agentforce agents using the Agent Script DSL.
⚠️ CRITICAL WARNINGS
API & Version Requirements
| Requirement | Value | Notes |
|---|
| API Version | 65.0+ | Required for Agent Script support |
| License | Agentforce | Required for agent authoring |
| Einstein Agent User | Required | Must exist in org for default_agent_user |
| File Extension | .agent | Single file contains entire agent definition |
MANDATORY Pre-Deployment Checks
default_agent_user MUST be valid - Query: SELECT Username FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true
- No mixed tabs/spaces - Use consistent indentation (2-space, 3-space, or tabs - never mix)
- Booleans are capitalized - Use
True/False, not true/false
- Exactly one
start_agent block - Multiple entry points cause compilation failure
⛔ SYNTAX CONSTRAINTS (Validated via Testing + Official Spec)
| Constraint | ❌ WRONG | ✅ CORRECT |
|---|
No else if keyword; no nested if | else if x: or else: + nested if (both invalid) | if x and y: (compound), or flatten to sequential ifs |
No top-level actions: block | actions: at root level | Actions only inside topic.reasoning.actions: |
No inputs:/outputs: in action INVOCATIONS (Level 2) | inputs: block inside reasoning.actions: invocation | Use with/set in reasoning.actions: invocations. The topic-level actions: definitions DO use inputs:/outputs: blocks. |
Multiple available when supported | (previously listed as error) | available when A + available when B on same action is valid (TDD validated 2026-02-14). Org-dependent: compiles on AgentforceTesting but REJECTED on some orgs with "Duplicate 'available when' clause." Use compound and conditions for portability. |
| Avoid reserved action names | escalate: @utils.escalate | escalate_now: @utils.escalate |
... is slot-filling only | my_var: mutable string = ... | my_var: mutable string = "" |
| No defaults on linked vars | id: linked string = "" | id: linked string + source: |
| Linked vars: no object/list | data: linked object | Use linked string or parse in Flow |
| Post-action only on @actions |
🔴 Reserved Field Names (Breaking in Recent Releases)
Common field names that cause parse errors when used as variable or I/O field names:
❌ RESERVED as variable/field names:
description, label, is_required, is_displayable, is_used_by_planner
✅ WORKAROUNDS for variable/field names:
description → descriptions, description_text, desc_field
label → label_text, display_label, label_field
Important distinction: is_required, is_displayable, is_used_by_planner, and label are reserved as variable/field names but are valid as action I/O metadata properties. For example, you cannot name a variable label, but you CAN use label: as a property on an action definition, input, or output. See references/feature-validity.md.
Feature Validity, Data Types & UI Bugs
See references/feature-validity.md for the full feature validity by context table (which properties work on @utils.transition vs target-backed actions).
See references/complex-data-types.md for the complex_data_type_name mapping table and Agent Script → Lightning type mapping.
Canvas View can silently corrupt syntax (== → {! OPERATOR.EQUAL }, missing colons, de-indentation). Always use Script view for structural edits. Preview Mode has known bugs with linked variables and output property access — see references/known-issues.md for workarounds.
Conditional nesting: else if is NOT valid, nested if inside if/else: is NOT valid (TDD disproved). Use compound if A and B: or flatten to sequential ifs. ... is slot-filling only (for with param=...). Post-action set/run only works on @actions.*, NOT @utils.*. See references/syntax-reference.md for detailed examples.
💰 PRODUCTION GOTCHAS
See references/production-gotchas.md for the full production guide including: credit consumption table, lifecycle hooks (before_reasoning:/after_reasoning: syntax), supervision vs handoff, zero-hallucination routing with filter_from_agent/is_used_by_planner, action I/O metadata properties, action chaining, latch variable pattern, loop protection, token limits, progress indicators, VS Code limitations, and language block quirks.
Key highlights:
- Framework operations (
@utils.*, if/else, set, lifecycle hooks) are FREE — only Flow/Apex/API actions cost 20 credits each
before_reasoning:/after_reasoning: content goes directly under the block (NO instructions: wrapper)
- Use
filter_from_agent: True + is_used_by_planner: True on outputs for zero-hallucination routing
Cross-Skill Orchestration
| Direction | Pattern | Priority |
|---|
| Before Agent Script | /sf-flow - Create Flows for flow:// action targets | ⚠️ REQUIRED |
| After Agent Script | /sf-ai-agentforce-testing - Test topic routing and actions | ✅ RECOMMENDED |
| For Deployment | /sf-deploy - Publish agent with sf agent publish authoring-bundle | ⚠️ REQUIRED |
Tip: Open Agentforce Studio list view with sf org open authoring-bundle -o TARGET_ORG (v2.121.7+). Open a specific agent with sf org open agent --api-name MyAgent -o TARGET_ORG.
📋 QUICK REFERENCE: Agent Script Syntax
Block Structure (CORRECTED Order per Official Spec)
config:
variables:
system:
connection:
knowledge:
language:
start_agent:
topic:
Config Block Field Names (CRITICAL)
| Documented Field (Wrong) | Actual Field (Correct) | Notes |
|---|
agent_name | developer_name | Must match folder name (case-sensitive) |
description | agent_description | Agent's purpose description |
| (missing) | agent_type | Required: AgentforceServiceAgent or AgentforceEmployeeAgent |
config:
developer_name: "my_agent"
agent_description: "Handles customer support inquiries"
agent_type: "AgentforceServiceAgent"
default_agent_user: "agent_user@00dxx000001234.ext"
Naming Rules
- Only letters, numbers, underscores. Must begin with a letter.
- No spaces, no consecutive underscores, cannot end with underscore. Max 80 characters.
Instruction Syntax Patterns
| Pattern | Purpose | Example |
|---|
instructions: | | Literal multi-line (no expressions) | instructions: | Help the user. |
instructions: -> | Procedural (enables expressions) | instructions: -> if @variables.x: |
| text | Literal text for LLM prompt | | Hello + variable injection |
if @variables.x: | Conditional (resolves before LLM) | if @variables.verified == True: |
run @actions.x | Execute action during resolution | run @actions.load_customer |
set @var = @outputs.y | Capture action output | set @variables.risk = @outputs.score |
{!@variables.x} | Variable injection in text | Risk score: {!@variables.risk} |
available when | Control action visibility to LLM | available when @variables.verified == True |
with param=... | LLM slot-filling (extracts from conversation) | with query=... |
Transition vs Delegation (CRITICAL DISTINCTION)
| Syntax | Behavior | Returns? | Use When |
|---|
@utils.transition to @topic.X | Permanent handoff | ❌ No | Checkout, escalation, final states |
@topic.X (in reasoning.actions) | Delegation | ✅ Yes | Get expert advice, sub-tasks |
transition to @topic.X (inline) | Deterministic jump | ❌ No | Post-action routing, gates |
Expression Operators (Safe Subset)
| Category | Operators | NOT Supported |
|---|
| Comparison | ==, !=, <, <=, >, >=, is, is not | ❌ <> (not valid, use !=) |
| Logical | and, or, not | |
| Arithmetic | +, - | ❌ *, /, % |
Variable Types
| Modifier | Behavior | Supported Types | Default Required? |
|---|
mutable | Read/write state | string, number, boolean, object, date, id, list[T] | ✅ Yes |
linked | Read-only from source | string, number, boolean, date, id | ❌ No (has source:) |
⚠️ Linked variables CANNOT use object or list types. timestamp, currency, datetime, time, integer, long compile but are absent from official GA variable type docs — prefer date for date/time. These types are valid for action I/O only. See references/actions-reference.md for the full type matrix.
Connection Block (Escalation Routing)
⚠️ Service Agents Only. Use connection messaging: (singular, NOT connections:). The outbound_route_name requires flow:// prefix.
connection messaging:
adaptive_response_allowed: True
connection messaging:
outbound_route_type: "OmniChannelFlow"
outbound_route_name: "flow://Route_from_Agent"
escalation_message: "Connecting you with a specialist."
adaptive_response_allowed: False
All-or-nothing rule: When outbound_route_type is present, ALL three route properties are required (outbound_route_type, outbound_route_name, escalation_message). Valid channel types: messaging, voice, web.
Two-Level Action System
Level 1: ACTION DEFINITION (in topic's `actions:` block)
→ Has `target:`, `inputs:`, `outputs:`, `description:`
Level 2: ACTION INVOCATION (in `reasoning.actions:` block)
→ References Level 1 via `@actions.name`
→ Specifies HOW to call it (with/set clauses)
For AiAuthoringBundle (Agent Script): flow:// and apex:// targets work directly — no GenAiFunction registration needed. I/O schemas (inputs: + outputs:) are REQUIRED for publish — omitting them causes "Internal Error." See references/actions-reference.md for complete action types, target protocols, I/O name matching rules, and the Bare @InvocableMethod pattern.
🔄 WORKFLOW: Agent Development Lifecycle
Phase 1: Requirements & Design
- Identify deterministic vs. subjective logic — Deterministic: security checks, thresholds, data lookups. Subjective: greetings, context understanding, NLG.
- Design FSM architecture — Map topics as states, transitions as edges
- Define variables — Mutable for state tracking, linked for session context
📋 Discovery Questions: Use the pre-authoring questionnaire in references/patterns-quick-ref.md to clarify Agent Identity, Topics, State, Actions, and Reasoning requirements before writing any code.
Phase 2: Agent Script Authoring
- Create
.agent file with required blocks (see Block Structure above)
- Write topics with instruction resolution pattern: post-action checks at TOP, pre-LLM data loading, dynamic instructions for LLM
- Configure actions with appropriate target protocols
- Add
available when guards to enforce security deterministically
Phase 3: Validation (LSP + CLI)
AUTOMATIC: LSP validation runs on every Write/Edit to .agent files — catches mixed tabs/spaces, lowercase booleans, missing blocks, invalid default_agent_user, and undefined topic references. Fix errors, re-save, repeat until clean.
sf agent validate authoring-bundle --api-name MyAgent -o TARGET_ORG --json
Phase 4: Testing (Delegate to /sf-ai-agentforce-testing)
Batch testing (up to 100 cases), quality metrics (Completeness, Coherence, Topic/Action Assertions), LLM-as-Judge scoring.
Phase 5: Deployment & Activation
⚠️ CRITICAL: Use sf agent publish authoring-bundle, NOT sf project deploy start
- Create bundle directory:
force-app/main/default/aiAuthoringBundles/AgentName/
- Add files:
AgentName.agent + AgentName.bundle-meta.xml (NOT .aiAuthoringBundle-meta.xml)
- Publish:
sf agent publish authoring-bundle --api-name AgentName -o TARGET_ORG --json
- Activate:
sf agent activate --api-name AgentName -o TARGET_ORG (no --json support)
⚠️ Publishing does NOT activate. After sf agent publish, the new BotVersion is Inactive. Tests and preview run against the previous active version. You MUST run sf agent activate separately.
Full lifecycle: Validate → Deploy → Publish → Activate → (Deactivate → Re-publish → Re-activate)
Preview modes: Before activating, test with sf agent preview. Default mode simulates actions; add --use-live-actions to test with real org data. Use --apex-debug for Apex logging and --output-dir to save transcripts. See references/cli-guide.md for details.
Phase 5.5: CustomerWebClient Surface Enablement
⚠️ Without CustomerWebClient surface, Agent Builder Preview shows "Something went wrong" and Agent Runtime API returns 500. See references/customer-web-client.md for the required 6-step post-publish patch workflow.
Phase 6: CLI Operations
See references/cli-guide.md for retrieve, validate, publish, and generate commands. Always use --json to suppress spinner output.
Bundle Structure
force-app/main/default/aiAuthoringBundles/MyAgent/
├── MyAgent.agent # Agent Script file
└── MyAgent.bundle-meta.xml # NOT .aiAuthoringBundle-meta.xml!
The bundle-meta.xml contains only: <AiAuthoringBundle xmlns="http://soap.sforce.com/2006/04/metadata"><bundleType>AGENT</bundleType></AiAuthoringBundle>
📊 SCORING SYSTEM (100 Points)
See references/scoring-rubric.md for the full 6-category breakdown, rubric details, and score report format.
Quick summary: Structure & Syntax (20), Deterministic Logic (25), Instruction Resolution (20), FSM Architecture (15), Action Configuration (10), Deployment Readiness (10). Score 90+ = deploy with confidence. Score <60 = BLOCK.
🔧 THE 6 DETERMINISTIC BUILDING BLOCKS
These execute as code, not suggestions. The LLM cannot override them.
| # | Block | Description | Example |
|---|
| 1 | Conditionals | if/else resolves before LLM | if @variables.attempts >= 3: |
| 2 | Topic Filters | Control action visibility | available when @variables.verified == True |
| 3 | Variable Checks | Numeric/boolean comparisons | if @variables.churn_risk >= 80: |
| 4 | Inline Actions | Immediate execution | run @actions.load_customer |
| 5 | Utility Actions | Built-in helpers | @utils.transition, @utils.escalate |
| 6 | Variable Injection | Template values | {!@variables.customer_name} |
📐 ARCHITECTURE PATTERNS
See references/architecture-patterns.md for Hub-and-Spoke, Verification Gate, and Post-Action Loop patterns with diagrams and code examples.
Post-Action Loop (most important): Topic re-resolves after action completes — put checks at TOP of instructions: ->.
🐛 DEBUGGING & COMMON ISSUES
See references/debugging-guide.md for the 6 span types (topic_enter, before_reasoning, reasoning, action_call, transition, after_reasoning), trace analysis workflow, and forensic debugging patterns.
Common Issues Quick Reference
| Issue | Symptom | Fix |
|---|
Internal Error, try again later | Invalid default_agent_user | Query Einstein Agent User in target org |
No .agent file found in directory | agent_name doesn't match folder | Make developer_name identical to folder name |
SyntaxError: cannot mix spaces and tabs | Mixed indentation | Use consistent spacing throughout |
SyntaxError: Unexpected 'if' | Nested if statements | Use compound if A and B: or flatten |
SyntaxError: Unexpected 'actions' | Top-level actions block | Move inside topic.reasoning.actions: |
SyntaxError: Unexpected 'inputs' | inputs: in Level 2 invocation | Use with param=value in invocations |
ValidationError: Tool target 'X'... | Action not defined or target missing | Ensure Level 1 definition + valid target |
Required fields missing: [BundleType] | Wrong deploy command | Use sf agent publish authoring-bundle |
Cannot find a bundle-meta.xml file | Wrong file naming | Use AgentName.bundle-meta.xml |
Full issue catalog: See references/known-issues.md for 17+ platform bugs and workarounds.
Verification Protocol
When something fails, fetch the relevant canonical URL from references/official-sources.md and verify. See the diagnostic decision tree mapping 6 error categories to specific doc pages.
Self-Improvement
This skill's resource files are editable. When you discover errors, new patterns, or platform bugs during a session — fix them in place. See references/known-issues.md for the issue template.
Deployment Gotchas (Validated by Testing)
| ❌ Wrong | ✅ Correct |
|---|
AgentName.aiAuthoringBundle-meta.xml | AgentName.bundle-meta.xml |
sf project deploy start | sf agent publish authoring-bundle |
sf agent validate --source-dir | sf agent validate authoring-bundle --source-dir |
| Query user from wrong org | Query target org specifically with -o flag |
Einstein Agent User Format (Org-Specific)
Formats vary: username@orgid.ext (production) or username.suffix@orgfarm.salesforce.com (dev). MANDATORY: Ask user to confirm which Einstein Agent User when creating a new agent.
sf data query -q "SELECT Username FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true" -o YOUR_TARGET_ORG --json
📚 DOCUMENT MAP (Progressive Disclosure)
Tier 1: Reference Guides (Extracted from this skill)
Tier 2: Resource Guides (Comprehensive)
Tier 3: Quick References (Docs)
Tier 4: Templates
🔗 CROSS-SKILL INTEGRATION
MANDATORY Delegations
| Task | Delegate To | Reason |
|---|
Create Flows for flow:// targets | /sf-flow | Flows must exist before agent uses them |
| Test agent routing & actions | /sf-ai-agentforce-testing | Specialized testing patterns |
| Deploy agent to org | /sf-deploy | Proper deployment validation |
Integration Patterns
| From | To | Pattern |
|---|
/sf-ai-agentscript | /sf-flow | Create Flow, then reference in agent |
/sf-ai-agentscript | /sf-apex | Create Apex class with @InvocableMethod, then use apex://ClassName target directly (NO GenAiFunction needed) |
/sf-ai-agentscript | /sf-integration | Set up Named Credentials for externalService:// |
✅ DEPLOYMENT CHECKLIST
Deployment Checklist: Validate → Deploy → Publish → Activate. Each step has specific CLI commands and required flags.
See references/cli-guide.md for the full deployment workflow with examples.
🚀 MINIMAL WORKING EXAMPLE
Minimal Working Example: See references/minimal-examples.md for a complete hello-world agent script with explanatory comments.
📖 OFFICIAL RESOURCES
Full Registry: See references/official-sources.md for 14 primary doc URLs, 8 recipe URLs, diagnostic decision tree, and fallback search patterns.
📚 SOURCES & VERSION HISTORY
See references/sources.md for full source attributions (trailheadapps/agent-script-recipes, @kunello PR #20, aquivalabs/my-org-butler, and more).
See references/version-history.md for the complete changelog from v1.0.0 through v2.3.0.