investigating-agentforce-architecture について
Salesforce 管理者や Agentforce 開発者向けのスキルで、単一の Agentforce エージェントの宣言メタデータを構造ツリーと文書にまとめます。並列クエリで統合ビューを作り、未解決の参照を示します。実行時の監査データは扱いません。
主な機能
- 01プランナー、トピック、アクションの構造を正規化
- 02Flow、Apex、プロンプト、プラグインを関連付け
- 03Tooling SOQL の並列クエリ
- 04JSON ツリーと Markdown 文書の生成
- 05メタデータのキャッシュと未解決参照の表示
活用シーン
- 01Agentforce エージェントの宣言アーキテクチャを把握
- 02アクションが参照する Flow と Apex を確認
- 03レビュー用のアーキテクチャ文書を作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill investigating-agentforce-architectureインストール後、Claude Code で/investigating-agentforce-architectureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdassets/cli/describe_sobject.yamldescribe_tooling_sobject.yamllist_metadata_genaiprompttemplate.yamlorg_display.yamlretrieve_genai_plugin.yamlshow_access_token.yamlassets/mermaid/action_tree.mmddata_flow.mmddependency_graph.mmdinvocation_sequence.mmdplanner_state.mmdassets/soql/apex_class_bodies_by_ids.soqlapex_class_bodies_by_names.soqlbot_definition_details.soqlbot_version_lookup.soqlflow_definition_by_ids.soqlflow_definition_ids_by_names.soqlflow_definition_view_by_durable_ids.soqlflow_metadata_by_id.soqlfunctions_by_plugins.soqlplanner_attrs_by_parent_ids.soqlplanner_bundle_functions.soqlplanner_definition_by_agent_chain.soqlplugin_functions_by_plugin_ids.soqlplugin_instructions_by_plugin_ids.soqlplugins_by_planner.soqlreferences/architecture_sections.mdcontract.jsonsoql_fields.md詳細
investigating-agentforce-architecture — 宣言されたアーキテクチャのスナップショット
1 つの Agentforce エージェントの設計時メタデータツリーです:プランナー → トピック → アクション → フロー → Apex → プロンプト → NGA プラグイン。宣言されたメタデータのみを読み取ります — BotDefinition、GenAiPlanner*、GenAiPlugin*、GenAiFunction*、Flow、ApexClass、GenAiPromptTemplate。実行時の監査行は読み取りません。
ランタイム予算:通常 30〜45 秒、ハード上限 ≤60 秒(参照フィクスチャの場合)。逐次処理のベースラインは 90〜220 秒です。並列 Tooling SOQL ファンアウトにより、3〜5 倍高速化されます。フローの多い大規模なボットでは、おおむね線形に拡大します — 各フローのメタデータ取得は 1 回のラウンドトリップです。
インラインで実行します — サブエージェントは使いません。すべてのフェーズは決定論的なファイル処理です。
実行に必要な情報が不足している場合
agent_api_name と org alias の両方が指定されずに呼び出された場合、以下のブロックをそのまま出力してください — 言い換えたり、スクリプトを事前実行したりしないでください。トリガー条件:$ARGUMENTS が空、またはエージェントが指定されていない(--agent フラグがなく、文章中に既知のエージェント API 名もない)、または org が指定されていない(--org フラグがなく、既知の alias もない)。
ドキュメント化するエージェントと org を指定してください。
必要な情報:
- Agent API name —
BotDefinitionのDeveloperNameです(例:MyAgent、MySalesAgent)。ラベルではありません。- Org alias —
sfCLI 認証に使う alias です(sf org loginで設定した alias)任意:
- Version —
v5のようなagent_version_api_nameです。省略した場合は、アクティブなBotVersionを解決します。--force— キャッシュされたツリーを無視し、すべてを再取得します。--reprobe— 7 日間のチャネルプローブキャッシュを再実行します(Salesforce のリリース後にのみ必要です)。メタデータパイプラインをインラインで実行します。成果物は
~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/に保存されます(--data-dirで変更できます)。
パイプラインの実行
ユーザーが --org <alias> と --agent <api_name>(および任意のフラグ)を指定した場合、このブロックを実行します。1 回の python3 呼び出しでパイプライン全体を実行します。main.py は .emit_ctx.json を書き込み、emit_result.py はそれを読み取って、最後に === RESULT === ブロックを 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}/investigating-agentforce-architecture}"
# 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/investigating-agentforce-architecture-$(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/tools/emit_result.py"
exit "$_rc"
入力
| 入力 | フラグ | 必須 | デフォルト |
|---|---|---|---|
org_alias | --org | はい | — |
agent_api_name | --agent | はい | — |
agent_version_api_name | --version | いいえ | アクティブな BotVersion |
force_refresh | --force | いいえ | false(キャッシュを使用) |
reprobe | --reprobe | いいえ | false(7 日間のチャネルプローブキャッシュを使用) |
parallelism | --parallelism | いいえ | 5 |
max_mermaid_nodes | --max-mermaid-nodes | いいえ | 80 |
data_dir | --data-dir | いいえ | ~/.vibe/data/investigating-agentforce-architecture |
cache_dir | --cache-dir | いいえ | ~/.vibe/cache/investigating-agentforce-architecture |
出力
すべての成果物は ~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/ に保存されます(デフォルト。--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)
パイプライン — インライン、サブエージェントなし
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):
- plugins_by_planner (GenAiPluginDefinition)
- planner_bundle_functions (GenAiPlannerFunctionDef join)
- functions_by_plugins (GenAiFunctionDefinition)
- planner_attrs_by_parent_ids (GenAiPlannerAttrDefinition)
- plugin_functions_by_plugin_ids (GenAiPluginFunctionDef join)
- plugin_instructions_by_plugin_ids (GenAiPluginInstructionDef)
parse_bundle.py → parse retrieved XML into normalized node shapes
parse_wave.py → BFS expansion: flow/apex/prompt refs discovered in nodes
→ SOQL for Flow/Apex bodies (batched by id list)
→ Metadata retrieve ONLY for GenAiPromptTemplate (+ NGA external plugins conditionally)
finalize.py → merge waves into metadata_tree.json
render_architecture.py → <agent>_<ver>_architecture.md + Mermaid invocation graph (capped at --max-mermaid-nodes)
チャネル戦略 — SOQL を優先。
- 正規化されたツリーノード(planner、plugins、functions、plugin-functions、plugin-instructions、planner-functions、planner-attrs)のすべてに Tooling SOQL を使用します — planner id をキーとする 6 つの並列チャネルに加え、エージェントチェーンから planner id を解決する
planner_definition_by_agent_chainシードクエリを使います。 - Flow(id による)と Apex(id または名前による)の本文には、Data API SOQL を使用します — バッチ処理されます。
- メタデータ取得は 2 つの場合に限ります:(a)
GenAiPromptTemplate(プロンプト本文は Tooling SOQL では適切に公開されないため)、(b) プランナーが Native Generative Agent 形式の場合の NGA 外部プラグイン(クラシック ReAct ではスキップします)。
これが 3〜5 倍の高速化を実現します。単純な実装では、すべてを Metadata API の ZIP 経由で逐次取得することになります。並列 Tooling SOQL により、1 回のファンアウトでツリーの約 80% をカバーします。
プランナーの形状 — 従来型 ReAct と NGA
このスキルでは、2 種類のプランナーファミリーを単一のツリー形状に正規化します。
| 形状 | GenAiPlannerDefinition.PlannerType | InvocationTarget の形式 | NGA プラグイン |
|---|---|---|---|
| 従来型 ReAct | ReactAiPlannerV1 / SequentialPlannerIntentClassifier / など | DeveloperName 文字列 | いいえ |
| NGA | ConcurrentMultiAgentOrchestration / AnthropicCompatibleV1 / など | 15/18 文字の ID の場合あり(ID プレフィックスでルーティング) | はい(メタデータ取得による外部プラグイン) |
resolve_invocation_target.py の ID プレフィックスルーターがこの 2 種類を判別します。ID のように見える NGA の InvocationTarget(01p… = ApexClass、301… = Flow など)は ID を指定した SOQL で解決され、DeveloperName のターゲットは名前を指定した SOQL で処理されます。不明なプレフィックスは _unresolved[] に reason="unknown-id-prefix:<prefix>" として出力され、黙って破棄されることはありません。
キャッシュ
- ツリーキャッシュ:
--forceを指定しない限り、metadata_tree.jsonを再利用します。キャッシュキーには、スキルに同梱されたすべての.soql/.yaml/.mmdテンプレートのアセットハッシュが含まれます。テンプレートを更新すると、キャッシュは自動的に無効になります。 - チャネルプローブキャッシュ:各組織の
sf sobject describe結果を 7 日間保持し、SOQL アセットが参照するすべてのフィールド名を検証します。Salesforce の四半期リリースでフィールドの名前が変更または削除されると、status: PROBE_FAILEDが発生します。--reprobeを指定すると更新を強制できます。
前提条件
| ツール | 必須 |
|---|---|
sf CLI(対象組織に対して認証済み) | はい — sf org login web --alias <alias> |
| Python 3.10+ | はい |
必要に応じて読み込むリファレンスドキュメント
先読みしないでください。ユーザーの質問で必要な場合に読み込んでください。
references/soql_fields.md— このスキルが扱う 13 個の sObject(Data API 2 個 + Tooling 11 個)のフィールドリファレンスです。[mandatory]と[optional]のタグが付いています。ユーザーが特定のフィールドについて質問した場合や、INVALID_FIELDSOQL エラーをデバッグする場合に読み込みます。references/contract.json—metadata_tree.jsonの機械可読なスキーマです。このツリーを使用する後続のツールを作成する場合に読み込みます。references/architecture_sections.md— レンダリングされた<agent>_<ver>_architecture.mdのセクションごとの構成です。
あらかじめ把握しておくべき不変条件
- パイプラインは決定論的です。 同じ
(org, agent, version)と静的な組織メタデータであれば、<agent>_<ver>_metadata_tree.jsonと<agent>_<ver>_architecture.mdはバイト単位で同一になります。再実行によって変動するのはマニフェストのタイムスタンプのみです。 - 前方のみをたどります。 検出されたすべての参照は、プランナーから子要素へと前方にたどります。逆方向の検索は行いません。
- 部分的な結果も表示し、黙って破棄しません。 未解決の参照はすべて、
reason=...とともに_unresolved[]に格納されます。いずれかのチャネルで失敗した場合はSTATUS=PARTIAL_OK、すべて正常に完了した場合のみSTATUS=OKになります。 - 循環検出はブランチ単位です。 同じフローが自身の祖先チェーン上で再度訪問されると、再帰せずに
_cycle_back_to:<path>を出力します。ブランチ単位の祖先セットには、防御策としてMAX_BFS_DEPTH=20のガードもあります。実際のエージェントでは、どちらの上限に達するよりも前に探索が終わります。(以前のドキュメントではハード上限を 5 としていましたが、それは過去の上限です。共有ユーティリティーフロー(handleFlowFaultなど)がネストされたツリーごとに上限に達していたため、廃止されました。理由についてはconfig.MAX_BFS_DEPTHを参照してください。) - 子要素は
api_nameのアルファベット順(大文字・小文字を区別しない)に並びます。 ルートレベルでは Topic が Topic 以外の plannerActions より前に並びます。Flow の actionCall の順序はソートされません。これはフロー作成者が指定した実行順序です。