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, diagram, inventory, audit, document, or diff (e.g. v3 vs v5) the architecture / action tree / topic structure / tool inventory of a specific agent by agent API name in a specific org. DO NOT TRIGGER for runtime session traces, conversation transcripts, generation timings, or gateway audit chains — this skill reads design-time metadata only (use agentforce-d360-analyze for session traces).
- Skill ID
- forcedotcom/sf-skills/agentforce-architecture-analyze
- Publisher
- forcedotcom
- Repository
- sf-skills
- Installs
- 0
- Files
- 91
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
forcedotcom/sf-skills/agentforce-architecture-analyzeInstalls these files- README.md
- SKILL.md
- assets/cli/describe_sobject.yaml
- assets/cli/describe_tooling_sobject.yaml
- assets/cli/list_metadata_genaiprompttemplate.yaml
- assets/cli/org_display.yaml
- assets/cli/retrieve_genai_plugin.yaml
- assets/cli/show_access_token.yaml
- assets/mermaid/action_tree.mmd
- assets/mermaid/data_flow.mmd
- assets/mermaid/dependency_graph.mmd
- assets/mermaid/invocation_sequence.mmd
- assets/mermaid/planner_state.mmd
- assets/soql/apex_class_bodies_by_ids.soql
- assets/soql/apex_class_bodies_by_names.soql
- assets/soql/bot_definition_details.soql
- assets/soql/bot_version_lookup.soql
- assets/soql/flow_definition_by_ids.soql
- assets/soql/flow_definition_ids_by_names.soql
- assets/soql/flow_definition_view_by_durable_ids.soql
- assets/soql/flow_metadata_by_id.soql
- assets/soql/functions_by_plugins.soql
- assets/soql/planner_attrs_by_parent_ids.soql
- assets/soql/planner_bundle_functions.soql
- assets/soql/planner_definition_by_agent_chain.soql
- assets/soql/plugin_functions_by_plugin_ids.soql
- assets/soql/plugin_instructions_by_plugin_ids.soql
- assets/soql/plugins_by_planner.soql
- references/architecture_sections.md
- references/contract.json
- references/soql_fields.md
- scripts/_shared/__init__.py
- scripts/_shared/fs_guard.py
- scripts/_shared/paths.py
- scripts/_shared/runtime.py
- scripts/_shared/sql.py
- scripts/cache_check.py
- scripts/config.py
- scripts/emit_env.py
- scripts/emit_result.py
- scripts/fetch_soql.py
- scripts/finalize.py
- scripts/main.py
- scripts/metadata_listing.py
- scripts/parallel_retrieve.py
- scripts/parse_bundle.py
- scripts/parse_wave.py
- scripts/probe_channels.py
- scripts/render_architecture.py
- scripts/resolve_bot.py
- scripts/resolve_invocation_target.py
- scripts/rest_client.py
- scripts/retrieve_planner.py
- scripts/sanitize.py
- scripts/sf_cli.py
- scripts/soql_loader.py
- scripts/summarize_tree.py
- scripts/tests/__init__.py
- scripts/tests/_bootstrap.py
- scripts/tests/fixtures/__init__.py
- scripts/tests/fixtures/genai_payloads.py
- scripts/tests/test_cache_check.py
- scripts/tests/test_cache_check_main.py
- scripts/tests/test_config.py
- scripts/tests/test_end_to_end_fixture.py
- scripts/tests/test_finalize.py
- scripts/tests/test_flow_children_inflation.py
- scripts/tests/test_fs_guard.py
- scripts/tests/test_iterative_wave_b.py
- scripts/tests/test_main_pipeline.py
- scripts/tests/test_parallel_retrieve.py
- scripts/tests/test_parse_bundle.py
- scripts/tests/test_parse_wave.py
- scripts/tests/test_parse_wave_classifiers.py
- scripts/tests/test_parse_wave_helpers.py
- scripts/tests/test_parse_wave_main.py
- scripts/tests/test_per_branch_visited.py
- scripts/tests/test_probe_channels.py
- scripts/tests/test_probe_cli_recipes.py
- scripts/tests/test_render_architecture.py
- scripts/tests/test_resolve_bot.py
- scripts/tests/test_resolve_creds.py
- scripts/tests/test_resolve_invocation_target.py
- scripts/tests/test_rest_client.py
- scripts/tests/test_runtime_override.py
- scripts/tests/test_sf_cli.py
- scripts/tests/test_signature_stamping.py
- scripts/tests/test_soql_loader.py
- scripts/tests/test_summarize_tree.py
- scripts/tests/test_write_emit_ctx.py
- scripts/write_emit_ctx.py
What this skill tells the agent
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 — theDeveloperNameof theBotDefinition(e.g.MyAgent,MySalesAgent). Not the label. - Org alias — forsfCLI auth (the alias you configured withsf org login) Optional: - Version — anagent_version_api_namelikev5. If omitted, I'll resolve the activeBotVersion. - `--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.
set -euo pipefail
# zsh arrays are 1-indexed by default; bash arrays are 0-indexed.
# This block uses 0-indexed semantics throughout (_args[$i] starting at i=0),
# so under zsh + `set -u` the very first read of `_args[0]` would trip
# `parameter not set`. KSH_ARRAYS makes zsh treat arrays as 0-indexed,
# matching the bash shebang's expectation. No-op under bash.
[ -n "${ZSH_VERSION:-}" ] && setopt KSH_ARRAYS
SKILL_ROOT="${SKILL_ROOT:-${PLUGIN_ROOT:-$HOME/.vibe/skills}/agentforce-architecture-analyze}"
# Argument parser. Accepts both `--org foo` and `--org=foo`.
# `$ARGUMENTS` is the raw user input Claude Code substitutes.
ARG_ORG=""
ARG_AGENT=""
ARG_VERSION=""
ARG_FORCE=""
ARG_REPROBE=""
ARG_PARALLELISM=""
ARG_MAX_MERMAID=""
# shellcheck disable=SC2206
_args=($ARGUMENTS)
i=0
while [ $i -lt ${#_args[@]} ]; do
tok="${_args[$i]}"
case "$tok" in
--org=*) ARG_ORG="${tok#--org=}" ;;
--org) i=$((i+1)); ARG_ORG="${_args[$i]:-}" ;;
--agent=*) ARG_AGENT="${tok#--agent=}" ;;
--agent) i=$((i+1)); ARG_AGENT="${_args[$i]:-}" ;;
--version=*) ARG_VERSION="${tok#--version=}" ;;
--version) i=$((i+1)); ARG_VERSION="${_args[$i]:-}" ;;
--parallelism=*) ARG_PARALLELISM="${tok#--parallelism=}" ;;
--parallelism) i=$((i+1)); ARG_PARALLELISM="${_args[$i]:-}" ;;
--max-mermaid-nodes=*) ARG_MAX_MERMAID="${tok#--max-mermaid-nodes=}" ;;
--max-mermaid-nodes) i=$((i+1)); ARG_MAX_MERMAID="${_args[$i]:-}" ;;
--force) ARG_FORCE="1" ;;
--reprobe) ARG_REPROBE="1" ;;
esac
i=$((i+1))
done
# Usage block if required flags missing. Agent reads stderr,
# prints verbatim, and stops — does NOT pre-run main.py.
if [ -z "$ARG_ORG" ] || [ -z "$ARG_AGENT" ]; then
cat >&2 <<'USAGE'
> Which agent should I document, and in which org?
>
> I need:
> - **Agent API name** — the BotDefinition.DeveloperName (e.g. `MyAgent`)
> - **Org alias** — for `sf` CLI auth (the alias you configured with `sf org login`)
>
> Optional flags:
> - `--version v5` — pin a specific BotVersion (default: Active+highest)
> - `--force` — bypass cache
> - `--reprobe` — force channel-probe refresh
> - `--parallelism N` — ThreadPoolExecutor size (default 5)
> - `--max-mermaid-nodes N` — cap Mermaid node count (default 80)
USAGE
exit 2
fi
# Fresh work dir per invocation. Epoch + random suffix avoids collisions
# between concurrent runs on the same host.
WORK_DIR="/tmp/agentforce-architecture-analyze-$(date +%s)-$RANDOM"
mkdir -p "$WORK_DIR"
# Input validation at the boundary, BEFORE any python3 call.
# fs_guard exits 1 and prints an INVALID_INPUT RESULT block on failure;
# `|| exit 1` is mandatory — bare calls silently continue past failures.
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_AGENT" agent_api_name api_name || exit 1
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_ORG" org_alias not_empty || exit 1
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR symlink || exit 1
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR owned || exit 1
if [ -n "$ARG_VERSION" ]; then
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_VERSION" agent_version api_name || exit 1
fi
# Single python3 call drives all pipeline phases. main.py writes
# `.emit_ctx.json` into $WORK_DIR — emit_result.py then renders the
# RESULT block from that ctx. No subprocess-per-phase.
_main_args=(--org-alias "$ARG_ORG" --agent "$ARG_AGENT" --work-dir "$WORK_DIR")
[ -n "$ARG_VERSION" ] && _main_args+=(--version "$ARG_VERSION")
[ -n "$ARG_FORCE" ] && _main_args+=(--force)
[ -n "$ARG_REPROBE" ] && _main_args+=(--reprobe)
[ -n "$ARG_PARALLELISM" ] && _main_args+=(--parallelism "$ARG_PARALLELISM")
[ -n "$ARG_MAX_MERMAID" ] && _main_args+=(--max-mermaid-nodes "$ARG_MAX_MERMAID")
# main.py returns nonzero on terminal failures; we DON'T short-circuit —
# emit_result still publishes the failure RESULT block. `set -e` is
# temporarily relaxed around this single call.
set +e
python3 "$SKILL_ROOT/scripts/main.py" "${_main_args[@]}"
_rc=$?
set -e
# Final RESULT block is emit_result.py's stdout — MUST be the last thing
# stdout sees. emit_result exits 0 on render success; the bash harness
# propagates main.py's rc for the agent's exit status.
WORK_DIR="$WORK_DIR" python3 "$SKILL_ROOT/scripts/emit_result.py"
exit "$_rc"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>):
<agent>_<ver>_metadata_tree.json primary artifact — normalized planner/topic/action/flow/apex/prompt/plugin tree
<agent>_<ver>_architecture.md human-readable section-by-section rendering (H1 + 7 numbered sections, plus a conditional Dependency graph appendix). Mermaid diagrams are embedded inside the relevant sections (Action tree, Data flow, and Dependency graph)Pipeline — inline, no subagent
resolve_bot.py → BotDefinition + BotVersion + planner name lookup
retrieve_planner.py → Metadata API zip retrieve for GenAiPlannerBundle (+ NGA plugins if present)
parallel_retrieve.py → 6 parallel Tooling SOQL channels fan out from the planner id
(resolved by the `planner_definition_by_agent_chain` seed query):More from forcedotcom
Use this skill in a project
Open any RiverX project, search the Skills panel for forcedotcom/sf-skills/agentforce-architecture-analyze, and install it in one click.
