Answers Salesforce admin/architect freshness questions like "when was X modified?", "who built this?", "what changed since last week?", "has this been touched since go-live?", "what changed in the last sprint?". Call `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }` and `sfi.changed_since`. Discloses v1.7 honesty axis: when Tooling API enrichment hasn't run, returns `enriched: false` with explicit guidance to run `sfi refresh --with-tooling-api`; never fabricates dates.
This skill is the cross-persona companion to v1.7's freshness tools:
sfi.last_modified (per-component lookup) and sfi.changed_since
(time-range scan). The question shape — "when was X modified?",
"who changed this?", "what's new since the deploy?" — comes from
admins ("what changed since last release?"), developers ("who
edited this trigger?"), and architects ("show me everything modified
in the deploy window") in roughly equal measure. Splitting into
admin/developer/architect variants would force the user to
pre-classify their own question; bundling all three personas into
one skill mirrors the v1.3 admin-legacy-automation decision and
keeps the routing surface narrow.
The skill's load-bearing teaching is the honesty axis v1.7
introduces: freshness data is opt-in. v1.0-v1.6 vaults shipped
with lastModifiedDate: null across the board because the offline
DX-source extraction pipeline does not have a way to ask the org
"when was this last touched?" — that requires a live Tooling API
call. v1.7 ships the live-API enrichment tier, but it is gated
behind the sfi refresh --with-tooling-api --target-org <alias>
flag (default refresh stays offline). When the enrichment has not
run, every freshness query honestly returns enriched: false (or,
for the range scan, a non-zero unenrichedCount) plus a verbatim
recommendation to run the enricher. The skill never fabricates a
date. The skill never estimates "this looks like a year-old
class" from training-data priors about how Salesforce orgs
typically evolve. The skill says "v1.7 Tooling API enrichment has
not run for this vault" and stops, because the alternative is
hallucinating freshness on a deploy decision.
The v1.7 R2/R3 enrichment covers six ComponentTypes: ApexClass,
ApexTrigger, Flow, Layout, CustomField, and ValidationRule. Other
types (Profile, PermissionSet, Group, Role, SharingRule, RecordType,
WorkflowRule, ApprovalProcess, etc.) remain enriched: false even
after --with-tooling-api runs — future v1.7+ iterations may
expand coverage, but as of v1.7 R3 these types have no Tooling API
endpoint the enricher consumes. When the user's question is about
an unsupported type, the skill names the type-coverage boundary
explicitly rather than treating "no data" as "never modified."
When to fire
Fire this skill on freshness-shaped phrasing. Concrete triggers:
"When was X modified?" — "When was Account.Industry__c last
modified?", "When was the AccountController class last touched?",
"When did this layout last change?".
"Who built / changed / modified X?" — "Who built the
Lead_Nurture flow?", "Who edited this trigger last?", "Who's
been working on the Opportunity layout?". Note: lastModifiedBy
names the user who last deployed the change, not necessarily
the original author — surface this caveat verbatim.
"What's the running API version of X?" — "What's the api
version of this Apex class?", "Is AccountTrigger still on
API 30?". Routes to sfi.last_modified's apiVersion field.
"What changed since {time}?" — "What changed since last
Tuesday?", "Show me everything modified after 2026-05-01.",
"What's new this sprint?", "Give me the diff since the
2026-04-15 release.". Routes to sfi.changed_since.
"Has X been touched since {event}?" — "Has this been
modified since go-live?", "Has the discount approval changed
since the audit?". Walks sfi.last_modified and compares the
timestamp against the event date.
Structural drift over time — "How has the org grown?", "What
changed between last week's snapshot and now?". Use sfi.trend
(needs sfi snapshot create after refreshes) and sfi.diff_snapshots
for label-to-label diffs (omit labels to auto-diff the latest two; add
summary: true for a compact churn digest). Freshness timestamps
and snapshot diffs answer different questions — use both when needed.
"What's stale / abandoned?" — "Show me Apex classes
untouched since 2024.", "Which flows have nobody owned for a
year?". sfi.changed_since with a far-back since gives the
changed set; the inverse is the not-emitted set — point the
user at sfi.list_components for full enumeration, then
intersect against the freshness scan result.
"What's hot / recently active?" — "What changed in the last
24 hours?", "Show me everything modified this week.". Direct
sfi.changed_since call with a near-recent since.
"Who's the busiest developer / admin?" — group-by question.
v1.7 surfaces lastModifiedBy per node; the skill can aggregate
client-side, but disclose that v1.7 names the LAST deployer,
not the cumulative contributor — a developer who edited a class
in v1, v2, and v3 only shows up in v3's lastModifiedBy.
"What's the freshness coverage in this vault?" — meta
question. Call sfi.run_analysis with { "name": "sfi.changed_since", "args": { … } } with a far-past since and
report the unenrichedCount alongside the enriched count.
"When did X stop being maintained?" — last-touch + extrapolate
question. The skill answers the literal data point (last
modified date) and refuses to speculate on "maintained vs.
abandoned" without runtime usage data.
When NOT to fire
Defer to another skill when:
The user asks "why can't user X see Y?" — visibility, not
freshness. Defer to admin-sharing-troubleshooting →
sfi.why_cant_user_see_record.
The user asks "what layout does user X see?" — page-layout
routing. Defer to admin-page-layout-routing →
sfi.layout_for_user.
The user asks "what breaks if I change X?" — impact analysis,
not freshness. Defer to architect-impact-analysis →
sfi.get_impact. (Though when the impact target is "freshly
modified," the two skills compose — the architect skill leads,
this one can be cited.)
The user asks "where is this field used in Apex?" — code-side
reference question. Defer to developer-apex-refactor →
sfi.find_code_usages.
The user asks "what changed structurally?" — diff question,
not freshness. Defer to whatever handles sfi.diff_snapshots /
sfi.compare_components. Freshness tells you when something
changed; structural diff tells you what changed.
The user wants to refresh, init, or check vault status. Fire
refreshing-the-org-vault, /sfi-init, or pre-flight-checks.
The user asks for record-level last-touched info ("when did
this Account record's Industry get updated?", "who edited
001xx12345's Owner?"). v1.7 surfaces component freshness
(when was the field definition modified), not record-row
freshness (when was a specific record's value modified). The
latter requires a live sf data query against SystemModstamp
/ LastModifiedById on the row — out of scope.
Steps
Walk these in order. Each step has a definite output that feeds the
next.
Step 1 — Identify the question target
The user's question maps to one of two shapes:
Component target ("when was X modified?", "who built X?") —
call sfi.run_analysis with { "name": "sfi.last_modified", "args": { … } } against the canonical id. Translate
"the AccountController class" → ApexClass:AccountController;
"the Industry field on Account" →
CustomField:Account.Industry__c (note the __c for custom
fields); "the Lead nurture flow" → Flow:Lead_Nurture. If the
user's reference is ambiguous, fall back to
sfi.search_components to resolve the canonical id before
firing the freshness lookup.
Time-range target ("what changed since X?", "what's new this
sprint?") — call sfi.run_analysis with { "name": "sfi.changed_since", "args": { … } } with the since boundary in
ISO 8601 (date-only YYYY-MM-DD or full
YYYY-MM-DDTHH:mm:ssZ). Translate "last Tuesday" → the actual
date relative to today's date; "the deploy on May 15" →
2026-05-15 (or the deploy's actual timestamp). When the user's
phrasing is genuinely vague ("recently", "lately"), ASK
before firing — there's no honest interpretation of "recently"
without a concrete boundary.
If both shapes are present in the question ("what changed in the
Apex layer since last sprint?"), the range scan answers the
"since" axis and the type filter (types: ['ApexClass', 'ApexTrigger']) narrows the scan.
When enriched: true, every freshness axis carries a value the
consumer can render. When enriched: false, the disclosure field
carries the verbatim recommendation: "v1.7 Tooling API enrichment
has not run for this vault. Run sfi refresh --with-tooling-api --target-org <alias> to populate lastModifiedDate / lastModifiedBy
/ apiVersion for the enriched types." Surface that verbatim —
do not paraphrase, do not estimate freshness from training-data
priors, do not "split the difference" with a hedged guess.
When enriched: false, the answer is a structured refusal with
a concrete next step (run the enricher). When the user pushes back
("just give me your best guess"), refuse again and name the
auth/enrichment prerequisite — the v1.7 honesty axis is
constitutional, not a courtesy.
The unenrichedCount is the v1.7 R2 honesty axis: it names how
many nodes (within the requested types) carry lastModifiedDate: null — these are nodes the offline DX-source extractor produced
without freshness data. Surface unenrichedCount whenever it is
non-zero with a single sentence: "47 components of this type are
not yet enriched — run sfi refresh --with-tooling-api for full
coverage." Without that disclosure, the answer looks complete when
it isn't.
When changed: [] AND unenrichedCount: 0, the answer is
"genuinely nothing changed in the time window for the requested
types." When changed: [] AND unenrichedCount > 0, the answer
is "we can't tell because nothing has been enriched" — distinct
shapes the consumer must distinguish.
Step 4 — Never fabricate dates or users
This step is the constitutional one. When the freshness tool
returns enriched: false or lastModifiedDate: null, the answer
is a refusal — not a fallback to:
General Salesforce knowledge ("ApexClass updates typically happen
during sprints, so probably last month").
Inferred dates from other axes ("the api version is 62.0, so it
was last touched after Spring '25 went GA").
"Most orgs..." statistical priors.
Sourcetree-hash extrapolation ("the manifest refreshedAt is
2026-05-27, so it's at most that old").
The honest answer is the disclosure string, plus the concrete
remediation: run the enricher. Never trade off the user's deploy
decision against a guess that looks like confidence.
Reporting format
The skill renders two distinct shapes — one for each tool. The
difference is load-bearing because the consumer reads the
disclosure differently.
Last modified: 2026-05-15 at 12:34:56 UTC (12 days ago).
Last modified by: Alice Adams (005xx00000ABCDE).
Running API version: 62.0.
Note: lastModifiedBy names the user who last deployed this
class — not necessarily the original author or every
contributor. A class first written by Bob in 2024, then edited
by Carol in 2025, then redeployed by Alice in May 2026 will
only show Alice here.
Enriched-false response (the verbatim disclosure)
Suppose the admin asks the same question against an un-enriched
vault:
{
"data": {
"componentId": "ApexClass:AccountController",
"enriched": false,
"lastModifiedDate": null,
"lastModifiedBy": null,
"apiVersion": null,
"disclosure": "v1.7 Tooling API enrichment has not run for this vault. Run `sfi refresh --with-tooling-api --target-org <alias>` to populate lastModifiedDate / lastModifiedBy / apiVersion for the enriched types."
}
}
Claude's presentation back to the user:
Freshness for ApexClass:AccountController is not available
in this vault.
v1.7 Tooling API enrichment has not run for this vault. Run
sfi refresh --with-tooling-api --target-org <alias> to
populate lastModifiedDate / lastModifiedBy / apiVersion for the
enriched types (ApexClass, ApexTrigger, Flow, Layout,
CustomField, ValidationRule).
I can't tell you when this class was last touched from
metadata alone — and I won't guess, because a deploy decision
based on a fabricated date is worse than no answer.
Range-scan response (sfi.changed_since)
Suppose the architect asks: "What changed in the Apex layer
since 2026-05-01?"
2 components changed in the Apex layer since 2026-05-01:
ApexClass:AccountController — 2026-05-15, Alice Adams.
ApexTrigger:AccountTrigger — 2026-05-12, Bob Brown.
Coverage note: 47 components of these types carry no
freshness data — the v1.7 enrichment has only partially
covered this vault. Run sfi refresh --with-tooling-api for
full coverage; until then, treat this list as a lower bound,
not an exhaustive one.
Boundary disclosure
v1.7's freshness tier has well-defined gaps. Surface this list
whenever the user is about to act on the report, and always
when enriched: false or unenrichedCount > 0:
Tooling API enrichment is opt-in. Default sfi refresh does
not call the API; freshness is null until sfi refresh --with-tooling-api --target-org <alias> runs. The skill says
so plainly rather than fabricating dates.
Only six ComponentTypes are enriched. v1.7 R3 covers
ApexClass, ApexTrigger, Flow, Layout, CustomField, and
ValidationRule. Other types (Profile, PermissionSet, Group,
Role, SharingRule, RecordType, WorkflowRule, ApprovalProcess,
AssignmentRule, AutoResponseRule, EscalationRule, DuplicateRule,
MatchingRule, EmailTemplate, Letterhead, LightningComponentBundle,
AuraDefinitionBundle, VisualforcePage, VisualforceComponent,
NamedCredential, ConnectedApp, AuthProvider, RemoteSiteSetting,
CspTrustedSite, ExternalDataSource, ExternalService, NetworkAccess,
CustomMetadataRecord, CustomSettingRecord, GlobalValueSet,
CustomLabel, StaticResource, PermissionSetAssignment,
BusinessProcess, CustomTab, CustomApplication, QuickAction,
PathAssistant) remain enriched: false even after enrichment
runs. Future v1.7+ iterations may extend coverage.
lastModifiedBy is the LAST DEPLOYER, not the original
author. Salesforce's Tooling API surfaces the user who last
touched the metadata in the running org. A class first authored
by Bob in 2024, edited by Carol in 2025, then redeployed by
Alice in May 2026 shows ONLY Alice in lastModifiedBy. The
skill cites this caveat verbatim when the user's question is
"who built this?" (as opposed to "who edited this last?").
Tooling API rate limit. Salesforce caps the Tooling API at
~3,500 queries per rolling hour per org. The R2 enricher
batches per-type but a large org with tens of thousands of
components can take longer than a single hour to enrich
completely. If unenrichedCount is still non-zero after a
recent --with-tooling-api refresh, the org may have hit the
rate limit; surface the possibility and recommend re-running
the enricher after the rate-limit window resets.
Setup Audit Trail is NOT extracted. Salesforce's per-action
audit log (who changed what setting when, from which IP, etc.)
is a separate API surface (SetupAuditTrail) v1.7 does not
read. Questions like "who changed the OWD setting in March?"
or "what permission did Alice grant on May 12?" require a
separate sf data query against SetupAuditTrail — out of
scope until a future v1.7.x extends to it.
lastModifiedDate lags wall-clock by query-time delta. Even
with fresh enrichment, the timestamp reflects the org's state
at the moment the API was queried — typically seconds before
the vault was written. At minute-level granularity, treat the
timestamp as lastModifiedDate ± query-window.
Tooling-API-vs-DX-source can disagree. When the running
Apex class has been edited in the Developer Console (live) but
the DX source has not been re-retrieved, the Tooling API's
LastModifiedDate is fresher than what the offline extractor
saw. v1.7 enrichment updates the freshness data but does NOT
refresh structural extraction — the graph nodes/edges reflect
DX source, the freshness reflects the API. Name this drift
verbatim when the user's question is sensitive to it.
Treat enriched: false verdicts as "v1.7 cannot tell" — not
as "never modified." Treat unenrichedCount > 0 scans as
"partial answer, run the enricher for full coverage."
Anti-patterns
Mistake
Why it's wrong
Presenting enriched: false or lastModifiedDate: null as "this component was never modified" or "this is brand new".
null is a gap, not a value. v1.7's enrichment is opt-in; null means "we have no data," not "the component is fresh." Surface the gap as the disclosure says: enrichment has not run, run the enricher.
Estimating freshness from training-data priors ("classes typically get updated every sprint, so probably 2 weeks ago").
The v1.7 honesty axis is constitutional. Fabricated freshness is worse than no freshness because a deploy decision based on a fabricated date is unrecoverable. Refuse honestly.
Conflating lastModifiedBy with the original author.
lastModifiedBy names the user who last deployed the change. A 5-year-old class that Alice redeployed yesterday will list Alice, not the original 2021 author. Cite the caveat verbatim when the question is about authorship.
Ignoring unenrichedCount in the changed_since response.
A changed: [] result with unenrichedCount: 47 means "we can't tell"; a changed: [] with unenrichedCount: 0 means "genuinely nothing changed." Surfacing only changed.length === 0 collapses both into "nothing changed" and misleads the consumer.
Citing apiVersion: null as "this class is on the latest API".
null is the same gap as the others — no enrichment, no data. The class's running API version is whatever the Tooling API would return; until the enricher fills it, the skill says so.
Running sfi.last_modified against a record-row id (001xx12345) instead of a component id.
v1.7 freshness covers component metadata (the field definition), not record rows. The handler returns component-not-found; translate the question to live-data shape ("query Account.SystemModstamp via sf data query") and disclose the shift.
Treating "I checked sfi.last_modified and it returned enriched: true" as proof a component is in active use.
Freshness is "when was the metadata last touched," not "is anyone using this." A class deployed yesterday may have zero callers; a class untouched since 2020 may be the org's load-bearing core. Use sfi.find_code_usages for usage, sfi.last_modified for freshness, and never confuse the two.
Skipping the boundary disclosure when enriched: true for one component but the user's question implies a broader sweep.
The disclosure protects the user's mental model. A single-component happy path doesn't mean the vault as a whole is enriched. When the user's question implies "across the org," the disclosure goes in even if the cited component happens to be enriched.
Suggesting "run a SOQL query to check" without naming sf data query --target-org <alias> and the specific object (ApexClass, Flow, FieldDefinition, etc.).
The user needs an executable next step. "Run a SOQL query" is too vague; "run sf data query --target-org <alias> --query 'SELECT LastModifiedDate, LastModifiedBy.Name FROM ApexClass WHERE Name = ''AccountController''' " is the load-bearing instruction.
Example interactions
Example 1 — Component freshness on an un-enriched vault
User: "When was the AccountController Apex class last modified?"
Firesfi.run_analysis with { "name": "sfi.last_modified", "args": { … } } with
{ componentId: 'ApexClass:AccountController' }.
The tool returns enriched: false, every freshness field
null, and the verbatim disclosure.
Refuse honestly with the disclosure surfaced verbatim:
"v1.7 Tooling API enrichment has not run for this vault. Run
sfi refresh --with-tooling-api --target-org <alias> to
populate lastModifiedDate / lastModifiedBy / apiVersion for
the enriched types. I can't tell you when this class was last
touched from metadata alone — and I won't guess."
Cite the boundary — enrichment is opt-in; only six types
are covered when it runs.
Example 2 — Range scan with partial enrichment
User: "What changed in the Flow layer since the May 1 release?"
Claude's flow:
Parse. Time-range target. since = '2026-05-01',
types = ['Flow'].
Firesfi.run_analysis with { "name": "sfi.changed_since", "args": { … } } with
{ since: '2026-05-01', types: ['Flow'] }.
Render the grouped list — apiName / modifier name /
timestamp per row.
Surface the coverage note verbatim: "12 Flow components
carry no freshness data — the v1.7 enrichment has only
partially covered this vault. Treat this list as a lower
bound; run sfi refresh --with-tooling-api for full
coverage."
Example 3 — Question about an unsupported ComponentType
User: "Who built the Sales_Manager profile?"
Claude's flow:
Parse. Component target = Profile:Sales_Manager. Note:
Profile is NOT in v1.7's enriched-type list.
Firesfi.run_analysis with { "name": "sfi.last_modified", "args": { … } } with
{ componentId: 'Profile:Sales_Manager' }.
The tool returns enriched: false even if the vault was
refreshed with --with-tooling-api (Profile is uncovered).
Disclose the type-coverage boundary, not just the
enrichment-not-run line: "v1.7 R3's Tooling API enrichment
covers ApexClass, ApexTrigger, Flow, Layout, CustomField, and
ValidationRule — Profile is not yet covered. Until a future
iteration extends coverage, the freshness fields for
Profile:Sales_Manager remain null."
Offer the live-data fallback: "If you need this now, run
sf data query --target-org <alias> --query 'SELECT LastModifiedDate, LastModifiedBy.Name FROM Profile WHERE Name = ''Sales_Manager''' against your org directly."
Example 4 — Authorship vs. last-deployer disambiguation
User: "Who originally wrote the Lead_Nurture flow?"
Claude's flow:
Parse. Component target = Flow:Lead_Nurture. The
question shape is authorship — distinct from
lastModifiedBy.
Firesfi.run_analysis with { "name": "sfi.last_modified", "args": { … } } with
{ componentId: 'Flow:Lead_Nurture' }.
Surface the value AND the authorship caveat verbatim:
"v1.7's lastModifiedBy names the user who last deployed
the change — Alice Adams here. That is NOT necessarily the
original author. A flow first built by Bob in 2024 and last
re-saved by Alice in May 2026 shows only Alice. For the
original author, check the org's Setup Audit Trail (sf data query --target-org <alias> --query 'SELECT CreatedBy.Name, CreatedDate FROM Flow WHERE Name = ''Lead_Nurture''')."
Verification
Before sending a response, confirm:
I identified the question target — component (use
sfi.last_modified) or time-range (use
sfi.changed_since).
If component target: I translated the user's reference into
a canonical {Type}:{ApiName} id, using
sfi.search_components when the reference was ambiguous.
If time-range target: I translated relative phrasing
("last Tuesday", "the deploy") into a concrete ISO 8601
since, asking the user when the phrasing was genuinely
vague.
I called sfi.run_analysis for sfi.last_modified or sfi.changed_since exactly
once per coherent question. (Component-by-component
iteration for a list is acceptable; round-tripping the same
id is not.)
When enriched: false (or lastModifiedDate: null), I
surfaced the disclosure verbatim and did NOT fabricate a
date.
When unenrichedCount > 0, I surfaced the partial-coverage
note before presenting the changed list.
I cited the lastModifiedBy caveat (last deployer, not
original author) when the user's question was about
authorship.
I cited canonical IDs (ApexClass:..., Flow:...,
CustomField:...) for every component named.
When the target ComponentType was outside v1.7's enriched
set (Profile, PermissionSet, etc.), I named the type-coverage
boundary explicitly and offered the live-data
sf data query fallback.
I did not estimate freshness from training-data priors,
apiVersion extrapolation, or sourcetree-hash inference. The
honesty axis is constitutional.
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). Default tool profile is core: only the core spine (including sfi.live_consent) is directly invokable. For every other sfi.* analysis, call sfi.run_analysis with { "name": "sfi.<tool>", "args": { … } } (or follow route_question.invoke, which already wraps non-core steps). Optional: sfi.describe_analysis first when args are unclear. 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.
1---2name: freshness-tracking3description: Answers Salesforce admin/architect freshness questions like "when was X modified?", "who built this?", "what changed since last week?", "has this been touched since go-live?", "what changed in the last sprint?". Call `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }` and `sfi.changed_since`. Discloses v1.7 honesty axis: when Tooling API enrichment hasn't run, returns `enriched: false` with explicit guidance to run `sfi refresh --with-tooling-api`; never fabricates dates.4---56# Freshness tracking78## Overview910This skill is the cross-persona companion to v1.7's freshness tools:11`sfi.last_modified` (per-component lookup) and `sfi.changed_since`12(time-range scan). The question shape — "when was X modified?",13"who changed this?", "what's new since the deploy?" — comes from14admins ("what changed since last release?"), developers ("who15edited this trigger?"), and architects ("show me everything modified16in the deploy window") in roughly equal measure. Splitting into17admin/developer/architect variants would force the user to18pre-classify their own question; bundling all three personas into19one skill mirrors the v1.3 `admin-legacy-automation` decision and20keeps the routing surface narrow.2122The skill's load-bearing teaching is the **honesty axis** v1.723introduces: freshness data is **opt-in**. v1.0-v1.6 vaults shipped24with `lastModifiedDate: null` across the board because the offline25DX-source extraction pipeline does not have a way to ask the org26"when was this last touched?" — that requires a live Tooling API27call. v1.7 ships the live-API enrichment tier, but it is gated28behind the `sfi refresh --with-tooling-api --target-org <alias>`29flag (default refresh stays offline). When the enrichment has not30run, every freshness query honestly returns `enriched: false` (or,31for the range scan, a non-zero `unenrichedCount`) plus a verbatim32recommendation to run the enricher. **The skill never fabricates a33date.** The skill never estimates "this looks like a year-old34class" from training-data priors about how Salesforce orgs35typically evolve. The skill says "v1.7 Tooling API enrichment has36not run for this vault" and stops, because the alternative is37hallucinating freshness on a deploy decision.3839The v1.7 R2/R3 enrichment covers **six ComponentTypes**: ApexClass,40ApexTrigger, Flow, Layout, CustomField, and ValidationRule. Other41types (Profile, PermissionSet, Group, Role, SharingRule, RecordType,42WorkflowRule, ApprovalProcess, etc.) remain `enriched: false` even43after `--with-tooling-api` runs — future v1.7+ iterations may44expand coverage, but as of v1.7 R3 these types have no Tooling API45endpoint the enricher consumes. When the user's question is about46an unsupported type, the skill names the type-coverage boundary47explicitly rather than treating "no data" as "never modified."4849## When to fire5051Fire this skill on freshness-shaped phrasing. Concrete triggers:52531. **"When was X modified?"** — "When was `Account.Industry__c` last54 modified?", "When was the AccountController class last touched?",55 "When did this layout last change?".562. **"Who built / changed / modified X?"** — "Who built the57 `Lead_Nurture` flow?", "Who edited this trigger last?", "Who's58 been working on the Opportunity layout?". Note: `lastModifiedBy`59 names the user who last *deployed* the change, not necessarily60 the original author — surface this caveat verbatim.613. **"What's the running API version of X?"** — "What's the api62 version of this Apex class?", "Is `AccountTrigger` still on63 API 30?". Routes to `sfi.last_modified`'s `apiVersion` field.644. **"What changed since {time}?"** — "What changed since last65 Tuesday?", "Show me everything modified after `2026-05-01`.",66 "What's new this sprint?", "Give me the diff since the67 2026-04-15 release.". Routes to `sfi.changed_since`.685. **"Has X been touched since {event}?"** — "Has this been69 modified since go-live?", "Has the discount approval changed70 since the audit?". Walks `sfi.last_modified` and compares the71 timestamp against the event date.726. **Structural drift over time** — "How has the org grown?", "What73 changed between last week's snapshot and now?". Use **`sfi.trend`**74 (needs `sfi snapshot create` after refreshes) and **`sfi.diff_snapshots`**75 for label-to-label diffs (omit labels to auto-diff the latest two; add76 `summary: true` for a compact churn digest). Freshness timestamps77 and snapshot diffs answer different questions — use both when needed.78797. **"What's stale / abandoned?"** — "Show me Apex classes80 untouched since 2024.", "Which flows have nobody owned for a81 year?". `sfi.changed_since` with a far-back `since` gives the82 *changed* set; the inverse is the not-emitted set — point the83 user at `sfi.list_components` for full enumeration, then84 intersect against the freshness scan result.857. **"What's hot / recently active?"** — "What changed in the last86 24 hours?", "Show me everything modified this week.". Direct87 `sfi.changed_since` call with a near-recent `since`.888. **"Who's the busiest developer / admin?"** — group-by question.89 v1.7 surfaces `lastModifiedBy` per node; the skill can aggregate90 client-side, but **disclose** that v1.7 names the LAST deployer,91 not the cumulative contributor — a developer who edited a class92 in v1, v2, and v3 only shows up in v3's `lastModifiedBy`.939. **"What's the freshness coverage in this vault?"** — meta94 question. Call `sfi.run_analysis` with `{ "name": "sfi.changed_since", "args": { … } }` with a far-past `since` and95 report the `unenrichedCount` alongside the enriched count.9610. **"When did X stop being maintained?"** — last-touch + extrapolate97 question. The skill answers the literal data point (last98 modified date) and refuses to speculate on "maintained vs.99 abandoned" without runtime usage data.100101## When NOT to fire102103Defer to another skill when:104105- **The user asks "why can't user X see Y?"** — visibility, not106 freshness. Defer to `admin-sharing-troubleshooting` →107 `sfi.why_cant_user_see_record`.108- **The user asks "what layout does user X see?"** — page-layout109 routing. Defer to `admin-page-layout-routing` →110 `sfi.layout_for_user`.111- **The user asks "what breaks if I change X?"** — impact analysis,112 not freshness. Defer to `architect-impact-analysis` →113 `sfi.get_impact`. (Though when the impact target is "freshly114 modified," the two skills compose — the architect skill leads,115 this one can be cited.)116- **The user asks "where is this field used in Apex?"** — code-side117 reference question. Defer to `developer-apex-refactor` →118 `sfi.find_code_usages`.119- **The user asks "what changed *structurally*?"** — diff question,120 not freshness. Defer to whatever handles `sfi.diff_snapshots` /121 `sfi.compare_components`. Freshness tells you *when* something122 changed; structural diff tells you *what* changed.123- **The user wants to refresh, init, or check vault status.** Fire124 `refreshing-the-org-vault`, `/sfi-init`, or `pre-flight-checks`.125- **The user asks for record-level last-touched info** ("when did126 this Account record's Industry get updated?", "who edited127 `001xx12345`'s Owner?"). v1.7 surfaces **component** freshness128 (when was the *field definition* modified), not **record-row**129 freshness (when was a specific record's value modified). The130 latter requires a live `sf data query` against `SystemModstamp`131 / `LastModifiedById` on the row — out of scope.132133## Steps134135Walk these in order. Each step has a definite output that feeds the136next.137138### Step 1 — Identify the question target139140The user's question maps to one of two shapes:141142- **Component target** ("when was X modified?", "who built X?") —143 call `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }` against the canonical id. Translate144 "the AccountController class" → `ApexClass:AccountController`;145 "the Industry field on Account" →146 `CustomField:Account.Industry__c` (note the `__c` for custom147 fields); "the Lead nurture flow" → `Flow:Lead_Nurture`. If the148 user's reference is ambiguous, fall back to149 `sfi.search_components` to resolve the canonical id before150 firing the freshness lookup.151- **Time-range target** ("what changed since X?", "what's new this152 sprint?") — call `sfi.run_analysis` with `{ "name": "sfi.changed_since", "args": { … } }` with the `since` boundary in153 ISO 8601 (date-only `YYYY-MM-DD` or full154 `YYYY-MM-DDTHH:mm:ssZ`). Translate "last Tuesday" → the actual155 date relative to today's date; "the deploy on May 15" →156 `2026-05-15` (or the deploy's actual timestamp). When the user's157 phrasing is genuinely vague ("recently", "lately"), **ASK**158 before firing — there's no honest interpretation of "recently"159 without a concrete boundary.160161If both shapes are present in the question ("what changed in the162Apex layer since last sprint?"), the range scan answers the163"since" axis and the type filter (`types: ['ApexClass',164'ApexTrigger']`) narrows the scan.165166### Step 2 — Component target: call `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }`167168Default invocation:169170```json171{172 "componentId": "ApexClass:AccountController"173}174```175176The response shape (per the v1.7 R3 contract):177178```json179{180 "data": {181 "componentId": "ApexClass:AccountController",182 "enriched": true,183 "lastModifiedDate": "2026-05-15T12:00:00.000Z",184 "lastModifiedBy": { "id": "005xx00000ABCDE", "name": "Alice Adams" },185 "apiVersion": 62.0,186 "disclosure": "Freshness fields populated. ..."187 }188}189```190191When `enriched: true`, every freshness axis carries a value the192consumer can render. When `enriched: false`, the `disclosure` field193carries the verbatim recommendation: "v1.7 Tooling API enrichment194has not run for this vault. Run `sfi refresh --with-tooling-api195--target-org <alias>` to populate lastModifiedDate / lastModifiedBy196/ apiVersion for the enriched types." **Surface that verbatim** —197do not paraphrase, do not estimate freshness from training-data198priors, do not "split the difference" with a hedged guess.199200When `enriched: false`, the answer is a **structured refusal** with201a concrete next step (run the enricher). When the user pushes back202("just give me your best guess"), refuse again and name the203auth/enrichment prerequisite — the v1.7 honesty axis is204constitutional, not a courtesy.205206### Step 3 — Time-range target: call `sfi.run_analysis` with `{ "name": "sfi.changed_since", "args": { … } }`207208Default invocation:209210```json211{212 "since": "2026-05-01",213 "types": ["ApexClass", "Flow"]214}215```216217The response shape (per the v1.7 R2 contract):218219```json220{221 "data": {222 "since": "2026-05-01T00:00:00.000Z",223 "changed": [224 {225 "id": "ApexClass:AccountController",226 "type": "ApexClass",227 "apiName": "AccountController",228 "lastModifiedDate": "2026-05-15T12:00:00.000Z",229 "lastModifiedBy": { "id": "005xx00000ABCDE", "name": "Alice Adams" }230 }231 ],232 "unenrichedCount": 47,233 "truncated": false234 }235}236```237238The `unenrichedCount` is the v1.7 R2 honesty axis: it names how239many nodes (within the requested types) carry `lastModifiedDate:240null` — these are nodes the offline DX-source extractor produced241without freshness data. **Surface `unenrichedCount` whenever it is242non-zero** with a single sentence: "47 components of this type are243not yet enriched — run `sfi refresh --with-tooling-api` for full244coverage." Without that disclosure, the answer looks complete when245it isn't.246247When `changed: []` AND `unenrichedCount: 0`, the answer is248"genuinely nothing changed in the time window for the requested249types." When `changed: []` AND `unenrichedCount > 0`, the answer250is "we can't tell because nothing has been enriched" — distinct251shapes the consumer must distinguish.252253### Step 4 — Never fabricate dates or users254255This step is the constitutional one. When the freshness tool256returns `enriched: false` or `lastModifiedDate: null`, the answer257is a refusal — *not* a fallback to:258259- General Salesforce knowledge ("ApexClass updates typically happen260 during sprints, so probably last month").261- Inferred dates from other axes ("the api version is 62.0, so it262 was last touched after Spring '25 went GA").263- "Most orgs..." statistical priors.264- Sourcetree-hash extrapolation ("the manifest refreshedAt is265 2026-05-27, so it's at most that old").266267The honest answer is the disclosure string, plus the concrete268remediation: run the enricher. Never trade off the user's deploy269decision against a guess that looks like confidence.270271## Reporting format272273The skill renders two distinct shapes — one for each tool. The274difference is load-bearing because the consumer reads the275disclosure differently.276277### Enriched-true response (sfi.last_modified happy path)278279Suppose the admin asks: "When was the `AccountController` Apex280class last modified?"281282The tool returns (illustrative):283284```json285{286 "data": {287 "componentId": "ApexClass:AccountController",288 "enriched": true,289 "lastModifiedDate": "2026-05-15T12:34:56.000Z",290 "lastModifiedBy": { "id": "005xx00000ABCDE", "name": "Alice Adams" },291 "apiVersion": 62.0,292 "disclosure": "Freshness fields populated. ..."293 }294}295```296297Claude's presentation back to the user:298299> Freshness for `ApexClass:AccountController`:300>301> - **Last modified:** 2026-05-15 at 12:34:56 UTC (12 days ago).302> - **Last modified by:** Alice Adams (`005xx00000ABCDE`).303> - **Running API version:** 62.0.304>305> Note: `lastModifiedBy` names the user who last *deployed* this306> class — not necessarily the original author or every307> contributor. A class first written by Bob in 2024, then edited308> by Carol in 2025, then redeployed by Alice in May 2026 will309> only show Alice here.310311### Enriched-false response (the verbatim disclosure)312313Suppose the admin asks the same question against an un-enriched314vault:315316```json317{318 "data": {319 "componentId": "ApexClass:AccountController",320 "enriched": false,321 "lastModifiedDate": null,322 "lastModifiedBy": null,323 "apiVersion": null,324 "disclosure": "v1.7 Tooling API enrichment has not run for this vault. Run `sfi refresh --with-tooling-api --target-org <alias>` to populate lastModifiedDate / lastModifiedBy / apiVersion for the enriched types."325 }326}327```328329Claude's presentation back to the user:330331> Freshness for `ApexClass:AccountController` is **not available**332> in this vault.333>334> v1.7 Tooling API enrichment has not run for this vault. Run335> `sfi refresh --with-tooling-api --target-org <alias>` to336> populate lastModifiedDate / lastModifiedBy / apiVersion for the337> enriched types (ApexClass, ApexTrigger, Flow, Layout,338> CustomField, ValidationRule).339>340> I can't tell you when this class was last touched from341> metadata alone — and I won't guess, because a deploy decision342> based on a fabricated date is worse than no answer.343344### Range-scan response (sfi.changed_since)345346Suppose the architect asks: "What changed in the Apex layer347since 2026-05-01?"348349The tool returns (illustrative):350351```json352{353 "data": {354 "since": "2026-05-01T00:00:00.000Z",355 "changed": [356 { "id": "ApexClass:AccountController", "apiName": "AccountController", "lastModifiedDate": "2026-05-15T12:34:56.000Z", "lastModifiedBy": { "id": "005xx00000ABCDE", "name": "Alice Adams" } },357 { "id": "ApexTrigger:AccountTrigger", "apiName": "AccountTrigger", "lastModifiedDate": "2026-05-12T09:00:00.000Z", "lastModifiedBy": { "id": "005xx00000FGHIJ", "name": "Bob Brown" } }358 ],359 "unenrichedCount": 47,360 "truncated": false361 }362}363```364365Claude's presentation back to the architect:366367> 2 components changed in the Apex layer since 2026-05-01:368>369> - `ApexClass:AccountController` — 2026-05-15, Alice Adams.370> - `ApexTrigger:AccountTrigger` — 2026-05-12, Bob Brown.371>372> Coverage note: 47 components of these types carry no373> freshness data — the v1.7 enrichment has only partially374> covered this vault. Run `sfi refresh --with-tooling-api` for375> full coverage; until then, treat this list as a lower bound,376> not an exhaustive one.377378## Boundary disclosure379380v1.7's freshness tier has well-defined gaps. Surface this list381whenever the user is about to act on the report, and **always**382when `enriched: false` or `unenrichedCount > 0`:383384- **Tooling API enrichment is opt-in.** Default `sfi refresh` does385 not call the API; freshness is null until `sfi refresh386 --with-tooling-api --target-org <alias>` runs. The skill says387 so plainly rather than fabricating dates.388- **Only six ComponentTypes are enriched.** v1.7 R3 covers389 ApexClass, ApexTrigger, Flow, Layout, CustomField, and390 ValidationRule. Other types (Profile, PermissionSet, Group,391 Role, SharingRule, RecordType, WorkflowRule, ApprovalProcess,392 AssignmentRule, AutoResponseRule, EscalationRule, DuplicateRule,393 MatchingRule, EmailTemplate, Letterhead, LightningComponentBundle,394 AuraDefinitionBundle, VisualforcePage, VisualforceComponent,395 NamedCredential, ConnectedApp, AuthProvider, RemoteSiteSetting,396 CspTrustedSite, ExternalDataSource, ExternalService, NetworkAccess,397 CustomMetadataRecord, CustomSettingRecord, GlobalValueSet,398 CustomLabel, StaticResource, PermissionSetAssignment,399 BusinessProcess, CustomTab, CustomApplication, QuickAction,400 PathAssistant) remain `enriched: false` even after enrichment401 runs. Future v1.7+ iterations may extend coverage.402- **`lastModifiedBy` is the LAST DEPLOYER, not the original403 author.** Salesforce's Tooling API surfaces the user who last404 touched the metadata in the running org. A class first authored405 by Bob in 2024, edited by Carol in 2025, then redeployed by406 Alice in May 2026 shows ONLY Alice in `lastModifiedBy`. The407 skill cites this caveat verbatim when the user's question is408 "who built this?" (as opposed to "who edited this last?").409- **Tooling API rate limit.** Salesforce caps the Tooling API at410 ~3,500 queries per rolling hour per org. The R2 enricher411 batches per-type but a large org with tens of thousands of412 components can take longer than a single hour to enrich413 completely. If `unenrichedCount` is still non-zero after a414 recent `--with-tooling-api` refresh, the org may have hit the415 rate limit; surface the possibility and recommend re-running416 the enricher after the rate-limit window resets.417- **Setup Audit Trail is NOT extracted.** Salesforce's per-action418 audit log (who changed what setting when, from which IP, etc.)419 is a separate API surface (`SetupAuditTrail`) v1.7 does not420 read. Questions like "who changed the OWD setting in March?"421 or "what permission did Alice grant on May 12?" require a422 separate `sf data query` against `SetupAuditTrail` — out of423 scope until a future v1.7.x extends to it.424- **`lastModifiedDate` lags wall-clock by query-time delta.** Even425 with fresh enrichment, the timestamp reflects the org's state426 at the moment the API was queried — typically seconds before427 the vault was written. At minute-level granularity, treat the428 timestamp as `lastModifiedDate ± query-window`.429- **Tooling-API-vs-DX-source can disagree.** When the running430 Apex class has been edited in the Developer Console (live) but431 the DX source has not been re-retrieved, the Tooling API's432 `LastModifiedDate` is fresher than what the offline extractor433 saw. v1.7 enrichment updates the freshness data but does NOT434 refresh structural extraction — the graph nodes/edges reflect435 DX source, the freshness reflects the API. Name this drift436 verbatim when the user's question is sensitive to it.437438Treat **`enriched: false`** verdicts as "v1.7 cannot tell" — not439as "never modified." Treat **`unenrichedCount > 0`** scans as440"partial answer, run the enricher for full coverage."441442## Anti-patterns443444| Mistake | Why it's wrong |445|---|---|446| Presenting `enriched: false` or `lastModifiedDate: null` as "this component was never modified" or "this is brand new". | `null` is a **gap**, not a value. v1.7's enrichment is opt-in; `null` means "we have no data," not "the component is fresh." Surface the gap as the disclosure says: enrichment has not run, run the enricher. |447| Estimating freshness from training-data priors ("classes typically get updated every sprint, so probably 2 weeks ago"). | The v1.7 honesty axis is constitutional. Fabricated freshness is worse than no freshness because a deploy decision based on a fabricated date is unrecoverable. Refuse honestly. |448| Conflating `lastModifiedBy` with the original author. | `lastModifiedBy` names the user who last *deployed* the change. A 5-year-old class that Alice redeployed yesterday will list Alice, not the original 2021 author. Cite the caveat verbatim when the question is about authorship. |449| Ignoring `unenrichedCount` in the `changed_since` response. | A `changed: []` result with `unenrichedCount: 47` means "we can't tell"; a `changed: []` with `unenrichedCount: 0` means "genuinely nothing changed." Surfacing only `changed.length === 0` collapses both into "nothing changed" and misleads the consumer. |450| Citing `apiVersion: null` as "this class is on the latest API". | `null` is the same gap as the others — no enrichment, no data. The class's *running* API version is whatever the Tooling API would return; until the enricher fills it, the skill says so. |451| Running `sfi.last_modified` against a record-row id (`001xx12345`) instead of a component id. | v1.7 freshness covers component metadata (the field definition), not record rows. The handler returns `component-not-found`; translate the question to live-data shape ("query `Account.SystemModstamp` via `sf data query`") and disclose the shift. |452| Treating "I checked `sfi.last_modified` and it returned `enriched: true`" as proof a component is in active use. | Freshness is "when was the metadata last touched," not "is anyone using this." A class deployed yesterday may have zero callers; a class untouched since 2020 may be the org's load-bearing core. Use `sfi.find_code_usages` for usage, `sfi.last_modified` for freshness, and never confuse the two. |453| Skipping the boundary disclosure when `enriched: true` for one component but the user's question implies a broader sweep. | The disclosure protects the user's mental model. A single-component happy path doesn't mean the vault as a whole is enriched. When the user's question implies "across the org," the disclosure goes in even if the cited component happens to be enriched. |454| Suggesting "run a SOQL query to check" without naming `sf data query --target-org <alias>` and the specific object (`ApexClass`, `Flow`, `FieldDefinition`, etc.). | The user needs an executable next step. "Run a SOQL query" is too vague; "run `sf data query --target-org <alias> --query 'SELECT LastModifiedDate, LastModifiedBy.Name FROM ApexClass WHERE Name = ''AccountController'''` " is the load-bearing instruction. |455456## Example interactions457458### Example 1 — Component freshness on an un-enriched vault459460User: *"When was the `AccountController` Apex class last modified?"*461462Claude's flow:4634641. **Parse.** Component target = `ApexClass:AccountController`.4652. **Fire** `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }` with466 `{ componentId: 'ApexClass:AccountController' }`.4673. The tool returns `enriched: false`, every freshness field468 `null`, and the verbatim disclosure.4694. **Refuse honestly** with the disclosure surfaced verbatim:470 "v1.7 Tooling API enrichment has not run for this vault. Run471 `sfi refresh --with-tooling-api --target-org <alias>` to472 populate lastModifiedDate / lastModifiedBy / apiVersion for473 the enriched types. I can't tell you when this class was last474 touched from metadata alone — and I won't guess."4755. **Cite the boundary** — enrichment is opt-in; only six types476 are covered when it runs.477478### Example 2 — Range scan with partial enrichment479480User: *"What changed in the Flow layer since the May 1 release?"*481482Claude's flow:4834841. **Parse.** Time-range target. `since = '2026-05-01'`,485 `types = ['Flow']`.4862. **Fire** `sfi.run_analysis` with `{ "name": "sfi.changed_since", "args": { … } }` with487 `{ since: '2026-05-01', types: ['Flow'] }`.4883. The tool returns489 `changed: [{ id: 'Flow:Lead_Nurture', lastModifiedDate: '...', lastModifiedBy: {...} }, ...]`,490 `unenrichedCount: 12`, `truncated: false`.4914. **Render** the grouped list — apiName / modifier name /492 timestamp per row.4935. **Surface the coverage note** verbatim: "12 Flow components494 carry no freshness data — the v1.7 enrichment has only495 partially covered this vault. Treat this list as a lower496 bound; run `sfi refresh --with-tooling-api` for full497 coverage."498499### Example 3 — Question about an unsupported ComponentType500501User: *"Who built the `Sales_Manager` profile?"*502503Claude's flow:5045051. **Parse.** Component target = `Profile:Sales_Manager`. Note:506 Profile is NOT in v1.7's enriched-type list.5072. **Fire** `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }` with508 `{ componentId: 'Profile:Sales_Manager' }`.5093. The tool returns `enriched: false` even if the vault was510 refreshed with `--with-tooling-api` (Profile is uncovered).5114. **Disclose the type-coverage boundary**, not just the512 enrichment-not-run line: "v1.7 R3's Tooling API enrichment513 covers ApexClass, ApexTrigger, Flow, Layout, CustomField, and514 ValidationRule — Profile is not yet covered. Until a future515 iteration extends coverage, the freshness fields for516 `Profile:Sales_Manager` remain `null`."5175. **Offer the live-data fallback**: "If you need this now, run518 `sf data query --target-org <alias> --query 'SELECT519 LastModifiedDate, LastModifiedBy.Name FROM Profile WHERE520 Name = ''Sales_Manager'''` against your org directly."521522### Example 4 — Authorship vs. last-deployer disambiguation523524User: *"Who originally wrote the `Lead_Nurture` flow?"*525526Claude's flow:5275281. **Parse.** Component target = `Flow:Lead_Nurture`. The529 question shape is *authorship* — distinct from530 `lastModifiedBy`.5312. **Fire** `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }` with532 `{ componentId: 'Flow:Lead_Nurture' }`.5333. The tool returns `enriched: true`,534 `lastModifiedBy: { id: '005xx...', name: 'Alice Adams' }`.5354. **Surface the value AND the authorship caveat verbatim**:536 "v1.7's `lastModifiedBy` names the user who last *deployed*537 the change — Alice Adams here. That is NOT necessarily the538 original author. A flow first built by Bob in 2024 and last539 re-saved by Alice in May 2026 shows only Alice. For the540 original author, check the org's Setup Audit Trail (`sf data541 query --target-org <alias> --query 'SELECT CreatedBy.Name,542 CreatedDate FROM Flow WHERE Name = ''Lead_Nurture'''`)."543544## Verification545546Before sending a response, confirm:547548- [ ] I identified the question target — component (use549 `sfi.last_modified`) or time-range (use550 `sfi.changed_since`).551- [ ] If component target: I translated the user's reference into552 a canonical `{Type}:{ApiName}` id, using553 `sfi.search_components` when the reference was ambiguous.554- [ ] If time-range target: I translated relative phrasing555 ("last Tuesday", "the deploy") into a concrete ISO 8601556 `since`, asking the user when the phrasing was genuinely557 vague.558- [ ] I called `sfi.run_analysis` for `sfi.last_modified` or `sfi.changed_since` exactly559 once per coherent question. (Component-by-component560 iteration for a list is acceptable; round-tripping the same561 id is not.)562- [ ] When `enriched: false` (or `lastModifiedDate: null`), I563 surfaced the disclosure verbatim and did NOT fabricate a564 date.565- [ ] When `unenrichedCount > 0`, I surfaced the partial-coverage566 note before presenting the `changed` list.567- [ ] I cited the `lastModifiedBy` caveat (last deployer, not568 original author) when the user's question was about569 authorship.570- [ ] I cited canonical IDs (`ApexClass:...`, `Flow:...`,571 `CustomField:...`) for every component named.572- [ ] When the target ComponentType was outside v1.7's enriched573 set (Profile, PermissionSet, etc.), I named the type-coverage574 boundary explicitly and offered the live-data575 `sf data query` fallback.576- [ ] I did not estimate freshness from training-data priors,577 apiVersion extrapolation, or sourcetree-hash inference. The578 honesty axis is constitutional.579580---581582**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). **Default tool profile is `core`:** only the core spine (including `sfi.live_consent`) is directly invokable. For every other `sfi.*` analysis, call `sfi.run_analysis` with `{ "name": "sfi.<tool>", "args": { … } }` (or follow `route_question.invoke`, which already wraps non-core steps). Optional: `sfi.describe_analysis` first when args are unclear. 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`.
Run npx skillmds@latest add pranavnagrecha/freshness-tracking in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Answers Salesforce admin/architect freshness questions like "when was X modified?", "who built this?", "what changed since last week?", "has this been touched since go-live?", "what changed in the last sprint?". Call `sfi.run_analysis` with `{ "name": "sfi.last_modified", "args": { … } }` and `sfi.changed_since`. Discloses v1.7 honesty axis: when Tooling API enrichment hasn't run, returns `enriched: false` with explicit guidance to run `sfi refresh --with-tooling-api`; never fabricates dates. It is listed under Integrations & APIs on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
PranavNagrecha (@pranavnagrecha) published this skill. Their other Agent Skills are listed on their SkillMD profile.