Agent Script for Developers: Coding Agentforce Agents Like Real Software
Building an agent by clicking through Agentforce Builder works fine until your logic gets specific — "offer free shipping only if the order total is over $100 AND the customer is a loyalty member AND it's not already on backorder." At that point, natural-language instructions to an LLM start to feel like duct tape. Agent Script is Salesforce's answer: a real, readable scripting language purpose-built for agents.
TL;DR: Agent Script is a declarative, human-readable language for defining Agentforce agents — their subagents (formerly called topics), instructions, variables, and actions — as code instead of only as clicks. It blends natural-language reasoning instructions with deterministic if/else logic, lives in a
.agentfile inside your Salesforce DX project, and is fully supported in VS Code with syntax highlighting and validation. If you've ever wished you could put an agent under version control, this is how.
Why Developers Should Care
Agentforce Builder's canvas view is genuinely good for admins — natural language in, working agent out. But every agent eventually needs the same things any serious codebase needs: predictable branching logic, reusable structure, code review, and a diff you can actually read. Agent Script gives you all of that because, under the hood, every agent you build in Agentforce — whether through chat, canvas, or script — is Agent Script. The Script view just lets you work with it directly instead of through a UI abstraction.
That matters for a very practical reason: it puts agent definitions in your Salesforce DX project, next to your Apex and LWC, where they can be versioned, code-reviewed, and deployed the same way as everything else you ship.
The Building Blocks of a Script File
An Agent Script file is organized into a small number of named blocks. Once you recognize them, most scripts read top to bottom without much translation:
| Block | What it holds |
|---|---|
config |
Core agent settings — developer_name, agent_label, description, agent_type, and which Salesforce user the agent runs as. |
system |
Agent-wide instructions and required messages like welcome and error. |
variables |
Named state the agent tracks across a conversation, referenced anywhere as @variables.<name>. |
subagent |
A self-contained unit of behavior — its own description, instructions, and available actions. This is where most of the actual logic lives. |
start_agent |
The entry point every conversation begins at; decides which subagent should handle the user's request. |
connected_subagent |
A reference to a different Agentforce agent in your org, so one agent can delegate work to another. |
If "subagent" sounds like a rename, it is — Salesforce renamed topics to subagents in April 2026 with no functional change, so don't be surprised if you see both terms depending on which doc or org version you're looking at.
A Worked Example: Order Status, in Script
Let's script a small piece of the same order-status scenario from our last post — but this time controlling when the agent should hand off to a human instead of just answering.
config:
developer_name: "Order_Support_Agent"
agent_label: "Order Support Agent"
agent_type: "AgentforceServiceAgent"
default_agent_user: "order_support_agent_user@yourorg.com"
description: "Helps customers check order status and escalates delayed orders to a human agent."
system:
welcome: "Hi! I can help you check on an order — what's your order number?"
error: "Something went wrong on my end. Let me connect you with a teammate."
variables:
order_status: string
days_delayed: number
subagent order_lookup:
description: "Looks up an order's status and delivery estimate when the customer provides an order number."
reasoning:
instructions:
"Ask for the order number if it hasn't been provided ->
If @variables.days_delayed > 3 | Apologize for the delay before sharing status details.
Otherwise | Share the order status plainly and offer to help with anything else."
actions:
- get_order_status
- transition_to_escalation
actions:
get_order_status:
description: "Calls Apex to retrieve status, delivery estimate, and delay in days for an order number."
target: apex://OrderStatusAction
subagent escalation:
description: "Hands off to a human agent when a delay is significant or the customer asks for a person."
reasoning:
instructions:
"If @variables.days_delayed > 7 | Explain that a specialist will follow up and transition immediately.
Otherwise | Ask one clarifying question before deciding whether to escalate."
A few things worth noticing:
- The line with
->insidereasoning.instructionsis where Agent Script earns its keep. Everything before it can be plain natural language; everything after can be a hard conditional evaluated against a real variable — not something the LLM has to infer from conversation history. get_order_statushere points atapex://OrderStatusAction— the exact custom Apex action with@InvocableMethodwe built in the previous post. Agent Script doesn't replace Apex actions; it's the orchestration layer that decides when and whether to call them.- Variables like
days_delayedgive the agent reliable memory instead of leaning on the LLM to remember and recompute values mid-conversation.
Three Ways to Write It (All Produce the Same Thing)
Salesforce is intentionally flexible about how you author a script:
- Chat with Agentforce and describe what you want ("if the order's more than a week late, hand it straight to a human") — Agentforce converts that into subagents, actions, and instructions for you.
- Canvas view — a visual, block-based editor where
/inserts logic patterns like if/else and@inserts references to subagents, actions, or variables. - Script view — write and edit the raw
.agentfile directly, with the same syntax highlighting and autocomplete you'd expect from any language extension in VS Code.
All three are the same underlying artifact. You can start in canvas view and drop into script view the moment the logic gets too specific for clicking — and back again.
Working in VS Code with Agentforce DX
If you'd rather live in your editor than in Setup, Agentforce DX brings the whole workflow local:
- Generate or retrieve an authoring bundle for your agent into your DX project — it lands at
force-app/main/default/aiAuthoringBundles/<Agent_API_Name>/<Agent_API_Name>.agent. - Edit the
.agentfile directly, or open the Agentforce Vibes panel to describe changes in natural language and let it edit the script for you. - Validate the file before you publish — VS Code's AFDX: Validate This Agent command (or the equivalent CLI command) checks that the script compiles and flags syntax errors with their exact location.
- Preview the agent from the script file itself to test behavior before publishing it back to your org.
One habit worth building early: validate often, not just before a deploy. Agent Script errors are usually small — a missing colon, a typo in a block name — and they're far easier to fix one at a time than after you've written fifty lines on top of a broken block.
Where This Fits with What You Already Know
If you've spent time in Flow, a lot of this will feel familiar wearing different clothes: subagents are a bit like Flow's screen-by-screen structure, reasoning instructions are your decision logic, and actions are the same invocable Apex, Flow, and prompt-template building blocks Agentforce already supports. The real shift is that it's all expressed as one readable, versionable file instead of a set of linked records you navigate by clicking.
The Bottom Line
Agent Script doesn't replace Agentforce Builder — it's what Agentforce Builder is writing on your behalf every time you build an agent through chat or canvas. Once your agent's logic outgrows what feels safe to leave entirely to LLM interpretation, dropping into Script view (or straight into VS Code with Agentforce DX) gives you the same rigor you already expect from Apex: version control, code review, and behavior you can actually predict.
Have you tried writing Agent Script directly, or are you still building through canvas view? Let me know how it's going in the comments below.
No comments:
Post a Comment