jaganpro

sf-ai-agentscript

41
5
# Install this skill:
npx skills add Jaganpro/sf-skills --skill "sf-ai-agentscript"

Install specific skill from multi-skill repository

# Description

>

# SKILL.md


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: "1.4.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)"
# Validation Framework
last_validated: "2026-01-20"
validation_status: "PASS"
validation_agents: 13
validate_by: "2026-02-19" # 30 days from last validation
validation_org: "R6-Agentforce-SandboxFull"
hooks:
PreToolUse:
- matcher: Bash
hooks:
- type: command
command: "python3 ${SHARED_HOOKS}/scripts/guardrails.py"
timeout: 5000
PostToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: "python3 ${SKILL_HOOKS}/agentscript-syntax-validator.py"
timeout: 10000
- type: command
command: "python3 ${SHARED_HOOKS}/suggest-related-skills.py sf-ai-agentscript"
timeout: 5000
SubagentStop:
- type: command
command: "python3 ${SHARED_HOOKS}/scripts/chain-validator.py sf-ai-agentscript"
timeout: 5000


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

  1. default_agent_user MUST be valid - Query: SELECT Username FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true
  2. No mixed tabs/spaces - Use consistent indentation (2-space, 3-space, or tabs - never mix)
  3. Booleans are capitalized - Use True/False, not true/false
  4. Exactly one start_agent block - Multiple entry points cause compilation failure

⛔ SYNTAX CONSTRAINTS (Validated via Testing + Official Spec)

Constraint ❌ WRONG ✅ CORRECT
No nested if statements if x: then if y: (nested) 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 actions inputs: block inside action Use with for inputs, set for outputs
One available when per action Two available when clauses available when A and B
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 @utils.X with set/run Only @actions.X supports post-action
agent_name must match folder Folder: MyAgent, config: my_agent Both must be identical (case-sensitive)
Reserved field names description: string, label: string Use descriptions, label_text, or suffix with _field

🔴 Reserved Field Names (Breaking in Recent Releases)

Common field names that cause parse errors:

❌ RESERVED (cannot use as variable/field names):
description, label, is_required, is_displayable, is_used_by_planner

✅ WORKAROUNDS:
description  → descriptions, description_text, desc_field
label        → label_text, display_label, label_field

🔴 Features NOT Valid in Current Release (TDD Validated 2026-01-20)

These features appear in documentation or recipes but do NOT compile in Winter '26.

Feature Where Mentioned Error Status
label: on topics agentforce.guide Unexpected 'label' ❌ NOT valid anywhere
label: on actions agentforce.guide Unexpected 'label' ❌ NOT valid anywhere
always_expect_input: Some docs Unexpected 'always_expect_input' ❌ NOT implemented
require_user_confirmation: on transitions Recipes Unexpected 'require_user_confirmation' ❌ NOT valid on @utils.transition
include_in_progress_indicator: on transitions Recipes Unexpected 'include_in_progress_indicator' ❌ NOT valid on @utils.transition
output_instructions: on transitions Recipes Unexpected 'output_instructions' ❌ NOT valid on @utils.transition
progress_indicator_message: on transitions Recipes Unexpected 'progress_indicator_message' ❌ May only work on flow:// targets

What DOES work on @utils.transition actions:

actions:
   go_next: @utils.transition to @topic.next
      description: "Navigate to next topic"   # ✅ ONLY this works

Note: Some of these may work on flow:// action targets (not validated). The @utils.transition utility action has limited property support.

🔴 complex_data_type_name Mapping Table (Critical for Actions)

"#1 source of compile errors" - Use this table when defining action inputs/outputs in Agentforce Assets.

Data Type complex_data_type_name Value Notes
string (none needed) Primitive type
number (none needed) Primitive type
boolean (none needed) Primitive type
object (SObject) lightning__recordInfoType Use for Account, Contact, etc.
list[string] lightning__textType Collection of text values
list[object] lightning__textType Serialized as JSON text
Apex Inner Class @apexClassType/NamespacedClass__InnerClass Namespace required
Custom LWC Type lightning__c__CustomTypeName Custom component types
Currency field lightning__currencyType For monetary values

Pro Tip: Don't manually edit complex_data_type_name - use the UI dropdown in Agentforce Assets > Action Definition, then export/import the action definition.

⚠️ Canvas View Corruption Bugs

CRITICAL: Canvas view can silently corrupt Agent Script syntax. Make complex edits in Script view.

Original Syntax Canvas Corrupts To Impact
== {! OPERATOR.EQUAL } Breaks conditionals
if condition: if condition (missing colon) Parse error
with email = with @inputs.email = Invalid syntax
4-space indent De-indented (breaks nesting) Structure lost
@topic.X (supervision) @utils.transition to @topic.X (handoff) Changes return behavior
A and B A {! and } B Breaks compound conditions

Safe Workflow:
1. Use Script view for all structural edits (conditionals, actions, transitions)
2. Use Canvas only for visual validation and simple text changes
3. Always review in Script view after any Canvas edit

⚠️ Preview Mode Critical Bugs

CRITICAL REFRESH BUG: Browser refresh required after every Agent Script save before preview works properly.

Issue Error Message Workaround
Linked vars in context, not state "Cannot access 'X': Not a declared field in dict" Convert to mutable + hardcode for testing
Output property access fails Silent failure, no error Assign to variable first, then use in conditional
Simulate vs Live behavior differs Works in Simulate, fails in Live Test in BOTH modes before committing

Pattern for Testing Linked Variables:

# ❌ DOESN'T WORK IN PREVIEW (linked var from session):
RoutableId: linked string
   source: @MessagingSession.Id

# ✅ WORKAROUND FOR TESTING (hardcode value):
RoutableId: mutable string = "test-session-123"
   description: "MessagingSession Id (hardcoded for testing)"

# After testing, switch back to linked for production

Output Property Access Pattern:

# ❌ DOESN'T WORK IN PREVIEW (direct output access):
if @actions.check_status.result == "approved":
   | Approved!

# ✅ CORRECT (assign to variable first):
set @variables.status = @outputs.result
if @variables.status == "approved":
   | Approved!

No Nested if - Two Valid Approaches

# ❌ WRONG - Nested if (causes SyntaxError)
if @variables.software_cost > 0:
   if @variables.software_cost <= 500:
      | Auto-approve this software request.

# ✅ CORRECT Approach 1 - Compound condition (when logic allows)
if @variables.software_cost > 0 and @variables.software_cost <= 500:
   | Auto-approve this software request.

# ✅ CORRECT Approach 2 - Flatten to sequential ifs (for separate messages)
if @variables.order_verified == False or @variables.payment_confirmed == False:
   | ❌ **PROCESSING BLOCKED**
   | Missing requirements:

if @variables.order_verified == False:
   | - Order verification pending

if @variables.payment_confirmed == False:
   | - Payment confirmation pending

When to use each: Use compound conditions when logic permits (single condition block). Use flattening when you need separate conditional outputs that can't be combined.

... is Slot-Filling Syntax (LLM Extracts from Conversation)

# ❌ WRONG - Using ... as default value
order_id: mutable string = ...

# ✅ CORRECT - Use ... only in action parameter binding
reasoning:
   actions:
      search: @actions.search_products
         with query=...           # LLM extracts from user message
         with category=...        # LLM decides based on context
         with limit=10            # Fixed value

Post-Action Directives: Only on @actions.*

# ❌ WRONG - @utils does NOT support set/run/if
go_next: @utils.transition to @topic.main
   set @variables.visited = True   # ERROR!

# ✅ CORRECT - Only @actions.* supports post-action
process: @actions.process_order
   with [email protected]_id
   set @variables.status = @outputs.status        # ✅ Works
   run @actions.send_notification                 # ✅ Works
   if @outputs.needs_review:                      # ✅ Works
      transition to @topic.review

Helper Topic Pattern (For Demo Agents Without Flows/Apex)

When you need to set variables without backend actions, use dedicated "helper topics":

# Main topic offers LLM-selectable action
topic verify_employee:
   reasoning:
      actions:
         complete_verification: @utils.transition to @topic.verification_success
            description: "Mark employee as verified"
            available when @variables.employee_verified == False

# Helper topic sets variables in instructions, then returns
topic verification_success:
   description: "Set verified state and return"
   reasoning:
      instructions: ->
         set @variables.employee_verified = True
         set @variables.employee_name = "Demo Employee"
         | ✓ Identity verified!
         transition to @topic.verify_employee  # Return to parent

Why this works: set statements ARE valid inside instructions: -> blocks. The topic loop pattern lets you change state without Flows/Apex.


💰 PRODUCTION GOTCHAS: Billing, Determinism & Performance

Credit Consumption Table

Key insight: Framework operations are FREE. Only actions that invoke external services consume credits.

Operation Credits Notes
@utils.transition FREE Framework navigation
@utils.setVariables FREE Framework state management
@utils.escalate FREE Framework escalation
if/else control flow FREE Deterministic resolution
before_reasoning FREE Deterministic pre-processing (see note below)
after_reasoning FREE Deterministic post-processing (see note below)
reasoning (LLM turn) FREE LLM reasoning itself is not billed
Prompt Templates 2-16 Per invocation (varies by complexity)
Flow actions 20 Per action execution
Apex actions 20 Per action execution
Any other action 20 Per action execution

✅ Lifecycle Hooks Validated (v1.3.0): The before_reasoning: and after_reasoning: lifecycle hooks are now TDD-validated. Content goes directly under the block (no instructions: wrapper). See "Lifecycle Hooks" section below for correct syntax.

Cost Optimization Pattern: Fetch data once in before_reasoning:, cache in variables, reuse across topics.

Lifecycle Hooks: before_reasoning: and after_reasoning:

TDD Validated (2026-01-20): These hooks enable deterministic pre/post-processing around LLM reasoning.

topic main:
   description: "Topic with lifecycle hooks"

   # BEFORE: Runs deterministically BEFORE LLM sees instructions
   before_reasoning:
      # Content goes DIRECTLY here (NO instructions: wrapper!)
      set @variables.pre_processed = True
      set @variables.customer_tier = "gold"

   # LLM reasoning phase
   reasoning:
      instructions: ->
         | Customer tier: {[email protected]_tier}
         | How can I help you today?

   # AFTER: Runs deterministically AFTER LLM finishes reasoning
   after_reasoning:
      # Content goes DIRECTLY here (NO instructions: wrapper!)
      set @variables.interaction_logged = True
      if @variables.needs_audit == True:
         set @variables.audit_flag = True

Key Points:
- Content goes directly under before_reasoning: / after_reasoning: (NO instructions: wrapper)
- Supports set, if, run statements (same as procedural instructions: ->)
- before_reasoning: is FREE (no credit cost) - use for data prep
- after_reasoning: is FREE (no credit cost) - use for logging, cleanup

❌ WRONG Syntax (causes compile error):

before_reasoning:
   instructions: ->      # ❌ NO! Don't wrap with instructions:
      set @variables.x = True

✅ CORRECT Syntax:

before_reasoning:
   set @variables.x = True   # ✅ Direct content under the block

Supervision vs Handoff (Clarified Terminology)

Term Syntax Behavior Use When
Handoff @utils.transition to @topic.X Control transfers completely, child generates final response Checkout, escalation, terminal states
Supervision @topic.X (as action reference) Parent orchestrates, child returns, parent synthesizes Expert consultation, sub-tasks
# HANDOFF - child topic takes over completely:
checkout: @utils.transition to @topic.order_checkout
   description: "Proceed to checkout"
# → @topic.order_checkout generates the user-facing response

# SUPERVISION - parent remains in control:
get_advice: @topic.product_expert
   description: "Consult product expert"
# → @topic.product_expert returns, parent topic synthesizes final response

KNOWN BUG: Adding ANY new action in Canvas view may inadvertently change Supervision references to Handoff transitions.

Action Output Flags for Zero-Hallucination Routing

Key Pattern for Determinism: Control what the LLM can see and say.

When defining actions in Agentforce Assets, use these output flags:

Flag Effect Use When
is_displayable: False LLM cannot show this value to user Preventing hallucinated responses
is_used_by_planner: True LLM can reason about this value Decision-making, routing

Zero-Hallucination Intent Classification Pattern:

# In Agentforce Assets - Action Definition outputs:
outputs:
   intent_classification: string
      is_displayable: False       # LLM cannot show this to user
      is_used_by_planner: True    # LLM can use for routing decisions

# In Agent Script - LLM routes but cannot hallucinate:
topic intent_router:
   reasoning:
      instructions: ->
         run @actions.classify_intent
         set @variables.intent = @outputs.intent_classification

         if @variables.intent == "refund":
            transition to @topic.refunds
         if @variables.intent == "order_status":
            transition to @topic.orders

Action Chaining with run Keyword

Known quirk: Parent action may complain about inputs needed by chained action - this is expected.

# Chained action execution:
process_order: @actions.create_order
   with customer_id = @variables.customer_id
   run @actions.send_confirmation        # Chains after create_order completes
   set @variables.order_id = @outputs.id

KNOWN BUG: Chained actions with Prompt Templates don't properly map inputs using Input:Query format:

# ❌ MAY NOT WORK with Prompt Templates:
run @actions.transform_recommendation
   with "Input:Reco_Input" = @variables.ProductReco

# ⚠️ TRY THIS (may still have issues):
run @actions.transform_recommendation
   with Reco_Input = @variables.ProductReco

Latch Variable Pattern for Topic Re-entry

Problem: Topic selector doesn't properly re-evaluate after user provides missing input.

Solution: Use a "latch" variable to force re-entry:

variables:
   verification_in_progress: mutable boolean = False

start_agent topic_selector:
   reasoning:
      instructions: ->
         # LATCH CHECK - force re-entry if verification was started
         if @variables.verification_in_progress == True:
            transition to @topic.verification

         | How can I help you today?
      actions:
         start_verify: @topic.verification
            description: "Start identity verification"
            # Set latch when user chooses this action
            set @variables.verification_in_progress = True

topic verification:
   reasoning:
      instructions: ->
         | Please provide your email to verify your identity.
      actions:
         verify: @actions.verify_identity
            with email = ...
            set @variables.verified = @outputs.success
            # Clear latch when verification completes
            set @variables.verification_in_progress = False

Loop Protection Guardrail

Agent Scripts have a built-in guardrail that limits iterations to approximately 3-4 loops before breaking out and returning to the Topic Selector.

Best Practice: Map out your execution paths - particularly topic transitions. Ensure testing covers all paths and specifically check for unintended circular references between topics.

Token & Size Limits

Limit Type Value Notes
Max response size 1,048,576 bytes (1MB) Per agent response
Plan trace limit (Frontend) 1M characters For debugging UI
Transformed plan trace (Backend) 32k tokens Internal processing
Active/Committed Agents per org 100 max Org limit

Progress Indicators

Add user feedback during long-running actions:

actions:
   fetch_data: @actions.get_customer_data
      description: "Fetch customer information"
      include_in_progress_indicator: True
      progress_indicator_message: "Fetching your account details..."

VS Code Pull/Push NOT Supported

# ❌ ERROR when using source tracking:
Failed to retrieve components using source tracking:
[SfError [UnsupportedBundleTypeError]: Unsupported Bundle Type: AiAuthoringBundle

# ✅ WORKAROUND - Use CLI directly:
sf project retrieve start -m AiAuthoringBundle:MyAgent
sf agent publish authoring-bundle --source-dir ./force-app/main/default/aiAuthoringBundles/MyAgent

Language Block Quirks

  • Hebrew and Indonesian appear twice in the language dropdown
  • Selecting from the second set causes save errors
  • Use adaptive_response_allowed: True for automatic language adaptation
language:
   locale: en_US
   adaptive_response_allowed: True  # Allow language adaptation

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 ⚠️ REQUIRED

📋 QUICK REFERENCE: Agent Script Syntax

Block Structure (CORRECTED Order per Official Spec)

config:        # 1. Required: Agent metadata (agent_name, default_agent_user)
variables:     # 2. Optional: State management (mutable/linked)
system:        # 3. Required: Global messages and instructions
connections:   # 4. Optional: Escalation routing
knowledge:     # 5. Optional: Knowledge base config
language:      # 6. Optional: Locale settings
start_agent:   # 7. Required: Entry point (exactly one)
topic:         # 8. Required: Conversation topics (one or more)

Naming Rules (All Identifiers)

  • Only letters, numbers, underscores
  • Must begin with a letter
  • No spaces, no consecutive underscores, cannot end with underscore
  • Maximum 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
set @var = value Set variable in instructions set @variables.count = 0
{[email protected]} Variable injection in text Risk score: {[email protected]}
{!expr if cond else alt} Conditional interpolation {[email protected] if @variables.status else "pending"}
available when Control action visibility to LLM available when @variables.verified == True
with param=... LLM slot-filling (extracts from conversation) with query=...
with param=value Fixed parameter value with limit=10

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
# Delegation - returns to current topic after specialist finishes
consulting: @topic.expert_topic
   description: "Get expert advice"

# Transition - permanent handoff, no return
checkout: @utils.transition to @topic.checkout
   description: "Proceed to purchase"

Expression Operators (Safe Subset)

Category Operators NOT Supported
Comparison ==, <> (not-equal), <, <=, >, >=, is, is not
Logical and, or, not
Arithmetic +, - *, /, %
Access . (property), [] (index)
Conditional x if condition else y

Variable Types

Modifier Behavior Supported Types Default Required?
mutable Read/write state string, number, boolean, object, date, timestamp, currency, id, list[T] ✅ Yes
linked Read-only from source string, number, boolean, date, timestamp, currency, id ❌ No (has source:)

⚠️ Linked variables CANNOT use object or list types

Variable vs Action I/O Type Matrix

Critical distinction: Some types are valid ONLY for action inputs/outputs, NOT for Agent Script variables.

Type Variables Action I/O Notes
string Universal
number Universal
boolean Universal
date Universal
currency Universal
id Salesforce IDs
list ✅ (mutable only) Collections
object ✅ (mutable only) ⚠️ Not for linked vars
datetime Actions only
time Actions only
integer Actions only
long Actions only

Source: AGENT_SCRIPT.md rules document from trailheadapps/agent-script-recipes

Action Target Protocols

Short Long Form Use When Validated?
flow flow:// Data operations, business logic ✅ TDD
apex apex:// Custom calculations, validation ✅ TDD
prompt generatePromptResponse:// Grounded LLM responses ✅ TDD
api api:// REST API calls ✅ TDD
retriever retriever:// RAG knowledge search ✅ TDD
externalService externalService:// Third-party APIs via Named Credentials ✅ TDD
standardInvocableAction standardInvocableAction:// Built-in SF actions (email, tasks) ✅ TDD
datacloudDataGraphAction datacloudDataGraphAction:// Data Cloud graph queries 📋 Spec
datacloudSegmentAction datacloudSegmentAction:// Data Cloud segment operations 📋 Spec
triggerByKnowledgeSource triggerByKnowledgeSource:// Knowledge article triggers 📋 Spec
contextGrounding contextGrounding:// Context grounding for LLM 📋 Spec
predictiveAI predictiveAI:// Einstein prediction models 📋 Spec
runAction runAction:// Execute sub-actions 📋 Spec
external external:// External service calls 📋 Spec
copilotAction copilotAction:// Salesforce Copilot actions 📋 Spec
@topic.X (inline) Topic delegation (returns to parent) ✅ TDD

Legend: ✅ TDD = Validated via deployment testing | 📋 Spec = Documented in AGENT_SCRIPT.md spec (requires specific org setup to test)

Connection Block (Full Escalation Pattern)

connections:
   # Messaging channel escalation
   connection messaging:
      escalation_message: "One moment, I'm transferring our conversation to get you more help."
      outbound_route_type: "OmniChannelFlow"
      outbound_route_name: "<flow://Escalate_Messaging_To_Live_Agent>"
      adaptive_response_allowed: False

   # Voice channel escalation
   connection voice:
      escalation_message: "Please hold while I transfer you to a specialist."
      outbound_route_type: "Queue"
      outbound_route_name: "Support_Queue"
      adaptive_response_allowed: True

   # Web chat escalation
   connection web:
      escalation_message: "Connecting you with a live agent now."
      outbound_route_type: "OmniChannelFlow"
      outbound_route_name: "<flow://Web_Chat_Escalation>"

Key Properties:
| Property | Required | Description |
|----------|----------|-------------|
| escalation_message | ✅ | Message shown to user during handoff |
| outbound_route_type | ✅ | OmniChannelFlow, Queue, or Skill |
| outbound_route_name | ✅ | Flow API name or Queue name |
| adaptive_response_allowed | ❌ | Allow LLM to adapt escalation message |


🔄 WORKFLOW: Agent Development Lifecycle

Phase 1: Requirements & Design

  1. Identify deterministic vs. subjective logic
  2. Deterministic: Security checks, financial thresholds, data lookups, counters
  3. Subjective: Greetings, context understanding, natural language generation
  4. Design FSM architecture - Map topics as states, transitions as edges
  5. Define variables - Mutable for state tracking, linked for session context

Phase 2: Agent Script Authoring

  1. Create .agent file with required blocks
  2. Write topics with instruction resolution pattern:
  3. Post-action checks at TOP (triggers on loop)
  4. Pre-LLM data loading
  5. Dynamic instructions for LLM
  6. Configure actions with appropriate target protocols
  7. Add available when guards to enforce security

Phase 3: Validation (LSP + CLI)

AUTOMATIC: LSP validation runs on every Write/Edit to .agent files. Errors are reported with line numbers and autofix suggestions.

LSP Validation Loop (Find Error → Autofix)

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Write/Edit  │ ──▶ │ LSP Analyze │ ──▶ │ Report      │
│ .agent file │     │ (automatic) │     │ Errors      │
└─────────────┘     └─────────────┘     └──────┬──────┘
                                               │
      ┌────────────────────────────────────────┘
      ▼
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Claude      │ ──▶ │ Apply Fix   │ ──▶ │ Re-validate │
│ Suggests Fix│     │ (Edit tool) │     │ (loop)      │
└─────────────┘     └─────────────┘     └─────────────┘

LSP Checks (Automatic)

Check Severity Autofix
Mixed tabs/spaces ❌ Error Convert to consistent spacing
Lowercase booleans (true/false) ❌ Error Capitalize to True/False
Missing required blocks ❌ Error Add missing block template
Missing default_agent_user ❌ Error Add placeholder with comment
Mutable + linked conflict ❌ Error Remove conflicting modifier
Undefined topic references ⚠️ Warning Create topic stub
Post-action check position ⚠️ Warning Move to top of instructions

CLI Validation (Before Deploy)

# Validate authoring bundle syntax
sf agent validate authoring-bundle --source-dir ./force-app/main/default/aiAuthoringBundles/MyAgent

Manual Checks

  • default_agent_user exists and is active Einstein Agent User
  • All topic references resolve to existing topics
  • Action targets (flow://, apex://, etc.) exist in org

Phase 4: Testing (Delegate to /sf-ai-agentforce-testing)

  1. Batch testing - Run up to 100 test cases simultaneously
  2. Quality metrics - Completeness, Coherence, Topic/Action Assertions
  3. LLM-as-Judge - Automated scoring against golden responses

Phase 5: Deployment

⚠️ CRITICAL: Use sf agent publish authoring-bundle, NOT sf project deploy start

  1. Create bundle directory: force-app/main/default/aiAuthoringBundles/AgentName/
  2. Add files:
  3. AgentName.agent - Your Agent Script
  4. AgentName.bundle-meta.xml - Metadata XML (NOT .aiAuthoringBundle-meta.xml)
  5. Publish: sf agent publish authoring-bundle --source-dir ./force-app/main/default/aiAuthoringBundles/AgentName
  6. Monitor - Use trace debugging for production issues

Phase 6: CLI Operations

# Retrieve from org
sf agent retrieve --name MyAgent --target-org sandbox

# Validate syntax
sf agent validate authoring-bundle --source-dir ./force-app/main/default/aiAuthoringBundles/MyAgent

# Publish to org (NOT sf project deploy!)
sf agent publish authoring-bundle --source-dir ./force-app/main/default/aiAuthoringBundles/MyAgent

Bundle Structure (CRITICAL)

force-app/main/default/aiAuthoringBundles/
└── MyAgent/
    ├── MyAgent.agent              # Agent Script file
    └── MyAgent.bundle-meta.xml    # NOT .aiAuthoringBundle-meta.xml!

bundle-meta.xml content:

<?xml version="1.0" encoding="UTF-8"?>
<AiAuthoringBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <bundleType>AGENT</bundleType>
</AiAuthoringBundle>

📊 SCORING SYSTEM (100 Points)

Categories

Category Points Key Criteria
Structure & Syntax 20 Block ordering, indentation consistency, required fields present
Deterministic Logic 25 Security via available when, post-action checks, proper conditionals
Instruction Resolution 20 Correct use of -> vs \|, template injection, action execution
FSM Architecture 15 Clear topic separation, explicit transitions, state management
Action Configuration 10 Correct protocols, input/output mapping, error handling
Deployment Readiness 10 Valid default_agent_user, no compilation errors, metadata complete

Scoring Rubric Details

Structure & Syntax (20 points)

Points Criteria
20 All required blocks present, consistent indentation, valid identifiers
15 Minor issues (e.g., inconsistent spacing within tolerance)
10 Missing optional blocks that would improve clarity
5 Block ordering issues or mixed indentation
0 Missing required blocks or compilation failures

Deterministic Logic (25 points)

Points Criteria
25 All security actions guarded with available when, post-action patterns used
20 Most guards present, minor gaps in deterministic enforcement
15 Some security logic relies on prompts instead of guards
10 Critical actions lack available when guards
0 Security logic entirely prompt-based (LLM can bypass)

Instruction Resolution (20 points)

Points Criteria
20 Arrow syntax for complex logic, proper template injection, correct action execution
15 Mostly correct, minor syntax issues
10 Uses pipe syntax where arrow needed, template injection errors
5 Incorrect phase ordering (data loads after LLM sees instructions)
0 Fundamental misunderstanding of resolution order

FSM Architecture (15 points)

Points Criteria
15 Clear topic boundaries, explicit transitions, appropriate escalation paths
12 Good structure with minor redundancy
9 Topics too broad or transitions unclear
5 Monolithic topic handling multiple concerns
0 No topic separation, all logic in start_agent

Action Configuration (10 points)

Points Criteria
10 Correct protocols, proper I/O mapping, descriptions present
8 Minor issues (missing descriptions)
5 Wrong protocol for use case
2 Input/output mapping errors
0 Actions don't compile

Deployment Readiness (10 points)

Points Criteria
10 Valid user, clean validation, metadata complete
8 Minor warnings
5 Validation errors that need fixing
2 Missing metadata files
0 Cannot deploy

Score Thresholds

Score Rating Action
90-100 ⭐⭐⭐⭐⭐ Excellent Deploy with confidence
80-89 ⭐⭐⭐⭐ Very Good Minor improvements recommended
70-79 ⭐⭐⭐ Good Review flagged issues before deploy
60-69 ⭐⭐ Needs Work Address issues before deploy
<60 ⭐ Critical BLOCK - Fix critical issues

Score Report Format

📊 AGENT SCRIPT SCORE REPORT
════════════════════════════════════════

Score: 85/100 ⭐⭐⭐⭐ Very Good
├─ Structure & Syntax:    18/20 (90%)
├─ Deterministic Logic:   22/25 (88%)
├─ Instruction Resolution: 16/20 (80%)
├─ FSM Architecture:      12/15 (80%)
├─ Action Configuration:   9/10 (90%)
└─ Deployment Readiness:   8/10 (80%)

Issues:
⚠️ [Deterministic] Missing `available when` on process_refund action
⚠️ [Resolution] Post-action check should be at TOP of instructions
✓ All Structure & Syntax checks passed
✓ All Action Configuration checks passed

🔧 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 {[email protected]_name}

📐 ARCHITECTURE PATTERNS

Pattern 1: Hub and Spoke

Central router (hub) to specialized topics (spokes). Use for multi-purpose agents.

       ┌─────────────┐
       │ topic_sel   │
       │   (hub)     │
       └──────┬──────┘
    ┌─────────┼─────────┐
    ▼         ▼         ▼
┌────────┐ ┌────────┐ ┌────────┐
│refunds │ │ orders │ │support │
└────────┘ └────────┘ └────────┘

Pattern 2: Verification Gate

Security gate before protected topics. Mandatory for sensitive data.

┌─────────┐     ┌──────────┐     ┌───────────┐
│  entry  │ ──▶ │ VERIFY   │ ──▶ │ protected │
└─────────┘     │  (GATE)  │     │  topics   │
                └────┬─────┘     └───────────┘
                     │ 3 fails
                     ▼
                ┌──────────┐
                │ lockout  │
                └──────────┘

Pattern 3: Post-Action Loop

Topic re-resolves after action completes - put checks at TOP.

topic refund:
  reasoning:
    instructions: ->
      # POST-ACTION CHECK (at TOP - triggers on next loop)
      if @variables.refund_status == "Approved":
        run @actions.create_crm_case
        transition to @topic.success

      # PRE-LLM DATA LOADING
      run @actions.check_churn_risk
      set @variables.risk = @outputs.score

      # DYNAMIC INSTRUCTIONS FOR LLM
      if @variables.risk >= 80:
        | Offer full refund to retain customer.
      else:
        | Offer $10 credit instead.

🐛 DEBUGGING: Trace Analysis

The 6 Span Types

Span Description
➡️ topic_enter Execution enters a topic
before_reasoning Deterministic pre-processing
🧠 reasoning LLM processes instructions
action_call Action invoked
transition Topic navigation
after_reasoning Deterministic post-processing

Debugging Workflow

  1. Interaction Details - Quick understanding of what happened
  2. Trace Waterfall - Technical view with exact prompts, latencies
  3. Variable State - Entry vs Exit values reveal when state was ignored
  4. Script View - Red squiggles show syntax errors

Common Debug Patterns

Symptom Check Fix
Wrong policy applied Variable Entry values Change mutable to linked with source:
Action executed without auth available when presence Add guard clause
LLM ignores variable Instruction resolution order Move data load before LLM text
Infinite loop Transition conditions Add exit condition

⚠️ COMMON ISSUES & FIXES

Issue Symptom Fix
Internal Error, try again later Invalid default_agent_user Query: sf data query -q "SELECT Username FROM User WHERE Profile.Name = 'Einstein Agent User'" -o TARGET_ORG
Default agent user X could not be found User doesn't exist in target org Query the specific target org (user formats vary: some use [email protected])
No .agent file found in directory agent_name doesn't match folder Make agent_name identical to folder name (case-sensitive)
SyntaxError: cannot mix spaces and tabs Mixed indentation Use consistent spacing throughout
SyntaxError: Unexpected 'if' Nested if statements Use compound condition: if A and B: or flatten to sequential ifs
SyntaxError: Unexpected 'actions' Top-level actions block Move actions inside topic.reasoning.actions:
SyntaxError: Unexpected 'inputs' inputs: block in action Use with param=value syntax instead
SyntaxError: Unexpected 'outputs' outputs: block in action Use set @variables.x = @outputs.y instead
SyntaxError: Unexpected 'set' set after @utils.setVariables Use Helper Topic Pattern (set in instructions: ->)
Duplicate 'available when' clause Multiple guards on action Combine: available when A and B
Unexpected 'escalate' Reserved action name Rename to escalate_now or escalate_to_human
Transition to undefined topic Typo in topic reference Check spelling, ensure topic exists
Variables cannot be both mutable AND linked Conflicting modifiers Choose one: mutable for state, linked for external
Required fields missing: [BundleType] Using wrong deploy command Use sf agent publish authoring-bundle, NOT sf project deploy start
Cannot find a bundle-meta.xml file Wrong file naming Rename to AgentName.bundle-meta.xml, NOT .aiAuthoringBundle-meta.xml
ValidationError: Tool target 'X' is not an action definition Action references non-existent Flow/Apex Create the action definition first, or use Helper Topic Pattern
LLM bypasses security check Using prompts for security Use available when guards instead
Post-action logic doesn't run Check not at TOP Move post-action check to first lines
Wrong data retrieved Missing filter Wrap retriever in Flow with filter inputs
Variables don't change Using @utils.setVariables with set Post-action set only works on @actions.*, use Helper Topics

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)

Einstein Agent User formats vary between orgs:
- Production/Partner orgs: Often use [email protected] format (e.g., [email protected])
- Dev orgs: May use [email protected] format

MANDATORY: Ask user to confirm which Einstein Agent User to use when creating a new agent.

Always query the specific target org:

# Query target org specifically
sf data query -q "SELECT Username FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true" -o YOUR_TARGET_ORG

Present the results to the user and ask them to select which user to use for default_agent_user.

⚠️ A user existing in one org does NOT mean it exists in another. Always verify in the deployment target.


📚 DOCUMENT MAP (Progressive Disclosure)

Tier 2: Resource Guides (Comprehensive)

Need Document Description
Syntax reference resources/syntax-reference.md Complete block & expression syntax
FSM design resources/fsm-architecture.md State machine patterns & examples
Instruction resolution resources/instruction-resolution.md Three-phase execution model
Data & multi-agent resources/grounding-multiagent.md Retriever actions & SOMA patterns
Debugging resources/debugging-guide.md Trace analysis & forensics
Testing resources/testing-guide.md Batch testing & quality metrics

Tier 3: Quick References (Docs)

Need Document Description
CLI commands docs/cli-guide.md sf agent retrieve/validate/deploy
Patterns docs/patterns-quick-ref.md Decision tree for pattern selection

🔗 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, then use apex:// protocol
/sf-ai-agentscript /sf-integration Set up Named Credentials for externalService://

✅ DEPLOYMENT CHECKLIST

Configuration

  • [ ] default_agent_user is valid Einstein Agent User
  • [ ] agent_name uses snake_case (no spaces)

Syntax

  • [ ] No mixed tabs/spaces
  • [ ] Booleans use True/False
  • [ ] Variable names use snake_case

Structure

  • [ ] Exactly one start_agent block
  • [ ] At least one topic block
  • [ ] All transitions reference existing topics

Security

  • [ ] Critical actions have available when guards
  • [ ] Session data uses linked variables (not mutable)

Testing

  • [ ] sf agent validate --source-dir ./my-agent passes
  • [ ] Preview mode tested before activation

🚀 MINIMAL WORKING EXAMPLE

config:
  agent_name: "simple_agent"
  agent_label: "Simple Agent"
  description: "A minimal working agent example"
  default_agent_user: "[email protected]"

system:
  messages:
    welcome: "Hello! How can I help you today?"
    error: "Sorry, something went wrong."
  instructions: "You are a helpful customer service agent."

variables:
  customer_verified: mutable boolean = False

topic main:
  description: "Main conversation handler"
  reasoning:
    instructions: ->
      if @variables.customer_verified == True:
        | You are speaking with a verified customer.
        | Help them with their request.
      else:
        | Please verify the customer's identity first.
    actions:
      verify: @actions.verify_customer
        description: "Verify customer identity"
        set @variables.customer_verified = @outputs.verified

start_agent entry:
  description: "Entry point for all conversations"
  reasoning:
    instructions: |
      Greet the customer and route to the main topic.
    actions:
      go_main: @utils.transition to @topic.main
        description: "Navigate to main conversation"

📖 OFFICIAL RESOURCES


📚 SOURCES & ACKNOWLEDGMENTS

This skill draws from multiple authoritative sources:

Source Contribution
trailheadapps/agent-script-recipes 20 reference recipes across 4 categories, AGENT_SCRIPT.md rules document, variable patterns, action target catalog
Salesforce Official Documentation Core syntax, API references, deployment guides
TDD Validation (this skill) 13 validation agents confirming current-release syntax compatibility
Tribal knowledge interviews Canvas View bugs, VS Code limitations, credit consumption patterns
agentforce.guide Unofficial but useful examples (note: some patterns don't compile in current release)

⚠️ Note on Feature Validation: Some patterns from external sources (e.g., always_expect_input:, label: property, certain action properties on transitions) do NOT compile in Winter '26. The before_reasoning:/after_reasoning: lifecycle hooks ARE valid but require direct content (no instructions: wrapper) - see the Lifecycle Hooks section for correct syntax. This skill documents only patterns that pass TDD validation.


🏷️ VERSION HISTORY

Version Date Changes
1.3.0 2026-01-20 Lifecycle hooks validated: Added full documentation for before_reasoning: and after_reasoning: with CORRECT syntax (content directly under block, NO instructions: wrapper). Added "Features NOT Valid in Current Release" section documenting 7 features that appear in docs/recipes but don't compile (label on topics/actions, always_expect_input, action properties on transitions). Updated validation_agents count to 13. Confirmed @utils.transition only supports description: property.
1.2.0 2026-01-20 Gap analysis vs agent-script-recipes: Expanded Action Target Protocols from 7 to 16 (with validation status indicators), added Variable vs Action I/O Type Matrix, added lifecycle hooks note with TDD validation caveat, added Sources & Acknowledgments section, documented future/planned features notice. TDD validation confirmed label: IS reserved (SKILL.md was correct), before_reasoning:/after_reasoning: syntax from recipes does NOT compile in current release
1.1.0 2026-01-20 "Ultimate Guide" tribal knowledge integration: Added complex_data_type_name mapping table, Canvas View corruption bugs, Reserved field names, Preview mode workarounds, Credit consumption table, Supervision vs Handoff clarification, Action output flags for zero-hallucination routing, Latch variable pattern, Loop protection guardrails, Token/size limits, Progress indicators, Connection block escalation patterns, VS Code limitations, Language block quirks. Added 4 new templates: flow-action-lookup, prompt-rag-search, deterministic-routing, escalation-pattern
1.0.4 2026-01-19 Progressive testing validation (Quiz_Master, Expense_Calculator, Order_Processor): Added constraints for no top-level actions: block, no inputs:/outputs: in reasoning.actions, expanded nested-if guidance with flattening approach, added new SyntaxError entries to common issues
1.0.3 2026-01-19 Added Einstein Agent User interview requirement - mandatory user confirmation when creating new agents
1.0.2 2026-01-19 Major corrections from GitHub reference: Fixed block order (config→system), added Helper Topic Pattern, transition vs delegation, expression operators (+/- only), naming rules (80 char max), slot-filling ... syntax, post-action directives (@actions.* only)
1.0.1 2026-01-19 Added syntax constraints from 0-shot testing: no nested if, one available when per action, reserved action names
1.0.0 2026-01 Initial release with 8-module coverage

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.