agentforce-architecture-analyze
Declared architecture snapshot for one Agentforce agent: planner, topics, actions, flows, Apex, prompt templates, and NGA plugins. Renders a human-readable architecture document and Mermaid invocation graph from design-time metadata (not runtime audit rows). TRIGGER when user asks to describe, diagr
By forcedotcom · 5,407 installs
npx skills add forcedotcom/sf-skills --skill agentforce-architecture-analyze
Source repository · Upstream listing
agentforce architecture analyze — declared architecture snapshot
Design time metadata tree for one Agentforce agent: planner → topics → actions → flows → Apex → prompts → NGA plugins. Reads declared metadata only — BotDefinition , GenAiPlanner , GenAiPlugin , GenAiFunction , Flow , ApexClass , GenAiPromptTemplate . Does not read runtime audit rows.
Runtime budget: 30–45s typical, ≤60s hard cap on reference fixtures. Sequential baseline would be 90–220s; parallel Tooling SOQL fan out delivers a 3–5× speedup. Large bots with many flows scale approximately linearly — each flow metadata retrieve is one round trip.
Runs inline — no subagent. Every phase is deterministic file processing.
If the user hasn't given enough to proceed
When invoked with no agent api name AND no org alias, print the following block verbatim — do not paraphrase, do not pre run any script. Trigger condition: $ARGUMENTS is empty OR names no agent (no agent flag and no known agent API name in the prose) OR names no org (no org flag and no known alias).
Which agent should I document, and in which org?
I need:
Agent API name — the DeveloperName of the BotDefinition (e.g. MyAgent , MySalesAgent ). Not the label.
Org alias — for sf CLI auth (the alias you configured with sf org login )
Optional:
Version — an agent version api name like v5 . If omitted, I'll resolve the active BotVersion .
force — ignore cached tree; re fetch everything.
reprobe — re run the 7 day channel probe cache (only needed after a Salesforce release).
I'll run the metadata pipeline inline. Artifacts land under ~/.vibe/data/agentforce architecture analyze/<org id15 /<agent api name <agent version / (overridable with data dir ).
Pipeline invocation
When the user has supplied org <alias + agent <api name (plus any optional flags), run this block. One python3 invocation drives the full pipeline. main.py writes .emit ctx.json ; emit result.py reads it and prints the final === RESULT === block last to stdout.
Inputs
Input Flag Required Default
org alias org yes —
agent api name agent yes —
agent version api name version no active BotVersion
force refresh force no false (honor cache)
reprobe reprobe no false (honor 7 day channel probe cache)
parallelism parallelism no 5
max mermaid nodes max mermaid nodes no 80
data dir data dir no ~/.vibe/data/agentforce architecture analyze
cache dir cache dir no ~/.vibe/cache/agentforce architecture analyze
Outputs
All artifacts under ~/.vibe/data/agentforce architecture analyze/<org id15 /<agent api name <agent version / (default; override with data dir <path ):
Pipeline — inline, no subagent
Channel strategy — SOQL first.
Tooling SOQL for every normalized tree node (planner, plugins, functions, plugin functions, plugin instructions, planner functions, planner attrs) — 6 parallel channels keyed on planner id, plus the planner definition by agent chain seed query that resolves the planner id from the agent chain.
Data API SOQL for Flow (by id) and Apex (by id or name) bodies — batched.
Metadata retrieve only for two cases: (a) GenAiPromptTemplate (prompt bodies aren't cleanly exposed via Tooling SOQL), and (b) NGA external plugins when the planner is Native Generative Agent shape (skipped for classic ReAct).
This is where the 3–5× speedup comes from. A naive implementation would retrieve everything via Metadata API zips sequentially; parallel Tooling SOQL covers ~80% of the tree in a single fan out.
Planner shapes — classic ReAct vs NGA
The skill normalizes two planner families into a single tree shape:
Shape GenAiPlannerDefinition.PlannerType InvocationTarget style NGA plugins?
Classic ReAct ReactAiPlannerV1 / SequentialPlannerIntentClassifier / etc. DeveloperName strings no
NGA ConcurrentMultiAgentOrchestration / AnthropicCompatibleV1 / etc. Sometimes 15/18 char Ids (ID prefix routed) yes (external plugins via Metadata retrieve)
The ID prefix router in resolve invocation target.py distinguishes the two: NGA InvocationTargets that look like ids ( 01p… = ApexClass, 301… = Flow, etc.) get resolved via id scoped SOQL; DeveloperName targets go through name scoped SOQL. Unknown prefixes surface as unresolved[] with reason="unknown id prefix:<prefix " — never silently dropped.
Caching
Tree cache : metadata tree.json is reused unless force is passed. Cache key includes the asset hash of every .soql / .yaml / .mmd template bundled with the skill — bump a template, the cache busts automatically.
Channel probe cache : 7 day TTL on the per org sf sobject describe results that validate every field name the SOQL assets reference. A Salesforce quarterly release that renames / removes a field triggers status: PROBE FAILED ; reprobe forces a refresh.
Prerequisites
Tool Required
sf CLI (authenticated against the target org) yes — sf org login web alias <alias
Python 3.10+ yes
Reference docs to load when needed
Do NOT load eagerly. Load when the user's question requires it:
references/soql fields.md — per sObject field reference for the 13 sObjects this skill touches (2 Data API + 11 Tooling), with [mandatory] vs [optional] tags. Load when the user asks about a specific field, or when debugging an INVALID FIELD SOQL error.
references/contract.json — machine readable schema for metadata tree.json . Load when writing downstream tooling that consumes the tree.
references/architecture sections.md — section by section structure of the rendered <agent <ver architecture.md .
Invariants worth knowing upfront
Pipeline is deterministic. Same (org, agent, version) + static org metadata → byte identical <agent <ver metadata tree.json and <agent <ver architecture.md . Only manifest timestamps drift across re runs.
Forward only traversal. Every discovered ref goes forward from planner → children. No backward lookups.
Partial results are surfaced, not silenced. Any unresolved reference lands in unresolved[] with reason=... . STATUS=PARTIAL OK if any channel failed; STATUS=OK only on a clean run.
Cycle detection is per branch. Same flow visited along its own ancestor chain emits cycle back to:<path instead of recursing. A defensive MAX BFS DEPTH=20 guard backs the per branch ancestor set; real world agents bottom out well before either limit fires. (Earlier docs claimed a hard cap of 5; that was the historical limit and was abandoned because shared utility flows like handleFlowFault tripped it on every nested tree — see config.MAX BFS DEPTH for the rationale.)
Child ordering is alphabetical by api name (case insensitive). Topics come before non topic plannerActions at the root level. Flow actionCall order is NOT sorted — that's the flow author's execution sequence.