Refreshing the org vault
Skill PranavNagrecha/Salesforce-Intelligence/.claude/skills/refreshing-the-org-vault
Salesforce Org Intelligence for AI agents - a read-only, offline, source-available MCP server and CLI answering metadata, dependency, permission, Apex and Flow questions grounded in real retrieved org metadata.
npx -y skills add PranavNagrecha/Salesforce-Intelligence --skill refreshing-the-org-vaultAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Refreshes the SfIntelligence vault from a live Salesforce org. Use when the user invokes `/sfi-refresh`, or says "refresh", "refresh the vault", "pull latest", "pull the latest from my org", "rebuild the vault", "rebuild the index", "my data is stale", "the vault is stale", "I just deployed changes", or any phrase signaling the vault is out of date relative to the org. Drives `sfi refresh`, which shells out to `sf project retrieve`, runs the full extractor graph, imports into DuckDB, renders Markdown, and writes a new manifest (including optional **coverage** metadata).
SKILL.md
12.2 KB, as published. Nobody here has run it
Refreshing the org vault
Overview
sfi refresh is the only way the vault learns about new metadata.
The pipeline runs five stages in order, and all five have to
finish for the vault to be usable:
- Pull —
sf project retrieve start --manifest <pkg.xml> --target-org <alias> --output-dir org-kb/source/. Network step. The slow one for real orgs. - Extract — walk
org-kb/source/, dispatch each file to the matching extractor (72 component types including Reports, FlexiPages, Permission Set Groups, OmniStudio, CPQ, etc.). Per-file failures are captured, not fatal. - Import — load extracted nodes and edges into the DuckDB graph
at
org-kb/graph/graph.duckdb. - Render — write Markdown component files under
org-kb/components/<Type>/..., plus Apex/Flow source pages and the vault index. - Manifest — recompute the source-tree hash, stamp
refreshedAt, writeorg-kb/meta/manifest.json(includingcoverageper metadata type when the retrieve result is available).
Optional after a successful refresh: sfi snapshot create --label <name>
so sfi.trend / sfi.diff_snapshots can compare structural history later.
A real org takes 5–15 minutes end-to-end, dominated by stage 1. Tell the user this before you start — silence during a long retrieve reads like a hang.
When to fire
Explicit:
- The user typed
/sfi-refresh.
Conversational triggers:
- "Refresh the vault" / "refresh the index" / "rebuild the vault".
- "Pull the latest from my org" / "pull latest".
- "My data is stale" / "the vault is stale" / "this is out of date".
- "I just deployed changes" / "I just pushed metadata" / "things changed in the org".
sfi.health_checkreturnsstatus: 'degraded'orfreshness.stale: true. Tell the user to run/sfi-refresh.status: 'unhealthy'orchecks.vaultExists: false→ route to/sfi-init.
When NOT to fire:
- The user is asking a question and the vault is already fresh.
Answer the question first; only refresh if
health_checkflags staleness. - The user wants live record data ("how many Accounts closed
today?"). Refresh pulls metadata, not records. Record counts need
the opt-in live plane (
sfi.live_*) orsf data query. - There is no
org-kb/directory yet. The user hasn't initialized the vault — point them to/sfi-init, not refresh.
Pre-flight checks
Run these before invoking sfi refresh. Each check that fails
stops the flow; do not proceed.
1. sf CLI authentication
Run:
sf org list --json
Parse the JSON for the alias the user is refreshing (or the
default). If the alias is not present, or its connectedStatus is
not Connected, stop and tell the user:
"The
sfCLI isn't authenticated to<alias>. Runsf org login web --alias <alias>(orsf org login web --set-default --alias <alias>if this should be the default), then ask me to refresh again."
If sf itself isn't installed (command not found), point the
user to the Salesforce CLI install docs and stop.
2. Vault config exists
Confirm org-kb/meta/config.json exists and parses. The CLI does
this too, but checking first lets you surface a clearer message:
"No vault config at
org-kb/meta/config.json. Run/sfi-initfirst."
3. Target alias matches (when the user specified one)
If the user said "refresh from <alias>" and the config's
targetOrg is a different alias, ask before overriding:
"Config has
targetOrg: <config-alias>. You asked me to refresh from<user-alias>. I'll pass--target-org <user-alias>for this run; want me to update the config too?"
Don't silently override. The config is the persisted intent.
Steps
-
Run the pre-flight checks above. If any fails, stop and surface the actionable message.
-
Set expectations. Before running the command, say something like:
"Running
sfi refreshagainst<alias>. This pulls metadata from Salesforce, runs nine extractors, rebuilds the graph, and re-renders the vault. Expect 5–15 minutes for a real org; faster for a small fixture org." If the user passed--no-pull(or said "the source tree is already populated, just re-extract"), say so: "Skippingsf project retrieve(you passed--no-pull). Re-extracting from the existingorg-kb/source/tree." -
Run the command. Forward whatever flags the user provided:
--target-org <alias>if specified.--no-pullif the user said the source tree is already there.--types <list>(comma-separated) if the user wants a subset refreshed.
Example invocations:
sfi refresh sfi refresh --target-org [email protected] sfi refresh --no-pull sfi refresh --types CustomObject,CustomField,ValidationRule -
Read the new manifest. After the command exits, read
org-kb/meta/manifest.json. Report:refreshedAtsourceOrgcomponentstotals by typeedgestotals by typesourceTreeHash(last 12 chars are fine; full hash is noisy)
If a previous manifest existed, compare counts and surface the delta ("CustomField: 312 → 318, +6"). Do this honestly — if a count dropped, say so; it usually means a metadata type was removed from the org (or a
--typesfilter excluded it). -
Handle non-success outcomes. The CLI exits non-zero on
partialandfailed. See Failure modes below.
Failure modes
| Symptom | Likely cause | What to surface |
|---|---|---|
sfi refresh exits with Fatal: sf project retrieve failed: ... and stderr mentions No authorization information found | sf not authenticated to the target alias | "The sf CLI lost its session for <alias>. Run sf org login web --alias <alias> and try again." |
Fatal: sf project retrieve failed: ... with timeout / ETIMEDOUT / ECONNRESET | Network blip, slow org, or VPN dropped | "Retrieve timed out. Retry with /sfi-refresh once. If it fails twice, check VPN/network and try sf org list to confirm the alias still responds." |
Refresh partial in N ms and the summary lists per-file errors | One or more metadata files were malformed or the extractor returned an error | Report exactly which files failed and the error.kind from each line. The vault is still coherent for the files that succeeded — say that explicitly. Do not claim success. |
Fatal: Vault config not found at .../org-kb/meta/config.json | /sfi-init hasn't been run | "No vault config. Run /sfi-init first." |
Fatal: openGraph: Could not find ... duckdb-neo (or Error: Cannot find module '@duckdb/node-api/...') on first install | pnpm blocked DuckDB's native postinstall script | "DuckDB's native binding didn't install. Run pnpm approve-builds and accept @duckdb/node-api, then try again." |
Fatal: renderVault: ... | Renderer crashed mid-stage; extracted nodes exist but Markdown isn't written | Surface the message verbatim. The graph may have stale data from a previous run. Tell the user the vault is in an inconsistent state and the next refresh will overwrite it. |
Fatal: saveManifest: ... | Filesystem error writing the manifest | The components and edges were rendered, but manifest.json is missing or stale. Tell the user to retry — the next refresh will write a fresh manifest. |
When you don't recognize the error, paste the Fatal: line back to
the user and ask whether they want to retry or investigate. Do not
guess a recovery path.
Common rationalizations
| Rationalization | Reality |
|---|---|
"It probably succeeded; I'll say done without reading the new manifest." | The user trusts your summary. Always read the manifest and report the actual counts and refreshedAt. |
| "The retrieve takes a while; I'll explain after it finishes." | Tell them before: "This may take 5–15 minutes." Silence reads like a hang and they'll cancel halfway. |
| "Partial means basically success." | No. Partial means some files failed. List which ones and the error kind for each. Inflating partial to success is how stale or incomplete vaults end up trusted. |
"I'll skip the sf org list check; if auth is bad, the retrieve will tell us." | The CLI's error message is buried in sf output. Catching it pre-flight gives the user a one-line fix instead of a stack trace. |
| "The user said 'refresh' but the vault was refreshed 10 minutes ago; I'll skip it." | Don't decide for them. Run sfi.health_check first; if it says ok, surface that — "vault was refreshed at HH:MM, sourceTreeHash matches; nothing to refresh. Refresh anyway?" — and let them choose. |
| "I'll just describe what the org probably looks like now." | The refresh's output is the org state. Do not speculate about what's in the org before the refresh succeeds. |
"If --no-pull is faster, I'll always pass it." | --no-pull only re-extracts the existing source tree. It does not pick up any changes from Salesforce. Only use it when the user explicitly says the source is already populated. |
"The retrieve failed twice; I'll edit config.json to a different alias to see if that works." | Don't. Ask the user. Config edits are persisted intent. |
Red flags
Stop and ask the user when:
- Two retries of
sfi refreshboth fail with the sameFatal:line. The third attempt won't help; surface the message and ask what the user wants to do. - The new manifest's component counts are drastically lower than
the previous manifest (e.g.,
CustomField: 312 → 8) and the user did not pass--types. Something pulled an empty package; ask before treating this as the new ground truth. sf org listshows the target alias asConnectedbutconnectedStatusis followed by a refresh-token expiry warning. Surface the warning; the next retrieve may succeed once before failing.- The user wants you to "refresh just one object" or "just the
fields on Account." The
--typesfilter scopes by metadata type, not by individual component. Tell them: refresh is all-or-nothing within a type. - The user asks you to commit the regenerated vault. That's their
call — don't
git add/git commiton their behalf. Mention thatorg-kb/components/,org-kb/meta/manifest.json, andorg-kb/graph/graph.duckdbare the typical commit targets if they want a diff-able snapshot.
Verification
Before telling the user the refresh is done, confirm:
- Did I run
sf org list --json(or read prior output) and confirm the target alias isConnected? - Did I tell the user — before running the command — that this could take 5–15 minutes?
- Did I read
org-kb/meta/manifest.jsonafter the run and report the actualrefreshedAt,sourceOrg, and counts? - If status is
partial, did I list the per-file errors with theirerror.kind, instead of summarizing as "mostly worked"? - If status is
failed, did I surface theFatal:line verbatim and name the recovery path? - Did I avoid claiming any state about the org's current contents that I didn't read from the new manifest or vault?
Grounding & routing (shared contract). For a vague or broad ask, call sfi.route_question first — in the default hybrid mode it returns a meaning-ranked toolCandidates shortlist (which YOU pick from) plus a suggested plane and a route hint (and whether to sfi.resolve a name first). Every org fact must come from an sfi.* tool call, cited by its canonical id — never from memory. Build the answer only from what the tools returned, then pass it through sfi.synthesize_answer, which flags any hallucinatedIds (canonical ids no tool produced). Full cascade: using-sf-intelligence.