Building an Agentforce action from a Flow: the no-code path, and the interface you can't take back
You don't need Apex to give an agent a new capability. An autolaunched Flow, wired up as an action, is the path most admins should reach for first — but the variable descriptions decide whether the agent ever calls it correctly, and the input/output contract locks the moment you activate. Here's the whole build, the running-user trap, and where a Flow action still loses to Apex.
There’s a reflex among Salesforce developers that the moment an agent needs to do something, you write an Apex class. Sometimes you should. But the majority of custom capabilities an Agentforce agent needs — look up a record and return a few fields, create a case with the right defaults, kick off a multi-step process you already automated — are things you’d build in Flow if a human were driving them. Agentforce doesn’t change that. It changes who’s driving. And an autolaunched Flow, exposed as an agent action, is the fastest governed way to hand an agent a new tool without opening a code editor.
We’ve covered the Apex custom action build in detail, and the broader Flow-versus-Apex-versus-Agentforce decision that should precede either. This post is the missing middle: the actual Flow-based build. What kind of Flow works, why the variable descriptions are the part that decides success, the running-user boundary that quietly governs everything, and the two or three moments where a Flow action stops being the right answer and Apex takes over.
An agent action is a tool, and the agent reads the label
Before the build, the mental model that makes the whole thing click. To the Atlas reasoning engine, an action is a tool in a list. When a user says something, Atlas looks at the topic it routed to, reads the descriptions of the actions assigned to that topic, and decides which one — if any — to call and what to pass it. It does not read your Flow’s logic. It reads your descriptions. This is the single most important thing to internalize: from the agent’s side, a Flow action and an Apex action are indistinguishable — both surface the same way in the tool list — so the choice between them is about maintenance and testing, never about how the agent perceives them. What the agent perceives is text you wrote.
That reframes the job. You’re not just building automation; you’re writing the documentation an LLM uses to decide whether your automation is the right one to run. Get the logic perfect and the descriptions vague, and the agent either ignores the action or calls it with garbage.
Step 1: build an autolaunched Flow (and only an autolaunched Flow)
Agent actions support exactly one Flow type: Autolaunched Flow (No Trigger). Not a screen flow — the agent has no screen to render. Not a record-triggered flow — the agent invokes the action deliberately, it doesn’t wait for a database event. The agent runs the Flow in the background, headless, so anything that assumes a UI or a triggering record is the wrong shape.
Create the Flow, then define your interface with two kinds of variables:
- Input variables — the data the agent collects from the conversation and passes in. Mark each Available for input.
- Output variables — what the Flow hands back for the agent to use in its reply or its next step. Mark each Available for output.
These variables are the entire interface between the agent and your logic. Everything else — the record lookups, the assignments, the decision elements — is invisible to Atlas. A resource that isn’t marked available for input or output simply doesn’t exist as far as the agent is concerned.
Autolaunched Flow: "Get Order Status"
INPUT orderNumber (Text, Available for input)
└ description: "The customer's order number, e.g. 'SO-10024'.
Ask the customer for it if not already known."
── Get Records: Order where OrderNumber = {!orderNumber} ──
── Decision: found? ──
OUTPUT status (Text, Available for output)
└ description: "The fulfillment status of the order:
Processing, Shipped, Delivered, or Not Found."
OUTPUT trackingUrl (Text, Available for output)
└ description: "Carrier tracking URL, empty if not yet shipped."
Notice the descriptions on the variables. That’s not decoration.
Step 2: write the descriptions like you’re briefing a new hire
This is where Flow actions succeed or fail, and it’s the same principle that governs why an agent keeps picking the wrong topic: the model can only act on what you wrote in the classification and input descriptions.
Three descriptions matter, and they do different jobs:
- The action description tells the agent when to use this action. Good ones state what the action does, include a couple of example user utterances that should trigger it, and — where relevant — note dependencies (“call Verify Customer before this”). “Gets order status” is too thin. “Returns the fulfillment status and tracking link for a customer’s order, given an order number. Use when the customer asks where their order is, whether it shipped, or for tracking” gives Atlas something to match against.
- Input descriptions tell the agent what to collect and how. State the expected format, where the value comes from, and whether to ask the user for it.
orderNumberabove tells the agent the format and to ask if it doesn’t have it. - Output descriptions tell the agent how to interpret what came back, so it phrases the reply correctly instead of dumping a raw field.
Write all three for a junior colleague who’s never seen your org. Vague descriptions don’t throw errors — they produce an agent that’s confidently inconsistent, calling the action every third time or passing the customer’s name into the order-number field. There’s no compiler to catch this; the batch-conversation tests in Testing Center are how you catch it, and you should treat a wrong-action-selection failure there as a description bug, not a model quirk.
Step 3: create the action and assign it to a topic
Activate the Flow, then create the agent action that points at it (in Agentforce Builder or as a reusable action), and assign that action to the relevant topic. Topic assignment is what scopes when the action is even a candidate — Atlas only considers actions attached to the topic it routed the conversation into. An action that isn’t assigned to a topic is dead weight. Add the action instructions here too: example utterances and any business rule that governs use (“only offer a reorder if status is Delivered”).
Then the constraint that catches teams out: once you activate the action, the interface is locked. You can change the Flow’s internal logic freely — swap a lookup, add a decision, fix a bug — but you cannot add, remove, or retype an input or output variable on a live action without recreating it. The contract with the agent is frozen. This is a feature, not a limitation: it means a running agent’s tool signatures don’t shift underneath it. But it means you design the interface deliberately before you activate, the same way you’d design a public API method signature you know you can’t break. Sketch the inputs and outputs on paper first. Ship the interface you can live with.
The running-user boundary governs everything the Flow touches
Here’s the part that’s easy to miss because it’s invisible in the builder. The Flow doesn’t run as the customer, and it doesn’t run as you. It runs as the agent user — the dedicated user the agent is configured to run as — with that user’s permission set, profile, and sharing. Every record the Flow reads or writes is subject to the agent user’s CRUD, FLS, and record access.
That has two consequences you design around:
- If the action returns nothing, check the agent user’s access before you touch the Flow. A perfectly correct lookup returns zero rows because the agent user can’t see the object or the record. This is the single most common “the Flow works when I test it but not in the agent” bug, and it’s a permission problem masquerading as a logic problem.
- The agent user’s permissions are your blast-radius control. A Flow action can only do what the agent user can do. Scope that user tightly — grant exactly the objects and fields the agent’s actions need, nothing more. This is the same least-privilege discipline that keeps an agent fleet from becoming shadow IT, applied at the action level.
For actions that write or that are hard to reverse, don’t lean on the model’s judgment about when to proceed. Design the confirmation in — gate the consequential step behind an explicit user confirmation or a human approval, using the pattern we lay out for human-in-the-loop agents. An autonomous Flow that cancels an order because the agent misread “track my order” as “cancel my order” is a support escalation you built yourself.
Watch the governor limits — a reasoning loop can spend them fast
A Flow action runs inside the same multitenant governor limits as any other Flow, but the consumption pattern is different: an agent may call your action multiple times in a single reasoning loop, or chain it with other actions, and the limits are shared across that turn. A Get Records inside a loop that was harmless when a human clicked it once can blow the SOQL query limit when an agent invokes the action repeatedly against a large result set.
Two habits keep this clean. First, enable Show Governor Limit Consumption in the Flow debug panel and actually read the SOQL-queries and query-rows numbers before you activate — treat a Flow that’s already near a limit on a single run as unshippable, because the agent will run it harder than you did. Second, keep actions single-purpose and bounded: one clear job, a bounded query, a predictable return. Bulkify inside the Flow, avoid unbounded loops, and if the work is genuinely heavy or asynchronous, that’s your signal to graduate to Apex.
When to stop and write Apex instead
Flow-first is the right default, and most agent actions never need more. Reach for Apex when you hit one of these:
- Complex or bulk logic that Flow expresses awkwardly — nested transformations, heavy data processing, anything where the Flow canvas becomes a maze.
- Callouts with real error handling — a Flow can call out, but Apex gives you the control over retries, timeouts, and partial failures that a production integration needs. If the action fronts an external system, Apex usually ages better.
- Anything you need to unit-test rigorously — Apex has a mature testing story; a Flow action’s correctness leans more on conversation-level testing. For an action whose failure is expensive, the Apex test suite is worth the code.
The reassuring part: because a Flow action and an Apex action look identical to the agent, this is purely an implementation decision. You can start in Flow, and if an action outgrows it, rebuild it in Apex behind the same action interface without the agent — or the reasoning you tuned — ever knowing. The one thing you can’t casually change is the input/output signature, so keep that stable across the swap.
The takeaway
A Flow is the right first tool for most Agentforce actions, and it’s genuinely no-code right up until the parts that aren’t about code at all. Use an autolaunched (no-trigger) Flow; mark your inputs and outputs available and describe them like you’re briefing a new hire, because those descriptions are what the agent actually reads; assign the action to a topic so Atlas will consider it; and design the interface deliberately, because activation locks it. Remember the Flow runs as the agent user — so a “broken” action is usually a permission gap — watch the governor limits an agent can burn faster than a human, and gate anything consequential behind a confirmation. Do that, and you’ll hand agents new capabilities in an afternoon, and know exactly why the one that misbehaves is misbehaving.
Understanding the basics
Can I build an Agentforce action without Apex?
Yes. An autolaunched Flow exposed as an agent action is a fully supported, no-code way to give an agent a new capability, and it’s the right first choice for most actions — record lookups, record creation, and multi-step processes you’d otherwise build in Flow for a human. You only need Apex for complex or bulk logic, callouts that require rigorous error handling, or actions you need to unit-test heavily. From the agent’s perspective a Flow action and an Apex action are indistinguishable, so the choice is about maintainability, not capability.
Why isn’t my Agentforce agent calling my Flow action correctly?
Almost always it’s the descriptions or the permissions, not the Flow logic. The agent decides whether to call an action and what to pass it by reading the action description, the input descriptions, and the topic it’s assigned to — so vague or missing descriptions produce inconsistent selection and bad inputs. And because the Flow runs as the agent user, a lookup that returns nothing is often a CRUD/FLS/sharing gap on that user, not a query bug. Check that the action is assigned to the right topic, that its descriptions include example utterances and input formats, and that the agent user can actually see the records.
Can I change a Flow action’s inputs and outputs after publishing?
No — once the action is activated, its input/output interface is locked. You can freely change the Flow’s internal logic (swap elements, fix bugs, add steps), but you can’t add, remove, or retype the available-for-input and available-for-output variables on a live action without recreating it. This keeps a running agent’s tool signatures stable, but it means you should design the interface deliberately before activating, the way you’d design an API method signature you can’t break later.
Deciding which agent capabilities belong in Flow, which need Apex, and how to scope the agent user so a new action doesn’t open a hole? Talk to us. Building governed agent actions to the ISV bar is exactly the work we do.
Keep reading
All insights