File size: 43,826 Bytes
8219127 a5f4433 87da848 a5f4433 87da848 a5f4433 87da848 a5f4433 87da848 a5f4433 8219127 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Agentforce deployment check — check your agent free</title>
<style>
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
</style>
<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/agentforce-action-audit"></head>
<body>
<div class="wrap">
<h1>Agentforce deployment check — check your agent free</h1>
<p class="lede">One audit pass over Salesforce Agentforce topic metadata: flags deploy blockers and the missing AI-disclosure line before you push an agent live. Runs entirely in your browser — nothing is uploaded.</p>
<textarea id="src" spellcheck="false"><?xml version="1.0" encoding="UTF-8"?>
<GenAiPlugin xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<description>Handles order status questions for retail customers in the EU & UK.</description>
<developerName>Order_Status</developerName>
<genAiFunctions>
<functionName>Get_Order_Status</functionName>
</genAiFunctions>
<genAiFunctions>
<functionName>Cancel_Order</functionName>
</genAiFunctions>
<genAiPluginInstructions>
<description>When the customer asks where their parcel is, run Get_Order_Status and read back the tracking number.</description>
<developerName>instruction_0</developerName>
<masterLabel>instruction_0</masterLabel>
</genAiPluginInstructions>
<genAiPluginInstructions>
<description>TODO: describe the refund path here.</description>
<developerName>instruction_0</developerName>
<masterLabel>instruction_1</masterLabel>
</genAiPluginInstructions>
<genAiPluginInstructions>
<description>If the customer is still unhappy, hand the case to support@acme-retail.example and close the conversation.</description>
<developerName>instruction_2</developerName>
<masterLabel>instruction_2</masterLabel>
</genAiPluginInstructions>
<language>en_US</language>
<masterLabel>Order Status</masterLabel>
<pluginType>Topic</pluginType>
</GenAiPlugin></textarea>
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
<div id="out" aria-live="polite"></div>
<div id="paid"><strong>Free here:</strong> Audit the Agentforce topic metadata file you have open and get every deploy blocker with its line number.. <strong>In the editor:</strong> Sweep every genAiPlugin and genAiPlannerBundle in the workspace in one run and export a dated AGENTFORCE-AUDIT.md — that part asks for a licence key.</div>
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
</div>
<script>var AFA_RULES = [
{"id": "missing_master_label", "sev": "error", "msg": "No top-level \u003cmasterLabel\u003e. The topic deploys without a name and the planner cannot list it."},
{"id": "missing_description", "sev": "error", "msg": "No top-level \u003cdescription\u003e. The planner routes on this text, so the topic is never selected."},
{"id": "missing_scope", "sev": "error", "msg": "No \u003cscope\u003e. Nothing bounds the topic, so the agent answers questions it was never meant to touch. Add a one-line topic boundary."},
{"id": "scope_too_short", "sev": "warn", "msg": "\u003cscope\u003e is under 40 characters. Too thin to bound the topic; say what the agent must refuse."},
{"id": "no_instructions", "sev": "error", "msg": "No \u003cgenAiPluginInstructions\u003e block. The topic carries no behaviour at all."},
{"id": "duplicate_instruction_name", "sev": "error", "msg": "Two instructions share one \u003cdeveloperName\u003e. Rename the duplicate or the metadata deploy fails."},
{"id": "instruction_placeholder", "sev": "error", "msg": "Generated placeholder text left in an instruction. Replace it before the agent reads it to a customer."},
{"id": "function_not_referenced", "sev": "warn", "msg": "A \u003cfunctionName\u003e is never named in any instruction or in \u003cscope\u003e. Name it so the planner picks it."},
{"id": "no_ai_disclosure", "sev": "error", "msg": "No instruction tells the person they are talking to an AI. EU AI Act Article 50(1) has applied since 2026-08-02; the Article 99(4) ceiling is 15 million euro or 3 percent of worldwide turnover."},
{"id": "pii_in_instruction", "sev": "error", "msg": "An instruction carries contact or identity data. Instruction text is sent to the model on every turn; move it out of the prompt."},
{"id": "insecure_endpoint", "sev": "warn", "msg": "An instruction points at a plain http:// address. Use a Named Credential over https."},
{"id": "unescaped_ampersand", "sev": "error", "msg": "A bare \u0026 that is not an XML entity. Escape it as \u0026amp; or the deploy stops on a parse error."},
{"id": "stale_api_version", "sev": "warn", "msg": "\u003capiVersion\u003e predates 62.0, the release Agentforce topics shipped in. Raise it to 62.0 or later."}
]
;</script>
<script>/* Agentforce Action Audit - one engine, runs in VS Code and in the browser. */
(function () {
'use strict';
var RULES = (typeof module !== 'undefined' && module.exports)
? require('./rules.json')
: window.AFA_RULES;
var BY_ID = {};
for (var i = 0; i < RULES.length; i++) BY_ID[RULES[i].id] = RULES[i];
var DISCLOSURE = /(\bA\.?I\b)|artificial intelligence|automated (assistant|agent)|virtual (agent|assistant)|not a human|chatbot/i;
var PLACEHOLDER = /\bTODO\b|\bFIXME\b|lorem ipsum|\[insert|<insert|your company name|\bXXXX\b/i;
var EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/;
var PHONE = /\+\d{1,3}[\s.-]?\(?\d{2,4}\)?[\s.-]?\d{3,4}[\s.-]?\d{3,4}/;
var NATID = /\b\d{3}-\d{2}-\d{4}\b/;
var AMP = /&(?![A-Za-z#][A-Za-z0-9]{0,8};)/g;
function flat(s) { return String(s || '').replace(/\s+/g, ' ').trim(); }
function check(text, opts) {
opts = opts || {};
var src = String(text || '');
var today = String(opts.today || '');
var findings = [];
function lineOf(idx) {
if (idx < 0) idx = 0;
return src.slice(0, idx).split('\n').length;
}
function add(id, idx, extra) {
var r = BY_ID[id];
if (!r) return;
var sev = r.sev;
if (id === 'no_ai_disclosure' && today && today < '2026-08-02') sev = 'warn';
findings.push({
check: id,
sev: sev,
msg: extra ? r.msg + ' (' + extra + ')' : r.msg,
line: lineOf(idx)
});
}
/* instruction blocks */
var instrs = [];
var blockRe = /<genAiPluginInstructions>([\s\S]*?)<\/genAiPluginInstructions>/g;
var m;
while ((m = blockRe.exec(src)) !== null) {
instrs.push({ body: m[1], index: m.index });
}
var outside = src.replace(blockRe, '');
function tagIn(hay, name) {
var re = new RegExp('<' + name + '>([\\s\\S]*?)</' + name + '>');
var hit = re.exec(hay);
return hit ? flat(hit[1]) : null;
}
function idxOf(name) {
var at = src.indexOf('<' + name + '>');
return at < 0 ? 0 : at;
}
var rootAt = src.search(/<GenAiPlugin[\s>]|<GenAiPlannerBundle[\s>]|<GenAiPlanner[\s>]/);
if (rootAt < 0) rootAt = 0;
/* 1-2 top level identity */
if (!tagIn(outside, 'masterLabel')) add('missing_master_label', rootAt);
if (!tagIn(outside, 'description')) add('missing_description', rootAt);
/* 3-4 scope */
var scope = tagIn(outside, 'scope');
if (scope === null) {
add('missing_scope', rootAt);
} else if (scope.length < 40) {
add('scope_too_short', idxOf('scope'), scope.length + ' characters');
}
/* 5 instructions present */
if (instrs.length === 0) add('no_instructions', rootAt);
/* 6 duplicate instruction developerName */
var seen = {};
for (var a = 0; a < instrs.length; a++) {
var dn = tagIn(instrs[a].body, 'developerName');
if (!dn) continue;
if (seen[dn]) add('duplicate_instruction_name', instrs[a].index, dn);
seen[dn] = true;
}
/* prompt text = every instruction description + scope */
var prompt = [];
for (var b = 0; b < instrs.length; b++) {
var d = tagIn(instrs[b].body, 'description');
prompt.push({ text: d || '', index: instrs[b].index });
}
if (scope) prompt.push({ text: scope, index: idxOf('scope') });
var promptAll = prompt.map(function (p) { return p.text; }).join(' \n ');
/* 7 placeholder, 10 pii, 11 insecure endpoint - per instruction */
for (var c = 0; c < prompt.length; c++) {
var t = prompt[c].text;
if (PLACEHOLDER.test(t)) add('instruction_placeholder', prompt[c].index);
var pii = EMAIL.exec(t) || PHONE.exec(t) || NATID.exec(t);
if (pii) add('pii_in_instruction', prompt[c].index, pii[0]);
if (/http:\/\//i.test(t)) add('insecure_endpoint', prompt[c].index);
}
/* 8 function never referenced */
var fnRe = /<functionName>([\s\S]*?)<\/functionName>/g;
var f;
while ((f = fnRe.exec(src)) !== null) {
var name = flat(f[1]);
if (!name) continue;
var loose = name.replace(/_/g, ' ');
if (promptAll.indexOf(name) === -1 && promptAll.toLowerCase().indexOf(loose.toLowerCase()) === -1) {
add('function_not_referenced', f.index, name);
}
}
/* 9 AI disclosure */
if (instrs.length > 0 && !DISCLOSURE.test(promptAll)) add('no_ai_disclosure', instrs[0].index);
/* 12 unescaped ampersand - anywhere in the file */
var amp;
AMP.lastIndex = 0;
while ((amp = AMP.exec(src)) !== null) add('unescaped_ampersand', amp.index);
/* 13 stale apiVersion */
var av = /<apiVersion>\s*([0-9]+(?:\.[0-9]+)?)\s*<\/apiVersion>/.exec(src);
if (av && parseFloat(av[1]) < 62) add('stale_api_version', av.index, av[1]);
findings.sort(function (x, y) { return x.line - y.line; });
return { findings: findings };
}
var API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
if (typeof module !== 'undefined' && module.exports) module.exports = API;
if (typeof window !== 'undefined') window.AFAENGINE = API;
})();
</script>
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
'use strict';
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
function summaryLine(res) {
const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
}
function toText(res, label) {
const f = (res && res.findings) || [];
const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
return lines.join('\n');
}
function toHtml(res) {
const f = (res && res.findings) || [];
if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
}
var AFAREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
if (typeof module !== 'undefined' && module.exports) module.exports = AFAREPORT;
else window.AFAREPORT = AFAREPORT;
</script>
<script>
(function(){
var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
today.value=new Date().toISOString().slice(0,10);
function run(){ try { var res=window.AFAENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.AFAREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
go.onclick=run; if (src.value.trim()) run();
})();
</script>
<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.agentforce-action-audit" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'agentforce-action-audit',src:'mp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/agentforce-action-audit" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'agentforce-action-audit',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/agentforce-action-audit" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'agentforce-action-audit',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://www.npmjs.com/package/@readystack/agentforce-action-audit" rel="noopener" data-yj-install-door="mcp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'agentforce-action-audit',src:'mcp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">MCP server (npx)</a><a href="https://hub.docker.com/r/getreadystack/agentforce-action-audit" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'agentforce-action-audit',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.agentforce-action-audit
npx @readystack/agentforce-action-audit <file>
npx @readystack/agentforce-action-audit --mcp</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 13 rules Agentforce Action Audit checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"agentforce-action-audit",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>
<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">13 rules on a Salesforce Agentforce topic file, before the deploy and before Article 50</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A Salesforce partner bills metadata review at about $150 an hour; one topic file takes roughly 20 minutes to read by hand.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_cItF01AndFQi4JGgKXw93gpuOPFIXq4LLR70d42siAL" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-20">Updated 2026-09-20</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-20","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku141697_result_card.jpg" alt="Agentforce Action Audit" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>Eight findings in one 30-line Agentforce topic file - six errors and two warnings - is what a Salesforce developer at an EU retailer gets the first time they run Agentforce Action Audit over the agent metadata they were about to deploy. The clean version of the same file returns zero. Both numbers come from the fixtures shipped with the extension, measured on 2026-09-20.</p>
<p>The eight are ordinary. No <scope>, so nothing bounds what the topic will answer. An <apiVersion> of 59.0, below the 62.0 release Agentforce topics shipped in. A bare & in <description>. A Cancel_Order function that no instruction ever names, so the planner rarely selects it. Two instructions both called instruction_0. A TODO: still sitting in text the agent will read to a customer. A mailbox, support@acme-retail.example, inside a prompt that is sent to the model on every turn. And no instruction anywhere that tells the person they are talking to an AI.</p>
<p>Seven of those eight deploy cleanly. Only the bare ampersand fails at parse time, which is the cheap failure - you see it in the terminal. The sf CLI validates agent metadata against the XML schema, and a topic with no scope, a duplicate instruction name and a TODO in its text is perfectly schema-valid. It ships, and it fails in front of a customer instead.</p>
<p>The last of the eight changed category on 2026-08-02. EU AI Act Article 50(1) began to apply on that date: a system that interacts directly with natural persons must be designed so those persons are informed that they are interacting with an AI, unless that is obvious from the context. In an Agentforce topic there is exactly one place that line can live - a <genAiPluginInstructions> entry - and nothing in the deploy pipeline looks for it. Article 99(4) puts the ceiling for that class of breach at 15 million euro or 3 percent of worldwide annual turnover, whichever is higher.</p>
<p>This is also where generated metadata is weakest. Ask an assistant for a topic that handles delivery questions and it returns a well-formed file with a description, functions and instructions. It does not know which org you sell into, so it does not volunteer a disclosure line. It does not know that the mailbox you pasted into an instruction has just become prompt text. It will happily leave the TODO it wrote for you.</p>
<p>Agentforce Action Audit runs 13 rules over the file: missing masterLabel, missing description, missing scope, thin scope, no instructions, duplicate instruction name, placeholder text, unreferenced function, no AI disclosure, contact data in a prompt, insecure endpoint, unescaped ampersand, stale apiVersion. Nine are errors and four are warnings. The engine is one file, ext/engine.js, reading ext/rules.json, and the same file runs in the one-page web edition with no server and no upload - agent metadata is not something you paste into a web form.</p>
<p>Free: the file you have open, all 13 checks, every finding with its line number. Nothing is blurred, timed or counted down; that audit finishes on its own. The full version is $29 once and changes the axis, not the depth: it sweeps every genAiPlugin and genAiPlannerBundle in the workspace in one run and exports a dated AGENTFORCE-AUDIT.md you can attach to the change request. A Salesforce partner bills metadata review at about $150 an hour, and one topic file takes roughly 20 minutes to read by hand, so a 12-topic agent is most of a billable day. One licence key per person or team seat, 7-day full refund.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku141697_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku141697_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does Agentforce Action Audit actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads a Salesforce Agentforce topic file - genAiPlugin or genAiPlannerBundle metadata - and reports 13 defects with line numbers: missing scope, duplicate instruction names, a bare ampersand that stops the deploy, generated placeholder text, contact data sitting inside a prompt, and the missing line that tells a person they are talking to an AI.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is it for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Salesforce DX developers and admins who ship Agentforce topics to production, and the partner consultants who review their pull requests. It is aimed at teams whose agents talk to customers in the European Union, where an agent that never discloses it is an AI is an Article 50 problem rather than a style problem.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why will a chatbot or the sf CLI not do this?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general chatbot cannot see the genAiPlugin XML sitting in your repository, and pasting it turns customer instructions into prompt text. The sf CLI validates the XML schema, not the behaviour: sf project deploy start happily accepts a topic with no scope, no disclosure line, and a TODO still left in an instruction.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what does the full version add?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free: the file you have open, all 13 checks, every finding with its line number. The 13 are missing masterLabel, missing description, missing scope, thin scope, no instructions, duplicate instruction name, placeholder text, unreferenced function, no AI disclosure, contact data in a prompt, insecure endpoint, unescaped ampersand, and stale apiVersion. The full version sweeps the whole workspace and exports a dated AGENTFORCE-AUDIT.md.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does this cost compared with having a person do it?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A Salesforce partner bills metadata review at about $150 an hour, and one topic file takes roughly 20 minutes to read by hand, so a 12-topic agent is most of a billable day. The full version is $29 once, one licence key per person or team seat,.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Agentforce Action Audit checks the file you open against 13 rules from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Agentforce Action Audit actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads a Salesforce Agentforce topic file - genAiPlugin or genAiPlannerBundle metadata - and reports 13 defects with line numbers: missing scope, duplicate instruction names, a bare ampersand that stops the deploy, generated placeholder text, contact data sitting inside a prompt, and the missing line that tells a person they are talking to an AI."}}, {"@type": "Question", "name": "Who is it for?", "acceptedAnswer": {"@type": "Answer", "text": "Salesforce DX developers and admins who ship Agentforce topics to production, and the partner consultants who review their pull requests. It is aimed at teams whose agents talk to customers in the European Union, where an agent that never discloses it is an AI is an Article 50 problem rather than a style problem."}}, {"@type": "Question", "name": "Why will a chatbot or the sf CLI not do this?", "acceptedAnswer": {"@type": "Answer", "text": "A general chatbot cannot see the genAiPlugin XML sitting in your repository, and pasting it turns customer instructions into prompt text. The sf CLI validates the XML schema, not the behaviour: sf project deploy start happily accepts a topic with no scope, no disclosure line, and a TODO still left in an instruction."}}, {"@type": "Question", "name": "What is free and what does the full version add?", "acceptedAnswer": {"@type": "Answer", "text": "Free: the file you have open, all 13 checks, every finding with its line number. The 13 are missing masterLabel, missing description, missing scope, thin scope, no instructions, duplicate instruction name, placeholder text, unreferenced function, no AI disclosure, contact data in a prompt, insecure endpoint, unescaped ampersand, and stale apiVersion. The full version sweeps the whole workspace and exports a dated AGENTFORCE-AUDIT.md."}}, {"@type": "Question", "name": "What does this cost compared with having a person do it?", "acceptedAnswer": {"@type": "Answer", "text": "A Salesforce partner bills metadata review at about $150 an hour, and one topic file takes roughly 20 minutes to read by hand, so a 12-topic agent is most of a billable day. The full version is $29 once, one licence key per person or team seat,."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Agentforce Action Audit checks the file you open against 13 rules from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:141697,slug:"agentforce-action-audit",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/en301549-lint"><span class="yj-rel-t">EN 301 549 Lint — European Accessibility Act rules, with the clause number, in</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/robots-txt-ai-crawler-audit"><span class="yj-rel-t">AI Crawler Rules - robots.txt Audit for AI Search</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/action-runtime-sunset-lint"><span class="yj-rel-t">Action Runtime Sunset Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/bulk-sender-lint"><span class="yj-rel-t">Bulk Sender Lint - the Gmail, Yahoo and Outlook.com rules, checked in your mai</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cra-24-72-14-reporting-lint"><span class="yj-rel-t">CRA 24/72/14 Reporting Lint (Article 14)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/dora-ict-contract-clause-lint"><span class="yj-rel-t">DORA Art. 30 ICT Contract Clause Lint</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
</html>
|