Actions Are the Contract

An Agentforce agent plans, but it doesn’t do anything — actions do. An action is a callable unit (Apex invocable, Flow, prompt template, or built-in) with a name, a description, input parameters, and an output.

The quality of your action library determines the agent’s real-world behavior. You can’t fix a sloppy action library with better prompts.

Principle 1: Name and Describe for the Reader

Atlas picks actions by reading their descriptions. Descriptions are for the reasoning engine, not for your teammates.

Bad: Get_Records — “Queries the database.”

Good: Get_Open_Cases_For_User — “Returns the open Cases owned by the current user, sorted by oldest first. Use when the user asks about their cases, their workload, or follow-ups. Do NOT use for closed cases or cases owned by other users.”

The “do not” clause is load-bearing. Without it, Atlas will occasionally reach for this action in the wrong context.

Principle 2: One Action, One Job

Actions that try to do many things fail in many ways. An action called Manage_Case that handles create, update, escalate, and resolve is ambiguous from Atlas’s perspective and gnarly to debug when something breaks.

Split it into Create_Case, Update_Case, Escalate_Case, Resolve_Case. The agent picks the right one because the right one has a clear name.

Principle 3: Small, Typed Inputs

Every input parameter is a place where the agent can pass garbage. Mitigate by keeping the input count small and the types explicit.

  • Use record IDs (Id type) instead of free-text “record names.”
  • Use picklist values typed as enums when the set is known.
  • Use DateTime over String for dates.
  • Validate in the action itself — never trust the agent to pass valid input.

Principle 4: Structured, Small Outputs

Outputs feed back into the reasoning loop. An action that returns 400 rows of raw data pollutes the context window and degrades the next step.

Return what the agent needs to reason next — typically a short structured summary plus 5–10 exemplar rows. Put the full dataset in an attachment or a link if the user needs it, not in the return value.

Principle 5: Idempotent When Possible

An action may be called more than once per conversation due to retries. Mutations should be idempotent.

  • Include a client request ID in inputs; reject duplicates.
  • For creates, use upsert with an external ID.
  • For sends (emails, notifications), check for a recent matching send before sending again.

This turns a class of bugs — “the agent sent the email twice” — into a non-issue.

Principle 6: Fail Loudly, With Useful Messages

When an action fails, the error message the agent receives becomes part of the conversation. A cryptic “INVALID_FIELD” surfaces as “I couldn’t do that for an unknown reason.” A clear “Account record not found for ID 001xx — either it was deleted or you don’t have access” lets the agent explain correctly.

Wrap Apex exceptions and return explicit error strings. Be specific without leaking internals.

Principle 7: Respect Governor Limits

Actions run inside standard Apex transactions. A chatty agent hitting an action 20 times in a conversation can burn through SOQL or DML budgets if the action is sloppy.

  • Use selective queries with proper indexes.
  • Avoid SOQL inside loops inside actions.
  • For bulk work, spin off a Queueable and return immediately.

Concrete Action Template (Apex)

public class Get_Recent_Activity_For_Account {
    @InvocableMethod(
        label='Get Recent Activity For Account'
        description='Returns the 10 most recent activities on the specified Account. Use when the user asks about recent communication, calls, or emails with an account. Do NOT use for closed or converted leads.'
    )
    public static List<Response> run(List<Request> requests) {
        List<Response> responses = new List<Response>();
        for (Request r : requests) {
            Response resp = new Response();
            try {
                List<Task> tasks = [
                    SELECT Id, Subject, ActivityDate, Status, Owner.Name
                    FROM Task
                    WHERE AccountId = :r.accountId
                    ORDER BY ActivityDate DESC
                    LIMIT 10
                ];
                resp.summary = tasks.isEmpty() 
                    ? 'No recent activity.' 
                    : tasks.size() + ' recent activities found.';
                resp.items = tasks;
            } catch (Exception e) {
                resp.error = 'Could not retrieve activity: ' + e.getMessage();
            }
            responses.add(resp);
        }
        return responses;
    }

    public class Request {
        @InvocableVariable(required=true 
                          description='The 15 or 18 character Account Id')
        public Id accountId;
    }

    public class Response {
        @InvocableVariable public String summary;
        @InvocableVariable public List<Task> items;
        @InvocableVariable public String error;
    }
}

Notice what’s intentional: the description tells Atlas when not to use it; the input is typed as Id, not String; the output has a summary for the agent to read and a list for display; errors return a string instead of throwing.

Testing Actions Before Wiring Them

Each action deserves an independent test. Agent Studio’s test surface can invoke an action with sample inputs — use it.

Test at three levels:

  1. Unit: does the action work with valid input?
  2. Edge: does it handle empty input, missing records, permissions failures?
  3. Integration: does the agent pick this action correctly for the intended prompts?

Skipping level 3 is the most common mistake. An action that works in isolation but never gets selected correctly is worth nothing.

Don’t Reinvent Standard Actions

Salesforce ships dozens of standard actions: Send Email, Create Record, Update Record, Call Flow, Query. Use them when the job fits. Custom actions should exist only when standard ones can’t express the behavior you need.

Frequently Asked Questions

Should I use Flow or Apex for actions?

Flow for simple CRUD and orchestration. Apex when you need transaction control, complex logic, or performance tuning. Prompt templates for LLM-generated content.

How many actions should one topic have?

As few as possible. A topic with 3–5 sharp actions is easier to reason about than one with 20 overlapping ones.

Can an action call another action?

Yes — via Flow subflows or invocable calls. But composition adds latency and failure surface. Prefer a single action that does the composite job when possible.

Share