Salesforce Agentforce (beta)

Find every Agentforce agent and what it can do, then make each sensitive action check with Intertrace before it acts. Beta: checked against Salesforce's documented APIs; not yet run against a live org.

Beta

What discovery finds

For each Agentforce agent in the org:

  • its topics and actions, and what each action runs: a Flow, an Apex class, a prompt template, an External Service or an MCP tool;
  • the user it runs as, that user's permission sets, and admin-like permissions (Modify All Data, View All Data, Author Apex, Customize Application, Manage Users);
  • which objects that user can read, change or delete;
  • whether Salesforce marks it external-facing (a customer-facing service agent);
  • which actions call the Intertrace guard before acting.

Risk reasons: a customer-facing agent with actions that change, delete or send; an agent user with Modify All Data or View All Data; actions that call outside Salesforce; sensitive actions that run without the guard. What an action does (read, change, send) is read from its name, and the reason says so.

Connect discovery (read-only)

  1. 1

    Create a read-only integration user

    A user with the Salesforce Integration license and a permission set with API Enabled and View Setup and Configuration. Do not give it Modify All Data or View All Data. Salesforce has no read-only API scope, so this user's permissions are what keep the connection read-only.

  2. 2

    Create an External Client App

    Setup → External Client Apps Manager → New External Client App. Enable OAuth with the scope Manage user data via APIs (api) and select Enable Client Credentials Flow. Then, on the app's Policies tab, enable Client Credentials Flow and set Run As (Username) to the integration user. No password is ever needed.

  3. 3

    Paste it in Discovery

    Discovery → Salesforce Agentforce → Connect: your My Domain URL (https://yourcompany.my.salesforce.com) and the app's consumer key and secret (Settings → OAuth Settings → Consumer Key and Secret). Intertrace signs in and reads one agent before saving; the key and secret are encrypted at rest.

Why a guard inside each action

Agentforce has no hook that lets an outside service decide before an action runs. Salesforce's own controls (Agent Script's available when conditions and before_reasoning blocks, an action's confirmation setting, the Einstein Trust Layer) run inside Salesforce, and session tracing records what happened afterwards. So the check goes inside the action: its first step asks Intertrace, and the action continues only when the answer is allow.

The decision is the enforcer's, exactly as for any other agent: the same policy, approvals and record, through POST https://intertrace.fly.dev/v1/actions/authorize.

Mint the runtime key

Import the agent from its Discovery finding (or create the agent in Estate), then create a runtime key for it. The key is shown once. One key per Agentforce agent keeps each agent's decisions apart.

Store the key in Salesforce

  1. 1

    External Credential

    Setup → Named Credentials → External Credentials → New: name Intertrace_Runtime, authentication protocol Custom. Add a principal (Named Principal) with an authentication parameter RuntimeKey whose value is the runtime key. Add a custom header Authorization with the value below.

  2. 2

    Named Credential

    New Named Credential: name Intertrace, URL https://intertrace.fly.dev, External Credential Intertrace_Runtime. Turn Generate Authorization Header off and Allow Formulas in HTTP Header on.

  3. 3

    Give the agent user access

    Assign the deployed permission set Intertrace Guard User to the agent's user, and add External Credential Principal Access for the principal to a permission set that user has.

Authorization = {!'Bearer ' & $Credential.Intertrace_Runtime.RuntimeKey}

Deploy the guard

The guard ships as source in the Intertrace repository under integrations/salesforce (an sfdx project: IntertraceGuard, its tests and the Intertrace Guard User permission set). Deploy to a sandbox first and run the tests:

cd integrations/salesforce
sf project deploy start --source-dir force-app --target-org my-sandbox
sf apex run test --class-names IntertraceGuardTest --target-org my-sandbox --result-format human

Call it first in each action

Flow actions: add the action Intertrace: check action as the first element. Inputs: Action name (the action's API name), Operation (read, write, delete, send or execute), Arguments (a JSON object of the values the action acts on, for example built with a text template), Session ID (the conversation, for example the MessagingSession id), and optionally Destination and Reason. Then a Decision on Allowed: when it is false, return Message to the agent and stop.

Apex actions: call the guard before any DML or other callout (Salesforce refuses a callout after uncommitted work):

IntertraceGuard.Request req = new IntertraceGuard.Request();
req.actionName = 'Issue_Refund';
req.operation = 'write';
req.argumentsJson = JSON.serialize(new Map<String, Object>{ 'order_id' => orderId, 'amount' => amount });
req.sessionId = sessionId;
IntertraceGuard.requireAllowed(req); // throws IntertraceGuard.GuardException unless allowed
// ...then do the refund

External Service, MCP and prompt actions cannot call the guard themselves: wrap each in a Flow that calls the guard first and use that Flow as the action. Discovery counts an action as guarded only when its own Flow or Apex class references IntertraceGuard.

What the agent sees

  • Allow (and monitor-mode allow): Allowed is true and the action runs.
  • Block: Allowed is false and Message is the enforcer's own words.
  • Ask: Allowed is false, with the approval link. After a person approves, the same action run again with the same details finds the approval and re-enters with it; approvals bind to the arguments and the session.
  • No answer within 10 seconds, an error status, an unreadable answer, or an allow that needs changed details (transform): the action does not run.

Several agents: create one Named Credential per Intertrace agent key and set the guard's Named credential input to its name.

Limits of the beta

  • Salesforce's queryable objects do not link an agent to its planner, so topics and actions come from the planner matched by name (the finding says so).
  • Which actions call the guard comes from MetadataComponentDependency, which Salesforce marks beta, and counts direct references only. If it can't be read, the finding says unknown, never unguarded.
  • Salesforce doesn't say which messaging channel routes to which agent; the finding lists the org's active channels for a customer-facing agent.
  • One Salesforce org per Intertrace organization for now.
  • The guard does not report the action's outcome after it runs.