Declared architecture snapshot for a single Agentforce agent: planner + topics + actions + flows + Apex + prompts + NGA plugins. Reads design-time metadata only (`BotDefinition` + `GenAi*` Tooling objects + Metadata API retrieve) — no runtime audit data.
Input: an `agent_api_name` (the `BotDefinition.DeveloperName`) and an org alias. Optional `agent_version_api_name` to pin a version; otherwise the active `BotVersion` resolves.
Output: two files under `~/.vibe/data/agentforce-architecture-analyze/<org_id15>/<agent>__<version>/` — a normalized `<agent>_<ver>_metadata_tree.json` and a human-readable `<agent>_<ver>_architecture.md`. Override with `--data-dir <path>` (other runtimes pass this to land artifacts under their own distribution layout).
---
## Runtime budget
**30–45s typical, ≤60s hard cap** on the reference fixtures.
A naive sequential implementation (Metadata API retrieves only) would take 90–220s. Speedup: **3–5×**.
Scaling note: large bots with many flows scale approximately linearly in flow count. Each Flow metadata retrieve is an individual SOQL round-trip; a 20-flow bot takes proportionally longer than a 5-flow bot. The 7 planner-side Tooling SOQL fan-outs are constant-cost (single fan-out regardless of bot size); the flow/apex body fetch wave scales with ref count.
---
## Prerequisites
| Tool | Why |
|---|---|
| `sf` CLI (authenticated against the target org) | Shells `sf org display --target-org <alias> --json` for access token, and `sf sobject describe` for the 7-day channel probe |
6 parallel Tooling SOQL channels (keyed on the resolved planner id):
- plugins_by_planner
- planner_bundle_functions (join)
- functions_by_plugins
- planner_attrs_by_parent_ids
- plugin_functions_by_plugin_ids (join)
- plugin_instructions_by_plugin_ids
+ Data API SOQL for Flow / Apex bodies (batched by id list)
+ Metadata retrieve ONLY for:
- GenAiPromptTemplate (prompt bodies)
- NGA external plugins (when planner is ConcurrentMultiAgentOrchestration etc.)
```
Most of the 3–5× speedup over a naive Metadata-API-only implementation comes from collapsing a sequential zip-retrieve chain into a single Tooling SOQL fan-out.
### Planner normalization — classic ReAct vs NGA
One tree shape, two planner families:
| `PlannerType` examples | Family | InvocationTarget style |
| `ConcurrentMultiAgentOrchestration`, `AnthropicCompatibleV1` | NGA | Sometimes 15/18-char Ids (ID-prefix routed) |
`resolve_invocation_target.py` routes NGA InvocationTargets by Salesforce ID prefix (`01p` → ApexClass, `301` → Flow, etc.). Unknown prefixes become `_unresolved[]` entries with `reason="unknown-id-prefix:<prefix>"` — never silently dropped.
### Cache layers
1.**Tree cache** — `metadata_tree.json` is reused unless `--force`. Cache key includes asset-hashes of every SOQL / YAML / Mermaid template shipped with the skill, so changing a template busts the cache automatically.
2.**Channel probe cache** — 7-day TTL on `sf sobject describe` results for the 13 sObjects the skill touches. `--reprobe` forces a refresh (needed after Salesforce quarterly releases that rename / remove fields). Mandatory-field gate: a probe that sees any mandatory field missing (per `probe_channels.MANDATORY_FIELDS`) flips `status: PROBE_FAILED` so the caller surfaces a clean error.
---
## Key behaviors
### Idempotence
Re-running the same `(org, agent, version)` overwrites prior artifacts in place. Safe to run repeatedly during development.
### Partial-results surfacing
No silent drops. Any unresolved ref — unknown ID prefix, failed SOQL, missing describe field — lands in `_unresolved[]` with a `reason=...` string. Top-level `STATUS` is `OK` on a clean run, `PARTIAL_OK` when any channel degrades.
### Cycle handling
Per-branch ancestor-path cycle detection is the primary termination primitive: the same flow visited along its own ancestor chain emits `_cycle_back_to:<path>` instead of recursing. `MAX_BFS_DEPTH=20` is a defensive last-resort guard against pathological graphs that evade per-branch detection; real-world agents bottom out well before that.
| `INVALID_FIELD` from a SOQL asset | Salesforce renamed / removed the field in a quarterly release. Run with `--reprobe` to refresh the 7-day channel cache and pick up the new schema |
| `STATUS=PROBE_FAILED` on first run | Channel probe saw a mandatory field missing. Check `channels.json` under the probe cache dir for which sObject / field — may require org-side feature enablement |
| Tree for classic ReAct agent shows `_unresolved` entries for NGA plugins | Expected — the NGA external-plugin retrieve is skipped when the planner shape is classic. Those entries can be ignored |