Experience Cms Brand Create
forcedotcom/sf-skills
Author a Salesforce Digital Experience brand (a "brand.json") so the VS Code Brand Toolkit can load, edit, and preview it.
Consume the salesforcedx-vscode-services extension API. An agent skill from forcedotcom/salesforcedx-vscode.
$ npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install forcedotcom/salesforcedx-vscode services-extension-consumption --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/forcedotcom/salesforcedx-vscode.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/services-extension-consumption .claude/skills/services-extension-consumption && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "services-extension-consumption" agent skill from https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/.claude/skills/services-extension-consumption into .claude/skills/services-extension-consumption/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "services-extension-consumption", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/.claude/skills/services-extension-consumptionType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install forcedotcom/salesforcedx-vscode services-extension-consumption --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/salesforcedx-vscode.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/services-extension-consumption .agents/skills/services-extension-consumption && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "services-extension-consumption" agent skill from https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/.claude/skills/services-extension-consumption into .agents/skills/services-extension-consumption/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "services-extension-consumption", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install forcedotcom/salesforcedx-vscode services-extension-consumption --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/salesforcedx-vscode.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/services-extension-consumption .cursor/skills/services-extension-consumption && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "services-extension-consumption" agent skill from https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/.claude/skills/services-extension-consumption into .cursor/skills/services-extension-consumption/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "services-extension-consumption", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/forcedotcom/salesforcedx-vscode.git --path .claude/skills/services-extension-consumption--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install forcedotcom/salesforcedx-vscode services-extension-consumption --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/salesforcedx-vscode.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/services-extension-consumption .gemini/skills/services-extension-consumption && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "services-extension-consumption" agent skill from https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/.claude/skills/services-extension-consumption into .gemini/skills/services-extension-consumption/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "services-extension-consumption", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install forcedotcom/salesforcedx-vscode services-extension-consumptionInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/forcedotcom/salesforcedx-vscode.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/services-extension-consumption .github/skills/services-extension-consumption && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "services-extension-consumption" agent skill from https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/.claude/skills/services-extension-consumption into .github/skills/services-extension-consumption/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "services-extension-consumption", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install forcedotcom/salesforcedx-vscode services-extension-consumption --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/salesforcedx-vscode.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/services-extension-consumption .opencode/skills/services-extension-consumption && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "services-extension-consumption" agent skill from https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/.claude/skills/services-extension-consumption into .opencode/skills/services-extension-consumption/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "services-extension-consumption", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
services-extension-consumptionConsume the salesforcedx-vscode-services extension API. An agent skill from forcedotcom/salesforcedx-vscode.
Services Extension Consumption is an agent skill from forcedotcom/salesforcedx-vscode. Consume the salesforcedx-vscode-services extension API. Use when an extension depends on salesforcedx-vscode-services and you are registering commands, calling its services (Workspace, Connection, Project, Settings, FS, Channel, Media, prompts), watching files/config/target-org, or wiring the AllServicesLayer/runtime in extensionProvider.ts.
Its SKILL.md is about 5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 13 other files, including reference files (for example `references/channel-service.md`, `references/component-set-service.md` and `references/connection-service.md`).
It sits in Sales & Support. It works with Visual Studio Code and Salesforce. The repository describes itself as: Salesforce Extensions for VS Code. The licence is BSD-3-Clause.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 27807f6. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Services Extension Consumption loads about 5k tokens when it runs, and up to ~13k if it reads all its reference files. Until then it costs about 94 tokens; SKILL.md has 1,086 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from forcedotcom/salesforcedx-vscode at commit 27807f6, republished under its BSD-3-Clause licence (© forcedotcom). 1,086 words, ~4,990 tokens.
.claude/skills/services-extension-consumption/SKILL.md (or your agent's skills folder). This skill also uses 12 other files; get the full folder from GitHub.Extensions depending on salesforcedx-vscode-services. Examples: salesforcedx-vscode-metadata, salesforcedx-vscode-org-browser.
Use ExtensionProviderService from @salesforce/effect-ext-utils:
import { ExtensionProviderService, getServicesApi } from '@salesforce/effect-ext-utils';
const ExtensionProviderServiceLive = Layer.effect(
ExtensionProviderService,
Effect.sync(() => ({
getServicesApi
}))
);
// In an Effect.gen:
const api = yield * (yield * ExtensionProviderService).getServicesApi;api.services.prebuiltServicesLayer — shared service instances plus redacting-logger FiberRef. Not the OTEL tracer. Provide or merge this layer directly.
api.services.prebuiltServicesDependencies — deprecated context-only field. Omits FiberRefs; use prebuiltServicesLayer.
Shares singleton instances (caches, watchers) across extensions; avoids re-building stateful services.
Per-extension layers (must build yourself):
| Layer | Why |
|---|---|
ChannelServiceLayer(displayName) | Own output channel |
ErrorHandlerService.Default | Depends on own ChannelService |
ExtensionContextServiceLayer(context) | Own ExtensionContext |
SdkLayerFor(context) | Own tracer (extension name/version in resource attributes) |
ExtensionProviderServiceLive | Local singleton |
Preferred: import buildAllServicesLayer from @salesforce/effect-ext-utils. It reads displayName from package.json, falling back to the second arg. services/extensionProvider.ts only needs the mutable AllServicesLayer + setter:
// services/extensionProvider.ts
import { buildAllServicesLayer } from '@salesforce/effect-ext-utils';
export let AllServicesLayer: ReturnType<typeof buildAllServicesLayer>;
export const setAllServicesLayer = (layer: ReturnType<typeof buildAllServicesLayer>) => {
AllServicesLayer = layer;
};In activate — pass the context and a localized fallback channel name:
import { buildAllServicesLayer } from '@salesforce/effect-ext-utils';
import { nls } from './messages';
import { setAllServicesLayer } from './services/extensionProvider';
export const activate = async (context: vscode.ExtensionContext): Promise<void> => {
setAllServicesLayer(buildAllServicesLayer(context, nls.localize('channel_name')));
await getRuntime().runPromise(activateEffect(context));
};Two patterns exist depending on whether the extension adds services beyond the shared base:
core, apex, apex-testing, lightning, lwc, org, visualforce): import buildAllServicesLayer directly from @salesforce/effect-ext-utils and pass it to setAllServicesLayer at activation. No local factory needed.apex-debugger, apex-log, apex-oas, apex-replay-debugger, metadata, org-browser, soql): define a local buildAllServicesLayer in services/extensionProvider.ts that calls buildSharedServicesLayer from @salesforce/effect-ext-utils and merges the extension's own Effect services via Layer.mergeAll. The extra services vary — apex-oas adds ApexMetadataService and LLMService; extensions with the notifications system add NotificationModeService.Default; org-browser adds OrgBrowserRetrieveService.buildAllServicesLayer merges suppressVersionMismatchWarning. Extension code keeps ManagedRuntime.make(AllServicesLayer); do not wrap it. The services activation runtime inlines Layer.setVersionMismatchErrorLogLevel(Option.none()) because it cannot import effect-ext-utils.ManagedRuntime.make(AllServicesLayer) and export getRuntime().getRuntime().runPromise(effect) / runFork(effect) for ad-hoc execution.Effect.provide(AllServicesLayer) at call sites — use the runtime instead.export const disposeRuntime = async (): Promise<void> => {
if (_runtime) {
await _runtime.dispose();
_runtime = undefined;
}
};
export const deactivate = async (): Promise<void> => {
await getRuntime().runPromise(deactivation()).finally(disposeRuntime);
};Prefer Effect scope ownership for resources created inside Effect services/layers:
scoped.Disposables with Effect.addFinalizer.Effect.forkIn.ManagedRuntime on deactivation so layer finalizers run.runDispose/dispose solely for consumers to add to context.subscriptions.context.subscriptions for resources created outside an Effect scope.Allocation and cleanup stay together. See ../effect-best-practices/SKILL.md#effect-owned-resources.
Use registerCommandWithRuntime:
import { myCommandEffect } from './commands/myCommand';
const api = yield * (yield * ExtensionProviderService).getServicesApi;
const registerCommand = api.services.registerCommandWithRuntime(getRuntime());
yield * registerCommand('sf.my.command', myCommandEffect);Commands auto:
activate() awaits getRuntime().runPromise(activateEffect(context)); it does not detach the main activation Effect. Only work explicitly started with Effect.fork* continues after activation completes.
Register all manifest-contributed UI before awaiting work that can be slow or unresolved:
Disposable in context.subscriptions when it is not scope-owned.Effect.forkIn for long-lived watchers that do not need to block activation.when clauses can expose a contributed command before its handler has registered. A context key owned by another extension, including sf:has_target_org, is a visibility hint, not proof that this extension has initialized. Do not make a contributed handler's registration depend on it. Keep target-org and authorization checks in the command implementation or shared service layer.
export const activateEffect = Effect.fn(`activation:${EXTENSION_NAME}`)(function* (context: vscode.ExtensionContext) {
const api = yield* (yield* ExtensionProviderService).getServicesApi;
const provider = new MyTreeProvider();
context.subscriptions.push(vscode.window.registerTreeDataProvider(VIEW_ID, provider));
yield* setInitialContext();
const registerCommand = api.services.registerCommandWithRuntime(getRuntime());
yield* registerCommand('sf.my.command', () => myCommand(provider));
yield* Effect.promise(() => vscode.commands.executeCommand('setContext', 'sf:myExtension.ready', true));
// Command registration must not wait for org-backed initialization.
yield* api.services.ConnectionService.getConnection();
});Effect.fn middleware runs left to right after the generator. Effect.tap and *SuccessNotification before catch* (catch, catchAll, catchAllCause, catchCause, catchCauseIf, catchIf, catchSome, catchSomeCause, catchTag, catchTags) — a success combinator after catch treats recovery as success. Later catch valid. Later non-success guard (preventOrgChanges) valid. Lint: local/effect-fn-catch-middleware-last on spanned Effect.fn (fn('span'), fn('name', options)). Skips fnUntraced, unspanned fn(function*), generator-body catch, .pipe catch.
export const deployActiveEditorCommand = Effect.fn('deploySourcePath.deployActiveEditor')(
function* () {
// ...core logic...
},
// runs only on success — placed before catchTag
withConfigurableSuccessNotification(nls.localize('command_succeeded_text', label)),
// catches errors — placed after success middleware
Effect.catchTag('NoActiveEditorError', () =>
Effect.promise(() => vscode.window.showErrorMessage(nls.localize('deploy_select_file_or_directory'))).pipe(
Effect.as(undefined)
)
)
);withConfigurableSuccessNotification wraps the effect with Effect.tap, so it only fires when the effect succeeds:
export const withConfigurableSuccessNotification =
(message: string) =>
<A, E, R>(effect: Effect.Effect<A, E, R>) =>
Effect.tap(effect, () =>
Effect.sync(() => {
const show = vscode.workspace.getConfiguration(SECTION).get<boolean>(KEY, false);
if (show) void vscode.window.showInformationMessage(message);
})
);sf.org.login.webCross-extension / executeCommand: vscode.commands.executeCommand('sf.org.login.web', instanceUrl?, reauthAliasOrUsername?).
instanceUrl: skips org-type quick pick.instanceUrl was provided: trimmed non-empty string becomes the auth alias (access-token re-auth); else alias defaults to reauth-vscodeOrg.Accessor pattern: call methods directly, don't assign to variable first.
HashableUri (comparisonKey of URI fields, not .toString())OrgMetadataCatalog - inventory/presence; getChildren / getEntries / resolveComponents. Types: catalog + entries, OrgMetadataCatalogError (type-only), OrgMetadataComponentReference, OrgMetadataCatalogChange. ADR 0021TransmogrifierService - REST/workspace SObject describe → canonical SObject. Types: TransmogrifierService, TransmogrifierError (type-only)FileChangePubSub — workspace FS (**/*), including project .sf/config.json. Filter event.uri / uri.path / Utils.*, not uri.fsPath.
Global ~/.sf/config.json and ~/.sfdx/alias.json: HostFileWatcher (internal, @salesforce/core/fs). Not on the public API; services already watch them. See FileChangePubSub vs HostFileWatcher.
import * as Stream from 'effect/Stream';
const pubsub = yield* api.services.FileChangePubSub;
yield* Stream.fromPubSub(pubsub).pipe(
Stream.filter(event => /* event.uri / uri.path / Utils.*; not uri.fsPath */),
Stream.runForEach(event =>
Effect.sync(() => {
// { type: 'create'|'change'|'delete', uri }
})
)
);Watch VS Code config changes:
import * as PubSub from 'effect/PubSub';
import * as Stream from 'effect/Stream';
import * as Duration from 'effect/Duration';
const pubsub = yield * PubSub.sliding<vscode.ConfigurationChangeEvent>(100);
const disposable = vscode.workspace.onDidChangeConfiguration(event => {
Effect.runSync(PubSub.publish(pubsub, event));
});
yield *
Effect.addFinalizer(() =>
Effect.sync(() => {
disposable?.dispose();
})
);
yield *
Stream.fromPubSub(pubsub).pipe(
Stream.filter(event => event.affectsConfiguration('section.setting')),
Stream.debounce(Duration.millis(100)),
Stream.runForEach(() => {
// Handle config change
})
);Watch org changes via TargetOrgRef (SubscriptionRef):
const ref = yield * api.services.TargetOrgRef();
yield *
ref.changes.pipe(
Stream.map(org => org.orgId),
Stream.changes,
Stream.tap(orgId => {
// Handle org change
}),
Stream.runForEach(() => {
// Refresh UI, invalidate caches, etc.
})
);TargetOrgRef is a SubscriptionRef: ref.changes already emits the current value first, so never prepend an explicit get. See the SubscriptionRef section of ../effect-best-practices/SKILL.md for the mechanic (incl. Stream.drop(1) to skip the initial snapshot).
Ref behavior (concise):
conn.getUsername() / AuthInfo login username.TargetOrgRef (DefaultOrgInfoSchema) value is always an object (never undefined); orgId/devHubOrgId are optional branded OrgId (Schema.optional(OrgId), like cliId).Call ClearDefaultOrgRef() to reset the in-process org ref (e.g., after deleting the default org):
yield* api.services.ClearDefaultOrgRef();Clears the reactive ref without rewriting config. Use when the CLI already mutated config but the in-process ref must reset to notify observers (e.g., the source tracking status bar icons). See orgDeleteDefaultCommand for an example.
// services/extensionProvider.ts
import { buildAllServicesLayer } from '@salesforce/effect-ext-utils';
export let AllServicesLayer: ReturnType<typeof buildAllServicesLayer>;
export const setAllServicesLayer = (layer: ReturnType<typeof buildAllServicesLayer>) => {
AllServicesLayer = layer;
};
// services/runtime.ts
import * as ManagedRuntime from 'effect/ManagedRuntime';
import { AllServicesLayer } from './extensionProvider';
const createRuntime = () => ManagedRuntime.make(AllServicesLayer);
let _runtime: ReturnType<typeof createRuntime> | undefined;
export const getRuntime = () => (_runtime ??= createRuntime());
// index.ts
import { buildAllServicesLayer } from '@salesforce/effect-ext-utils';
import { nls } from './messages';
import { myCommandEffect } from './commands/myCommand';
import { setAllServicesLayer } from './services/extensionProvider';
import { getRuntime } from './services/runtime';
export const activate = async (context: vscode.ExtensionContext) => {
setAllServicesLayer(buildAllServicesLayer(context, nls.localize('channel_name')));
await getRuntime().runPromise(activateEffect(context));
};
export const activateEffect = Effect.fn(`activation:${EXTENSION_NAME}`)(function* (_context: vscode.ExtensionContext) {
const providerService = yield* ExtensionProviderService;
const api = yield* providerService.getServicesApi;
yield* api.services.ChannelService.appendToChannel('Extension activating');
const registerCommand = api.services.registerCommandWithRuntime(getRuntime());
yield* registerCommand('sf.my.command', myCommandEffect);
yield* api.services.ChannelService.appendToChannel('Extension activation complete.');
});Mock services via Layer.succeed and combine with Layer.mergeAll. For static accessors (e.g., api.services.WorkspaceService.getWorkspaceInfo()), wire both the provider and service:
import { ExtensionProviderService } from '@salesforce/effect-ext-utils';
import { WorkspaceService } from 'salesforcedx-vscode-services/src/vscode/workspaceService';
import * as Effect from 'effect/Effect';
import * as Layer from 'effect/Layer';
// Mock both ExtensionProviderService and WorkspaceService
const mockWorkspaceLayer = Layer.mergeAll(
Layer.succeed(ExtensionProviderService, {
getServicesApi: Effect.succeed({
services: { WorkspaceService } // Accessor sees real class
} as unknown as SalesforceVSCodeServicesApi)
}),
Layer.succeed(
WorkspaceService,
new WorkspaceService({
getWorkspaceInfo: () => Effect.succeed({ path: '/mock', fsPath: '/mock', isEmpty: false, isVirtualFs: false, cwd: '/mock' }),
getWorkspaceInfoOrThrow: () => Effect.succeed(/* ... */)
} as unknown as WorkspaceService)
)
);
// Use in test
const result = await Effect.runPromise(
myEffect().pipe(Effect.provide(mockWorkspaceLayer))
);For direct service mocking (no accessor), use Layer.succeed(Service, mockImpl) alone.
api.services.prebuiltServicesLayer — don't add individual *.Default for services already thereimport { ICONS } outside Effect; MediaService inside EffectChannelServiceLayer before ErrorHandlerServicecontext to SdkLayerFor (extracts name/version from ExtensionContext)Effect.forkIn(..., yield* getExtensionScope()) for watcher cleanup on deactivationregisterCommandWithRuntime for all commands (tracing + error handling)getRuntime().runPromise / runFork instead of Effect.provide(AllServicesLayer) for execution// WRONG — creates new singleton instances, duplicating caches/watchers/state
return Layer.mergeAll(
ExtensionProviderServiceLive,
api.services.ExtensionContextServiceLayer(context),
api.services.FsService.Default, // ← already in prebuilt
api.services.AliasService.Default, // ← already in prebuilt
api.services.SdkLayerFor(context),
channelLayer,
errorHandlerWithChannel
);
// CORRECT — share the already-built singletons
return Layer.mergeAll(
api.services.prebuiltServicesLayer,
ExtensionProviderServiceLive,
api.services.ExtensionContextServiceLayer(context),
api.services.SdkLayerFor(context),
channelLayer,
errorHandlerWithChannel
);Invoke the effect-advocate subagent on plans and diffs — its top-priority finding category is "you re-implemented something that already exists in salesforcedx-vscode-services."
prebuiltServicesLayer contains ~27 services built once during services extension activation. Calling .Default on any of them creates a second instance with its own caches, watchers, and state — silently breaking cross-extension sharing.
© forcedotcom, BSD-3-Clause. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 12 other files (references) in .claude/skills/services-extension-consumption of forcedotcom/salesforcedx-vscode.
Open the folder on GitHubat commit 27807f6
Services Extension Consumption next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Services Extension Consumption this skillforcedotcom/salesforcedx-vscode | 1k | — | ~5k | Automated safety check: Pass | BSD-3-Clause | |
| Experience Cms Brand Createforcedotcom/sf-skills | 1.1k | — | ~2.8k | Automated safety check: Pass | Apache-2.0 | |
| Sf ApexJaganpro/sf-skills | 424 | — | ~2k | Automated safety check: Pass | MIT | |
| Sf DebugJaganpro/sf-skills | 424 | — | ~1.3k | Automated safety check: Pass | MIT | |
| Experience UI Bundle Custom App Generateforcedotcom/sf-skills | 1.1k | — | ~2.3k | Automated safety check: Pass | Apache-2.0 | |
| Churn Riskindranilbanerjee/digital-marketing-pro | 855 | 1 repos | ~2.4k | Automated safety check: Pass | MIT |
forcedotcom/sf-skills
Author a Salesforce Digital Experience brand (a "brand.json") so the VS Code Brand Toolkit can load, edit, and preview it.
Jaganpro/sf-skills
Generates and reviews Salesforce Apex code with 150-point scoring.
Jaganpro/sf-skills
Salesforce debug log analysis and troubleshooting with 100-point scoring.
forcedotcom/sf-skills
MUST activate when the project contains a uiBundles//src/ directory and the task involves creating or configuring a Custom Application for hosting a UI bundle in Lightning Experience.
indranilbanerjee/digital-marketing-pro
Score customer segments for churn risk from behavioral signals — email engagement decline, purchase recency, usage drops, support sentiment — producing a 0-100 risk scorecard with four tiers…
indranilbanerjee/digital-marketing-pro
Import leads into Salesforce, HubSpot, Zoho, or Pipedrive with validation, deduplication against existing CRM records, lead scoring, consent and compliance checks, and source attribution — then push…
forcedotcom/salesforcedx-vscode
Command palette, CodeLens, context menus, package.nls titles, and NotificationModeService.
forcedotcom/salesforcedx-vscode
Polish the automated CHANGELOG on develop before the next stable build.
forcedotcom/salesforcedx-vscode
Public API exported by salesforcedx-vscode-core activate(). An agent skill from forcedotcom/salesforcedx-vscode.
forcedotcom/salesforcedx-vscode
Operate a real VS Code instance through drivable-vscode. An agent skill from forcedotcom/salesforcedx-vscode.
forcedotcom/salesforcedx-vscode
Enforces Effect-TS patterns for services, errors, layers, atoms, and Effect.pipe composition.
forcedotcom/salesforcedx-vscode
Known external consumers of APIs from this monorepo's extensions.
Works with
Categories
Consume the salesforcedx-vscode-services extension API. An agent skill from forcedotcom/salesforcedx-vscode. Services Extension Consumption is an agent skill from forcedotcom/salesforcedx-vscode. Consume the salesforcedx-vscode-services extension API.
Services Extension Consumption fits situations like: an extension depends on salesforcedx-vscode-services and you are registering commands; calling its services (Workspace; watching files/config/target-org; wiring the AllServicesLayer/runtime in extensionProvider.ts.
Run `npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a claude-code`. Or copy the skill folder (.claude/skills/services-extension-consumption in forcedotcom/salesforcedx-vscode) into .claude/skills/services-extension-consumption in your project. Claude Code loads it when a task matches its description.
Run `npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a codex`. Or copy the skill folder (.claude/skills/services-extension-consumption in forcedotcom/salesforcedx-vscode) into .agents/skills/services-extension-consumption in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add forcedotcom/salesforcedx-vscode --skill services-extension-consumption -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/services-extension-consumption, .gemini/skills/services-extension-consumption, .github/skills/services-extension-consumption and .opencode/skills/services-extension-consumption in your project.
SKILL.md names no scripts, command-line tools or credentials: Services Extension Consumption is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Services Extension Consumption is published under the BSD-3-Clause licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5k tokens (SKILL.md is roughly 20k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 8.4k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Services Extension Consumption: Experience Cms Brand Create (forcedotcom/sf-skills, 1.1k stars), Sf Apex (Jaganpro/sf-skills, 424 stars), Sf Debug (Jaganpro/sf-skills, 424 stars) and Experience UI Bundle Custom App Generate (forcedotcom/sf-skills, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
forcedotcom (a GitHub organization) maintains it in forcedotcom/salesforcedx-vscode, which has 1,035 GitHub stars. The repository holds 37 skills in this directory. The repository was last updated on October 8, 2026.
Source: forcedotcom/salesforcedx-vscode on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.