@ryanstark24/sfgraph-skills 1.1.4 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/package.json +3 -2
  2. package/skills/sf-cross-layer-trace/SKILL.md +16 -5
  3. package/skills/sf-cross-org-diff/SKILL.md +7 -1
  4. package/skills/sf-dead-code-audit/SKILL.md +10 -3
  5. package/skills/sf-debug-log-analysis/SKILL.md +107 -0
  6. package/skills/sf-debug-root-cause/SKILL.md +111 -0
  7. package/skills/sf-deployment-manifest/SKILL.md +13 -7
  8. package/skills/sf-explain-code/SKILL.md +16 -1
  9. package/skills/sf-find-similar/SKILL.md +10 -4
  10. package/skills/sf-flow-impact/SKILL.md +6 -0
  11. package/skills/sf-governor-risk-fix/SKILL.md +50 -10
  12. package/skills/sf-graph-plus-source/SKILL.md +46 -0
  13. package/skills/sf-graph-router/SKILL.md +146 -0
  14. package/skills/sf-impact-from-diff/SKILL.md +11 -5
  15. package/skills/sf-metadata-refresh/SKILL.md +9 -3
  16. package/skills/sf-omnistudio-migration-audit/SKILL.md +15 -5
  17. package/skills/sf-schema-overview/SKILL.md +8 -2
  18. package/skills/sf-security-audit/SKILL.md +14 -6
  19. package/skills/sf-snapshot-compare/SKILL.md +6 -0
  20. package/skills/sf-web-explorer/SKILL.md +6 -1
  21. package/skills/sf-what-broke/SKILL.md +28 -22
  22. package/skills/sf-wip-impact/SKILL.md +8 -0
  23. package/dist/__tests__/cursor-format.test.d.ts +0 -2
  24. package/dist/__tests__/cursor-format.test.d.ts.map +0 -1
  25. package/dist/__tests__/cursor-format.test.js +0 -44
  26. package/dist/__tests__/cursor-format.test.js.map +0 -1
  27. package/dist/__tests__/installer.test.d.ts +0 -2
  28. package/dist/__tests__/installer.test.d.ts.map +0 -1
  29. package/dist/__tests__/installer.test.js +0 -64
  30. package/dist/__tests__/installer.test.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sf-governor-risk-fix
3
- description: Detect governor-limit risks (SOQL/DML in loops, unbounded queries) and produce a remediation checklist.
3
+ description: Detect governor-limit risks (SOQL, SOSL and DML in loops, triggers that are not bulk-safe, unbounded queries) and produce a remediation checklist.
4
4
  triggers:
5
5
  - "governor limit"
6
6
  - "SOQL in loop"
@@ -17,24 +17,61 @@ tools_used:
17
17
 
18
18
  Use when the user wants to find Apex code that risks hitting governor limits at scale. The skill produces a prioritised remediation checklist; it never rewrites Apex automatically.
19
19
 
20
+ ## Evidence rule — say it only if something backs it
21
+
22
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
23
+
24
+ ## What the tool actually emits
25
+
26
+ `governor_risk_check` reports only the risk types the analyzer can prove from
27
+ the graph. Each record has `risk` (one of the kinds below), the method or trigger
28
+ qname, and evidence (the query text or DML target):
29
+
30
+ - **`soql_in_loop`** (high): a SOQL query whose `EXECUTES_SOQL` edge is tagged
31
+ `inLoop` (AST-verified: the query sits inside a for/while/do-while body).
32
+ - **`sosl_in_loop`** (high): the same for SOSL (`EXECUTES_SOSL`).
33
+ - **`dynamic_soql_in_loop`** (high): `Database.query(...)` inside a loop.
34
+ - **`dml_in_loop`** (high): the same for DML statements.
35
+ - **`no_bulk`** (high): a trigger that doesn't iterate `Trigger.new` (body-scan path).
36
+ - **`unbounded_query`** (medium): a query with no `WHERE` and no `LIMIT`. Only the
37
+ body-scan path (project ingests, where the full query text is available) emits it;
38
+ live-org ingests do not, because the captured query head makes it pure noise.
39
+
40
+ Medium and above are listed by default; `min_severity: "high"` keeps only the loop and
41
+ bulk findings. `includeTests: true` adds test code. There is no class or namespace
42
+ parameter: the tool scans the whole org, so filter its findings to the scope the user
43
+ asked about, and say that you did.
44
+
45
+ The check is per method: SOQL in a method that is *called* from a loop is not flagged.
46
+ Say so when the user asks about a call chain.
47
+
48
+ Do **not** promise non-selective queries, callouts in loops, heap size or trigger
49
+ recursion: the tool does not check them.
50
+
51
+ **Live-ingest prerequisite:** `inLoop` tagging comes from the Apex AST parser. A
52
+ graph ingested before that parser change has zero `inLoop` edges, so the check
53
+ returns nothing. If `governor_risk_check` returns empty on an org you believe has
54
+ in-loop SOQL, the fix is a re-ingest (`sfgraph ingest --org <alias> --rebuild`),
55
+ not "the org is clean" — say so explicitly rather than reporting a false all-clear.
56
+
20
57
  ## Playbook
21
58
 
22
- 1. Call `governor_risk_check` over the requested scope (single class, namespace, or full org). The tool returns risk records with rule id (`SOQL_IN_LOOP`, `DML_IN_LOOP`, `UNBOUNDED_QUERY`, `NON_SELECTIVE_QUERY`, `CALLOUT_IN_LOOP`, `LARGE_HEAP`, `RECURSIVE_TRIGGER`), location (class + method + line), and severity.
23
- 2. Group findings by rule id; within each group, sort by call-site fan-in (more callers = higher blast radius).
24
- 3. For each finding, describe the canonical fix pattern (e.g. "extract the SOQL above the loop and key the result by `Id`") in one or two sentences — do not write the code.
25
- 4. Render the Mermaid heat-map (class-by-rule) from the tool response.
59
+ 1. Call `governor_risk_check` for the org, then keep the findings in the requested scope (a class, a namespace, or the whole org). Records are keyed on the **method** qname (`ApexMethod:Class.method(n)`) or the trigger, with `risk` (one of the six kinds above) and evidence (the query text or DML target).
60
+ 2. Group findings by `risk`; within each group, sort by call-site fan-in (more callers = higher blast radius). Use `trace_upstream` on the owning class to get fan-in.
61
+ 3. For each finding, describe the canonical fix pattern (e.g. "extract the SOQL above the loop and key the result by `Id`") in one or two sentences — do not write the code. To actually design the bulkified fix, hand off to **`sf-architect-apex`** (or **`sf-architect-performance`** for LDV/query-plan work) with these call sites as grounding, so the rewrite respects the org's real selectors and trigger framework rather than a generic template.
62
+ 4. Render a Mermaid heat-map (class-by-rule) yourself from the tool's table findings — `governor_risk_check` returns a table + structured data, not a diagram. See **Visualization**.
26
63
  5. Produce a checklist the user can copy into a ticket: `- [ ] ClassName.methodName:line — rule — recommended pattern`.
27
64
  6. Recommend `sf-impact-from-diff` after the user applies fixes, to verify nothing downstream regressed.
28
65
 
29
66
  ## Visualization
30
67
 
31
- Render a **`flowchart TD`** heat-map: rows are Apex classes (top N by fan-in), columns are rule ids. Cell colour encodes severity (high/medium/low). When the tool returns its own Mermaid heat-map, embed that and skip this template.
68
+ Render a **`flowchart TD`** heat-map: rows are Apex classes (top N by fan-in), columns are rule ids. Cell colour encodes severity (high/medium/low). Build it yourself from the tool's findings — `governor_risk_check` returns a table, not a diagram.
32
69
 
33
70
  ```
34
71
  flowchart TD
35
- ClassA -->|SOQL_IN_LOOP: high| Risk1[:::hi]
36
- ClassA -->|UNBOUNDED_QUERY: med| Risk2[:::med]
37
- ClassB -->|DML_IN_LOOP: high| Risk3[:::hi]
72
+ ClassA -->|soql_in_loop: high| Risk1[:::hi]
73
+ ClassA -->|unbounded_query: med| Risk2[:::med]
74
+ ClassB -->|dml_in_loop: high| Risk3[:::hi]
38
75
  classDef hi fill:#fcc,stroke:#900
39
76
  classDef med fill:#ffe6cc,stroke:#c60
40
77
  ```
@@ -43,6 +80,8 @@ If the scan returns >50 findings, render only the top-10-by-fan-in row and link
43
80
 
44
81
  ## Staleness check
45
82
 
83
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
84
+
46
85
  Before calling `governor_risk_check`, invoke `staleness_check` for the target org. If the report says stale, surface a warning to the user:
47
86
 
48
87
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -60,5 +99,6 @@ Then continue with the playbook.
60
99
 
61
100
  - **Never auto-apply fixes.** This skill does not edit Apex.
62
101
  - Do not flatten severities — the bucket ordering matters.
63
- - Do not invent additional rules; only report what `governor_risk_check` returns.
102
+ - Do not invent additional rules; only report what `governor_risk_check` returns (the six kinds above).
103
+ - Do not report "no governor risks" without first checking staleness — an empty result on a pre-AST-parser ingest means the graph lacks `inLoop` tags, not that the code is clean. Recommend a re-ingest.
64
104
  - Do not silently exclude managed-package code; mention it was filtered out if so.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: sf-graph-plus-source
3
+ description: Use when you have file access AND sfgraph tools and the question is about references, flows, field usage, downstream reach or similar code. The graph gives the fast, complete-looking answer; this skill says what to double-check in the source before you finish, so graph speed and your own reading both count.
4
+ triggers:
5
+ - "where is this used"
6
+ - "trace downstream"
7
+ - "analyze field"
8
+ - "cross layer"
9
+ - "find similar"
10
+ tools_used:
11
+ - analyze_field
12
+ - cross_layer_flow_map
13
+ - trace_downstream
14
+ - find_similar
15
+ ---
16
+
17
+ # sf-graph-plus-source
18
+
19
+ The graph is the starting point, not the last word. Call the tool first, then spend a few file reads on the gaps below. Do not re-derive what the graph already returned.
20
+
21
+ ## Recipe: analyze_field / who reads or writes a field
22
+ 1. `analyze_field` for the field. Keep every component it lists.
23
+ 2. Grep the source once for the field's API name (`Field__c`). Add a component only if you see the name written in its source (Apex, Flow, LWC, Vlocity JSON). Skip profiles, layouts and permission sets.
24
+
25
+ ## Recipe: cross_layer_flow_map
26
+ 1. Call `cross_layer_flow_map` and keep its whole chain.
27
+ 2. Check each hop that crosses a layer boundary (LWC to Apex, Apex to Flow, Flow to Apex, OmniScript to Integration Procedure to DataRaptor). Grep for the hop's name; add a missing hop only when its source names the next component.
28
+
29
+ ## Recipe: trace_downstream
30
+ 1. Call `trace_downstream`. It is usually complete, and extras are the common error here.
31
+ 2. Do not add components from a grep. Only remove or flag one when the source shows it is only mentioned in a comment or string that is not a real reference. Remember objects, fields, validation rules and named credentials are leaves.
32
+
33
+ ## Recipe: find_similar
34
+ 1. Call `find_similar`. Open the top few hits and keep only those that do the same job (same inputs and effect), not just similar names.
35
+
36
+ ## Complete the set, then verify each layer
37
+ Before you answer a "list every ..." question:
38
+ 1. Write the candidate list, each with its source: the tool, a grep hit, or a file you read.
39
+ 2. Go layer by layer (UI, Apex, Flow, OmniStudio, objects and fields) and confirm each candidate in that layer, or drop it with a reason.
40
+ 3. Compare your count with the count the tool states (the "Found N" line, the trace total, any "N hidden" note). If they differ, name the difference.
41
+ 4. Names built in strings (`'Obj__c'`, `put('Field__c', ...)`, a class name in a variable) can be missing from the graph. Grep for the name before you call the list complete.
42
+
43
+ ## Always
44
+ - Say which parts came from the graph and which you confirmed in source.
45
+ - If the two disagree, trust the source you actually read and say so in a short sentence.
46
+ - Keep the answer plain: lead with the finding, then one short line per component.
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: sf-graph-router
3
+ description: Start here for ANY Salesforce development, design, or debugging task on an org sfgraph has ingested. Routes intent to the right sfgraph skill + MCP tool, and enforces the grounding-first rule — query the org graph for real schema / dependencies / security / governor facts BEFORE generating or changing Apex, LWC, Flow, or config. Use when the user asks to build, design, refactor, review, or debug Salesforce metadata and you are unsure which skill or tool applies, or when about to write Salesforce code from memory.
4
+ triggers:
5
+ - "help me build"
6
+ - "design a"
7
+ - "write a trigger"
8
+ - "write apex"
9
+ - "create an LWC"
10
+ - "refactor this"
11
+ - "review my"
12
+ - "is this safe to deploy"
13
+ - "which sfgraph tool"
14
+ - "where do I start"
15
+ - "debug this"
16
+ - "why is this failing"
17
+ tools_used:
18
+ - find_nodes
19
+ - analyze_field
20
+ - find_similar
21
+ - staleness_check
22
+ ---
23
+
24
+ # sf-graph-router — start here
25
+
26
+ sfgraph has a **local, queryable graph of the real org** (every Apex class, LWC, Flow,
27
+ field, profile, Vlocity/OmniStudio component, and the edges between them). That graph is
28
+ the antidote to the #1 failure of LLM-assisted Salesforce work: **hallucinating field
29
+ names, classes, and call chains that don't exist in this org.** This skill decides which
30
+ specialised skill/tool to use, and enforces one rule above all.
31
+
32
+ ## Evidence rule — say it only if something backs it
33
+
34
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
35
+
36
+ ## The grounding-first rule (non-negotiable)
37
+
38
+ **Before you generate or modify any Salesforce metadata — Apex, LWC, Flow, validation
39
+ rule, permission set — query the graph to ground yourself in what the org actually
40
+ contains.** Designing from training data alone is how you invent `Account.Tier__c` when
41
+ the org has `Account.Customer_Tier__c`, call a method arity that doesn't exist, or write a
42
+ trigger that ignores the three triggers already on the object.
43
+
44
+ Minimum grounding before writing code that touches object/field `X` or class `Y`:
45
+
46
+ 1. `find_nodes` — confirm the qnames exist (`CustomField:Account.*`, `ApexClass:*Order*`).
47
+ 2. `analyze_field` — for any field you'll read/write: who already reads/writes it, its type.
48
+ 3. `find_similar` — is there existing code that already does this? Reuse beats regenerate.
49
+ 4. For changes to existing Apex: `trace_upstream` (callers / blast radius) + `explain_code`.
50
+
51
+ If `staleness_check` says the ingest is old, say so — your grounding may be out of date —
52
+ and recommend `sfgraph ingest --org <alias>`. If the org isn't ingested at all, say the
53
+ grounding step is unavailable and proceed with explicit low-confidence caveats.
54
+
55
+ Only after grounding do you hand off to a design/knowledge skill (`sf-architect-*`, when installed; it is not part of sfgraph, so design directly if it is missing) to
56
+ write the code. Ground → design → verify. Never design → hope.
57
+
58
+ ## When the graph doesn't hold what the analysis needs — pull it from the org
59
+
60
+ The graph is **metadata structure**, not source code or record data. When an analysis
61
+ genuinely needs something the graph doesn't store, fetch it — don't guess and don't analyse
62
+ a stub. Two cases, with very different guardrails:
63
+
64
+ - **Source code & metadata definitions (fetch freely).** The graph stores source for Apex
65
+ methods (`ApexMethod:…`), trigger bodies (`ApexTrigger:…`), and Flow definitions
66
+ (`Flow:…`) — but NOT whole classes, LWC JS, or managed/`(hidden)` code, and some metadata
67
+ isn't ingested. Get the real definition when you need more: read the
68
+ **local sfdx file** (`force-app/main/default/{classes,triggers,flows,objects}/…`) first, else
69
+ retrieve from the org (`sf project retrieve start -m "ApexTrigger:<Name>"` / `Flow:<Name>` /
70
+ `CustomObject:<Name>`, or Tooling `SELECT Body FROM ApexClass WHERE Name='…'`).
71
+ - **CONFIG / metadata RECORDS (fetch when needed).** Custom Metadata records, Custom Setting
72
+ rows, picklist/record-type values, Named Credential config — these are deploy-time config,
73
+ not customer data. Pull them with `sf data query -q "SELECT … FROM <Type>__mdt"` (or the
74
+ setting `__c`, or Tooling for record types/picklists) when a trace/debug needs the value the
75
+ config resolves to. (1.4.0+ ingests CMDT/label/setting values into the graph, but older
76
+ graphs or un-ingested types may lack them — fetch then.)
77
+ - **BUSINESS SObject records (the bounded EXCEPTION — pull minimally, with care).** sfgraph is
78
+ deliberately **local-first and metadata-only**; actual records (Account/Contact/Opportunity
79
+ rows, etc.) are out of the graph by design, and they are **real, possibly-PII customer data**.
80
+ Only when analysis truly requires it — e.g. to see a misbehaving field's real value shape or
81
+ confirm a data-skew assumption — pull a **small bounded sample**: always `LIMIT` (≤ a handful
82
+ of rows), prefer `COUNT()`/aggregates over raw rows, never bulk-dump, and **tell the user
83
+ you're stepping outside the local-first boundary to read live records**. If aggregates answer
84
+ the question, don't pull rows at all.
85
+
86
+ State which source you used (graph / local file / org metadata / live records) so the reader
87
+ knows the provenance and whether it left the local-only guarantee.
88
+
89
+ ## Route by intent
90
+
91
+ ### DEVELOPMENT — writing or changing code
92
+ | Intent | Ground with | Then design with |
93
+ |---|---|---|
94
+ | "Write/extend Apex on `<Object>`" | `sf-schema-overview` (`<Object>`) + `find_nodes ApexClass:*<Object>*` + `find_similar` | `sf-architect-apex` |
95
+ | "Build an LWC for `<feature>`" | `find_similar` (existing LWCs) + `analyze_field` (bound fields) | `sf-architect-ui` |
96
+ | "Add an integration / callout" | `find_nodes NamedCredential:*` + `find_similar` | `sf-architect-integrations` |
97
+ | "Reuse — is this already built?" | `sf-find-similar` (free-text concept mode) | — |
98
+ | "Explain this method/trigger/Flow" | `sf-explain-code` (a class: explain its methods, `ApexMethod:Class.m(n)`) | — |
99
+ | "Who calls / uses `<method/class>`" | `trace_upstream` on its qname (`depth: 1` for direct callers) | — |
100
+ | "Which tests cover `<class>`" | `trace_upstream` with `rel_types: ["IS_TEST_FOR"]` | — |
101
+
102
+ ### DESIGN — architecture & data model
103
+ | Intent | Skill |
104
+ |---|---|
105
+ | "Show the data model / ERD for `<Object>`" | `sf-schema-overview` |
106
+ | "Trace `<field/LWC/method>` UI → DB" | `sf-cross-layer-trace` |
107
+ | "Where is `<field>` used / what writes it" | `sf-flow-impact` (Flow/automation) or `analyze_field` (all layers) |
108
+ | "Find duplicate / similar logic to consolidate" | `sf-find-similar` |
109
+
110
+ ### DEBUGGING — something is wrong
111
+ | Intent | Skill |
112
+ |---|---|
113
+ | "This Apex/test fails / this error — why" | `sf-debug-root-cause` |
114
+ | "Read/interpret this debug log / stack trace / 'Too many SOQL' / CPU-time log" | `sf-debug-log-analysis` |
115
+ | "What broke after the last deploy" | `sf-what-broke` |
116
+ | "Will my uncommitted change break anything" | `sf-wip-impact` |
117
+ | "Blast radius + test gaps of this PR/branch" | `sf-impact-from-diff` |
118
+ | "Compare two points in time / snapshots" | `sf-snapshot-compare` |
119
+
120
+ ### QUALITY / GOVERNANCE — review before ship
121
+ | Intent | Skill |
122
+ |---|---|
123
+ | "Governor-limit risks (SOQL/DML in loops)" | `sf-governor-risk-fix` |
124
+ | "FLS / sharing / who-has-access audit" | `sf-security-audit` |
125
+ | "What's unused / safe to delete" | `sf-dead-code-audit` |
126
+ | "Generate a deployment manifest" | `sf-deployment-manifest` |
127
+ | "Diff two orgs (sandbox vs prod)" | `sf-cross-org-diff` |
128
+ | "Vlocity ↔ OmniStudio migration inventory" | `sf-omnistudio-migration-audit` |
129
+ | "Is the graph fresh / how do I refresh" | `sf-metadata-refresh` |
130
+ | "Show me the graph visually" | `sf-web-explorer` |
131
+ | "Export findings for CI / code scanning (SARIF)" | `export_sarif` |
132
+
133
+ When you also have the project's source files, follow **`sf-graph-plus-source`** after the tool call: it says which parts of a graph answer to double-check in the source.
134
+
135
+ Most skills start with `staleness_check`. With `SFGRAPH_TOOLS=core` the server does not offer it (nor `list_orgs`, `snapshot_*` or `freshness_report`): skip those steps and say the graph's freshness was not checked.
136
+
137
+ ## Disambiguation (commonly confused)
138
+ - **Committed vs uncommitted vs post-deploy change analysis:** PR/branch/commit → `sf-impact-from-diff`; uncommitted working tree → `sf-wip-impact`; already deployed, something regressed → `sf-what-broke`.
139
+ - **Two orgs vs two snapshots vs one org over time:** different orgs → `sf-cross-org-diff`; named snapshots of one org → `sf-snapshot-compare`; "since last deploy" → `sf-what-broke`.
140
+ - **Explain one unit vs trace across layers:** plain-English of one method → `sf-explain-code`; full UI→DB chain → `sf-cross-layer-trace`.
141
+
142
+ ## Don't
143
+ - Don't generate Salesforce code before grounding when the org is ingested — that's the whole point of the graph.
144
+ - Don't re-implement the routing logic in prose every turn; pick the skill and go.
145
+ - Don't block on grounding if the org isn't ingested — degrade gracefully with a stated caveat.
146
+ - Don't treat this skill as a destination; it hands off. Its job is selection + the grounding rule.
@@ -16,13 +16,17 @@ tools_used:
16
16
 
17
17
  # sf-impact-from-diff
18
18
 
19
- Use when the user wants to understand the downstream consequences of a pending change in their working tree (uncommitted or branch-vs-base) before merging.
19
+ Use when the user wants to understand the downstream consequences of committed changes (a PR, a branch or a commit range) before merging. For uncommitted or staged work, use **sf-wip-impact**, which reads the working tree itself.
20
+
21
+ ## Evidence rule — say it only if something backs it
22
+
23
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
20
24
 
21
25
  ## Playbook
22
26
 
23
- 1. Confirm the diff source: working tree, staged, or a branch range (e.g. `origin/main...HEAD`). If unspecified, default to staged + unstaged against the merge-base of `origin/main`.
24
- 2. Call `impact_from_git_diff` with the resolved diff scope. Expect a list of changed metadata nodes plus their downstream dependents grouped by edge type (`READS_FIELD`, `CALLS_METHOD`, `INVOKES_FLOW`, `RENDERS_COMPONENT`, …).
25
- 3. Call `test_gap_intelligence_from_git_diff` on the same diff scope. Cross-reference impacted nodes against existing Apex test coverage and surface the uncovered set.
27
+ 1. Get the diff text yourself: the tools take the unified diff as their `diff` argument and do not run git. Confirm the range with the user (a PR's base and head, a branch, or a commit range); if unspecified, use `git diff origin/main...HEAD`.
28
+ 2. Call `impact_from_git_diff(diff=…, depth=…)`. Expect a list of changed metadata nodes plus their downstream dependents grouped by edge type (`READS_FIELD`, `CALLS`, `FLOW_INVOKES_APEX`, `EMBEDS_LWC`, …).
29
+ 3. Call `test_gap_intelligence_from_git_diff` with the same `diff` text. Cross-reference impacted nodes against existing Apex test coverage and surface the uncovered set.
26
30
  4. Group findings by risk tier — **direct edits**, **first-degree dependents**, **transitive (depth ≥ 2)** — and call out anything that crosses metadata layers (LWC -> Apex -> Flow).
27
31
  5. Render the Mermaid impact graph returned by the tool. If the impact set is large (>40 nodes), summarise by category and offer a follow-up call scoped to a single changed file.
28
32
  6. If test gaps exist, list the specific impacted classes + methods that lack assertions, not just totals.
@@ -30,7 +34,7 @@ Use when the user wants to understand the downstream consequences of a pending c
30
34
 
31
35
  ## Visualization
32
36
 
33
- Render a **`flowchart LR`** impact graph. Changed nodes are leftmost (highlighted), first-degree dependents in the middle, transitive (depth >= 2) on the right. Edge style encodes edge type (`CALLS_METHOD`, `READS_FIELD`, `INVOKES_FLOW`, `RENDERS_COMPONENT`).
37
+ Render a **`flowchart LR`** impact graph. Changed nodes are leftmost (highlighted), first-degree dependents in the middle, transitive (depth >= 2) on the right. Edge style encodes edge type (`CALLS`, `READS_FIELD`, `FLOW_INVOKES_APEX`, `EMBEDS_LWC`).
34
38
 
35
39
  ```
36
40
  flowchart LR
@@ -44,6 +48,8 @@ When the impact set exceeds 40 nodes, summarise per category and offer the user
44
48
 
45
49
  ## Staleness check
46
50
 
51
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
52
+
47
53
  Before calling `impact_from_git_diff`, invoke `staleness_check` for the linked org. A stale graph will under-report dependents added since the last sync. If the report says stale, surface a warning to the user:
48
54
 
49
55
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -18,12 +18,16 @@ tools_used:
18
18
 
19
19
  Use when the user asks whether their sfgraph data is current, how to refresh it, or wants to see both graph staleness and org-side dead-metadata freshness.
20
20
 
21
+ ## Evidence rule — say it only if something backs it
22
+
23
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
24
+
21
25
  ## Playbook
22
26
 
23
27
  1. Call `staleness_check` for the target org. Report the exact age in days and whether it's stale.
24
- 2. If stale, call `start_ingest_job` — it does NOT run the ingest. It returns
25
- `{ executed: false, run_this_command: "sfgraph ingest --org <alias>" }`.
26
- Surface that command verbatim to the user. Do not promise the MCP server
28
+ 2. If stale, call `start_ingest_job`. It does NOT run the ingest: its report says
29
+ nothing was started and shows the command to run (for example
30
+ `sfgraph ingest --org <alias>`). Surface that command verbatim to the user. Do not promise the MCP server
27
31
  will run it. After the user has executed the ingest in a shell, MCP tools
28
32
  will see the new data on their next invocation.
29
33
  3. Suggest the right shape of the command for their situation:
@@ -54,6 +58,8 @@ Pair it with the bucketed freshness table from `freshness_report` for the org-si
54
58
 
55
59
  ## Staleness check
56
60
 
61
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
62
+
57
63
  `staleness_check` _is_ the first step here — the whole skill is the staleness check. If `staleness_check` returns `stale=false`, still continue to `freshness_report` so the user sees the org-side picture.
58
64
 
59
65
  ## Response Shape
@@ -8,6 +8,8 @@ triggers:
8
8
  - "omnistudio audit"
9
9
  - "migrate from vlocity"
10
10
  tools_used:
11
+ - find_nodes
12
+ - trace_downstream
11
13
  - cross_org_diff
12
14
  - staleness_check
13
15
  ---
@@ -16,11 +18,17 @@ tools_used:
16
18
 
17
19
  Use when the user is mid-migration from Vlocity CMT (managed package) to OmniStudio on Core and wants to verify parity by category.
18
20
 
21
+ ## Evidence rule — say it only if something backs it
22
+
23
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
24
+
19
25
  ## Playbook
20
26
 
21
- 1. Enumerate Vlocity-CMT node categories present in the graph: `vlocity_cmt__DataRaptor`, `vlocity_cmt__IntegrationProcedure`, `vlocity_cmt__OmniScript`, `vlocity_cmt__VlocityCard`.
22
- 2. Enumerate the OmniStudio-on-Core equivalents: `OmniDataTransform`, `OmniIntegrationProcedure`, `OmniProcess` (OmniScript), `OmniUiCard`.
23
- 3. For each pair, count nodes on both sides and count `CANONICAL_OF` edges that mirror a CMT asset to its OmniStudio twin. Report `cmt_count`, `core_count`, `canonical_pairs`, `unmirrored_cmt`, `unmirrored_core`.
27
+ No tool computes these counts; you build them from `find_nodes` and `trace_downstream` results, and say so. The graph labels are the same whatever the org's namespace (there is no `vlocity_cmt__` prefix on a label).
28
+
29
+ 1. List the Vlocity-CMT assets with `find_nodes(label=…)` for each of `DataRaptor`, `IntegrationProcedure`, `OmniScript` and `VlocityCard`. Raise `limit` until the result is not truncated.
30
+ 2. List the OmniStudio-on-Core twins the same way: `OmniDataTransform`, `OmniIntegrationProcedure`, `OmniProcess` (OmniScript) and `OmniUiCard`. The pairs are DataRaptor ↔ OmniDataTransform, IntegrationProcedure ↔ OmniIntegrationProcedure, OmniScript ↔ OmniProcess, VlocityCard ↔ OmniUiCard.
31
+ 3. For each CMT asset, `trace_downstream(qname, depth=1, rel_types=["CANONICAL_OF"])` finds its twin (the edge is written both ways when the names match). With many assets, check a sample and say so. Per pair of labels, report the CMT count, the Core count, the mirrored pairs, and the unmirrored assets on each side.
24
32
  4. If the user provided two orgs (typically a CMT-only sandbox vs an OmniStudio-on-Core sandbox), call `cross_org_diff` to highlight assets present in one and not the other.
25
33
  5. Bucket findings:
26
34
  - **fully migrated** — pair exists, `CANONICAL_OF` edge present, no logic drift.
@@ -35,13 +43,13 @@ Render a **`flowchart LR`** parity diagram. Left subgraph is Vlocity-CMT; right
35
43
  ```
36
44
  flowchart LR
37
45
  subgraph CMT
38
- D1[vlocity_cmt__DataRaptor:Foo]
46
+ D1[DataRaptor:Foo]
39
47
  end
40
48
  subgraph Core
41
49
  D2[OmniDataTransform:Foo]
42
50
  end
43
51
  D1 -. CANONICAL_OF .-> D2
44
- D3[vlocity_cmt__OmniScript:Bar]:::unmirrored
52
+ D3[OmniScript:Bar]:::unmirrored
45
53
  classDef unmirrored stroke-dasharray:4 4,fill:#fdd
46
54
  ```
47
55
 
@@ -49,6 +57,8 @@ For orgs with >50 CMT assets, swap the diagram for a per-category counts table
49
57
 
50
58
  ## Staleness check
51
59
 
60
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
61
+
52
62
  Before running the audit, invoke `staleness_check` for each org in scope. A stale ingest means recently-created CANONICAL_OF edges or new OmniStudio twins are missing, which inflates the "not started" bucket. If the report says stale, surface a warning to the user:
53
63
 
54
64
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -19,14 +19,18 @@ tools_used:
19
19
 
20
20
  Use when the user wants a high-level picture of the data model — which objects exist in a domain, how they connect via Lookup/MasterDetail, and which Apex/Flow/LWC artifacts depend on them.
21
21
 
22
+ ## Evidence rule — say it only if something backs it
23
+
24
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
25
+
22
26
  ## Playbook
23
27
 
24
28
  1. Identify the focal object(s) from the user's question. If they named a domain ("the Order schema"), pick the lead object and include its first-degree neighbours.
25
29
  2. Call `staleness_check` for the org. Warn if stale.
26
- 3. For each focal object, call `trace_downstream` with `qname=CustomObject:<name>` to enumerate Lookup/MasterDetail references coming out of it.
30
+ 3. For each focal object, call `trace_downstream(qname="CustomObject:<name>", depth=2, rel_types=["DEFINES_FIELD", "REFERENCES_OBJECT"])`. A relationship shows up as two hops: the object defines a lookup field, and the field references the target object (`CustomObject:Invoice__c` → `CustomField:Invoice__c.Account__c` → `CustomObject:Account`). For relationships pointing **into** an object, call `trace_upstream(qname="CustomObject:<name>", depth=1, rel_types=["REFERENCES_OBJECT"])`: it lists the lookup fields on other objects.
27
31
  4. Call `trace_upstream` for the same object to find what depends on it (Apex selectors, Flows, LWCs, layouts).
28
32
  5. If the user named a specific field, call `analyze_field` to get its readers/writers and a precise role description.
29
- 6. Produce an ERD-like diagram with one entity per object and relationship lines for each Lookup/MasterDetail edge.
33
+ 6. Produce an ERD-like diagram with one entity per object and one relationship line per lookup field. The report does not say whether a relationship is a Lookup or a Master-Detail: read the field's metadata (`objects/<Object>/fields/<Field>.field-meta.xml`, `<type>`) when the cardinality matters, or draw it as a plain relationship and say so.
30
34
 
31
35
  ## Visualization
32
36
 
@@ -43,6 +47,8 @@ When the schema has >20 entities, prune to the focal object's two-hop neighbourh
43
47
 
44
48
  ## Staleness check
45
49
 
50
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
51
+
46
52
  Before tracing, invoke `staleness_check` for the org. New custom objects/fields and recently-added relationships are invisible in a stale graph. If the report says stale, surface a warning to the user:
47
53
 
48
54
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -18,14 +18,20 @@ tools_used:
18
18
 
19
19
  Use when the user asks about who can read or write a field/object, what sharing rules apply, or whether FLS / CRUD is consistent with intent.
20
20
 
21
+ ## Evidence rule — say it only if something backs it
22
+
23
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
24
+
21
25
  ## Playbook
22
26
 
23
- 1. Resolve the target. Call `analyze_field` if the user gave `SObject.Field`; otherwise treat as SObject-level.
24
- 2. Call `security_audit` with the resolved target. Capture profiles, permission sets, permission set groups, sharing rules (criteria + owner-based), OWD, and any `without sharing` Apex that touches the field.
25
- 3. Build the access matrix: Profile/PSet -> Read / Edit / Delete / View All / Modify All.
26
- 4. Identify sharing exposure: OWD setting, sharing rules expanding access, role-hierarchy inheritance toggles.
27
- 5. Flag risks: `without sharing` Apex selectors, missing `stripInaccessible` / `WITH SECURITY_ENFORCED`, guest user access, Experience Cloud profile reach.
28
- 6. Render the Mermaid access matrix returned by the tool.
27
+ 1. Resolve the target. Call `analyze_field` if the user gave `SObject.Field`; otherwise treat as SObject-level. `analyze_field` takes **separate `object` and `field`** params (not a single `Account.Status` string) — split before calling.
28
+ 2. Call `security_audit` with the resolved target (`object` / `field` to narrow; whole-org if neither). Capture full-access sharing rules and the FLS gap list.
29
+ - **FLS gaps are pre-filtered** to FLS-relevant fields: Custom Metadata Type (`__mdt`), platform-event (`__e`), big-object (`__b`), and standard system/audit fields (Id, CreatedById, SystemModstamp, …) are excluded as noise. The response notes `+N CMDT/system fields hidden`. Only pass `include_non_fls_fields: true` if the user explicitly wants that raw set — never lead with it.
30
+ - The inline gap list is capped (`limit`, default 30). Narrow with `object`, or raise `limit`, rather than dumping thousands of rows.
31
+ 3. Build the field access matrix: for one field, the report lists every profile and permission set that grants read or edit ("Granted by"); a profile or permission set whose entry denies access is not counted. Run the audit per field you need in the matrix.
32
+ 4. Report sharing exposure from what the tool returns: the sharing rules that give edit or full access. The tool does **not** report org-wide defaults, the role hierarchy, object CRUD per profile, or `without sharing` Apex; say so, and check those in the source or the org if the user needs them (label them as not graph-confirmed).
33
+ 5. Flag risks you can back with evidence: full-access sharing rules and FLS gaps from the tool; `without sharing` classes, missing `stripInaccessible` / `WITH SECURITY_ENFORCED`, guest user and Experience Cloud reach only from source you read.
34
+ 6. Render the access matrix as Mermaid yourself from the report's "Granted by" lists. The tool does not draw a diagram. See **Visualization** below.
29
35
 
30
36
  ## Visualization
31
37
 
@@ -43,6 +49,8 @@ When more than 25 Profiles/PSets have access, collapse to a count table and only
43
49
 
44
50
  ## Staleness check
45
51
 
52
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
53
+
46
54
  Before calling `security_audit`, invoke `staleness_check` for the target org. Permission set/profile assignments change frequently; a stale graph misrepresents access. If the report says stale, surface a warning to the user:
47
55
 
48
56
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -18,6 +18,10 @@ tools_used:
18
18
 
19
19
  Use when the user wants to compare two named points in time — typically a pre-deploy checkpoint vs current, or two milestone snapshots taken during a release.
20
20
 
21
+ ## Evidence rule — say it only if something backs it
22
+
23
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
24
+
21
25
  ## Playbook
22
26
 
23
27
  1. Call `snapshot_list` for the org. Present available snapshots with their `id`, `label`, `createdAt`, and `kind` (auto/manual).
@@ -45,6 +49,8 @@ If `gitGraph` isn't supported by the client, fall back to a small **`flowchart L
45
49
 
46
50
  ## Staleness check
47
51
 
52
+ If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
53
+
48
54
  Before calling `point_in_time_diff` with `to='current'`, invoke `staleness_check` for the org. If the report says stale, surface a warning to the user:
49
55
 
50
56
  > Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
@@ -7,7 +7,8 @@ triggers:
7
7
  - "open the web view"
8
8
  - "see the relationships visually"
9
9
  - "render the whole org"
10
- tools_used: []
10
+ tools_used:
11
+ - staleness_check
11
12
  when_to_use: Visual exploration of an ingested org. Pairs with `analyze_field`, `trace_upstream`, `trace_downstream`, and `cross_layer_flow_map` when the markdown answers are not enough and the user wants to click around.
12
13
  ---
13
14
 
@@ -17,6 +18,10 @@ The MCP tool surface is great for answering specific questions, but sometimes th
17
18
 
18
19
  This skill does not call any MCP tool. It instructs the user how to launch the viewer and what to do once it's open.
19
20
 
21
+ ## Evidence rule — say it only if something backs it
22
+
23
+ State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
24
+
20
25
  ## Playbook
21
26
 
22
27
  1. Confirm the org has been ingested (use `staleness_check` if uncertain).