Wrapping a governance check as an Agentforce action — Flow vs Apex vs LWC
sf-dev-ai answers governance questions for an external agent over MCP. But a lot of the audience for those answers is inside Salesforce — admins and architects working in an Agentforce agent, not a separate IDE. So the natural next surface is an Agentforce action: the same check, callable by an in-org agent.
The interesting decisions aren't "how do I call an LLM." They're: which surface (Flow, Apex, or LWC), and how to keep an agent-callable action from becoming a privilege-escalation hole.
The three surfaces
- Apex
@InvocableMethod— when the action is logic: queries, an allow-list, security context. Testable, statically analyzable, version-controlled. This is where governance belongs. - Flow — great declarative glue, and it can call the Apex action. But putting the security logic in a Flow is awkward to test and easy to get subtly wrong. Use it to orchestrate, not to enforce.
- LWC — when the agent needs to render a rich result to a human (a sortable table of offending permission sets) rather than narrate text. A presentation layer over the same action, not a replacement for it.
I built the check as Apex. Here's the part that matters:
The security is the point
An agent-callable action widens who can invoke your code — from "a developer who wrote a SOQL query" to "anyone who can talk to the agent." Two properties keep that safe, and both are in the Apex, not the prompt:
WITH USER_MODE— the query runs in the caller's security context. The action can't return permission data the running user couldn't already see.- The allow-list —
permissionApiNameis checked against a fixedSetof auditable permissions before it touches a query. The agent can't coerce it into reading an arbitrary field.
I verified the class with the Salesforce Code Analyzer — the same engine sf-dev-ai proxies as run_code_analyzer — and got it to 0 violations (it caught a dynamic-SOQL injection flag and a missing CRUD check on the first pass; both are gone). That's the bar I'd hold a customer's agent actions to: statically clean, user-mode, allow-listed, tested.
Wiring it up
Once deployed, the action shows up in Agent Builder: Topics → New Action → Apex → "Audit dangerous permissions." Map the input, write the instruction for when to use it, activate, and ask the agent "which permission sets grant Modify All Data?" in the preview.
Deploy needs an Agentforce-enabled org — a current free Developer Edition has it. Code, tests, and the wiring steps: sf-dev-ai-agentforce. The governance check is now three surfaces — MCP tool, retrieval corpus, and Agentforce action — over one idea.